]> www.infradead.org Git - users/hch/xfs.git/commitdiff
xfs: check that the rtrmapbt maxlevels doesn't increase when growing fs
authorDarrick J. Wong <djwong@kernel.org>
Thu, 15 Aug 2024 18:48:57 +0000 (11:48 -0700)
committerChristoph Hellwig <hch@lst.de>
Sun, 22 Sep 2024 08:48:14 +0000 (10:48 +0200)
The size of filesystem transaction reservations depends on the maximum
height (maxlevels) of the realtime btrees.  Since we don't want a grow
operation to increase the reservation size enough that we'll fail the
minimum log size checks on the next mount, constrain growfs operations
if they would cause an increase in those maxlevels.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
fs/xfs/xfs_fsops.c
fs/xfs/xfs_rtalloc.c
fs/xfs/xfs_rtalloc.h
fs/xfs/xfs_trace.h

index cb7a69dccb71617650caaa95953f1593783df60a..e892d08d57d3766befbeaf4a71e7ffb9095e2a2f 100644 (file)
@@ -22,6 +22,7 @@
 #include "xfs_ag_resv.h"
 #include "xfs_trace.h"
 #include "xfs_rtalloc.h"
+#include "xfs_rtrmap_btree.h"
 
 /*
  * Write new AG headers to disk. Non-transactional, but need to be
@@ -114,6 +115,12 @@ xfs_growfs_data_private(
                xfs_buf_relse(bp);
        }
 
+       /* Make sure the new fs size won't cause problems with the log. */
+       error = xfs_growfs_check_rtgeom(mp, nb, mp->m_sb.sb_rblocks,
+                       mp->m_sb.sb_rextsize);
+       if (error)
+               return error;
+
        nb_div = nb;
        nb_mod = do_div(nb_div, mp->m_sb.sb_agblocks);
        if (nb_mod && nb_mod >= XFS_MIN_AG_BLOCKS)
@@ -223,7 +230,11 @@ xfs_growfs_data_private(
                error = xfs_fs_reserve_ag_blocks(mp);
                if (error == -ENOSPC)
                        error = 0;
+
+               /* Compute new maxlevels for rt btrees. */
+               xfs_rtrmapbt_compute_maxlevels(mp);
        }
+
        return error;
 
 out_trans_cancel:
index 92b227bdda075e1be336ba1f295851be7861a5ae..178ef3bbec6a01ac154fa0969f7e96e429d6e54a 100644 (file)
@@ -30,6 +30,7 @@
 #include "xfs_metafile.h"
 #include "xfs_rtgroup.h"
 #include "xfs_error.h"
+#include "xfs_trace.h"
 
 /*
  * Return whether there are any free extents in the size range given
@@ -989,9 +990,11 @@ xfs_growfs_rt_bmblock(
                goto out_free;
 
        /*
-        * Ensure the mount RT feature flag is now set.
+        * Ensure the mount RT feature flag is now set, and compute new
+        * maxlevels for rt btrees.
         */
        mp->m_features |= XFS_FEAT_REALTIME;
+       xfs_rtrmapbt_compute_maxlevels(mp);
 
        kfree(nmp);
        return 0;
@@ -1158,29 +1161,37 @@ out_rele:
        return error;
 }
 
-static int
+int
 xfs_growfs_check_rtgeom(
        const struct xfs_mount  *mp,
+       xfs_rfsblock_t          dblocks,
        xfs_rfsblock_t          rblocks,
        xfs_extlen_t            rextsize)
 {
+       xfs_extlen_t            min_logfsbs;
        struct xfs_mount        *nmp;
-       int                     error = 0;
 
        nmp = xfs_growfs_rt_alloc_fake_mount(mp, rblocks, rextsize);
        if (!nmp)
                return -ENOMEM;
+       nmp->m_sb.sb_dblocks = dblocks;
+
+       xfs_rtrmapbt_compute_maxlevels(nmp);
+       xfs_trans_resv_calc(nmp, M_RES(nmp));
 
        /*
         * New summary size can't be more than half the size of the log.  This
         * prevents us from getting a log overflow, since we'll log basically
         * the whole summary file at once.
         */
-       if (nmp->m_rsumblocks > (mp->m_sb.sb_logblocks >> 1))
-               error = -EINVAL;
+       min_logfsbs = min_t(xfs_extlen_t, xfs_log_calc_minimum_size(nmp),
+                       nmp->m_rsumblocks * 2);
 
        kfree(nmp);
-       return error;
+
+       if (min_logfsbs > mp->m_sb.sb_logblocks)
+               return -EINVAL;
+       return 0;
 }
 
 /*
@@ -1297,7 +1308,8 @@ xfs_growfs_rt(
                goto out_unlock;
 
        /* Make sure the new fs size won't cause problems with the log. */
-       error = xfs_growfs_check_rtgeom(mp, in->newblocks, in->extsize);
+       error = xfs_growfs_check_rtgeom(mp,  mp->m_sb.sb_dblocks, in->newblocks,
+                       in->extsize);
        if (error)
                goto out_unlock;
 
index d87523e6a550068e436047c9d4eb4b54ced5d6cb..9044f7226ab6fc0352a38665a67d85ecadec9696 100644 (file)
@@ -46,6 +46,8 @@ xfs_growfs_rt(
        xfs_growfs_rt_t         *in);   /* user supplied growfs struct */
 
 int xfs_rtalloc_reinit_frextents(struct xfs_mount *mp);
+int xfs_growfs_check_rtgeom(const struct xfs_mount *mp, xfs_rfsblock_t dblocks,
+               xfs_rfsblock_t rblocks, xfs_agblock_t rextsize);
 #else
 # define xfs_growfs_rt(mp,in)                          (-ENOSYS)
 # define xfs_rtalloc_reinit_frextents(m)               (0)
@@ -65,6 +67,14 @@ xfs_rtmount_init(
 # define xfs_rtunmount_inodes(m)
 # define xfs_rt_resv_free(mp)                          ((void)0)
 # define xfs_rt_resv_init(mp)                          (0)
+
+static inline int
+xfs_growfs_check_rtgeom(const struct xfs_mount *mp,
+               xfs_rfsblock_t dblocks, xfs_rfsblock_t rblocks,
+               xfs_extlen_t rextsize)
+{
+       return 0;
+}
 #endif /* CONFIG_XFS_RT */
 
 #endif /* __XFS_RTALLOC_H__ */
index 1ab54b4f4661b4235c2909a2818574bef2e18420..ceef9010ed8f93a0a0e06ecbc895243fe0030925 100644 (file)
@@ -5544,6 +5544,27 @@ DEFINE_METAFILE_RESV_EVENT(xfs_metafile_resv_free_space);
 DEFINE_METAFILE_RESV_EVENT(xfs_metafile_resv_critical);
 DEFINE_INODE_ERROR_EVENT(xfs_metafile_resv_init_error);
 
+#ifdef CONFIG_XFS_RT
+TRACE_EVENT(xfs_growfs_check_rtgeom,
+       TP_PROTO(const struct xfs_mount *mp, unsigned int min_logfsbs),
+       TP_ARGS(mp, min_logfsbs),
+       TP_STRUCT__entry(
+               __field(dev_t, dev)
+               __field(unsigned int, logblocks)
+               __field(unsigned int, min_logfsbs)
+       ),
+       TP_fast_assign(
+               __entry->dev = mp->m_super->s_dev;
+               __entry->logblocks = mp->m_sb.sb_logblocks;
+               __entry->min_logfsbs = min_logfsbs;
+       ),
+       TP_printk("dev %d:%d logblocks %u min_logfsbs %u",
+                 MAJOR(__entry->dev), MINOR(__entry->dev),
+                 __entry->logblocks,
+                 __entry->min_logfsbs)
+);
+#endif /* CONFIG_XFS_RT */
+
 #endif /* _TRACE_XFS_H */
 
 #undef TRACE_INCLUDE_PATH