[PATCH 22/22] mkfs: enable reflink on the realtime device

Darrick J. Wong
2025-02-06T23:02:30Z

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@kernel.org>
---
libxfs/init.c | 4 +--
libxfs/libxfs_api_defs.h | 1 +
mkfs/xfs_mkfs.c | 63 ++++++++++++++++++++++++++++++++++++++++++----
3 files changed, 60 insertions(+), 8 deletions(-)

diff --git a/libxfs/init.c b/libxfs/init.c
index 00bd46a6013e28..5b45ed3472762c 100644
--- a/libxfs/init.c
+++ b/libxfs/init.c
@@ -305,9 +305,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/libxfs/libxfs_api_defs.h b/libxfs/libxfs_api_defs.h
index 66cbb34f05a48f..530feef2a47db8 100644
--- a/libxfs/libxfs_api_defs.h
+++ b/libxfs/libxfs_api_defs.h
@@ -323,6 +323,7 @@
#define xfs_rtrefcountbt_absolute_maxlevels libxfs_rtrefcountbt_absolute_maxlevels
#define xfs_rtrefcountbt_calc_reserves libxfs_rtrefcountbt_calc_reserves
#define xfs_rtrefcountbt_calc_size libxfs_rtrefcountbt_calc_size
+#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_droot_maxrecs libxfs_rtrefcountbt_droot_maxrecs
diff --git a/mkfs/xfs_mkfs.c b/mkfs/xfs_mkfs.c
index 9239109434d748..c794f918573f91 100644
--- a/mkfs/xfs_mkfs.c
+++ b/mkfs/xfs_mkfs.c
@@ -2671,12 +2671,36 @@ _("inode btree counters not supported without finobt support\n"));
}

if (cli->xi->rt.name) {
- 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 (cfg->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.metadir && cli->sb_feat.reflink) {
+ if (cli_opt_set(&mopts, M_REFLINK) &&
+ cli_opt_set(&mopts, M_METADIR)) {
+ fprintf(stderr,
+_("reflink not supported on realtime devices without metadir feature\n"));
+ usage();
+ } else if (cli_opt_set(&mopts, M_REFLINK)) {
+ cli->sb_feat.metadir = true;
+ } else {
+ cli->sb_feat.reflink = false;
+ }
}
- cli->sb_feat.reflink = false;

if (!cli->sb_feat.metadir && cli->sb_feat.rmapbt) {
if (cli_opt_set(&mopts, M_RMAPBT) &&
@@ -2874,6 +2898,19 @@ validate_rtextsize(
usage();
}
cfg->rtextblocks = (xfs_extlen_t)(rtextbytes >> cfg->blocklog);
+ } else if (cli->sb_feat.reflink && cli->xi->rt.name) {
+ /*
+ * 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,
@@ -2905,6 +2942,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. */
@@ -5087,11 +5130,19 @@ check_rt_meta_prealloc(
error = -libxfs_metafile_resv_init(rtg_rmap(rtg), ask);
if (error)
prealloc_fail(mp, error, ask, _("realtime rmap btree"));
+
+ ask = libxfs_rtrefcountbt_calc_reserves(mp);
+ error = -libxfs_metafile_resv_init(rtg_refcount(rtg), ask);
+ if (error)
+ prealloc_fail(mp, error, ask,
+ _("realtime refcount btree"));
}

/* 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));
+ }

/* Unreserve the per-AG reservations. */
while ((pag = xfs_perag_next(mp, pag)))