From 96c172dc0402da63c4d3790c9f245c5ff23a45bf Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Wed, 3 Jul 2024 14:22:25 -0700 Subject: [PATCH] xfs_repair: allow sysadmins to add realtime reverse mapping indexes 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 --- libxfs/libxfs_api_defs.h | 4 +++ repair/phase2.c | 70 +++++++++++++++++++++++++++++++++++++--- 2 files changed, 69 insertions(+), 5 deletions(-) diff --git a/libxfs/libxfs_api_defs.h b/libxfs/libxfs_api_defs.h index f36e11182..775b33fc5 100644 --- a/libxfs/libxfs_api_defs.h +++ b/libxfs/libxfs_api_defs.h @@ -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 @@ -214,6 +215,8 @@ #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 @@ -304,6 +307,7 @@ #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 diff --git a/repair/phase2.c b/repair/phase2.c index ead8ffb50..2f3c041e3 100644 --- a/repair/phase2.c +++ b/repair/phase2.c @@ -276,9 +276,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); } @@ -291,6 +290,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; } @@ -513,6 +517,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, @@ -520,7 +555,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. */ @@ -596,6 +634,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 @@ -611,13 +664,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 -- 2.50.1