]> www.infradead.org Git - users/hch/xfsprogs.git/commitdiff
xfs_repair: allow sysadmins to add realtime reflink
authorDarrick J. Wong <djwong@kernel.org>
Mon, 12 Aug 2024 21:19:26 +0000 (14:19 -0700)
committerDarrick J. Wong <djwong@kernel.org>
Wed, 14 Aug 2024 03:08:24 +0000 (20:08 -0700)
Allow the sysadmin to use xfs_repair to upgrade an existing filesystem
to support the realtime reference count btree, and therefore reflink on
realtime volumes.

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

index c0ce84f2a59e3da34717f8892db37168422acac3..93220c2faa9296bb9293e96972f5aee58ba59251 100644 (file)
 #define xfs_rtgroup_update_super       libxfs_rtgroup_update_super
 
 #define xfs_rtrefcountbt_absolute_maxlevels    libxfs_rtrefcountbt_absolute_maxlevels
+#define xfs_rtrefcountbt_calc_reserves libxfs_rtrefcountbt_calc_reserves
 #define xfs_rtrefcountbt_calc_size             libxfs_rtrefcountbt_calc_size
 #define xfs_rtrefcountbt_commit_staged_btree   libxfs_rtrefcountbt_commit_staged_btree
 #define xfs_rtrefcountbt_create                libxfs_rtrefcountbt_create
index b91d03d3e14bcd772c86b79d8c87cb450d80254c..486b587989935adf1c05f36492955492951363c8 100644 (file)
@@ -250,14 +250,19 @@ set_reflink(
                exit(0);
        }
 
-       if (xfs_has_realtime(mp)) {
-               printf(_("Reflink feature not supported with realtime.\n"));
+       if (xfs_has_realtime(mp) && !xfs_has_rtgroups(mp)) {
+               printf(_("Reference count btree requires realtime groups.\n"));
                exit(0);
        }
 
        printf(_("Adding reflink support to filesystem.\n"));
        new_sb->sb_features_ro_compat |= XFS_SB_FEAT_RO_COMPAT_REFLINK;
        new_sb->sb_features_incompat |= XFS_SB_FEAT_INCOMPAT_NEEDSREPAIR;
+
+       /* Quota counts will be wrong once we add the refcount inodes. */
+       if (xfs_has_realtime(mp))
+               quotacheck_skip();
+
        return true;
 }
 
@@ -560,6 +565,38 @@ reserve_rtrmap_inode(
        return -libxfs_metafile_resv_init(ip, ask);
 }
 
+/*
+ * Reserve space to handle rt refcount btree expansion.
+ *
+ * If the refcount 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.  If the inode does not exist, the amount of space
+ * needed to handle a new maximally sized refcount btree is added to @new_resv.
+ */
+static int
+reserve_rtrefcount_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_REFCOUNT];
+       xfs_filblks_t           ask;
+
+       if (!xfs_has_rtreflink(mp))
+               return 0;
+
+       ask = libxfs_rtrefcountbt_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,
@@ -659,6 +696,18 @@ _("Not enough free space would remain for rtgroup %u rmap inode.\n"),
                        do_error(
 _("Error %d while checking rtgroup %u rmap inode space reservation.\n"),
                                        error, rtg->rtg_rgno);
+
+               error = reserve_rtrefcount_inode(rtg, &new_resv);
+               if (error == ENOSPC) {
+                       printf(
+_("Not enough free space would remain for rtgroup %u refcount inode.\n"),
+                                       rtg->rtg_rgno);
+                       exit(0);
+               }
+               if (error)
+                       do_error(
+_("Error %d while checking rtgroup %u refcount inode space reservation.\n"),
+                                       error, rtg->rtg_rgno);
        }
 
        /*
@@ -688,6 +737,7 @@ _("Error %d while checking rtgroup %u rmap inode space reservation.\n"),
        /* Unreserve the realtime metadata reservations. */
        for_each_rtgroup(mp, rgno, rtg) {
                libxfs_metafile_resv_free(rtg->rtg_inodes[XFS_RTG_RMAP]);
+               libxfs_metafile_resv_free(rtg->rtg_inodes[XFS_RTG_REFCOUNT]);
        }
 
        /*