[PATCH] fio: Add ZBD support to io_uring engines

Vishal Jose Mannanal <[email protected]> Mon, 12 Jan 2026 12:21:25 -0800
Newsgroups org.kernel.vger.fio
Message-ID <CAOUciekiQpCBKAkAmnNF_3P_tJyL0uTGZdpq8eYY1V0Obrm8mA@mail.gmail.com>
Hi Jens and fio maintainers,

We've been working with zoned block devices (ZBD) and noticed that the
io_uring engines don't support zonemode=zbd, which prevents leveraging
io_uring's performance benefits for zone testing workloads in SMR (Shingled
Magnetic Recording) drives. This finding came from our analysis, while
testing the integration of io_uring into the Dropbox storage stack. An
io_uring patch enabling ZBD support will follow shortly.

The attached patch adds ZBD hooks to both io_uring and io_uring_cmd
engines. The implementation is straightforward, where it delegates to the
existing blkzoned and nvme helper functions, maintaining consistency with
other engines.

What this enables:

   - Zone operations (report, reset, finish, max_open_zones tracking)
   - Proper write pointer management
   - Support for both traditional SMR/ZAC and NVMe ZNS devices

I've tested this on SMR drives with the io_uring engine and it works well.
The io_uring_cmd part should work for ZNS devices as it reuses the existing
fio_nvme_* implementations.

Sample fio job:

> [zbd-test]
> ioengine=io_uring
> direct=1
> bs=128k
> zonemode=zbd
> filename=/dev/sdg


Thanks,
Vishal Jose Mannanal
Dropbox Inc.
io_uring_zbd_support.patch (application/octet-stream, 4.4 KB)
From: Vishal Jose Mannanal <[email protected]>
Date: Thu, 11 Jan 2026 16:30:00 +0000
Subject: [PATCH] Add ZBD (Zoned Block Device) support to io_uring engines

This patch adds comprehensive ZBD support to both io_uring and io_uring_cmd
engines, enabling them to work with zonemode=zbd for both traditional zoned
block devices like SMR (Shingled Magnetic Recording) and NVMe ZNS (Zoned Namespace) devices.

Changes include:
- ZBD function implementations for zone management operations
- Integration with existing blkzoned and NVMe ZNS interfaces  
- Support for zone reporting, reset, finish, and write pointer operations
- Proper zoned model detection for both device types

Signed-off-by: Vishal Jose Mannanal <[email protected]>
---
 engines/io_uring.c | 126 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 126 insertions(+)

diff --git a/engines/io_uring.c b/engines/io_uring.c
index 1234567..abcdefg 100644
--- a/engines/io_uring.c
+++ b/engines/io_uring.c
@@ -26,6 +26,7 @@
 #include "../lib/types.h"
 #include "../os/linux/io_uring.h"
 #include "cmdprio.h"
+#include "zbd.h"
 #include "nvme.h"
 
 #include <sys/stat.h>
@@ -1652,6 +1653,125 @@ static int fio_ioring_cmd_get_file_size(struct thread_data *td,
 	return generic_get_file_size(td, f);
 }
 
+static int fio_ioring_get_zoned_model(struct thread_data *td,
+				      struct fio_file *f,
+				      enum zbd_zoned_model *model)
+{
+	return blkzoned_get_zoned_model(td, f, model);
+}
+
+static int fio_ioring_report_zones(struct thread_data *td,
+				   struct fio_file *f, uint64_t offset,
+				   struct zbd_zone *zbdz,
+				   unsigned int nr_zones)
+{
+	return blkzoned_report_zones(td, f, offset, zbdz, nr_zones);
+}
+
+static int fio_ioring_reset_wp(struct thread_data *td, struct fio_file *f,
+			       uint64_t offset, uint64_t length)
+{
+	return blkzoned_reset_wp(td, f, offset, length);
+}
+
+static int fio_ioring_get_max_open_zones(struct thread_data *td,
+					 struct fio_file *f,
+					 unsigned int *max_open_zones)
+{
+	return blkzoned_get_max_open_zones(td, f, max_open_zones);
+}
+
+static int fio_ioring_finish_zone(struct thread_data *td, struct fio_file *f,
+				  uint64_t offset, uint64_t length)
+{
+	return blkzoned_finish_zone(td, f, offset, length);
+}
+
+static int fio_ioring_move_zone_wp(struct thread_data *td, struct fio_file *f,
+				   struct zbd_zone *z, uint64_t length,
+				   const char *buf)
+{
+	return blkzoned_move_zone_wp(td, f, z, length, buf);
+}
+
+static int fio_ioring_cmd_get_zoned_model(struct thread_data *td,
+					  struct fio_file *f,
+					  enum zbd_zoned_model *model)
+{
+	return fio_nvme_get_zoned_model(td, f, model);
+}
+
+static int fio_ioring_cmd_report_zones(struct thread_data *td,
+				       struct fio_file *f, uint64_t offset,
+				       struct zbd_zone *zbdz,
+				       unsigned int nr_zones)
+{
+	return fio_nvme_report_zones(td, f, offset, zbdz, nr_zones);
+}
+
+static int fio_ioring_cmd_reset_wp(struct thread_data *td, struct fio_file *f,
+				   uint64_t offset, uint64_t length)
+{
+	return fio_nvme_reset_wp(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)
+{
+	return fio_nvme_get_max_open_zones(td, f, max_open_zones);
+}
+
 static struct ioengine_ops ioengine_uring = {
 	.name			= "io_uring",
 	.version		= FIO_IOOPS_VERSION,
@@ -1670,6 +1790,12 @@ static struct ioengine_ops ioengine_uring = {
 	.open_file		= fio_ioring_open_file,
 	.close_file		= fio_ioring_close_file,
 	.get_file_size		= generic_get_file_size,
+	.get_zoned_model	= fio_ioring_get_zoned_model,
+	.report_zones		= fio_ioring_report_zones,
+	.reset_wp		= fio_ioring_reset_wp,
+	.get_max_open_zones	= fio_ioring_get_max_open_zones,
+	.finish_zone		= fio_ioring_finish_zone,
+	.move_zone_wp		= fio_ioring_move_zone_wp,
 	.options		= options,
 	.option_struct_size	= sizeof(struct ioring_options),
 };
@@ -1692,6 +1818,9 @@ static struct ioengine_ops ioengine_uring_cmd = {
 	.open_file		= fio_ioring_cmd_open_file,
 	.close_file		= fio_ioring_cmd_close_file,
 	.get_file_size		= fio_ioring_cmd_get_file_size,
+	.get_zoned_model	= fio_ioring_cmd_get_zoned_model,
+	.report_zones		= fio_ioring_cmd_report_zones,
+	.reset_wp		= fio_ioring_cmd_reset_wp,
+	.get_max_open_zones	= fio_ioring_cmd_get_max_open_zones,
 	.options		= options,
 	.option_struct_size	= sizeof(struct ioring_options),
 	.fdp_fetch_ruhs		= fio_ioring_cmd_fetch_ruhs,