]> 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>
Thu, 15 Aug 2024 18:57:41 +0000 (11:57 -0700)
committerDarrick J. Wong <djwong@kernel.org>
Fri, 16 Aug 2024 21:57:42 +0000 (14:57 -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 8a4dac171aa3cf0350ad137e74d404eb60e2aac0..9a0a1b11fc314d0af58b1959bcf9ed23a0011dec 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_metafile_iget              libxfs_metafile_iget
 #define xfs_trans_metafile_iget                libxfs_trans_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_update_rtsb                        libxfs_update_rtsb
 #define xfs_rtgroup_get                        libxfs_rtgroup_get
 #define xfs_rtgroup_put                        libxfs_rtgroup_put
+#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 721ad60467d88130ef06facc482bb0e7049827c3..949b05dc0dd1e8088a9c144e1e6394909bde6166 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_RTGI_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_RTGI_RMAP]);
+       }
+
        /*
         * Release the per-AG reservations and mark the per-AG structure as
         * uninitialized so that we don't trip over stale cached counters