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