]> www.infradead.org Git - users/hch/xfsprogs.git/commitdiff
xfs_repair: allow sysadmins to add realtime reverse mapping indexes
authorDarrick J. Wong <djwong@kernel.org>
Mon, 12 Aug 2024 21:19:14 +0000 (14:19 -0700)
committerDarrick J. Wong <djwong@kernel.org>
Wed, 14 Aug 2024 03:08:22 +0000 (20:08 -0700)
Allow the sysadmin to use xfs_repair to upgrade an existing filesystem
to support the reverse mapping btree index for realtime volumes.  This
is needed for online fsck.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
libxfs/libxfs_api_defs.h
repair/phase2.c

index f36e111820136f11308e3ec4f17702c833dc40c9..775b33fc5d9b847cc30988e47ee17761d1dd697b 100644 (file)
@@ -74,6 +74,7 @@
 #define xfs_btree_bload                        libxfs_btree_bload
 #define xfs_btree_bload_compute_geometry libxfs_btree_bload_compute_geometry
 #define xfs_btree_calc_size            libxfs_btree_calc_size
+#define xfs_btree_compute_maxlevels    libxfs_btree_compute_maxlevels
 #define xfs_btree_decrement            libxfs_btree_decrement
 #define xfs_btree_del_cursor           libxfs_btree_del_cursor
 #define xfs_btree_delete               libxfs_btree_delete
 #define xfs_log_sb                     libxfs_log_sb
 
 #define xfs_metafile_iget              libxfs_metafile_iget
+#define xfs_metafile_resv_free         libxfs_metafile_resv_free
+#define xfs_metafile_resv_init         libxfs_metafile_resv_init
 #define xfs_metafile_set_iflag         libxfs_metafile_set_iflag
 #define xfs_metadir_cancel             libxfs_metadir_cancel
 #define xfs_metadir_commit             libxfs_metadir_commit
 #define xfs_rtgroup_get                        libxfs_rtgroup_get
 #define xfs_rtgroup_put                        libxfs_rtgroup_put
 #define xfs_rtgroup_update_super       libxfs_rtgroup_update_super
+#define xfs_rtrmapbt_calc_reserves     libxfs_rtrmapbt_calc_reserves
 #define xfs_rtrmapbt_calc_size         libxfs_rtrmapbt_calc_size
 #define xfs_rtrmapbt_commit_staged_btree       libxfs_rtrmapbt_commit_staged_btree
 #define xfs_rtrmapbt_create            libxfs_rtrmapbt_create
index 921e5ea0e4a578c502fdb47fefdc805d908f9bac..b91d03d3e14bcd772c86b79d8c87cb450d80254c 100644 (file)
@@ -277,9 +277,8 @@ set_rmapbt(
                exit(0);
        }
 
-       if (xfs_has_realtime(mp)) {
-               printf(
-       _("Reverse mapping btree feature not supported with realtime.\n"));
+       if (xfs_has_realtime(mp) && !xfs_has_rtgroups(mp)) {
+               printf(_("Reverse mapping btree requires realtime groups.\n"));
                exit(0);
        }
 
@@ -292,6 +291,11 @@ set_rmapbt(
        printf(_("Adding reverse mapping btrees to filesystem.\n"));
        new_sb->sb_features_ro_compat |= XFS_SB_FEAT_RO_COMPAT_RMAPBT;
        new_sb->sb_features_incompat |= XFS_SB_FEAT_INCOMPAT_NEEDSREPAIR;
+
+       /* Quota counts will be wrong once we add the rmap inodes. */
+       if (xfs_has_realtime(mp))
+               quotacheck_skip();
+
        return true;
 }
 
@@ -525,6 +529,37 @@ check_free_space(
        return avail > GIGABYTES(10, mp->m_sb.sb_blocklog);
 }
 
+/*
+ * Reserve space to handle rt rmap btree expansion.
+ *
+ * If the rmap inode for this group already exists, we assume that we're adding
+ * some other feature.  Note that we have not validated the metadata directory
+ * tree, so we must perform the lookup by hand and abort the upgrade if there
+ * are errors.  Otherwise, the amount of space needed to handle a new maximally
+ * sized rmap btree is added to @new_resv.
+ */
+static int
+reserve_rtrmap_inode(
+       struct xfs_rtgroup      *rtg,
+       xfs_rfsblock_t          *new_resv)
+{
+       struct xfs_mount        *mp = rtg->rtg_mount;
+       struct xfs_inode        *ip = rtg->rtg_inodes[XFS_RTG_RMAP];
+       xfs_filblks_t           ask;
+
+       if (!xfs_has_rtrmapbt(mp))
+               return 0;
+
+       ask = libxfs_rtrmapbt_calc_reserves(mp);
+
+       /* failed to load the rtdir inode? */
+       if (!ip) {
+               *new_resv += ask;
+               return 0;
+       }
+       return -libxfs_metafile_resv_init(ip, ask);
+}
+
 static void
 check_fs_free_space(
        struct xfs_mount                *mp,
@@ -532,7 +567,10 @@ check_fs_free_space(
        struct xfs_sb                   *new_sb)
 {
        struct xfs_perag                *pag;
+       struct xfs_rtgroup              *rtg;
+       xfs_rfsblock_t                  new_resv = 0;
        xfs_agnumber_t                  agno;
+       xfs_rgnumber_t                  rgno;
        int                             error;
 
        /* Make sure we have enough space for per-AG reservations. */
@@ -608,6 +646,21 @@ check_fs_free_space(
                libxfs_trans_cancel(tp);
        }
 
+       /* Realtime metadata btree inodes */
+       for_each_rtgroup(mp, rgno, rtg) {
+               error = reserve_rtrmap_inode(rtg, &new_resv);
+               if (error == ENOSPC) {
+                       printf(
+_("Not enough free space would remain for rtgroup %u rmap inode.\n"),
+                                       rtg->rtg_rgno);
+                       exit(0);
+               }
+               if (error)
+                       do_error(
+_("Error %d while checking rtgroup %u rmap inode space reservation.\n"),
+                                       error, rtg->rtg_rgno);
+       }
+
        /*
         * If we're adding parent pointers, we need at least 25% free since
         * scanning the entire filesystem to guesstimate the overhead is
@@ -623,13 +676,20 @@ check_fs_free_space(
 
        /*
         * Would the post-upgrade filesystem have enough free space on the data
-        * device after making per-AG reservations?
+        * device after making per-AG reservations and reserving rt metadata
+        * inode blocks?
         */
-       if (!check_free_space(mp, mp->m_sb.sb_fdblocks, mp->m_sb.sb_dblocks)) {
+       if (new_resv > mp->m_sb.sb_fdblocks ||
+           !check_free_space(mp, mp->m_sb.sb_fdblocks, mp->m_sb.sb_dblocks)) {
                printf(_("Filesystem will be low on space after upgrade.\n"));
                exit(1);
        }
 
+       /* Unreserve the realtime metadata reservations. */
+       for_each_rtgroup(mp, rgno, rtg) {
+               libxfs_metafile_resv_free(rtg->rtg_inodes[XFS_RTG_RMAP]);
+       }
+
        /*
         * Release the per-AG reservations and mark the per-AG structure as
         * uninitialized so that we don't trip over stale cached counters