From: Darrick J. Wong <djwong@xxxxxxxxxx> 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@xxxxxxxxxx> --- libxfs/libxfs_api_defs.h | 1 + repair/phase2.c | 75 +++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 74 insertions(+), 2 deletions(-) diff --git a/libxfs/libxfs_api_defs.h b/libxfs/libxfs_api_defs.h index 5c7396a53a6..63607cf2b94 100644 --- a/libxfs/libxfs_api_defs.h +++ b/libxfs/libxfs_api_defs.h @@ -251,6 +251,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_commit_staged_btree libxfs_rtrefcountbt_commit_staged_btree #define xfs_rtrefcountbt_create libxfs_rtrefcountbt_create #define xfs_rtrefcountbt_create_path libxfs_rtrefcountbt_create_path diff --git a/repair/phase2.c b/repair/phase2.c index 35c1214be9a..ded281e4b88 100644 --- a/repair/phase2.c +++ b/repair/phase2.c @@ -242,14 +242,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; } @@ -462,6 +467,55 @@ reserve_rtrmap_inode( return -libxfs_imeta_resv_init_inode(rtg->rtg_rmapip, 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_imeta_path *path; + xfs_ino_t ino; + xfs_filblks_t ask; + int error; + + if (!xfs_has_rtreflink(mp)) + return 0; + + error = -libxfs_rtrefcountbt_create_path(mp, rtg->rtg_rgno, &path); + if (error) + return error; + + ask = libxfs_rtrefcountbt_calc_reserves(mp); + + error = -libxfs_imeta_lookup(mp, path, &ino); + libxfs_imeta_free_path(path); + if (error == EFSCORRUPTED) { + if (ask > mp->m_sb.sb_fdblocks) + return ENOSPC; + + *new_resv += ask; + return 0; + } + if (error) + return error; + + error = -libxfs_imeta_iget(mp, ino, XFS_DIR3_FT_REG_FILE, + &rtg->rtg_refcountip); + if (error) + return error; + + return -libxfs_imeta_resv_init_inode(rtg->rtg_refcountip, ask); +} + static void check_fs_free_space( struct xfs_mount *mp, @@ -561,6 +615,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"), rtg->rtg_rgno, error); + + 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"), + rtg->rtg_rgno, error); } /* @@ -581,6 +647,11 @@ _("Error %d while checking rtgroup %u rmap inode space reservation.\n"), libxfs_imeta_irele(rtg->rtg_rmapip); rtg->rtg_rmapip = NULL; } + if (rtg->rtg_refcountip) { + libxfs_imeta_resv_free_inode(rtg->rtg_refcountip); + libxfs_imeta_irele(rtg->rtg_refcountip); + rtg->rtg_refcountip = NULL; + } } /*