Line data Source code
1 : // SPDX-License-Identifier: GPL-2.0
2 : /*
3 : * Copyright (c) 2000-2005 Silicon Graphics, Inc.
4 : * All Rights Reserved.
5 : */
6 : #include "xfs.h"
7 : #include "xfs_fs.h"
8 : #include "xfs_shared.h"
9 : #include "xfs_format.h"
10 : #include "xfs_log_format.h"
11 : #include "xfs_trans_resv.h"
12 : #include "xfs_sb.h"
13 : #include "xfs_mount.h"
14 : #include "xfs_trans.h"
15 : #include "xfs_error.h"
16 : #include "xfs_alloc.h"
17 : #include "xfs_fsops.h"
18 : #include "xfs_trans_space.h"
19 : #include "xfs_log.h"
20 : #include "xfs_log_priv.h"
21 : #include "xfs_ag.h"
22 : #include "xfs_ag_resv.h"
23 : #include "xfs_trace.h"
24 : #include "xfs_rtgroup.h"
25 : #include "xfs_rtalloc.h"
26 : #include "xfs_rtrmap_btree.h"
27 : #include "xfs_rtrefcount_btree.h"
28 :
29 : /*
30 : * Write new AG headers to disk. Non-transactional, but need to be
31 : * written and completed prior to the growfs transaction being logged.
32 : * To do this, we use a delayed write buffer list and wait for
33 : * submission and IO completion of the list as a whole. This allows the
34 : * IO subsystem to merge all the AG headers in a single AG into a single
35 : * IO and hide most of the latency of the IO from us.
36 : *
37 : * This also means that if we get an error whilst building the buffer
38 : * list to write, we can cancel the entire list without having written
39 : * anything.
40 : */
41 : static int
42 90 : xfs_resizefs_init_new_ags(
43 : struct xfs_trans *tp,
44 : struct aghdr_init_data *id,
45 : xfs_agnumber_t oagcount,
46 : xfs_agnumber_t nagcount,
47 : xfs_rfsblock_t delta,
48 : struct xfs_perag *last_pag,
49 : bool *lastag_extended)
50 : {
51 90 : struct xfs_mount *mp = tp->t_mountp;
52 90 : xfs_rfsblock_t nb = mp->m_sb.sb_dblocks + delta;
53 90 : int error;
54 :
55 90 : *lastag_extended = false;
56 :
57 90 : INIT_LIST_HEAD(&id->buffer_list);
58 90 : for (id->agno = nagcount - 1;
59 7780 : id->agno >= oagcount;
60 7690 : id->agno--, delta -= id->agsize) {
61 :
62 7690 : if (id->agno == nagcount - 1)
63 86 : id->agsize = nb - (id->agno *
64 86 : (xfs_rfsblock_t)mp->m_sb.sb_agblocks);
65 : else
66 7604 : id->agsize = mp->m_sb.sb_agblocks;
67 :
68 7690 : error = xfs_ag_init_headers(mp, id);
69 7690 : if (error) {
70 0 : xfs_buf_delwri_cancel(&id->buffer_list);
71 0 : return error;
72 : }
73 : }
74 :
75 90 : error = xfs_buf_delwri_submit(&id->buffer_list);
76 90 : if (error)
77 : return error;
78 :
79 90 : if (delta) {
80 28 : *lastag_extended = true;
81 28 : error = xfs_ag_extend_space(last_pag, tp, delta);
82 : }
83 : return error;
84 : }
85 :
86 : /*
87 : * growfs operations
88 : */
89 : static int
90 336 : xfs_growfs_data_private(
91 : struct xfs_mount *mp, /* mount point for filesystem */
92 : struct xfs_growfs_data *in) /* growfs data input struct */
93 : {
94 336 : struct xfs_buf *bp;
95 336 : int error;
96 336 : xfs_agnumber_t nagcount;
97 336 : xfs_agnumber_t nagimax = 0;
98 336 : xfs_rfsblock_t nb, nb_div, nb_mod;
99 336 : int64_t delta;
100 336 : bool lastag_extended = false;
101 336 : xfs_agnumber_t oagcount;
102 336 : struct xfs_trans *tp;
103 336 : struct aghdr_init_data id = {};
104 336 : struct xfs_perag *last_pag;
105 :
106 336 : nb = in->newblocks;
107 336 : error = xfs_sb_validate_fsb_count(&mp->m_sb, nb);
108 336 : if (error)
109 : return error;
110 :
111 336 : if (nb > mp->m_sb.sb_dblocks) {
112 90 : error = xfs_buf_read_uncached(mp->m_ddev_targp,
113 90 : XFS_FSB_TO_BB(mp, nb) - XFS_FSS_TO_BB(mp, 1),
114 : XFS_FSS_TO_BB(mp, 1), 0, &bp, NULL);
115 90 : if (error)
116 : return error;
117 90 : xfs_buf_relse(bp);
118 : }
119 :
120 : /* Make sure the new fs size won't cause problems with the log. */
121 336 : error = xfs_growfs_check_rtgeom(mp, nb, mp->m_sb.sb_rblocks,
122 : mp->m_sb.sb_rextsize, mp->m_sb.sb_rextents,
123 : mp->m_sb.sb_rbmblocks, mp->m_sb.sb_rextslog);
124 336 : if (error)
125 : return error;
126 :
127 336 : nb_div = nb;
128 336 : nb_mod = do_div(nb_div, mp->m_sb.sb_agblocks);
129 336 : if (nb_mod && nb_mod >= XFS_MIN_AG_BLOCKS)
130 298 : nb_div++;
131 38 : else if (nb_mod)
132 8 : nb = nb_div * mp->m_sb.sb_agblocks;
133 :
134 336 : if (nb_div > XFS_MAX_AGNUMBER + 1) {
135 0 : nb_div = XFS_MAX_AGNUMBER + 1;
136 0 : nb = nb_div * mp->m_sb.sb_agblocks;
137 : }
138 336 : nagcount = nb_div;
139 336 : delta = nb - mp->m_sb.sb_dblocks;
140 : /*
141 : * Reject filesystems with a single AG because they are not
142 : * supported, and reject a shrink operation that would cause a
143 : * filesystem to become unsupported.
144 : */
145 336 : if (delta < 0 && nagcount < 2)
146 : return -EINVAL;
147 :
148 336 : oagcount = mp->m_sb.sb_agcount;
149 : /* allocate the new per-ag structures */
150 336 : if (nagcount > oagcount) {
151 86 : error = xfs_initialize_perag(mp, nagcount, nb, &nagimax);
152 86 : if (error)
153 : return error;
154 250 : } else if (nagcount < oagcount) {
155 : /* TODO: shrinking the entire AGs hasn't yet completed */
156 : return -EINVAL;
157 : }
158 :
159 334 : if (delta > 0)
160 90 : error = xfs_trans_alloc(mp, &M_RES(mp)->tr_growdata,
161 90 : XFS_GROWFS_SPACE_RES(mp), 0, XFS_TRANS_RESERVE,
162 : &tp);
163 : else
164 244 : error = xfs_trans_alloc(mp, &M_RES(mp)->tr_growdata, -delta, 0,
165 : 0, &tp);
166 334 : if (error)
167 : return error;
168 :
169 281 : last_pag = xfs_perag_get(mp, oagcount - 1);
170 281 : if (delta > 0) {
171 90 : error = xfs_resizefs_init_new_ags(tp, &id, oagcount, nagcount,
172 : delta, last_pag, &lastag_extended);
173 : } else {
174 191 : xfs_warn_mount(mp, XFS_OPSTATE_WARNED_SHRINK,
175 : "EXPERIMENTAL online shrink feature in use. Use at your own risk!");
176 :
177 191 : error = xfs_ag_shrink_space(last_pag, &tp, -delta);
178 : }
179 281 : xfs_perag_put(last_pag);
180 281 : if (error)
181 154 : goto out_trans_cancel;
182 :
183 : /*
184 : * Update changed superblock fields transactionally. These are not
185 : * seen by the rest of the world until the transaction commit applies
186 : * them atomically to the superblock.
187 : */
188 127 : if (nagcount > oagcount)
189 86 : xfs_trans_mod_sb(tp, XFS_TRANS_SB_AGCOUNT, nagcount - oagcount);
190 127 : if (delta)
191 127 : xfs_trans_mod_sb(tp, XFS_TRANS_SB_DBLOCKS, delta);
192 127 : if (id.nfree)
193 86 : xfs_trans_mod_sb(tp, XFS_TRANS_SB_FDBLOCKS, id.nfree);
194 :
195 : /*
196 : * Sync sb counters now to reflect the updated values. This is
197 : * particularly important for shrink because the write verifier
198 : * will fail if sb_fdblocks is ever larger than sb_dblocks.
199 : */
200 127 : if (xfs_has_lazysbcount(mp))
201 127 : xfs_log_sb(tp);
202 :
203 127 : xfs_trans_set_sync(tp);
204 127 : error = xfs_trans_commit(tp);
205 127 : if (error)
206 : return error;
207 :
208 : /* New allocation groups fully initialized, so update mount struct */
209 127 : if (nagimax)
210 86 : mp->m_maxagi = nagimax;
211 127 : xfs_set_low_space_thresholds(mp);
212 127 : mp->m_alloc_set_aside = xfs_alloc_set_aside(mp);
213 :
214 127 : if (delta > 0) {
215 : /*
216 : * If we expanded the last AG, free the per-AG reservation
217 : * so we can reinitialize it with the new size.
218 : */
219 90 : if (lastag_extended) {
220 28 : struct xfs_perag *pag;
221 :
222 28 : pag = xfs_perag_get(mp, id.agno);
223 28 : xfs_ag_resv_free(pag);
224 28 : xfs_perag_put(pag);
225 : }
226 :
227 : /*
228 : * Reserve AG metadata blocks. ENOSPC here does not mean there
229 : * was a growfs failure, just that there still isn't space for
230 : * new user data after the grow has been run.
231 : */
232 90 : error = xfs_fs_reserve_ag_blocks(mp);
233 90 : if (error == -ENOSPC)
234 0 : error = 0;
235 :
236 : /* Compute new maxlevels for rt btrees. */
237 90 : xfs_rtrmapbt_compute_maxlevels(mp);
238 90 : xfs_rtrefcountbt_compute_maxlevels(mp);
239 : }
240 :
241 : return error;
242 :
243 : out_trans_cancel:
244 154 : xfs_trans_cancel(tp);
245 154 : return error;
246 : }
247 :
248 : static int
249 0 : xfs_growfs_log_private(
250 : struct xfs_mount *mp, /* mount point for filesystem */
251 : struct xfs_growfs_log *in) /* growfs log input struct */
252 : {
253 0 : xfs_extlen_t nb;
254 :
255 0 : nb = in->newblocks;
256 0 : if (nb < XFS_MIN_LOG_BLOCKS || nb < XFS_B_TO_FSB(mp, XFS_MIN_LOG_BYTES))
257 : return -EINVAL;
258 0 : if (nb == mp->m_sb.sb_logblocks &&
259 0 : in->isint == (mp->m_sb.sb_logstart != 0))
260 0 : return -EINVAL;
261 : /*
262 : * Moving the log is hard, need new interfaces to sync
263 : * the log first, hold off all activity while moving it.
264 : * Can have shorter or longer log in the same space,
265 : * or transform internal to external log or vice versa.
266 : */
267 : return -ENOSYS;
268 : }
269 :
270 : static int
271 0 : xfs_growfs_imaxpct(
272 : struct xfs_mount *mp,
273 : __u32 imaxpct)
274 : {
275 0 : struct xfs_trans *tp;
276 0 : int dpct;
277 0 : int error;
278 :
279 0 : if (imaxpct > 100)
280 : return -EINVAL;
281 :
282 0 : error = xfs_trans_alloc(mp, &M_RES(mp)->tr_growdata,
283 0 : XFS_GROWFS_SPACE_RES(mp), 0, XFS_TRANS_RESERVE, &tp);
284 0 : if (error)
285 : return error;
286 :
287 0 : dpct = imaxpct - mp->m_sb.sb_imax_pct;
288 0 : xfs_trans_mod_sb(tp, XFS_TRANS_SB_IMAXPCT, dpct);
289 0 : xfs_trans_set_sync(tp);
290 0 : return xfs_trans_commit(tp);
291 : }
292 :
293 : /*
294 : * protected versions of growfs function acquire and release locks on the mount
295 : * point - exported through ioctls: XFS_IOC_FSGROWFSDATA, XFS_IOC_FSGROWFSLOG,
296 : * XFS_IOC_FSGROWFSRT
297 : */
298 : int
299 336 : xfs_growfs_data(
300 : struct xfs_mount *mp,
301 : struct xfs_growfs_data *in)
302 : {
303 336 : int error = 0;
304 :
305 336 : if (!capable(CAP_SYS_ADMIN))
306 : return -EPERM;
307 336 : if (!mutex_trylock(&mp->m_growlock))
308 : return -EWOULDBLOCK;
309 :
310 : /* update imaxpct separately to the physical grow of the filesystem */
311 336 : if (in->imaxpct != mp->m_sb.sb_imax_pct) {
312 0 : error = xfs_growfs_imaxpct(mp, in->imaxpct);
313 0 : if (error)
314 0 : goto out_error;
315 : }
316 :
317 336 : if (in->newblocks != mp->m_sb.sb_dblocks) {
318 336 : error = xfs_growfs_data_private(mp, in);
319 336 : if (error)
320 209 : goto out_error;
321 : }
322 :
323 : /* Post growfs calculations needed to reflect new state in operations */
324 127 : if (mp->m_sb.sb_imax_pct) {
325 127 : uint64_t icount = mp->m_sb.sb_dblocks * mp->m_sb.sb_imax_pct;
326 127 : do_div(icount, 100);
327 127 : M_IGEO(mp)->maxicount = XFS_FSB_TO_INO(mp, icount);
328 : } else
329 0 : M_IGEO(mp)->maxicount = 0;
330 :
331 : /* Update secondary superblocks now the physical grow has completed */
332 127 : error = xfs_update_secondary_sbs(mp);
333 127 : if (error)
334 0 : goto out_error;
335 127 : error = xfs_rtgroup_update_secondary_sbs(mp);
336 :
337 336 : out_error:
338 : /*
339 : * Increment the generation unconditionally, the error could be from
340 : * updating the secondary superblocks, in which case the new size
341 : * is live already.
342 : */
343 336 : mp->m_generation++;
344 336 : mutex_unlock(&mp->m_growlock);
345 336 : return error;
346 : }
347 :
348 : int
349 0 : xfs_growfs_log(
350 : xfs_mount_t *mp,
351 : struct xfs_growfs_log *in)
352 : {
353 0 : int error;
354 :
355 0 : if (!capable(CAP_SYS_ADMIN))
356 : return -EPERM;
357 0 : if (!mutex_trylock(&mp->m_growlock))
358 : return -EWOULDBLOCK;
359 0 : error = xfs_growfs_log_private(mp, in);
360 0 : mutex_unlock(&mp->m_growlock);
361 0 : return error;
362 : }
363 :
364 : /*
365 : * exported through ioctl XFS_IOC_FSCOUNTS
366 : */
367 :
368 : void
369 11318 : xfs_fs_counts(
370 : xfs_mount_t *mp,
371 : xfs_fsop_counts_t *cnt)
372 : {
373 11318 : cnt->allocino = percpu_counter_read_positive(&mp->m_icount);
374 11318 : cnt->freeino = percpu_counter_read_positive(&mp->m_ifree);
375 11318 : cnt->freedata = percpu_counter_read_positive(&mp->m_fdblocks) -
376 : xfs_fdblocks_unavailable(mp);
377 11318 : cnt->freertx = percpu_counter_read_positive(&mp->m_frextents);
378 11318 : }
379 :
380 : /*
381 : * exported through ioctl XFS_IOC_SET_RESBLKS & XFS_IOC_GET_RESBLKS
382 : *
383 : * xfs_reserve_blocks is called to set m_resblks
384 : * in the in-core mount table. The number of unused reserved blocks
385 : * is kept in m_resblks_avail.
386 : *
387 : * Reserve the requested number of blocks if available. Otherwise return
388 : * as many as possible to satisfy the request. The actual number
389 : * reserved are returned in outval
390 : *
391 : * A null inval pointer indicates that only the current reserved blocks
392 : * available should be returned no settings are changed.
393 : */
394 :
395 : int
396 143805 : xfs_reserve_blocks(
397 : xfs_mount_t *mp,
398 : uint64_t *inval,
399 : xfs_fsop_resblks_t *outval)
400 : {
401 143805 : int64_t lcounter, delta;
402 143805 : int64_t fdblks_delta = 0;
403 143805 : uint64_t request;
404 143805 : int64_t free;
405 143805 : int error = 0;
406 :
407 : /* If inval is null, report current values and return */
408 143805 : if (inval == (uint64_t *)NULL) {
409 6 : if (!outval)
410 : return -EINVAL;
411 6 : outval->resblks = mp->m_resblks;
412 6 : outval->resblks_avail = mp->m_resblks_avail;
413 6 : return 0;
414 : }
415 :
416 143799 : request = *inval;
417 :
418 : /*
419 : * With per-cpu counters, this becomes an interesting problem. we need
420 : * to work out if we are freeing or allocation blocks first, then we can
421 : * do the modification as necessary.
422 : *
423 : * We do this under the m_sb_lock so that if we are near ENOSPC, we will
424 : * hold out any changes while we work out what to do. This means that
425 : * the amount of free space can change while we do this, so we need to
426 : * retry if we end up trying to reserve more space than is available.
427 : */
428 143799 : spin_lock(&mp->m_sb_lock);
429 :
430 : /*
431 : * If our previous reservation was larger than the current value,
432 : * then move any unused blocks back to the free pool. Modify the resblks
433 : * counters directly since we shouldn't have any problems unreserving
434 : * space.
435 : */
436 143799 : if (mp->m_resblks > request) {
437 70784 : lcounter = mp->m_resblks_avail - request;
438 70784 : if (lcounter > 0) { /* release unused blocks */
439 70784 : fdblks_delta = lcounter;
440 70784 : mp->m_resblks_avail -= lcounter;
441 : }
442 70784 : mp->m_resblks = request;
443 0 : if (fdblks_delta) {
444 70784 : spin_unlock(&mp->m_sb_lock);
445 70784 : error = xfs_mod_fdblocks(mp, fdblks_delta, 0);
446 70784 : spin_lock(&mp->m_sb_lock);
447 : }
448 :
449 70784 : goto out;
450 : }
451 :
452 : /*
453 : * If the request is larger than the current reservation, reserve the
454 : * blocks before we update the reserve counters. Sample m_fdblocks and
455 : * perform a partial reservation if the request exceeds free space.
456 : *
457 : * The code below estimates how many blocks it can request from
458 : * fdblocks to stash in the reserve pool. This is a classic TOCTOU
459 : * race since fdblocks updates are not always coordinated via
460 : * m_sb_lock. Set the reserve size even if there's not enough free
461 : * space to fill it because mod_fdblocks will refill an undersized
462 : * reserve when it can.
463 : */
464 73015 : free = percpu_counter_sum(&mp->m_fdblocks) -
465 : xfs_fdblocks_unavailable(mp);
466 73015 : delta = request - mp->m_resblks;
467 73015 : mp->m_resblks = request;
468 73015 : if (delta > 0 && free > 0) {
469 : /*
470 : * We'll either succeed in getting space from the free block
471 : * count or we'll get an ENOSPC. Don't set the reserved flag
472 : * here - we don't want to reserve the extra reserve blocks
473 : * from the reserve.
474 : *
475 : * The desired reserve size can change after we drop the lock.
476 : * Use mod_fdblocks to put the space into the reserve or into
477 : * fdblocks as appropriate.
478 : */
479 70788 : fdblks_delta = min(free, delta);
480 70788 : spin_unlock(&mp->m_sb_lock);
481 70788 : error = xfs_mod_fdblocks(mp, -fdblks_delta, 0);
482 70788 : if (!error)
483 70788 : xfs_mod_fdblocks(mp, fdblks_delta, 0);
484 70788 : spin_lock(&mp->m_sb_lock);
485 : }
486 2227 : out:
487 143799 : if (outval) {
488 18 : outval->resblks = mp->m_resblks;
489 18 : outval->resblks_avail = mp->m_resblks_avail;
490 : }
491 :
492 143799 : spin_unlock(&mp->m_sb_lock);
493 143799 : return error;
494 : }
495 :
496 : int
497 4816 : xfs_fs_goingdown(
498 : xfs_mount_t *mp,
499 : uint32_t inflags)
500 : {
501 4816 : switch (inflags) {
502 0 : case XFS_FSOP_GOING_FLAGS_DEFAULT: {
503 0 : if (!freeze_bdev(mp->m_super->s_bdev)) {
504 0 : xfs_force_shutdown(mp, SHUTDOWN_FORCE_UMOUNT);
505 0 : thaw_bdev(mp->m_super->s_bdev);
506 : }
507 : break;
508 : }
509 199 : case XFS_FSOP_GOING_FLAGS_LOGFLUSH:
510 199 : xfs_force_shutdown(mp, SHUTDOWN_FORCE_UMOUNT);
511 199 : break;
512 4617 : case XFS_FSOP_GOING_FLAGS_NOLOGFLUSH:
513 4617 : xfs_force_shutdown(mp,
514 : SHUTDOWN_FORCE_UMOUNT | SHUTDOWN_LOG_IO_ERROR);
515 4617 : break;
516 : default:
517 : return -EINVAL;
518 : }
519 :
520 : return 0;
521 : }
522 :
523 : /*
524 : * Force a shutdown of the filesystem instantly while keeping the filesystem
525 : * consistent. We don't do an unmount here; just shutdown the shop, make sure
526 : * that absolutely nothing persistent happens to this filesystem after this
527 : * point.
528 : *
529 : * The shutdown state change is atomic, resulting in the first and only the
530 : * first shutdown call processing the shutdown. This means we only shutdown the
531 : * log once as it requires, and we don't spam the logs when multiple concurrent
532 : * shutdowns race to set the shutdown flags.
533 : */
534 : void
535 1729773 : xfs_do_force_shutdown(
536 : struct xfs_mount *mp,
537 : uint32_t flags,
538 : char *fname,
539 : int lnnum)
540 : {
541 1729773 : int tag;
542 1729773 : const char *why;
543 :
544 :
545 3459546 : if (test_and_set_bit(XFS_OPSTATE_SHUTDOWN, &mp->m_opstate)) {
546 1722250 : xlog_shutdown_wait(mp->m_log);
547 1722250 : return;
548 : }
549 7523 : if (mp->m_sb_bp)
550 7523 : mp->m_sb_bp->b_flags |= XBF_DONE;
551 :
552 7523 : if (flags & SHUTDOWN_FORCE_UMOUNT)
553 4816 : xfs_alert(mp, "User initiated shutdown received.");
554 :
555 7523 : if (xlog_force_shutdown(mp->m_log, flags)) {
556 : tag = XFS_PTAG_SHUTDOWN_LOGERROR;
557 : why = "Log I/O Error";
558 2906 : } else if (flags & SHUTDOWN_CORRUPT_INCORE) {
559 : tag = XFS_PTAG_SHUTDOWN_CORRUPT;
560 : why = "Corruption of in-memory data";
561 1857 : } else if (flags & SHUTDOWN_CORRUPT_ONDISK) {
562 : tag = XFS_PTAG_SHUTDOWN_CORRUPT;
563 : why = "Corruption of on-disk metadata";
564 1857 : } else if (flags & SHUTDOWN_DEVICE_REMOVED) {
565 : tag = XFS_PTAG_SHUTDOWN_IOERROR;
566 : why = "Block device removal";
567 : } else {
568 1857 : tag = XFS_PTAG_SHUTDOWN_IOERROR;
569 1857 : why = "Metadata I/O Error";
570 : }
571 :
572 7523 : trace_xfs_force_shutdown(mp, tag, flags, fname, lnnum);
573 :
574 7523 : xfs_alert_tag(mp, tag,
575 : "%s (0x%x) detected at %pS (%s:%d). Shutting down filesystem.",
576 : why, flags, __return_address, fname, lnnum);
577 7523 : xfs_alert(mp,
578 : "Please unmount the filesystem and rectify the problem(s)");
579 7523 : if (xfs_error_level >= XFS_ERRLEVEL_HIGH)
580 0 : xfs_stack_trace();
581 : }
582 :
583 : /*
584 : * Reserve free space for per-AG metadata.
585 : */
586 : int
587 46733 : xfs_fs_reserve_ag_blocks(
588 : struct xfs_mount *mp)
589 : {
590 46733 : xfs_agnumber_t agno;
591 46733 : struct xfs_perag *pag;
592 46733 : int error = 0;
593 46733 : int err2;
594 :
595 46733 : mp->m_finobt_nores = false;
596 300073 : for_each_perag(mp, agno, pag) {
597 253340 : err2 = xfs_ag_resv_init(pag, NULL);
598 253340 : if (err2 && !error)
599 36 : error = err2;
600 : }
601 :
602 46733 : if (error && error != -ENOSPC) {
603 36 : xfs_warn(mp,
604 : "Error %d reserving per-AG metadata reserve pool.", error);
605 36 : xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE);
606 36 : return error;
607 : }
608 :
609 46697 : if (xfs_has_realtime(mp)) {
610 570 : err2 = xfs_rt_resv_init(mp);
611 570 : if (err2 && err2 != -ENOSPC) {
612 0 : xfs_warn(mp,
613 : "Error %d reserving realtime metadata reserve pool.", err2);
614 0 : xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE);
615 : }
616 :
617 570 : if (err2 && !error)
618 0 : error = err2;
619 : }
620 :
621 : return error;
622 : }
623 :
624 : /*
625 : * Free space reserved for per-AG metadata.
626 : */
627 : void
628 48874 : xfs_fs_unreserve_ag_blocks(
629 : struct xfs_mount *mp)
630 : {
631 48874 : struct xfs_perag *pag;
632 48874 : xfs_agnumber_t agno;
633 :
634 48874 : if (xfs_has_realtime(mp))
635 572 : xfs_rt_resv_free(mp);
636 :
637 310532 : for_each_perag(mp, agno, pag) {
638 : /*
639 : * Bring the AG back online because our AG hiding only exists
640 : * in-core and we need the superblock to be written out with
641 : * the super fdblocks reflecting the AGF freeblks. Do this
642 : * before adding the per-AG reservations back to fdblocks.
643 : */
644 261658 : xfs_ag_clear_noalloc(pag);
645 261658 : xfs_ag_resv_free(pag);
646 : }
647 48874 : }
|