From: "Darrick J. Wong" <djwong@xxxxxxxxxx> Make it so that we can create filesystems with the forcealign feature turned on. Signed-off-by: Darrick J. Wong <djwong@xxxxxxxxxx> #jpg: set .forcealign = true in SB Signed-off-by: John Garry <john.g.garry@xxxxxxxxxx> --- libxfs/xfs_format.h | 3 +- man/man8/mkfs.xfs.8.in | 14 +++++ mkfs/xfs_mkfs.c | 127 +++++++++++++++++++++++++++++++++++++++-- 3 files changed, 139 insertions(+), 5 deletions(-) diff --git a/libxfs/xfs_format.h b/libxfs/xfs_format.h index d718b73f48ca..afb843b14074 100644 --- a/libxfs/xfs_format.h +++ b/libxfs/xfs_format.h @@ -358,7 +358,8 @@ xfs_sb_has_compat_feature( (XFS_SB_FEAT_RO_COMPAT_FINOBT | \ XFS_SB_FEAT_RO_COMPAT_RMAPBT | \ XFS_SB_FEAT_RO_COMPAT_REFLINK| \ - XFS_SB_FEAT_RO_COMPAT_INOBTCNT) + XFS_SB_FEAT_RO_COMPAT_INOBTCNT | \ + XFS_SB_FEAT_RO_COMPAT_FORCEALIGN) #define XFS_SB_FEAT_RO_COMPAT_UNKNOWN ~XFS_SB_FEAT_RO_COMPAT_ALL static inline bool xfs_sb_has_ro_compat_feature( diff --git a/man/man8/mkfs.xfs.8.in b/man/man8/mkfs.xfs.8.in index 9742482dcee9..b86ee4794206 100644 --- a/man/man8/mkfs.xfs.8.in +++ b/man/man8/mkfs.xfs.8.in @@ -657,6 +657,20 @@ Extend maximum values of inode data and attr fork extent counters from 2^31 - omitted, 1 is assumed. This feature is disabled by default. This feature is only available for filesystems formatted with -m crc=1. .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 bffe0b7ea8b0..292d0cbad31a 100644 --- a/mkfs/xfs_mkfs.c +++ b/mkfs/xfs_mkfs.c @@ -90,6 +90,7 @@ enum { I_PROJID32BIT, I_SPINODES, I_NREXT64, + I_FORCEALIGN, I_MAX_OPTS, }; @@ -467,6 +468,7 @@ static struct opt_params iopts = { [I_PROJID32BIT] = "projid32bit", [I_SPINODES] = "sparse", [I_NREXT64] = "nrext64", + [I_FORCEALIGN] = "forcealign", [I_MAX_OPTS] = NULL, }, .subopt_params = { @@ -521,7 +523,13 @@ static struct opt_params iopts = { .minval = 0, .maxval = 1, .defaultval = 1, - } + }, + { .index = I_FORCEALIGN, + .conflicts = { { NULL, LAST_CONFLICT } }, + .minval = 0, + .maxval = 1, + .defaultval = 1, + }, }, }; @@ -874,6 +882,7 @@ struct sb_feat_args { bool nodalign; bool nortalign; bool nrext64; + bool forcealign; /* XFS_SB_FEAT_RO_COMPAT_FORCEALIGN */ }; struct cli_params { @@ -1008,7 +1017,8 @@ usage( void ) sectsize=num,extsize=num\n\ /* force overwrite */ [-f]\n\ /* inode size */ [-i perblock=n|size=num,maxpct=n,attr=0|1|2,\n\ - projid32bit=0|1,sparse=0|1,nrext64=0|1]\n\ + projid32bit=0|1,sparse=0|1,nrext64=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\ @@ -1674,6 +1684,17 @@ inode_opts_parser( case I_NREXT64: cli->sb_feat.nrext64 = getnum(value, opts, subopt); break; + case I_FORCEALIGN: + long long 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; } @@ -2329,6 +2350,13 @@ _("64 bit extent count not supported without CRC support\n")); usage(); } cli->sb_feat.nrext64 = 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) { @@ -2363,6 +2391,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)) { + fprintf(stderr, +_("forcealign requires a nonzero extent size hint and no cow extent size hint\n")); + usage(); + } + /* * Copy features across to config structure now. */ @@ -2612,6 +2647,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(); + } +} + /* Complain if this filesystem is not a supported configuration. */ static void validate_supported( @@ -3155,11 +3218,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; @@ -3380,6 +3495,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; @@ -4184,6 +4301,7 @@ main( .nortalign = false, .bigtime = true, .nrext64 = false, + .forcealign = true, /* * When we decide to enable a new feature by default, * please remember to update the mkfs conf files. @@ -4334,7 +4452,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); @@ -4357,6 +4475,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); validate_supported(mp, &cli); -- 2.34.1