Recent changes (master)
Jens Axboe <[email protected]> Fri, 26 Jun 2026 06:00:01 -0600
| Newsgroups | org.kernel.vger.fio |
|---|---|
| Message-ID | <[email protected]> |
The following changes since commit d72bcf71534b5ac82359e3b987ff109b0de57af0:
t/io_uring_cmd: better default for fio executable (2026-06-24 13:25:19 -0400)
are available in the Git repository at:
git://git.kernel.dk/fio.git master
for you to fetch changes up to 360e4d6ae2fafcb17438df45499e514406f4d746:
Merge branch 'master' of https://github.com/Krien/fio (2026-06-25 12:54:29 -0400)
----------------------------------------------------------------
Krijn Doekemeijer (2):
io_uring: add fio_ioring_cmd_finish_zone when using uring_cmd
io_uring: add support for zone appends when using ZBD
Vincent Fu (3):
ci: split 16-bit Guard PI QEMU tests
ci: split ZBD tests across configurations
Merge branch 'master' of https://github.com/Krien/fio
.github/workflows/qemu.yml | 31 ++++++++++++++++++---
HOWTO.rst | 3 ++
engines/io_uring.c | 33 ++++++++++++++++++++--
engines/nvme.c | 54 +++++++++++++++++++++++++++++++++++-
engines/nvme.h | 5 ++++
examples/uring-cmd-zoned-append.fio | 36 ++++++++++++++++++++++++
examples/uring-cmd-zoned-append.png | Bin 0 -> 128287 bytes
fio.1 | 3 ++
8 files changed, 157 insertions(+), 8 deletions(-)
create mode 100644 examples/uring-cmd-zoned-append.fio
create mode 100644 examples/uring-cmd-zoned-append.png
---
Diff of recent changes:
diff --git a/.github/workflows/qemu.yml b/.github/workflows/qemu.yml
index db90b03d..e01b4061 100644
--- a/.github/workflows/qemu.yml
+++ b/.github/workflows/qemu.yml
@@ -20,12 +20,19 @@ jobs:
-device nvme-ns,id=nvm-0,drive=nvm-0,bus=nvme0,nsid=1
test_cmd: "python3 t/run-fio-tests.py --nvmecdev /dev/ng0n1 --run-only 1014 1015 1022 -p '1022:--skip 30 31 32 33 34 40 50 51 53 70'"
extra_pkgs: "nvme-cli"
- - config: 16-bit Guard PI tests (long)
+ - config: 512 16-bit Guard PI tests (long)
device: >-
-device nvme,id=nvme0,serial=deadbeef
-drive id=nvm-0,file=nvme0.img,format=raw,if=none,discard=unmap,media=disk
-device nvme-ns,id=nvm-0,drive=nvm-0,bus=nvme0,nsid=1
- test_cmd: "python3 t/nvmept_pi.py --fio ./fio --dut /dev/ng0n1"
+ test_cmd: "python3 t/nvmept_pi.py --fio ./fio --dut /dev/ng0n1 --lbaf 1 2 3"
+ extra_pkgs: "nvme-cli"
+ - config: 4K 16-bit Guard PI tests (long)
+ device: >-
+ -device nvme,id=nvme0,serial=deadbeef
+ -drive id=nvm-0,file=nvme0.img,format=raw,if=none,discard=unmap,media=disk
+ -device nvme-ns,id=nvm-0,drive=nvm-0,bus=nvme0,nsid=1
+ test_cmd: "python3 t/nvmept_pi.py --fio ./fio --dut /dev/ng0n1 --lbaf 5 6 7"
extra_pkgs: "nvme-cli"
- config: 4K+16 w/64-bit Guard PI
device: >- # 4K+16 w/64-bit Guard PI
@@ -53,9 +60,25 @@ jobs:
device:
test_cmd: "python3 t/verify-trim.py"
extra_pkgs: sg3-utils
- - config: ZBD
+ - config: ZBD1-5
+ device:
+ test_cmd: "./t/zbd/run-tests-against-nullb -s 1 -s 2 -s 3 -s 4 -s 5"
+ extra_pkgs: sg3-utils
+ - config: ZBD6-10
+ device:
+ test_cmd: "./t/zbd/run-tests-against-nullb -s 6 -s 7 -s 8 -s 9 -s 10"
+ extra_pkgs: sg3-utils
+ - config: ZBD11-15
+ device:
+ test_cmd: "./t/zbd/run-tests-against-nullb -s 11 -s 12 -s 13 -s 14 -s 15"
+ extra_pkgs: sg3-utils
+ - config: ZBD16-20
+ device:
+ test_cmd: "./t/zbd/run-tests-against-nullb -s 16 -s 17 -s 18 -s 19 -s 20"
+ extra_pkgs: sg3-utils
+ - config: ZBD21-25
device:
- test_cmd: "./t/zbd/run-tests-against-nullb"
+ test_cmd: "./t/zbd/run-tests-against-nullb -s 21 -s 22 -s 23 -s 24 -s 25"
extra_pkgs: sg3-utils
env:
diff --git a/HOWTO.rst b/HOWTO.rst
index ef079214..f4663003 100644
--- a/HOWTO.rst
+++ b/HOWTO.rst
@@ -3049,6 +3049,9 @@ with the caveat that when used on the command line, they must come after the
**verify**
Use Verify commands for write operations
+ **zone_append**
+ Use zone append commands for write operations. Requires zonemode=zbd
+
Multiple modes with mix ratios can be specified using the format
``mode/pct:mode/pct:...``. Percentages must sum to 100. If a
percentage is omitted, the remaining percentage is split evenly among
diff --git a/engines/io_uring.c b/engines/io_uring.c
index bd50cdca..bc7e33da 100644
--- a/engines/io_uring.c
+++ b/engines/io_uring.c
@@ -100,13 +100,15 @@ enum uring_cmd_type {
};
enum uring_cmd_write_mode {
- FIO_URING_CMD_WMODE_WRITE = 1,
+ FIO_URING_CMD_WMODE_WRITE = 0,
FIO_URING_CMD_WMODE_UNCOR,
FIO_URING_CMD_WMODE_ZEROES,
FIO_URING_CMD_WMODE_VERIFY,
+ FIO_URING_CMD_WMODE_ZONE_APPEND,
+ FIO_URING_CMD_WMODE_LAST
};
-#define WMODE_SPLIT_MAX 4
+#define WMODE_SPLIT_MAX FIO_URING_CMD_WMODE_LAST
struct wmode_split_entry {
uint8_t opcode;
@@ -236,6 +238,8 @@ static uint8_t wmode_str_to_opcode(const char *mode)
return nvme_cmd_write_zeroes;
if (!strcmp(mode, "verify"))
return nvme_cmd_verify;
+ if (!strcmp(mode, "zone_append"))
+ return nvme_zns_cmd_append;
return 0xff;
}
@@ -261,6 +265,8 @@ static int str_write_mode_cb(void *data, const char *str)
o->write_mode = FIO_URING_CMD_WMODE_ZEROES;
else if (op == nvme_cmd_verify)
o->write_mode = FIO_URING_CMD_WMODE_VERIFY;
+ else if (op == nvme_zns_cmd_append)
+ o->write_mode = FIO_URING_CMD_WMODE_ZONE_APPEND;
else
o->write_mode = FIO_URING_CMD_WMODE_WRITE;
o->wmode_split_nr = 0;
@@ -402,7 +408,7 @@ static struct fio_option options[] = {
.lname = "Write command type(s) with optional mix ratios",
.type = FIO_OPT_STR,
.cb = str_write_mode_cb,
- .help = "Single: write|uncor|zeroes|verify. "
+ .help = "Single: write|uncor|zeroes|verify|zone_append. "
"Mixed: mode/pct:mode/pct:... (e.g. write/60:zeroes/40). "
"Blank pct evenly splits the remainder (e.g. write/50:zeroes/:uncor/)",
.def = "write",
@@ -1554,6 +1560,17 @@ static void parse_prchk_flags(struct ioring_options *o)
static int fio_ioring_cmd_init(struct thread_data *td, struct ioring_data *ld)
{
struct ioring_options *o = td->eo;
+ int append, i;
+
+ append = o->write_mode == FIO_URING_CMD_WMODE_ZONE_APPEND;
+ for (i = 0; i < (int)o->wmode_split_nr; i++)
+ append |= o->wmode_split[i].opcode == nvme_zns_cmd_append;
+
+ if (append && td->o.zone_mode != ZONE_MODE_ZBD) {
+ log_err("fio: io_uring_cmd with write_mode=zone_append "
+ "requires zonemode=zbd\n");
+ return 1;
+ }
if (o->cmd_type == FIO_URING_CMD_NVME) {
if (td_write(td)) {
@@ -1585,6 +1602,9 @@ static int fio_ioring_cmd_init(struct thread_data *td, struct ioring_data *ld)
case FIO_URING_CMD_WMODE_VERIFY:
ld->write_opcode = nvme_cmd_verify;
break;
+ case FIO_URING_CMD_WMODE_ZONE_APPEND:
+ ld->write_opcode = nvme_zns_cmd_append;
+ break;
default:
ld->write_opcode = nvme_cmd_write;
break;
@@ -2192,6 +2212,12 @@ static int fio_ioring_cmd_reset_wp(struct thread_data *td, struct fio_file *f,
return -EINVAL;
}
+static int fio_ioring_cmd_finish_zone(struct thread_data *td, struct fio_file *f,
+ uint64_t offset, uint64_t length)
+{
+ return fio_nvme_finish_zone(td, f, offset, length);
+}
+
static int fio_ioring_cmd_get_max_open_zones(struct thread_data *td,
struct fio_file *f,
unsigned int *max_open_zones)
@@ -2290,6 +2316,7 @@ static struct ioengine_ops ioengine_uring_cmd = {
.get_zoned_model = fio_ioring_cmd_get_zoned_model,
.report_zones = fio_ioring_cmd_report_zones,
.reset_wp = fio_ioring_cmd_reset_wp,
+ .finish_zone = fio_ioring_cmd_finish_zone,
.get_max_open_zones = fio_ioring_cmd_get_max_open_zones,
.options = options,
.option_struct_size = sizeof(struct ioring_options),
diff --git a/engines/nvme.c b/engines/nvme.c
index e480fce0..e989306a 100644
--- a/engines/nvme.c
+++ b/engines/nvme.c
@@ -7,6 +7,7 @@
#include "nvme.h"
#include "../crc/crc-t10dif.h"
#include "../crc/crc64.h"
+#include "zbd.h"
static void fio_nvme_generate_pi_16b_guard(struct nvme_data *data,
struct io_u *io_u,
@@ -352,6 +353,8 @@ int fio_nvme_uring_cmd_prep(struct nvme_uring_cmd *cmd, struct io_u *io_u,
{
struct nvme_data *data = FILE_ENG_DATA(io_u->file);
__u64 slba;
+ __u64 offset;
+ __u64 zone_size;
__u32 nlb;
memset(cmd, 0, sizeof(struct nvme_uring_cmd));
@@ -375,7 +378,14 @@ int fio_nvme_uring_cmd_prep(struct nvme_uring_cmd *cmd, struct io_u *io_u,
return -ENOTSUP;
}
- slba = get_slba(data, io_u->offset);
+ /* Zone appends must be issued to the start of the target zone */
+ if (cmd->opcode == nvme_zns_cmd_append && io_u->file->zbd_info) {
+ zone_size = io_u->file->zbd_info->zone_size;
+ offset = io_u->offset & (~(zone_size - 1));
+ } else {
+ offset = io_u->offset;
+ }
+ slba = get_slba(data, offset);
nlb = get_nlb(data, io_u->xfer_buflen);
/* cdw10 and cdw11 represent starting lba */
@@ -395,6 +405,7 @@ int fio_nvme_uring_cmd_prep(struct nvme_uring_cmd *cmd, struct io_u *io_u,
case nvme_cmd_read:
case nvme_cmd_write:
case nvme_cmd_compare:
+ case nvme_zns_cmd_append:
cmd->addr = (__u64)(uintptr_t)io_u->xfer_buf;
cmd->data_len = io_u->xfer_buflen;
break;
@@ -852,6 +863,47 @@ int fio_nvme_reset_wp(struct thread_data *td, struct fio_file *f,
return -ret;
}
+int fio_nvme_finish_zone(struct thread_data *td, struct fio_file *f,
+ uint64_t offset, uint64_t length)
+{
+ struct nvme_data *data = FILE_ENG_DATA(f);
+ unsigned int nr_zones;
+ unsigned long long zslba;
+ int i, fd, ret = 0;
+
+ /* If the file is not yet opened, open it for this function. */
+ fd = f->fd;
+ if (fd < 0) {
+ fd = open(f->file_name, O_RDWR | O_LARGEFILE);
+ if (fd < 0)
+ return -errno;
+ }
+
+ zslba = offset >> data->lba_shift;
+ nr_zones = (length + td->o.zone_size - 1) / td->o.zone_size;
+
+ for (i = 0; i < nr_zones; i++, zslba += (td->o.zone_size >> data->lba_shift)) {
+ struct nvme_passthru_cmd cmd = {
+ .opcode = nvme_zns_cmd_mgmt_send,
+ .nsid = data->nsid,
+ .cdw10 = zslba & 0xffffffff,
+ .cdw11 = zslba >> 32,
+ .cdw13 = NVME_ZNS_ZSA_FINISH,
+ .addr = (__u64)(uintptr_t)NULL,
+ .data_len = 0,
+ .timeout_ms = NVME_DEFAULT_IOCTL_TIMEOUT,
+ };
+
+ ret = ioctl(fd, NVME_IOCTL_IO_CMD, &cmd);
+ if (ret)
+ break;
+ }
+
+ if (f->fd < 0)
+ close(fd);
+ return -ret;
+}
+
int fio_nvme_get_max_open_zones(struct thread_data *td, struct fio_file *f,
unsigned int *max_open_zones)
{
diff --git a/engines/nvme.h b/engines/nvme.h
index 4371eb5b..08f359d5 100644
--- a/engines/nvme.h
+++ b/engines/nvme.h
@@ -50,6 +50,7 @@ struct nvme_uring_cmd {
#define NVME_ZNS_ZRA_REPORT_ZONES 0
#define NVME_ZNS_ZRAS_FEAT_ERZ (1 << 16)
+#define NVME_ZNS_ZSA_FINISH 0x2
#define NVME_ZNS_ZSA_RESET 0x4
#define NVME_ZONE_TYPE_SEQWRITE_REQ 0x2
@@ -84,6 +85,7 @@ enum nvme_io_opcode {
nvme_cmd_io_mgmt_recv = 0x12,
nvme_zns_cmd_mgmt_send = 0x79,
nvme_zns_cmd_mgmt_recv = 0x7a,
+ nvme_zns_cmd_append = 0x7d,
};
enum nvme_zns_zs {
@@ -445,6 +447,9 @@ int fio_nvme_pi_verify(struct nvme_data *data, struct io_u *io_u);
int fio_nvme_get_zoned_model(struct thread_data *td, struct fio_file *f,
enum zbd_zoned_model *model);
+int fio_nvme_finish_zone(struct thread_data *td, struct fio_file *f,
+ uint64_t offset, uint64_t length);
+
int fio_nvme_report_zones(struct thread_data *td, struct fio_file *f,
uint64_t offset, struct zbd_zone *zbdz,
unsigned int nr_zones);
diff --git a/examples/uring-cmd-zoned-append.fio b/examples/uring-cmd-zoned-append.fio
new file mode 100644
index 00000000..ecba1d96
--- /dev/null
+++ b/examples/uring-cmd-zoned-append.fio
@@ -0,0 +1,36 @@
+# io_uring_cmd I/O engine for nvme-ns generic zoned character device
+# with zone appends
+#
+# NOTE:
+# Unlike regular writes, zone appends in a zone can be issued at
+# a QD higher than 1.
+
+[global]
+filename=/dev/ng1n1
+ioengine=io_uring_cmd
+cmd_type=nvme
+zonemode=zbd
+write_mode=zone_append
+size=1z
+bs=8K
+verify=crc32c
+stonewall=1
+
+[rand-write]
+iodepth=1
+rw=randwrite
+
+[write-opts]
+iodepth=4
+rw=write
+registerfiles=1
+sqthread_poll=1
+sqthread_poll_cpu=0
+
+[randwrite-opts]
+iodepth=4
+rw=randwrite
+sqthread_poll=1
+sqthread_poll_cpu=0
+nonvectored=1
+registerfiles=1
diff --git a/examples/uring-cmd-zoned-append.png b/examples/uring-cmd-zoned-append.png
new file mode 100644
index 00000000..52e509fe
Binary files /dev/null and b/examples/uring-cmd-zoned-append.png differ
diff --git a/fio.1 b/fio.1
index bdb7662d..13bc01de 100644
--- a/fio.1
+++ b/fio.1
@@ -2834,6 +2834,9 @@ Use Write Zeroes commands for write operations
.TP
.B verify
Use Verify commands for write operations
+.TP
+.B zone_append
+Use Zone Append commands for write operations. Requires zonemode=zbd
.RE
.P
Multiple modes with mix ratios can be specified using the format