From 2c0500e6036dc996ea9553c9d56b26f54d815e45 Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" 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" Signed-off-by: John Garry --- 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