From: Darrick J. Wong <djwong@xxxxxxxxxx> Allow the creation of filesystems with both reflink and realtime volumes enabled. For now we don't support a realtime extent size > 1. Signed-off-by: Darrick J. Wong <djwong@xxxxxxxxxx> --- libxfs/init.c | 4 ++-- mkfs/proto.c | 44 +++++++++++++++++++++++++++++++++++++++++ mkfs/xfs_mkfs.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++----- 3 files changed, 100 insertions(+), 7 deletions(-) diff --git a/libxfs/init.c b/libxfs/init.c index 40ebbbce39d..a4023f78655 100644 --- a/libxfs/init.c +++ b/libxfs/init.c @@ -448,9 +448,9 @@ rtmount_init( if (mp->m_sb.sb_rblocks == 0) return 0; - if (xfs_has_reflink(mp)) { + if (xfs_has_reflink(mp) && mp->m_sb.sb_rextsize > 1) { fprintf(stderr, - _("%s: Reflink not compatible with realtime device. Please try a newer xfsprogs.\n"), + _("%s: Reflink not compatible with realtime extent size > 1. Please try a newer xfsprogs.\n"), progname); return -1; } diff --git a/mkfs/proto.c b/mkfs/proto.c index 96eab25da45..c98568ca507 100644 --- a/mkfs/proto.c +++ b/mkfs/proto.c @@ -851,6 +851,48 @@ rtrmapbt_create( libxfs_imeta_free_path(path); } +/* Create the realtime refcount btree inode. */ +static void +rtrefcountbt_create( + struct xfs_rtgroup *rtg) +{ + struct xfs_mount *mp = rtg->rtg_mount; + struct xfs_imeta_update upd; + struct xfs_imeta_path *path; + struct xfs_trans *tp; + int error; + + error = -libxfs_rtrefcountbt_create_path(mp, rtg->rtg_rgno, &path); + if (error) + fail( _("rtrefcount inode path creation failed"), error); + + error = -libxfs_imeta_ensure_dirpath(mp, path); + if (error) + fail(_("rtgroup allocation failed"), + error); + + error = -libxfs_imeta_start_update(mp, path, &upd); + if (error) + res_failed(error); + + error = -libxfs_trans_alloc(mp, &M_RES(mp)->tr_imeta_create, + libxfs_imeta_create_space_res(mp), 0, 0, &tp); + if (error) + res_failed(error); + + error = -libxfs_rtrefcountbt_create(&tp, path, &upd, + &rtg->rtg_refcountip); + if (error) + fail(_("rtrefcount inode creation failed"), error); + + error = -libxfs_trans_commit(tp); + if (error) + fail(_("rtrefcountbt commit failed"), error); + + libxfs_imeta_end_update(mp, &upd, 0); + libxfs_imeta_free_path(path); +} + /* Initialize block headers of rt free space files. */ static int init_rtblock_headers( @@ -1033,6 +1075,8 @@ rtinit( for_each_rtgroup(mp, rgno, rtg) { if (xfs_has_rtrmapbt(mp)) rtrmapbt_create(rtg); + if (xfs_has_rtreflink(mp)) + rtrefcountbt_create(rtg); } if (mp->m_sb.sb_rbmblocks) { diff --git a/mkfs/xfs_mkfs.c b/mkfs/xfs_mkfs.c index dcce3d0136e..e406fa6a5ea 100644 --- a/mkfs/xfs_mkfs.c +++ b/mkfs/xfs_mkfs.c @@ -2385,12 +2385,36 @@ _("inode btree counters not supported without finobt support\n")); } if (cli->xi->rtname) { - if (cli->sb_feat.reflink && cli_opt_set(&mopts, M_REFLINK)) { - fprintf(stderr, -_("reflink not supported with realtime devices\n")); - usage(); + if (cli->rtextsize && cli->sb_feat.reflink) { + if (cli_opt_set(&mopts, M_REFLINK)) { + fprintf(stderr, +_("reflink not supported on realtime devices with rt extent size specified\n")); + usage(); + } + cli->sb_feat.reflink = false; + } + if (cli->blocksize < XFS_MIN_RTEXTSIZE && cli->sb_feat.reflink) { + if (cli_opt_set(&mopts, M_REFLINK)) { + fprintf(stderr, +_("reflink not supported on realtime devices with blocksize %d < %d\n"), + cli->blocksize, + XFS_MIN_RTEXTSIZE); + usage(); + } + cli->sb_feat.reflink = false; + } + if (!cli->sb_feat.rtgroups && cli->sb_feat.reflink) { + if (cli_opt_set(&mopts, M_REFLINK) && + cli_opt_set(&ropts, R_RTGROUPS)) { + fprintf(stderr, +_("reflink not supported on realtime devices without rtgroups feature\n")); + usage(); + } else if (cli_opt_set(&mopts, M_REFLINK)) { + cli->sb_feat.rtgroups = true; + } else { + cli->sb_feat.reflink = false; + } } - cli->sb_feat.reflink = false; if (!cli->sb_feat.rtgroups && cli->sb_feat.rmapbt) { if (cli_opt_set(&mopts, M_RMAPBT) && @@ -2558,6 +2582,19 @@ validate_rtextsize( usage(); } cfg->rtextblocks = (xfs_extlen_t)(rtextbytes >> cfg->blocklog); + } else if (cli->sb_feat.reflink && cli->xi->rtname) { + /* + * reflink doesn't support rt extent size > 1FSB yet, so set + * an extent size of 1FSB. Make sure we still satisfy the + * minimum rt extent size. + */ + if (cfg->blocksize < XFS_MIN_RTEXTSIZE) { + fprintf(stderr, + _("reflink not supported on rt volume with blocksize %d\n"), + cfg->blocksize); + usage(); + } + cfg->rtextblocks = 1; } else { /* * If realtime extsize has not been specified by the user, @@ -2589,6 +2626,12 @@ validate_rtextsize( } } ASSERT(cfg->rtextblocks); + + if (cli->sb_feat.reflink && cfg->rtblocks > 0 && cfg->rtextblocks > 1) { + fprintf(stderr, +_("reflink not supported on realtime with extent sizes > 1\n")); + usage(); + } } /* Validate the incoming extsize hint. */ @@ -4583,10 +4626,16 @@ check_rt_meta_prealloc( error = -libxfs_imeta_resv_init_inode(rtg->rtg_rmapip, ask); if (error) prealloc_fail(mp, error, ask, _("realtime rmap btree")); + + ask = libxfs_rtrefcountbt_calc_reserves(mp); + error = -libxfs_imeta_resv_init_inode(rtg->rtg_refcountip, ask); + if (error) + prealloc_fail(mp, error, ask, _("realtime refcount btree")); } /* Unreserve the realtime metadata reservations. */ for_each_rtgroup(mp, rgno, rtg) { + libxfs_imeta_resv_free_inode(rtg->rtg_refcountip); libxfs_imeta_resv_free_inode(rtg->rtg_rmapip); }