315 lines
8.9 KiB
Diff
315 lines
8.9 KiB
Diff
From 2c0500e6036dc996ea9553c9d56b26f54d815e45 Mon Sep 17 00:00:00 2001
|
|
From: "Darrick J. Wong" <djwong@kernel.org>
|
|
Date: Fri, 29 Sep 2023 09:53:42 +0000
|
|
Subject: [PATCH 07/11] mkfs: enable the new force-align feature
|
|
|
|
Make it so that we can create filesystems with the forcealign feature
|
|
turned on.
|
|
|
|
jpg: enforce extsize must be a power-of-2 for forcealign, relocate
|
|
is_power_of_2() to be accessible for mkfs
|
|
|
|
Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
|
|
Signed-off-by: John Garry <john.g.garry@oracle.com>
|
|
|
|
---
|
|
include/libxfs.h | 6 +++
|
|
libxfs/libxfs_priv.h | 6 ---
|
|
man/man8/mkfs.xfs.8 | 15 ++++++
|
|
mkfs/xfs_mkfs.c | 124 ++++++++++++++++++++++++++++++++++++++++++-
|
|
4 files changed, 143 insertions(+), 8 deletions(-)
|
|
|
|
diff --git a/include/libxfs.h b/include/libxfs.h
|
|
index 24424d0..cf4baff 100644
|
|
--- a/include/libxfs.h
|
|
+++ b/include/libxfs.h
|
|
@@ -43,6 +43,12 @@ struct iomap;
|
|
#define round_up(x, y) ((((x)-1) | __round_mask(x, y))+1)
|
|
#define unlikely(x) (x)
|
|
|
|
+static inline __attribute__((const))
|
|
+int is_power_of_2(unsigned long n)
|
|
+{
|
|
+ return (n != 0 && ((n & (n - 1)) == 0));
|
|
+}
|
|
+
|
|
/*
|
|
* This mirrors the kernel include for xfs_buf.h - it's implicitly included in
|
|
* every files via a similar include in the kernel xfs_linux.h.
|
|
diff --git a/libxfs/libxfs_priv.h b/libxfs/libxfs_priv.h
|
|
index 15bae1f..0dc6627 100644
|
|
--- a/libxfs/libxfs_priv.h
|
|
+++ b/libxfs/libxfs_priv.h
|
|
@@ -369,12 +369,6 @@ find_next_zero_bit(const unsigned long *addr, unsigned long size,
|
|
}
|
|
#define find_first_zero_bit(addr, size) find_next_zero_bit((addr), (size), 0)
|
|
|
|
-static inline __attribute__((const))
|
|
-int is_power_of_2(unsigned long n)
|
|
-{
|
|
- return (n != 0 && ((n & (n - 1)) == 0));
|
|
-}
|
|
-
|
|
/*
|
|
* xfs_iroundup: round up argument to next power of two
|
|
*/
|
|
diff --git a/man/man8/mkfs.xfs.8 b/man/man8/mkfs.xfs.8
|
|
index 5cd69fa..8f159a4 100644
|
|
--- a/man/man8/mkfs.xfs.8
|
|
+++ b/man/man8/mkfs.xfs.8
|
|
@@ -654,6 +654,21 @@ space over time such that no free extents are large enough to
|
|
accommodate a chunk of 64 inodes. Without this feature enabled, inode
|
|
allocations can fail with out of space errors under severe fragmented
|
|
free space conditions.
|
|
+.TP
|
|
+.BI forcealign[= value]
|
|
+If
|
|
+.B value
|
|
+is 1, mark the root directory so that all file data extent allocations will be
|
|
+aligned to the extent size hint.
|
|
+These allocations will be mapped into the file range at offsets that are
|
|
+aligned to the extent size hint.
|
|
+The
|
|
+.B extszinherit
|
|
+option must be specified.
|
|
+The
|
|
+.B cowextsize
|
|
+option must not be specified.
|
|
+This feature is only available for filesystems formatted with -m crc=1.
|
|
.RE
|
|
.PP
|
|
.PD 0
|
|
diff --git a/mkfs/xfs_mkfs.c b/mkfs/xfs_mkfs.c
|
|
index fb0c53f..1253ece 100644
|
|
--- a/mkfs/xfs_mkfs.c
|
|
+++ b/mkfs/xfs_mkfs.c
|
|
@@ -81,6 +81,7 @@ enum {
|
|
I_ATTR,
|
|
I_PROJID32BIT,
|
|
I_SPINODES,
|
|
+ I_FORCEALIGN,
|
|
I_MAX_OPTS,
|
|
};
|
|
|
|
@@ -451,6 +452,7 @@ static struct opt_params iopts = {
|
|
[I_ATTR] = "attr",
|
|
[I_PROJID32BIT] = "projid32bit",
|
|
[I_SPINODES] = "sparse",
|
|
+ [I_FORCEALIGN] = "forcealign",
|
|
[I_MAX_OPTS] = NULL,
|
|
},
|
|
.subopt_params = {
|
|
@@ -500,6 +502,12 @@ static struct opt_params iopts = {
|
|
.maxval = 1,
|
|
.defaultval = 1,
|
|
},
|
|
+ { .index = I_FORCEALIGN,
|
|
+ .conflicts = { { NULL, LAST_CONFLICT } },
|
|
+ .minval = 0,
|
|
+ .maxval = 1,
|
|
+ .defaultval = 1,
|
|
+ },
|
|
},
|
|
};
|
|
|
|
@@ -829,6 +837,7 @@ struct sb_feat_args {
|
|
bool bigtime; /* XFS_SB_FEAT_INCOMPAT_BIGTIME */
|
|
bool nodalign;
|
|
bool nortalign;
|
|
+ bool forcealign; /* XFS_SB_FEAT_RO_COMPAT_FORCEALIGN */
|
|
};
|
|
|
|
struct cli_params {
|
|
@@ -961,6 +970,7 @@ usage( void )
|
|
/* force overwrite */ [-f]\n\
|
|
/* inode size */ [-i perblock=n|size=num,maxpct=n,attr=0|1|2,\n\
|
|
projid32bit=0|1,sparse=0|1]\n\
|
|
+ forcealign=0|1\n\
|
|
/* no discard */ [-K]\n\
|
|
/* log subvol */ [-l agnum=n,internal,size=num,logdev=xxx,version=n\n\
|
|
sunit=value|su=num,sectsize=num,lazy-count=0|1]\n\
|
|
@@ -1601,6 +1611,8 @@ inode_opts_parser(
|
|
const char *value,
|
|
struct cli_params *cli)
|
|
{
|
|
+ long long val;
|
|
+
|
|
switch (subopt) {
|
|
case I_ALIGN:
|
|
cli->sb_feat.inode_align = getnum(value, opts, subopt);
|
|
@@ -1623,6 +1635,17 @@ inode_opts_parser(
|
|
case I_SPINODES:
|
|
cli->sb_feat.spinodes = getnum(value, opts, subopt);
|
|
break;
|
|
+ case I_FORCEALIGN:
|
|
+ val = getnum(value, opts, subopt);
|
|
+
|
|
+ if (val == 1) {
|
|
+ cli->sb_feat.forcealign = true;
|
|
+ cli->fsx.fsx_xflags |= FS_XFLAG_FORCEALIGN;
|
|
+ } else {
|
|
+ cli->sb_feat.forcealign = false;
|
|
+ cli->fsx.fsx_xflags &= ~FS_XFLAG_FORCEALIGN;
|
|
+ }
|
|
+ break;
|
|
default:
|
|
return -EINVAL;
|
|
}
|
|
@@ -2228,6 +2251,13 @@ _("timestamps later than 2038 not supported without CRC support\n"));
|
|
usage();
|
|
}
|
|
cli->sb_feat.bigtime = false;
|
|
+
|
|
+ if (cli->sb_feat.forcealign) {
|
|
+ fprintf(stderr,
|
|
+_("forced file data alignment not supported without CRC support\n"));
|
|
+ usage();
|
|
+ }
|
|
+ cli->sb_feat.forcealign = false;
|
|
}
|
|
|
|
if (!cli->sb_feat.finobt) {
|
|
@@ -2262,6 +2292,13 @@ _("cowextsize not supported without reflink support\n"));
|
|
usage();
|
|
}
|
|
|
|
+ if ((cli->fsx.fsx_xflags & FS_XFLAG_FORCEALIGN) &&
|
|
+ (cli->fsx.fsx_cowextsize > 0 || cli->fsx.fsx_extsize == 0 || !is_power_of_2(cli->fsx.fsx_extsize))) {
|
|
+ fprintf(stderr,
|
|
+_("forcealign requires a non-zero power-of-2 extent size hint and no cow extent size hint\n"));
|
|
+ usage();
|
|
+ }
|
|
+
|
|
/*
|
|
* Copy features across to config structure now.
|
|
*/
|
|
@@ -2511,6 +2548,34 @@ _("illegal CoW extent size hint %lld, must be less than %u.\n"),
|
|
}
|
|
}
|
|
|
|
+/* Validate the incoming forcealign flag. */
|
|
+static void
|
|
+validate_forcealign(
|
|
+ struct xfs_mount *mp,
|
|
+ struct cli_params *cli)
|
|
+{
|
|
+ if (!(cli->fsx.fsx_xflags & FS_XFLAG_FORCEALIGN))
|
|
+ return;
|
|
+
|
|
+ if (cli->fsx.fsx_cowextsize != 0) {
|
|
+ fprintf(stderr,
|
|
+_("cannot set CoW extent size hint when forcealign is set.\n"));
|
|
+ usage();
|
|
+ }
|
|
+
|
|
+ if (cli->fsx.fsx_extsize == 0) {
|
|
+ fprintf(stderr,
|
|
+_("cannot set forcealign without an extent size hint.\n"));
|
|
+ usage();
|
|
+ }
|
|
+
|
|
+ if (cli->fsx.fsx_xflags & (FS_XFLAG_REALTIME | FS_XFLAG_RTINHERIT)) {
|
|
+ fprintf(stderr,
|
|
+_("cannot set forcealign and realtime flags.\n"));
|
|
+ usage();
|
|
+ }
|
|
+}
|
|
+
|
|
/*
|
|
* Validate the configured stripe geometry, or is none is specified, pull
|
|
* the configuration from the underlying device.
|
|
@@ -2978,11 +3043,63 @@ _("agsize (%s) not a multiple of fs blk size (%d)\n"),
|
|
*/
|
|
static void
|
|
align_ag_geometry(
|
|
- struct mkfs_params *cfg)
|
|
+ struct mkfs_params *cfg,
|
|
+ struct cli_params *cli)
|
|
{
|
|
uint64_t tmp_agsize;
|
|
int dsunit = cfg->dsunit;
|
|
|
|
+ /*
|
|
+ * If the sysadmin wants to force all file data space mappings to be
|
|
+ * aligned to the extszinherit value, then we need the AGs to be
|
|
+ * aligned to the same value. Skip these checks if the extent size
|
|
+ * hint is zero; the extszinherit validation will fail the format
|
|
+ * later.
|
|
+ */
|
|
+ if (cli->sb_feat.forcealign && cli->fsx.fsx_extsize != 0) {
|
|
+ /* Perfect alignment; we're done. */
|
|
+ if (cfg->agsize % cli->fsx.fsx_extsize == 0)
|
|
+ goto validate;
|
|
+
|
|
+ /*
|
|
+ * Round up to file extent size boundary. Make sure that
|
|
+ * agsize is still larger than XFS_AG_MIN_BLOCKS(blocklog).
|
|
+ */
|
|
+ tmp_agsize = ((cfg->agsize + cli->fsx.fsx_extsize - 1) /
|
|
+ cli->fsx.fsx_extsize) * cli->fsx.fsx_extsize;
|
|
+
|
|
+ /*
|
|
+ * Round down to file extent size boundary if rounding up
|
|
+ * created an AG size that is larger than the AG max.
|
|
+ */
|
|
+ if (tmp_agsize > XFS_AG_MAX_BLOCKS(cfg->blocklog))
|
|
+ tmp_agsize = (cfg->agsize / cli->fsx.fsx_extsize) *
|
|
+ cli->fsx.fsx_extsize;
|
|
+
|
|
+ if (tmp_agsize < XFS_AG_MIN_BLOCKS(cfg->blocklog) &&
|
|
+ tmp_agsize > XFS_AG_MAX_BLOCKS(cfg->blocklog)) {
|
|
+ /*
|
|
+ * Set the agsize to the invalid value so the following
|
|
+ * validation of the ag will fail and print a nice error
|
|
+ * and exit.
|
|
+ */
|
|
+ cfg->agsize = tmp_agsize;
|
|
+ goto validate;
|
|
+ }
|
|
+
|
|
+ /* Update geometry to be file extent size aligned */
|
|
+ cfg->agsize = tmp_agsize;
|
|
+ if (!cli_opt_set(&dopts, D_AGCOUNT))
|
|
+ cfg->agcount = cfg->dblocks / cfg->agsize +
|
|
+ (cfg->dblocks % cfg->agsize != 0);
|
|
+
|
|
+ if (cli_opt_set(&dopts, D_AGSIZE))
|
|
+ fprintf(stderr,
|
|
+_("agsize rounded to %lld, extszhint = %d\n"),
|
|
+ (long long)cfg->agsize, cli->fsx.fsx_extsize);
|
|
+ goto validate;
|
|
+ }
|
|
+
|
|
if (!dsunit)
|
|
goto validate;
|
|
|
|
@@ -3202,6 +3319,8 @@ sb_set_features(
|
|
sbp->sb_features_ro_compat |= XFS_SB_FEAT_RO_COMPAT_REFLINK;
|
|
if (fp->inobtcnt)
|
|
sbp->sb_features_ro_compat |= XFS_SB_FEAT_RO_COMPAT_INOBTCNT;
|
|
+ if (fp->forcealign)
|
|
+ sbp->sb_features_ro_compat |= XFS_SB_FEAT_RO_COMPAT_FORCEALIGN;
|
|
if (fp->bigtime)
|
|
sbp->sb_features_incompat |= XFS_SB_FEAT_INCOMPAT_BIGTIME;
|
|
|
|
@@ -4164,7 +4283,7 @@ main(
|
|
* aligns to device geometry correctly.
|
|
*/
|
|
calculate_initial_ag_geometry(&cfg, &cli);
|
|
- align_ag_geometry(&cfg);
|
|
+ align_ag_geometry(&cfg, &cli);
|
|
|
|
calculate_imaxpct(&cfg, &cli);
|
|
|
|
@@ -4187,6 +4306,7 @@ main(
|
|
/* Validate the extent size hints now that @mp is fully set up. */
|
|
validate_extsize_hint(mp, &cli);
|
|
validate_cowextsize_hint(mp, &cli);
|
|
+ validate_forcealign(mp, &cli);
|
|
|
|
/* Print the intended geometry of the fs. */
|
|
if (!quiet || dry_run) {
|
|
--
|
|
2.33.0
|
|
|