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" <djwong@kernel.org>
diff --git a/libxfs/topology.c b/libxfs/topology.c
index 96ee74b..7764687 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)))
@@ -279,6 +286,34 @@
}
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,
struct device_topology *dt,
@@ -316,6 +351,7 @@
}
} 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 207a8a7..f0ca65f 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 6c8cc71..7d3e9dd 100644
--- a/mkfs/xfs_mkfs.c
+++ b/mkfs/xfs_mkfs.c
@@ -3379,6 +3379,32 @@
}
}
+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 @@
*/
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 @@
(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 @@
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 @@
* 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