From: Darrick J. Wong <djwong@xxxxxxxxxx> Try to align the AG size to the maximum hardware atomic write unit so that we can give users maximum flexibility in choosing an RWF_ATOMIC write size. Signed-off-by: "Darrick J. Wong" <djwong@xxxxxxxxxx> --- libxfs/topology.h | 6 ++++-- libxfs/topology.c | 36 ++++++++++++++++++++++++++++++++++++ mkfs/xfs_mkfs.c | 48 +++++++++++++++++++++++++++++++++++++++++++----- 3 files changed, 83 insertions(+), 7 deletions(-) diff --git a/libxfs/topology.h b/libxfs/topology.h index 207a8a7f150556..f0ca65f3576e92 100644 --- a/libxfs/topology.h +++ b/libxfs/topology.h @@ -13,8 +13,10 @@ struct device_topology { int logical_sector_size; /* logical sector size */ int physical_sector_size; /* physical sector size */ - int sunit; /* stripe unit */ - int swidth; /* stripe width */ + int sunit; /* stripe unit */ + int swidth; /* stripe width */ + int awu_min; /* min atomic write unit in bbcounts */ + int awu_max; /* max atomic write unit in bbcounts */ }; struct fs_topology { diff --git a/libxfs/topology.c b/libxfs/topology.c index 96ee74b61b30f5..7764687beac000 100644 --- a/libxfs/topology.c +++ b/libxfs/topology.c @@ -4,11 +4,18 @@ * All Rights Reserved. */ +#ifdef OVERRIDE_SYSTEM_STATX +#define statx sys_statx +#endif +#include <fcntl.h> +#include <sys/stat.h> + #include "libxfs_priv.h" #include "libxcmd.h" #include <blkid/blkid.h> #include "xfs_multidisk.h" #include "libfrog/platform.h" +#include "libfrog/statx.h" #define TERABYTES(count, blog) ((uint64_t)(count) << (40 - (blog))) #define GIGABYTES(count, blog) ((uint64_t)(count) << (30 - (blog))) @@ -278,6 +285,34 @@ blkid_get_topology( device); } +static void +get_hw_atomic_writes_topology( + struct libxfs_dev *dev, + struct device_topology *dt) +{ + struct statx sx; + int fd; + int ret; + + fd = open(dev->name, O_RDONLY); + if (fd < 0) + return; + + ret = statx(fd, "", AT_EMPTY_PATH, STATX_WRITE_ATOMIC, &sx); + if (ret) + goto out_close; + + if (!(sx.stx_mask & STATX_WRITE_ATOMIC)) + goto out_close; + + dt->awu_min = sx.stx_atomic_write_unit_min >> 9; + dt->awu_max = max(sx.stx_atomic_write_unit_max_opt, + sx.stx_atomic_write_unit_max) >> 9; + +out_close: + close(fd); +} + static void get_device_topology( struct libxfs_dev *dev, @@ -316,6 +351,7 @@ get_device_topology( } } else { blkid_get_topology(dev->name, dt, force_overwrite); + get_hw_atomic_writes_topology(dev, dt); } ASSERT(dt->logical_sector_size); diff --git a/mkfs/xfs_mkfs.c b/mkfs/xfs_mkfs.c index 6c8cc715d3476b..7d3e9dd567b7b2 100644 --- a/mkfs/xfs_mkfs.c +++ b/mkfs/xfs_mkfs.c @@ -3379,6 +3379,32 @@ _("illegal CoW extent size hint %lld, must be less than %u and a multiple of %u. } } +static void +validate_device_awu( + struct mkfs_params *cfg, + struct device_topology *dt) +{ + /* Ignore hw atomic write capability if it can't do even 1 fsblock */ + if (BBTOB(dt->awu_min) > cfg->blocksize || + BBTOB(dt->awu_max) < cfg->blocksize) { + dt->awu_min = 0; + dt->awu_max = 0; + } +} + +static void +validate_hw_atomic_writes( + struct mkfs_params *cfg, + struct cli_params *cli, + struct fs_topology *ft) +{ + validate_device_awu(cfg, &ft->data); + if (cli->xi->log.name) + validate_device_awu(cfg, &ft->log); + if (cli->xi->rt.name) + validate_device_awu(cfg, &ft->rt); +} + /* Complain if this filesystem is not a supported configuration. */ static void validate_supported( @@ -4051,10 +4077,20 @@ _("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 fs_topology *ft) { - uint64_t tmp_agsize; - int dsunit = cfg->dsunit; + uint64_t tmp_agsize; + int dsunit = cfg->dsunit; + + /* + * We've already validated (or discarded) the hardware atomic write + * geometry. Try to align the agsize to the maximum atomic write unit + * to give users maximum flexibility in choosing atomic write sizes. + */ + if (ft->data.awu_max > 0) + dsunit = max(DTOBT(ft->data.awu_max, cfg->blocklog), + dsunit); if (!dsunit) goto validate; @@ -4110,7 +4146,8 @@ _("agsize rounded to %lld, sunit = %d\n"), (long long)cfg->agsize, dsunit); } - if ((cfg->agsize % cfg->dswidth) == 0 && + if (cfg->dswidth > 0 && + (cfg->agsize % cfg->dswidth) == 0 && cfg->dswidth != cfg->dsunit && cfg->agcount > 1) { @@ -5874,6 +5911,7 @@ main( cfg.rtblocks = calc_dev_size(cli.rtsize, &cfg, &ropts, R_SIZE, "rt"); validate_rtextsize(&cfg, &cli, &ft); + validate_hw_atomic_writes(&cfg, &cli, &ft); /* * Open and validate the device configurations @@ -5892,7 +5930,7 @@ main( * aligns to device geometry correctly. */ calculate_initial_ag_geometry(&cfg, &cli, &xi); - align_ag_geometry(&cfg); + align_ag_geometry(&cfg, &ft); if (cfg.sb_feat.zoned) calculate_zone_geometry(&cfg, &cli, &xi, &zt); else