* 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)))
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,
}
} else {
blkid_get_topology(dev->name, dt, force_overwrite);
+ get_hw_atomic_writes_topology(dev, dt);
}
ASSERT(dt->logical_sector_size);
}
}
+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(
*/
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;
(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) {
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
* 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