LCOV - code coverage report
Current view: top level - fs/xfs - xfs_fsops.c (source / functions) Hit Total Coverage
Test: fstests of 6.5.0-rc4-xfsx @ Mon Jul 31 20:08:34 PDT 2023 Lines: 220 265 83.0 %
Date: 2023-07-31 20:08:34 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             : #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         439 : 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         439 :         struct xfs_mount        *mp = tp->t_mountp;
      52         439 :         xfs_rfsblock_t          nb = mp->m_sb.sb_dblocks + delta;
      53         439 :         int                     error;
      54             : 
      55         439 :         *lastag_extended = false;
      56             : 
      57         439 :         INIT_LIST_HEAD(&id->buffer_list);
      58         439 :         for (id->agno = nagcount - 1;
      59       41560 :              id->agno >= oagcount;
      60       41121 :              id->agno--, delta -= id->agsize) {
      61             : 
      62       41121 :                 if (id->agno == nagcount - 1)
      63         417 :                         id->agsize = nb - (id->agno *
      64         417 :                                         (xfs_rfsblock_t)mp->m_sb.sb_agblocks);
      65             :                 else
      66       40704 :                         id->agsize = mp->m_sb.sb_agblocks;
      67             : 
      68       41121 :                 error = xfs_ag_init_headers(mp, id);
      69       41121 :                 if (error) {
      70           0 :                         xfs_buf_delwri_cancel(&id->buffer_list);
      71           0 :                         return error;
      72             :                 }
      73             :         }
      74             : 
      75         439 :         error = xfs_buf_delwri_submit(&id->buffer_list);
      76         439 :         if (error)
      77             :                 return error;
      78             : 
      79         439 :         if (delta) {
      80         104 :                 *lastag_extended = true;
      81         104 :                 error = xfs_ag_extend_space(last_pag, tp, delta);
      82             :         }
      83             :         return error;
      84             : }
      85             : 
      86             : /*
      87             :  * growfs operations
      88             :  */
      89             : static int
      90        1816 : 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        1816 :         struct xfs_buf          *bp;
      95        1816 :         int                     error;
      96        1816 :         xfs_agnumber_t          nagcount;
      97        1816 :         xfs_agnumber_t          nagimax = 0;
      98        1816 :         xfs_rfsblock_t          nb, nb_div, nb_mod;
      99        1816 :         int64_t                 delta;
     100        1816 :         bool                    lastag_extended = false;
     101        1816 :         xfs_agnumber_t          oagcount;
     102        1816 :         struct xfs_trans        *tp;
     103        1816 :         struct aghdr_init_data  id = {};
     104        1816 :         struct xfs_perag        *last_pag;
     105             : 
     106        1816 :         nb = in->newblocks;
     107        1816 :         error = xfs_sb_validate_fsb_count(&mp->m_sb, nb);
     108        1816 :         if (error)
     109             :                 return error;
     110             : 
     111        1816 :         if (nb > mp->m_sb.sb_dblocks) {
     112        1756 :                 error = xfs_buf_read_uncached(mp->m_ddev_targp,
     113         439 :                                 XFS_FSB_TO_BB(mp, nb) - XFS_FSS_TO_BB(mp, 1),
     114         439 :                                 XFS_FSS_TO_BB(mp, 1), 0, &bp, NULL);
     115         439 :                 if (error)
     116             :                         return error;
     117         439 :                 xfs_buf_relse(bp);
     118             :         }
     119             : 
     120             :         /* Make sure the new fs size won't cause problems with the log. */
     121        1816 :         error = xfs_growfs_check_rtgeom(mp, nb, mp->m_sb.sb_rblocks,
     122             :                         mp->m_sb.sb_rextsize, mp->m_sb.sb_rextents,
     123        1816 :                         mp->m_sb.sb_rbmblocks, mp->m_sb.sb_rextslog);
     124        1816 :         if (error)
     125             :                 return error;
     126             : 
     127        1816 :         nb_div = nb;
     128        1816 :         nb_mod = do_div(nb_div, mp->m_sb.sb_agblocks);
     129        1816 :         if (nb_mod && nb_mod >= XFS_MIN_AG_BLOCKS)
     130        1607 :                 nb_div++;
     131         209 :         else if (nb_mod)
     132          44 :                 nb = nb_div * mp->m_sb.sb_agblocks;
     133             : 
     134        1816 :         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        1816 :         nagcount = nb_div;
     139        1816 :         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        1816 :         if (delta < 0 && nagcount < 2)
     146             :                 return -EINVAL;
     147             : 
     148        1607 :         oagcount = mp->m_sb.sb_agcount;
     149             :         /* allocate the new per-ag structures */
     150        1607 :         if (nagcount > oagcount) {
     151         417 :                 error = xfs_initialize_perag(mp, nagcount, nb, &nagimax);
     152         417 :                 if (error)
     153             :                         return error;
     154        1190 :         } else if (nagcount < oagcount) {
     155             :                 /* TODO: shrinking the entire AGs hasn't yet completed */
     156             :                 return -EINVAL;
     157             :         }
     158             : 
     159        1596 :         if (delta > 0)
     160         439 :                 error = xfs_trans_alloc(mp, &M_RES(mp)->tr_growdata,
     161         439 :                                 XFS_GROWFS_SPACE_RES(mp), 0, XFS_TRANS_RESERVE,
     162             :                                 &tp);
     163             :         else
     164        1157 :                 error = xfs_trans_alloc(mp, &M_RES(mp)->tr_growdata, -delta, 0,
     165             :                                 0, &tp);
     166        1596 :         if (error)
     167             :                 return error;
     168             : 
     169        1080 :         last_pag = xfs_perag_get(mp, oagcount - 1);
     170        1080 :         if (delta > 0) {
     171         439 :                 error = xfs_resizefs_init_new_ags(tp, &id, oagcount, nagcount,
     172             :                                 delta, last_pag, &lastag_extended);
     173             :         } else {
     174         641 :                 xfs_warn_mount(mp, XFS_OPSTATE_WARNED_SHRINK,
     175             :         "EXPERIMENTAL online shrink feature in use. Use at your own risk!");
     176             : 
     177         641 :                 error = xfs_ag_shrink_space(last_pag, &tp, -delta);
     178             :         }
     179        1080 :         xfs_perag_put(last_pag);
     180        1080 :         if (error)
     181         414 :                 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         666 :         if (nagcount > oagcount)
     189         417 :                 xfs_trans_mod_sb(tp, XFS_TRANS_SB_AGCOUNT, nagcount - oagcount);
     190         666 :         if (delta)
     191         666 :                 xfs_trans_mod_sb(tp, XFS_TRANS_SB_DBLOCKS, delta);
     192         666 :         if (id.nfree)
     193         417 :                 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         666 :         if (xfs_has_lazysbcount(mp))
     201         666 :                 xfs_log_sb(tp);
     202             : 
     203         666 :         xfs_trans_set_sync(tp);
     204         666 :         error = xfs_trans_commit(tp);
     205         666 :         if (error)
     206             :                 return error;
     207             : 
     208             :         /* New allocation groups fully initialized, so update mount struct */
     209         666 :         if (nagimax)
     210         417 :                 mp->m_maxagi = nagimax;
     211         666 :         xfs_set_low_space_thresholds(mp);
     212         666 :         mp->m_alloc_set_aside = xfs_alloc_set_aside(mp);
     213             : 
     214         666 :         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         439 :                 if (lastag_extended) {
     220         104 :                         struct xfs_perag        *pag;
     221             : 
     222         104 :                         pag = xfs_perag_get(mp, id.agno);
     223         104 :                         xfs_ag_resv_free(pag);
     224         104 :                         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         439 :                 error = xfs_fs_reserve_ag_blocks(mp);
     233         439 :                 if (error == -ENOSPC)
     234           0 :                         error = 0;
     235             : 
     236             :                 /* Compute new maxlevels for rt btrees. */
     237         439 :                 xfs_rtrmapbt_compute_maxlevels(mp);
     238         439 :                 xfs_rtrefcountbt_compute_maxlevels(mp);
     239             :         }
     240             : 
     241             :         return error;
     242             : 
     243             : out_trans_cancel:
     244         414 :         xfs_trans_cancel(tp);
     245         414 :         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           0 :                 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        1816 : xfs_growfs_data(
     300             :         struct xfs_mount        *mp,
     301             :         struct xfs_growfs_data  *in)
     302             : {
     303        1816 :         int                     error = 0;
     304             : 
     305        1816 :         if (!capable(CAP_SYS_ADMIN))
     306             :                 return -EPERM;
     307        1816 :         if (!mutex_trylock(&mp->m_growlock))
     308             :                 return -EWOULDBLOCK;
     309             : 
     310             :         /* update imaxpct separately to the physical grow of the filesystem */
     311        1816 :         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        1816 :         if (in->newblocks != mp->m_sb.sb_dblocks) {
     318        1816 :                 error = xfs_growfs_data_private(mp, in);
     319        1816 :                 if (error)
     320        1150 :                         goto out_error;
     321             :         }
     322             : 
     323             :         /* Post growfs calculations needed to reflect new state in operations */
     324         666 :         if (mp->m_sb.sb_imax_pct) {
     325         666 :                 uint64_t icount = mp->m_sb.sb_dblocks * mp->m_sb.sb_imax_pct;
     326         666 :                 do_div(icount, 100);
     327         666 :                 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         666 :         error = xfs_update_secondary_sbs(mp);
     333         666 :         if (error)
     334           0 :                 goto out_error;
     335         666 :         error = xfs_rtgroup_update_secondary_sbs(mp);
     336             : 
     337        1816 : 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        1816 :         mp->m_generation++;
     344        1816 :         mutex_unlock(&mp->m_growlock);
     345        1816 :         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       47158 : xfs_fs_counts(
     370             :         xfs_mount_t             *mp,
     371             :         xfs_fsop_counts_t       *cnt)
     372             : {
     373       47158 :         cnt->allocino = percpu_counter_read_positive(&mp->m_icount);
     374       47158 :         cnt->freeino = percpu_counter_read_positive(&mp->m_ifree);
     375       47158 :         cnt->freedata = percpu_counter_read_positive(&mp->m_fdblocks) -
     376             :                                                 xfs_fdblocks_unavailable(mp);
     377       47158 :         cnt->freertx = percpu_counter_read_positive(&mp->m_frextents);
     378       47158 : }
     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      271529 : xfs_reserve_blocks(
     397             :         xfs_mount_t             *mp,
     398             :         uint64_t              *inval,
     399             :         xfs_fsop_resblks_t      *outval)
     400             : {
     401      271529 :         int64_t                 lcounter, delta;
     402      271529 :         int64_t                 fdblks_delta = 0;
     403      271529 :         uint64_t                request;
     404      271529 :         int64_t                 free;
     405      271529 :         int                     error = 0;
     406             : 
     407             :         /* If inval is null, report current values and return */
     408      271529 :         if (inval == (uint64_t *)NULL) {
     409          33 :                 if (!outval)
     410             :                         return -EINVAL;
     411          33 :                 outval->resblks = mp->m_resblks;
     412          33 :                 outval->resblks_avail = mp->m_resblks_avail;
     413          33 :                 return 0;
     414             :         }
     415             : 
     416      271496 :         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      271496 :         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      271496 :         if (mp->m_resblks > request) {
     437      134666 :                 lcounter = mp->m_resblks_avail - request;
     438      134666 :                 if (lcounter  > 0) {         /* release unused blocks */
     439      134666 :                         fdblks_delta = lcounter;
     440      134666 :                         mp->m_resblks_avail -= lcounter;
     441             :                 }
     442      134666 :                 mp->m_resblks = request;
     443           0 :                 if (fdblks_delta) {
     444      134666 :                         spin_unlock(&mp->m_sb_lock);
     445      134666 :                         error = xfs_mod_fdblocks(mp, fdblks_delta, 0);
     446      134666 :                         spin_lock(&mp->m_sb_lock);
     447             :                 }
     448             : 
     449      134666 :                 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      136830 :         free = percpu_counter_sum(&mp->m_fdblocks) -
     465             :                                                 xfs_fdblocks_unavailable(mp);
     466      136830 :         delta = request - mp->m_resblks;
     467      136830 :         mp->m_resblks = request;
     468      136830 :         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      134681 :                 fdblks_delta = min(free, delta);
     480      134681 :                 spin_unlock(&mp->m_sb_lock);
     481      134681 :                 error = xfs_mod_fdblocks(mp, -fdblks_delta, 0);
     482      134681 :                 if (!error)
     483      134681 :                         xfs_mod_fdblocks(mp, fdblks_delta, 0);
     484      134681 :                 spin_lock(&mp->m_sb_lock);
     485             :         }
     486        2149 : out:
     487      271496 :         if (outval) {
     488          92 :                 outval->resblks = mp->m_resblks;
     489          92 :                 outval->resblks_avail = mp->m_resblks_avail;
     490             :         }
     491             : 
     492      271496 :         spin_unlock(&mp->m_sb_lock);
     493      271496 :         return error;
     494             : }
     495             : 
     496             : int
     497        5676 : xfs_fs_goingdown(
     498             :         xfs_mount_t     *mp,
     499             :         uint32_t        inflags)
     500             : {
     501        5676 :         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        1077 :         case XFS_FSOP_GOING_FLAGS_LOGFLUSH:
     510        1077 :                 xfs_force_shutdown(mp, SHUTDOWN_FORCE_UMOUNT);
     511        1077 :                 break;
     512        4599 :         case XFS_FSOP_GOING_FLAGS_NOLOGFLUSH:
     513        4599 :                 xfs_force_shutdown(mp,
     514             :                                 SHUTDOWN_FORCE_UMOUNT | SHUTDOWN_LOG_IO_ERROR);
     515        4599 :                 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     1918274 : xfs_do_force_shutdown(
     536             :         struct xfs_mount *mp,
     537             :         uint32_t        flags,
     538             :         char            *fname,
     539             :         int             lnnum)
     540             : {
     541     1918274 :         int             tag;
     542     1918274 :         const char      *why;
     543             : 
     544             : 
     545     1918274 :         if (test_and_set_bit(XFS_OPSTATE_SHUTDOWN, &mp->m_opstate)) {
     546     1909252 :                 xlog_shutdown_wait(mp->m_log);
     547     1909252 :                 return;
     548             :         }
     549        9021 :         if (mp->m_sb_bp)
     550        9021 :                 mp->m_sb_bp->b_flags |= XBF_DONE;
     551             : 
     552        9021 :         if (flags & SHUTDOWN_FORCE_UMOUNT)
     553        5676 :                 xfs_alert(mp, "User initiated shutdown received.");
     554             : 
     555        9021 :         if (xlog_force_shutdown(mp->m_log, flags)) {
     556             :                 tag = XFS_PTAG_SHUTDOWN_LOGERROR;
     557             :                 why = "Log I/O Error";
     558        4422 :         } else if (flags & SHUTDOWN_CORRUPT_INCORE) {
     559             :                 tag = XFS_PTAG_SHUTDOWN_CORRUPT;
     560             :                 why = "Corruption of in-memory data";
     561        2693 :         } else if (flags & SHUTDOWN_CORRUPT_ONDISK) {
     562             :                 tag = XFS_PTAG_SHUTDOWN_CORRUPT;
     563             :                 why = "Corruption of on-disk metadata";
     564        2693 :         } else if (flags & SHUTDOWN_DEVICE_REMOVED) {
     565             :                 tag = XFS_PTAG_SHUTDOWN_IOERROR;
     566             :                 why = "Block device removal";
     567             :         } else {
     568        2693 :                 tag = XFS_PTAG_SHUTDOWN_IOERROR;
     569        2693 :                 why = "Metadata I/O Error";
     570             :         }
     571             : 
     572        9021 :         trace_xfs_force_shutdown(mp, tag, flags, fname, lnnum);
     573             : 
     574        9021 :         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        9021 :         xfs_alert(mp,
     578             :                 "Please unmount the filesystem and rectify the problem(s)");
     579        9021 :         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      132204 : xfs_fs_reserve_ag_blocks(
     588             :         struct xfs_mount        *mp)
     589             : {
     590      132204 :         xfs_agnumber_t          agno;
     591      132204 :         struct xfs_perag        *pag;
     592      132204 :         int                     error = 0;
     593      132204 :         int                     err2;
     594             : 
     595      132204 :         mp->m_finobt_nores = false;
     596     1143174 :         for_each_perag(mp, agno, pag) {
     597     1010970 :                 err2 = xfs_ag_resv_init(pag, NULL);
     598     1010970 :                 if (err2 && !error)
     599         180 :                         error = err2;
     600             :         }
     601             : 
     602      132204 :         if (error && error != -ENOSPC) {
     603         180 :                 xfs_warn(mp,
     604             :         "Error %d reserving per-AG metadata reserve pool.", error);
     605         180 :                 xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE);
     606         180 :                 return error;
     607             :         }
     608             : 
     609      132024 :         if (xfs_has_realtime(mp)) {
     610       45832 :                 err2 = xfs_rt_resv_init(mp);
     611       45832 :                 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       45832 :                 if (err2 && !error)
     618           3 :                         error = err2;
     619             :         }
     620             : 
     621             :         return error;
     622             : }
     623             : 
     624             : /*
     625             :  * Free space reserved for per-AG metadata.
     626             :  */
     627             : void
     628      133914 : xfs_fs_unreserve_ag_blocks(
     629             :         struct xfs_mount        *mp)
     630             : {
     631      133914 :         struct xfs_perag        *pag;
     632      133914 :         xfs_agnumber_t          agno;
     633             : 
     634      133914 :         if (xfs_has_realtime(mp))
     635       45876 :                 xfs_rt_resv_free(mp);
     636             : 
     637     1150915 :         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     1017001 :                 xfs_ag_clear_noalloc(pag);
     645     1017001 :                 xfs_ag_resv_free(pag);
     646             :         }
     647      133914 : }

Generated by: LCOV version 1.14