zbd: check write ranges for zone_reset_threshold option
authorShin'ichiro Kawasaki <shinichiro.kawasaki@wdc.com>
Thu, 9 Feb 2023 07:09:05 +0000 (16:09 +0900)
committerVincent Fu <vincent.fu@samsung.com>
Tue, 14 Feb 2023 14:52:52 +0000 (09:52 -0500)
The valid data bytes accounting is used for zone_reset_threshold option.
This accounting usage has two issues. The first issue is unexpected
zone reset due to different IO ranges. The valid data bytes accounting
is done for all IO ranges per device, and shared by all jobs. On the
other hand, the zone_reset_threshold option is defined as the ratio to
each job's IO range. When a job refers to the accounting value, it
includes writes to IO ranges out of the job's IO range. Then zone reset
is triggered earlier than expected.

The second issue is accounting value initialization. The initialization
of the accounting field is repeated for each job, then the value
initialized by the first job is overwritten by other jobs. This works as
expected for single job or multiple jobs with same write range. However,
when multiple jobs have different write ranges, the overwritten value is
wrong except for the last job.

To ensure that the accounting works as expected for the option, check
that write ranges of all jobs are same. If jobs have different write
ranges, report it as an error. Initialize the accounting field only once
for the first job. All jobs have same write range, then one time
initialization is enough. Update man page to clarify this limitation of
the option.

Signed-off-by: Shin'ichiro Kawasaki <shinichiro.kawasaki@wdc.com>
Reviewed-by: Niklas Cassel <niklas.cassel@wdc.com>
Signed-off-by: Vincent Fu <vincent.fu@samsung.com>
HOWTO.rst
fio.1
zbd.c
zbd.h

index a5f8cc2df3c089de01d7eaaed7985927954e7af7..158c5d897e520c5d075d201cee8b10bf6fc81386 100644 (file)
--- a/HOWTO.rst
+++ b/HOWTO.rst
@@ -1088,7 +1088,9 @@ Target file/device
        A number between zero and one that indicates the ratio of written bytes
        in the zones with write pointers in the IO range to the size of the IO
        range. When current ratio is above this ratio, zones are reset
-       periodically as :option:`zone_reset_frequency` specifies.
+       periodically as :option:`zone_reset_frequency` specifies. If there are
+       multiple jobs when using this option, the IO range for all write jobs
+       has to be the same.
 
 .. option:: zone_reset_frequency=float
 
diff --git a/fio.1 b/fio.1
index 3556ad358f44b9107ee5d129862776aaf430a5df..00a09353900f14980c511ad2048e5671ee902169 100644 (file)
--- a/fio.1
+++ b/fio.1
@@ -857,7 +857,8 @@ value to be larger than the device reported limit. Default: false.
 A number between zero and one that indicates the ratio of written bytes in the
 zones with write pointers in the IO range to the size of the IO range. When
 current ratio is above this ratio, zones are reset periodically as
-\fBzone_reset_frequency\fR specifies.
+\fBzone_reset_frequency\fR specifies. If there are multiple jobs when using this
+option, the IO range for all write jobs has to be the same.
 .TP
 .BI zone_reset_frequency \fR=\fPfloat
 A number between zero and one that indicates how often a zone reset should be
diff --git a/zbd.c b/zbd.c
index 6783acf987cb2399a6d179a715e746156a4ffa5b..893794315b8933d140d7a3dce7141015fee16b2e 100644 (file)
--- a/zbd.c
+++ b/zbd.c
@@ -542,7 +542,7 @@ static bool zbd_using_direct_io(void)
 }
 
 /* Whether or not the I/O range for f includes one or more sequential zones */
-static bool zbd_is_seq_job(struct fio_file *f)
+static bool zbd_is_seq_job(const struct fio_file *f)
 {
        uint32_t zone_idx, zone_idx_b, zone_idx_e;
 
@@ -1201,10 +1201,33 @@ static uint64_t zbd_set_vdb(struct thread_data *td, const struct fio_file *f)
 {
        struct fio_zone_info *zb, *ze, *z;
        uint64_t wp_vdb = 0;
+       struct zoned_block_device_info *zbdi = f->zbd_info;
 
        if (!accounting_vdb(td, f))
                return 0;
 
+       /*
+        * Ensure that the I/O range includes one or more sequential zones so
+        * that f->min_zone and f->max_zone have different values.
+        */
+       if (!zbd_is_seq_job(f))
+               return 0;
+
+       if (zbdi->write_min_zone != zbdi->write_max_zone) {
+               if (zbdi->write_min_zone != f->min_zone ||
+                   zbdi->write_max_zone != f->max_zone) {
+                       td_verror(td, EINVAL,
+                                 "multi-jobs with different write ranges are "
+                                 "not supported with zone_reset_threshold");
+                       log_err("multi-jobs with different write ranges are "
+                               "not supported with zone_reset_threshold\n");
+               }
+               return 0;
+       }
+
+       zbdi->write_min_zone = f->min_zone;
+       zbdi->write_max_zone = f->max_zone;
+
        zb = zbd_get_zone(f, f->min_zone);
        ze = zbd_get_zone(f, f->max_zone);
        for (z = zb; z < ze; z++) {
@@ -1214,9 +1237,9 @@ static uint64_t zbd_set_vdb(struct thread_data *td, const struct fio_file *f)
                }
        }
 
-       pthread_mutex_lock(&f->zbd_info->mutex);
-       f->zbd_info->wp_valid_data_bytes = wp_vdb;
-       pthread_mutex_unlock(&f->zbd_info->mutex);
+       pthread_mutex_lock(&zbdi->mutex);
+       zbdi->wp_valid_data_bytes = wp_vdb;
+       pthread_mutex_unlock(&zbdi->mutex);
 
        for (z = zb; z < ze; z++)
                if (z->has_wp)
diff --git a/zbd.h b/zbd.h
index 20b2fe17ddffffbbff7ded8080022e545a4528e1..05189555e0b68b98c125762604acdb6245e51108 100644 (file)
--- a/zbd.h
+++ b/zbd.h
@@ -55,6 +55,8 @@ struct fio_zone_info {
  *             num_open_zones).
  * @zone_size: size of a single zone in bytes.
  * @wp_valid_data_bytes: total size of data in zones with write pointers
+ * @write_min_zone: Minimum zone index of all job's write ranges. Inclusive.
+ * @write_max_zone: Maximum zone index of all job's write ranges. Exclusive.
  * @zone_size_log2: log2 of the zone size in bytes if it is a power of 2 or 0
  *             if the zone size is not a power of 2.
  * @nr_zones: number of zones
@@ -75,6 +77,8 @@ struct zoned_block_device_info {
        pthread_mutex_t         mutex;
        uint64_t                zone_size;
        uint64_t                wp_valid_data_bytes;
+       uint32_t                write_min_zone;
+       uint32_t                write_max_zone;
        uint32_t                zone_size_log2;
        uint32_t                nr_zones;
        uint32_t                refcount;