@@ -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;
}
@@ -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) {
@@ -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);
}