zbd: add a new --ignore_zone_limits option
authorNiklas Cassel <niklas.cassel@wdc.com>
Thu, 27 May 2021 11:12:32 +0000 (11:12 +0000)
committerJens Axboe <axboe@kernel.dk>
Thu, 27 May 2021 22:04:58 +0000 (16:04 -0600)
In commit d2f442bc0bd5 ("ioengines: add get_max_open_zones zoned block
device operation") we added a check that verifies that the specified
--max_open_zones value is lower than the max value reported by the device.

For ZNS devices there is a max open zones and a max active zones limit.
For ZAC/ZBC devices there is only a max open zones limit.

On ZAC/ZBC, there is thus no limit on the amount of zones that can be
in zone state closed.
When doing a write to an empty or closed zone, a ZAC/ZBC drive will
close an arbitrary implicit open zone in order to handle the write.

The ZNS specification has no requirement on closing a zone in order to
handle a write to an empty or closed zone. The drive is free to return
an error.

Even on ZAC/ZBC, you do not want to exceed the max open zones limit,
since it will lead to additional implicit close zone and implicit open
zone operations, which may degrade performance.
However, it seems that this is sometimes done on purpose, in order to
measure the overhead of these additional operations. Therefore, add
an option that allows the user to ignore the reported device limits.

Signed-off-by: Niklas Cassel <niklas.cassel@wdc.com>
Reviewed-by: Damien Le Moal <damien.lemoal@wdc.com>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
cconv.c
fio.1
options.c
server.h
thread_options.h
zbd.c

diff --git a/cconv.c b/cconv.c
index d4dfb81b3f473d916217f3f3c17791dffab0f8ed..74c241063abb6491586f18751502ff572f50edc0 100644 (file)
--- a/cconv.c
+++ b/cconv.c
@@ -232,6 +232,7 @@ void convert_thread_options_to_cpu(struct thread_options *o,
        o->zone_skip = le64_to_cpu(top->zone_skip);
        o->zone_mode = le32_to_cpu(top->zone_mode);
        o->max_open_zones = __le32_to_cpu(top->max_open_zones);
+       o->ignore_zone_limits = le32_to_cpu(top->ignore_zone_limits);
        o->lockmem = le64_to_cpu(top->lockmem);
        o->offset_increment_percent = le32_to_cpu(top->offset_increment_percent);
        o->offset_increment = le64_to_cpu(top->offset_increment);
@@ -575,6 +576,7 @@ void convert_thread_options_to_net(struct thread_options_pack *top,
        top->zone_skip = __cpu_to_le64(o->zone_skip);
        top->zone_mode = __cpu_to_le32(o->zone_mode);
        top->max_open_zones = __cpu_to_le32(o->max_open_zones);
+       top->ignore_zone_limits = cpu_to_le32(o->ignore_zone_limits);
        top->lockmem = __cpu_to_le64(o->lockmem);
        top->ddir_seq_add = __cpu_to_le64(o->ddir_seq_add);
        top->file_size_low = __cpu_to_le64(o->file_size_low);
diff --git a/fio.1 b/fio.1
index ab08cb012048d2cf756488ef8fdf9415a86e7d67..5aa54a4d0471772276737edae926bba7b7f7e63b 100644 (file)
--- a/fio.1
+++ b/fio.1
@@ -835,6 +835,11 @@ threads/processes.
 .BI job_max_open_zones \fR=\fPint
 Limit on the number of simultaneously opened zones per single thread/process.
 .TP
+.BI ignore_zone_limits \fR=\fPbool
+If this isn't set, fio will query the max open zones limit from the zoned block
+device, and exit if the specified \fBmax_open_zones\fR value is larger than the
+limit reported by the device. Default: false.
+.TP
 .BI zone_reset_threshold \fR=\fPfloat
 A number between zero and one that indicates the ratio of logical blocks with
 data to the total number of logical blocks in the test above which zones
index b82a10aa444f6a36cd07891da23fbdc85405d0ec..a8986d116716fb7f5df8e572caff0a6c8dfdc995 100644 (file)
--- a/options.c
+++ b/options.c
@@ -3492,6 +3492,16 @@ struct fio_option fio_options[FIO_MAX_OPTS] = {
                .category = FIO_OPT_C_IO,
                .group  = FIO_OPT_G_INVALID,
        },
+       {
+               .name   = "ignore_zone_limits",
+               .lname  = "Ignore zone resource limits",
+               .type   = FIO_OPT_BOOL,
+               .off1   = offsetof(struct thread_options, ignore_zone_limits),
+               .def    = "0",
+               .help   = "Ignore the zone resource limits (max open/active zones) reported by the device",
+               .category = FIO_OPT_C_IO,
+               .group  = FIO_OPT_G_INVALID,
+       },
        {
                .name   = "zone_reset_threshold",
                .lname  = "Zone reset threshold",
index 8cf3a60b4b0413c4f315902119b5adc3107ca3d2..c128df28adda112d04ad67549e1d0fa4194f5b1c 100644 (file)
--- a/server.h
+++ b/server.h
@@ -48,7 +48,7 @@ struct fio_net_cmd_reply {
 };
 
 enum {
-       FIO_SERVER_VER                  = 90,
+       FIO_SERVER_VER                  = 91,
 
        FIO_SERVER_MAX_FRAGMENT_PDU     = 1024,
        FIO_SERVER_MAX_CMD_MB           = 2048,
index 4d48e462999cf416d8ea8a6f24e84b82cd3193ec..05c2d1383e68403190d175608b995ece11d958fa 100644 (file)
@@ -355,6 +355,7 @@ struct thread_options {
        unsigned int read_beyond_wp;
        int max_open_zones;
        unsigned int job_max_open_zones;
+       unsigned int ignore_zone_limits;
        fio_fp64_t zrt;
        fio_fp64_t zrf;
 };
@@ -657,6 +658,7 @@ struct thread_options_pack {
 
        uint32_t zone_mode;
        int32_t max_open_zones;
+       uint32_t ignore_zone_limits;
 } __attribute__((packed));
 
 extern void convert_thread_options_to_cpu(struct thread_options *o, struct thread_options_pack *top);
diff --git a/zbd.c b/zbd.c
index 68cd58e1b9db99dfa883dab39bc06daea6b972e8..5d9e331ac9347f8e2af3441f4e3a519550b95602 100644 (file)
--- a/zbd.c
+++ b/zbd.c
@@ -588,7 +588,7 @@ static int zbd_set_max_open_zones(struct thread_data *td, struct fio_file *f)
        unsigned int max_open_zones;
        int ret;
 
-       if (zbd->model != ZBD_HOST_MANAGED) {
+       if (zbd->model != ZBD_HOST_MANAGED || td->o.ignore_zone_limits) {
                /* Only host-managed devices have a max open limit */
                zbd->max_open_zones = td->o.max_open_zones;
                goto out;