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 90 : 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 90 : struct xfs_mount *mp = tp->t_mountp;
48 90 : xfs_rfsblock_t nb = mp->m_sb.sb_dblocks + delta;
49 90 : int error;
50 :
51 90 : *lastag_extended = false;
52 :
53 90 : INIT_LIST_HEAD(&id->buffer_list);
54 90 : for (id->agno = nagcount - 1;
55 7780 : id->agno >= oagcount;
56 7690 : id->agno--, delta -= id->agsize) {
57 :
58 7690 : if (id->agno == nagcount - 1)
59 86 : id->agsize = nb - (id->agno *
60 86 : (xfs_rfsblock_t)mp->m_sb.sb_agblocks);
61 : else
62 7604 : id->agsize = mp->m_sb.sb_agblocks;
63 :
64 7690 : error = xfs_ag_init_headers(mp, id);
65 7690 : if (error) {
66 0 : xfs_buf_delwri_cancel(&id->buffer_list);
67 0 : return error;
68 : }
69 : }
70 :
71 90 : error = xfs_buf_delwri_submit(&id->buffer_list);
72 90 : if (error)
73 : return error;
74 :
75 90 : if (delta) {
76 28 : *lastag_extended = true;
77 28 : error = xfs_ag_extend_space(last_pag, tp, delta);
78 : }
79 : return error;
80 : }
81 :
82 : /*
83 : * growfs operations
84 : */
85 : static int
86 362 : 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 362 : struct xfs_buf *bp;
91 362 : int error;
92 362 : xfs_agnumber_t nagcount;
93 362 : xfs_agnumber_t nagimax = 0;
94 362 : xfs_rfsblock_t nb, nb_div, nb_mod;
95 362 : int64_t delta;
96 362 : bool lastag_extended = false;
97 362 : xfs_agnumber_t oagcount;
98 362 : struct xfs_trans *tp;
99 362 : struct aghdr_init_data id = {};
100 362 : struct xfs_perag *last_pag;
101 :
102 362 : nb = in->newblocks;
103 362 : error = xfs_sb_validate_fsb_count(&mp->m_sb, nb);
104 362 : if (error)
105 : return error;
106 :
107 362 : if (nb > mp->m_sb.sb_dblocks) {
108 90 : error = xfs_buf_read_uncached(mp->m_ddev_targp,
109 90 : XFS_FSB_TO_BB(mp, nb) - XFS_FSS_TO_BB(mp, 1),
110 : XFS_FSS_TO_BB(mp, 1), 0, &bp, NULL);
111 90 : if (error)
112 : return error;
113 90 : xfs_buf_relse(bp);
114 : }
115 :
116 362 : nb_div = nb;
117 362 : nb_mod = do_div(nb_div, mp->m_sb.sb_agblocks);
118 362 : if (nb_mod && nb_mod >= XFS_MIN_AG_BLOCKS)
119 324 : nb_div++;
120 38 : else if (nb_mod)
121 8 : nb = nb_div * mp->m_sb.sb_agblocks;
122 :
123 362 : 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 362 : nagcount = nb_div;
128 362 : 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 362 : if (delta < 0 && nagcount < 2)
135 : return -EINVAL;
136 :
137 362 : oagcount = mp->m_sb.sb_agcount;
138 : /* allocate the new per-ag structures */
139 362 : if (nagcount > oagcount) {
140 86 : error = xfs_initialize_perag(mp, nagcount, nb, &nagimax);
141 86 : if (error)
142 : return error;
143 276 : } else if (nagcount < oagcount) {
144 : /* TODO: shrinking the entire AGs hasn't yet completed */
145 : return -EINVAL;
146 : }
147 :
148 360 : if (delta > 0)
149 90 : error = xfs_trans_alloc(mp, &M_RES(mp)->tr_growdata,
150 90 : XFS_GROWFS_SPACE_RES(mp), 0, XFS_TRANS_RESERVE,
151 : &tp);
152 : else
153 270 : error = xfs_trans_alloc(mp, &M_RES(mp)->tr_growdata, -delta, 0,
154 : 0, &tp);
155 360 : if (error)
156 : return error;
157 :
158 301 : last_pag = xfs_perag_get(mp, oagcount - 1);
159 301 : if (delta > 0) {
160 90 : error = xfs_resizefs_init_new_ags(tp, &id, oagcount, nagcount,
161 : delta, last_pag, &lastag_extended);
162 : } else {
163 211 : xfs_warn_mount(mp, XFS_OPSTATE_WARNED_SHRINK,
164 : "EXPERIMENTAL online shrink feature in use. Use at your own risk!");
165 :
166 211 : error = xfs_ag_shrink_space(last_pag, &tp, -delta);
167 : }
168 301 : xfs_perag_put(last_pag);
169 301 : if (error)
170 175 : 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 126 : if (nagcount > oagcount)
178 86 : xfs_trans_mod_sb(tp, XFS_TRANS_SB_AGCOUNT, nagcount - oagcount);
179 126 : if (delta)
180 126 : xfs_trans_mod_sb(tp, XFS_TRANS_SB_DBLOCKS, delta);
181 126 : if (id.nfree)
182 86 : 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 126 : if (xfs_has_lazysbcount(mp))
190 126 : xfs_log_sb(tp);
191 :
192 126 : xfs_trans_set_sync(tp);
193 126 : error = xfs_trans_commit(tp);
194 126 : if (error)
195 : return error;
196 :
197 : /* New allocation groups fully initialized, so update mount struct */
198 126 : if (nagimax)
199 86 : mp->m_maxagi = nagimax;
200 126 : xfs_set_low_space_thresholds(mp);
201 126 : mp->m_alloc_set_aside = xfs_alloc_set_aside(mp);
202 :
203 126 : 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 90 : if (lastag_extended) {
209 28 : struct xfs_perag *pag;
210 :
211 28 : pag = xfs_perag_get(mp, id.agno);
212 28 : error = xfs_ag_resv_free(pag);
213 28 : xfs_perag_put(pag);
214 28 : 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 90 : error = xfs_fs_reserve_ag_blocks(mp);
223 90 : if (error == -ENOSPC)
224 0 : error = 0;
225 : }
226 : return error;
227 :
228 : out_trans_cancel:
229 175 : xfs_trans_cancel(tp);
230 175 : 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 : 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 362 : xfs_growfs_data(
285 : struct xfs_mount *mp,
286 : struct xfs_growfs_data *in)
287 : {
288 362 : int error = 0;
289 :
290 362 : if (!capable(CAP_SYS_ADMIN))
291 : return -EPERM;
292 362 : if (!mutex_trylock(&mp->m_growlock))
293 : return -EWOULDBLOCK;
294 :
295 : /* update imaxpct separately to the physical grow of the filesystem */
296 362 : 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 362 : if (in->newblocks != mp->m_sb.sb_dblocks) {
303 362 : error = xfs_growfs_data_private(mp, in);
304 362 : if (error)
305 236 : goto out_error;
306 : }
307 :
308 : /* Post growfs calculations needed to reflect new state in operations */
309 126 : if (mp->m_sb.sb_imax_pct) {
310 126 : uint64_t icount = mp->m_sb.sb_dblocks * mp->m_sb.sb_imax_pct;
311 126 : do_div(icount, 100);
312 126 : 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 126 : error = xfs_update_secondary_sbs(mp);
318 :
319 362 : 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 362 : mp->m_generation++;
326 362 : mutex_unlock(&mp->m_growlock);
327 362 : 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 13068 : xfs_fs_counts(
352 : xfs_mount_t *mp,
353 : xfs_fsop_counts_t *cnt)
354 : {
355 13068 : cnt->allocino = percpu_counter_read_positive(&mp->m_icount);
356 13068 : cnt->freeino = percpu_counter_read_positive(&mp->m_ifree);
357 13068 : cnt->freedata = percpu_counter_read_positive(&mp->m_fdblocks) -
358 : xfs_fdblocks_unavailable(mp);
359 13068 : cnt->freertx = percpu_counter_read_positive(&mp->m_frextents);
360 13068 : }
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 119652 : xfs_reserve_blocks(
379 : xfs_mount_t *mp,
380 : uint64_t *inval,
381 : xfs_fsop_resblks_t *outval)
382 : {
383 119652 : int64_t lcounter, delta;
384 119652 : int64_t fdblks_delta = 0;
385 119652 : uint64_t request;
386 119652 : int64_t free;
387 119652 : int error = 0;
388 :
389 : /* If inval is null, report current values and return */
390 119652 : if (inval == (uint64_t *)NULL) {
391 6 : if (!outval)
392 : return -EINVAL;
393 6 : outval->resblks = mp->m_resblks;
394 6 : outval->resblks_avail = mp->m_resblks_avail;
395 6 : return 0;
396 : }
397 :
398 119646 : 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 119646 : 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 119646 : if (mp->m_resblks > request) {
419 58725 : lcounter = mp->m_resblks_avail - request;
420 58725 : if (lcounter > 0) { /* release unused blocks */
421 58725 : fdblks_delta = lcounter;
422 58725 : mp->m_resblks_avail -= lcounter;
423 : }
424 58725 : mp->m_resblks = request;
425 0 : if (fdblks_delta) {
426 58725 : spin_unlock(&mp->m_sb_lock);
427 58725 : error = xfs_mod_fdblocks(mp, fdblks_delta, 0);
428 58725 : spin_lock(&mp->m_sb_lock);
429 : }
430 :
431 58725 : 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 60921 : free = percpu_counter_sum(&mp->m_fdblocks) -
447 : xfs_fdblocks_unavailable(mp);
448 60921 : delta = request - mp->m_resblks;
449 60921 : mp->m_resblks = request;
450 60921 : 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 58728 : fdblks_delta = min(free, delta);
462 58728 : spin_unlock(&mp->m_sb_lock);
463 58728 : error = xfs_mod_fdblocks(mp, -fdblks_delta, 0);
464 58728 : if (!error)
465 58728 : xfs_mod_fdblocks(mp, fdblks_delta, 0);
466 58728 : spin_lock(&mp->m_sb_lock);
467 : }
468 2193 : out:
469 119646 : if (outval) {
470 18 : outval->resblks = mp->m_resblks;
471 18 : outval->resblks_avail = mp->m_resblks_avail;
472 : }
473 :
474 119646 : spin_unlock(&mp->m_sb_lock);
475 119646 : return error;
476 : }
477 :
478 : int
479 4709 : xfs_fs_goingdown(
480 : xfs_mount_t *mp,
481 : uint32_t inflags)
482 : {
483 4709 : 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 199 : case XFS_FSOP_GOING_FLAGS_LOGFLUSH:
492 199 : xfs_force_shutdown(mp, SHUTDOWN_FORCE_UMOUNT);
493 199 : break;
494 4510 : case XFS_FSOP_GOING_FLAGS_NOLOGFLUSH:
495 4510 : xfs_force_shutdown(mp,
496 : SHUTDOWN_FORCE_UMOUNT | SHUTDOWN_LOG_IO_ERROR);
497 4510 : 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 1715823 : xfs_do_force_shutdown(
518 : struct xfs_mount *mp,
519 : uint32_t flags,
520 : char *fname,
521 : int lnnum)
522 : {
523 1715823 : int tag;
524 1715823 : const char *why;
525 :
526 :
527 3431645 : if (test_and_set_bit(XFS_OPSTATE_SHUTDOWN, &mp->m_opstate)) {
528 1708774 : xlog_shutdown_wait(mp->m_log);
529 1708774 : return;
530 : }
531 7048 : if (mp->m_sb_bp)
532 7048 : mp->m_sb_bp->b_flags |= XBF_DONE;
533 :
534 7048 : if (flags & SHUTDOWN_FORCE_UMOUNT)
535 4709 : xfs_alert(mp, "User initiated shutdown received.");
536 :
537 7048 : if (xlog_force_shutdown(mp->m_log, flags)) {
538 : tag = XFS_PTAG_SHUTDOWN_LOGERROR;
539 : why = "Log I/O Error";
540 2538 : } else if (flags & SHUTDOWN_CORRUPT_INCORE) {
541 : tag = XFS_PTAG_SHUTDOWN_CORRUPT;
542 : why = "Corruption of in-memory data";
543 1696 : } else if (flags & SHUTDOWN_CORRUPT_ONDISK) {
544 : tag = XFS_PTAG_SHUTDOWN_CORRUPT;
545 : why = "Corruption of on-disk metadata";
546 1696 : } else if (flags & SHUTDOWN_DEVICE_REMOVED) {
547 : tag = XFS_PTAG_SHUTDOWN_IOERROR;
548 : why = "Block device removal";
549 : } else {
550 1696 : tag = XFS_PTAG_SHUTDOWN_IOERROR;
551 1696 : why = "Metadata I/O Error";
552 : }
553 :
554 7048 : trace_xfs_force_shutdown(mp, tag, flags, fname, lnnum);
555 :
556 7048 : 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 7048 : xfs_alert(mp,
560 : "Please unmount the filesystem and rectify the problem(s)");
561 7048 : 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 46446 : xfs_fs_reserve_ag_blocks(
570 : struct xfs_mount *mp)
571 : {
572 46446 : xfs_agnumber_t agno;
573 46446 : struct xfs_perag *pag;
574 46446 : int error = 0;
575 46446 : int err2;
576 :
577 46446 : mp->m_finobt_nores = false;
578 298642 : for_each_perag(mp, agno, pag) {
579 252196 : err2 = xfs_ag_resv_init(pag, NULL);
580 252196 : if (err2 && !error)
581 36 : error = err2;
582 : }
583 :
584 46446 : if (error && error != -ENOSPC) {
585 36 : xfs_warn(mp,
586 : "Error %d reserving per-AG metadata reserve pool.", error);
587 36 : xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE);
588 : }
589 :
590 46446 : return error;
591 : }
592 :
593 : /*
594 : * Free space reserved for per-AG metadata.
595 : */
596 : int
597 48554 : xfs_fs_unreserve_ag_blocks(
598 : struct xfs_mount *mp)
599 : {
600 48554 : xfs_agnumber_t agno;
601 48554 : struct xfs_perag *pag;
602 48554 : int error = 0;
603 48554 : int err2;
604 :
605 308936 : for_each_perag(mp, agno, pag) {
606 260382 : err2 = xfs_ag_resv_free(pag);
607 260382 : if (err2 && !error)
608 0 : error = err2;
609 : }
610 :
611 48554 : if (error)
612 0 : xfs_warn(mp,
613 : "Error %d freeing per-AG metadata reserve pool.", error);
614 :
615 48554 : return error;
616 : }
|