From: Darrick J. Wong Date: Thu, 15 Aug 2024 18:57:41 +0000 (-0700) Subject: xfs_repair: allow sysadmins to add realtime reverse mapping indexes X-Git-Url: https://www.infradead.org/git/?a=commitdiff_plain;h=5dcb56eff528bb6310c688f6bbbd9ee8b33fd175;p=users%2Fhch%2Fxfsprogs.git 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 --- diff --git a/libxfs/libxfs_api_defs.h b/libxfs/libxfs_api_defs.h index 8a4dac171..9a0a1b11f 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 @@ -215,6 +216,8 @@ #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 @@ -308,6 +311,7 @@ #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 diff --git a/repair/phase2.c b/repair/phase2.c index 721ad6046..949b05dc0 100644 --- a/repair/phase2.c +++ b/repair/phase2.c @@ -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