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

Generated by: LCOV version 1.14