LCOV - code coverage report
Current view: top level - fs/xfs - xfs_fsops.c (source / functions) Hit Total Coverage
Test: fstests of 6.5.0-rc3-acha @ Mon Jul 31 20:08:06 PDT 2023 Lines: 209 252 82.9 %
Date: 2023-07-31 20:08:07 Functions: 9 12 75.0 %

          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             : }

Generated by: LCOV version 1.14