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> --- repair/phase2.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 50 insertions(+), 3 deletions(-) diff --git a/repair/phase2.c b/repair/phase2.c index b1288bf3dd90cd..8dc936b572196e 100644 --- a/repair/phase2.c +++ b/repair/phase2.c @@ -250,14 +250,15 @@ 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; + return true; } @@ -497,6 +498,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_mount(rtg); + struct xfs_inode *ip = rtg_refcount(rtg); + 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, @@ -594,6 +627,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_rgno(rtg)); + + error = reserve_rtrefcount_inode(rtg, &new_resv); + if (error == ENOSPC) { + printf( +_("Not enough free space would remain for rtgroup %u refcount inode.\n"), + rtg_rgno(rtg)); + exit(0); + } + if (error) + do_error( +_("Error %d while checking rtgroup %u refcount inode space reservation.\n"), + error, rtg_rgno(rtg)); } /* @@ -621,8 +666,10 @@ _("Error %d while checking rtgroup %u rmap inode space reservation.\n"), } /* Unreserve the realtime metadata reservations. */ - while ((rtg = xfs_rtgroup_next(mp, rtg))) + while ((rtg = xfs_rtgroup_next(mp, rtg))) { libxfs_metafile_resv_free(rtg_rmap(rtg)); + libxfs_metafile_resv_free(rtg_refcount(rtg)); + } /* * Release the per-AG reservations and mark the per-AG structure as