From 62a3ef0a49769d66d2331c61d93dd80a91e2f437 Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Mon, 12 Aug 2024 14:19:26 -0700 Subject: [PATCH] xfs_repair: allow sysadmins to add realtime reflink 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 --- libxfs/libxfs_api_defs.h | 1 + repair/phase2.c | 54 ++++++++++++++++++++++++++++++++++++++-- 2 files changed, 53 insertions(+), 2 deletions(-) diff --git a/libxfs/libxfs_api_defs.h b/libxfs/libxfs_api_defs.h index c0ce84f2a..93220c2fa 100644 --- a/libxfs/libxfs_api_defs.h +++ b/libxfs/libxfs_api_defs.h @@ -309,6 +309,7 @@ #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 diff --git a/repair/phase2.c b/repair/phase2.c index b91d03d3e..486b58798 100644 --- a/repair/phase2.c +++ b/repair/phase2.c @@ -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]); } /* -- 2.50.1