From b245cf32529350a593454389f652e8df1d421752 Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Tue, 1 Jul 2025 10:45:14 -0700 Subject: [PATCH] mkfs: try to align AG size based on atomic write capabilities 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" Reviewed-by: John Garry --- libxfs/topology.c | 36 +++++++++++++++++++++++++++++++++++ libxfs/topology.h | 6 ++++-- mkfs/xfs_mkfs.c | 48 ++++++++++++++++++++++++++++++++++++++++++----- 3 files changed, 83 insertions(+), 7 deletions(-) diff --git a/libxfs/topology.c b/libxfs/topology.c index 96ee74b6..7764687b 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 +#include + #include "libxfs_priv.h" #include "libxcmd.h" #include #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 @@ out_free_probe: 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/libxfs/topology.h b/libxfs/topology.h index 207a8a7f..f0ca65f3 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/mkfs/xfs_mkfs.c b/mkfs/xfs_mkfs.c index b6de13ce..d2080804 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( @@ -4052,10 +4078,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; @@ -4111,7 +4147,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) { @@ -5875,6 +5912,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 @@ -5893,7 +5931,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 -- 2.47.3