fio: groundwork for adding slat, lat percentiles
[fio.git] / zbd.c
diff --git a/zbd.c b/zbd.c
index 09ddcca42e7c011f1a7f2d30211a4b0beb227d56..ee8bcb30416a0fdc12af8a9ce79d5e9d1e341427 100644 (file)
--- a/zbd.c
+++ b/zbd.c
 #include <sys/stat.h>
 #include <unistd.h>
 #include <linux/blkzoned.h>
+
 #include "file.h"
 #include "fio.h"
 #include "lib/pow2.h"
 #include "log.h"
+#include "oslib/asprintf.h"
 #include "smalloc.h"
 #include "verify.h"
 #include "zbd.h"
@@ -119,6 +121,30 @@ static bool zbd_verify_sizes(void)
                                continue;
                        if (!zbd_is_seq_job(f))
                                continue;
+
+                       if (!td->o.zone_size) {
+                               td->o.zone_size = f->zbd_info->zone_size;
+                               if (!td->o.zone_size) {
+                                       log_err("%s: invalid 0 zone size\n",
+                                               f->file_name);
+                                       return false;
+                               }
+                       } else if (td->o.zone_size != f->zbd_info->zone_size) {
+                               log_err("%s: job parameter zonesize %llu does not match disk zone size %llu.\n",
+                                       f->file_name, (unsigned long long) td->o.zone_size,
+                                       (unsigned long long) f->zbd_info->zone_size);
+                               return false;
+                       }
+
+                       if (td->o.zone_skip &&
+                           (td->o.zone_skip < td->o.zone_size ||
+                            td->o.zone_skip % td->o.zone_size)) {
+                               log_err("%s: zoneskip %llu is not a multiple of the device zone size %llu.\n",
+                                       f->file_name, (unsigned long long) td->o.zone_skip,
+                                       (unsigned long long) td->o.zone_size);
+                               return false;
+                       }
+
                        zone_idx = zbd_zone_idx(f, f->file_offset);
                        z = &f->zbd_info->zone_info[zone_idx];
                        if (f->file_offset != z->start) {
@@ -411,8 +437,8 @@ static int parse_zone_info(struct thread_data *td, struct fio_file *f)
        if (td->o.zone_size == 0) {
                td->o.zone_size = zone_size;
        } else if (td->o.zone_size != zone_size) {
-               log_info("fio: %s job parameter zonesize %llu does not match disk zone size %llu.\n",
-                        f->file_name, (unsigned long long) td->o.zone_size,
+               log_err("fio: %s job parameter zonesize %llu does not match disk zone size %llu.\n",
+                       f->file_name, (unsigned long long) td->o.zone_size,
                        (unsigned long long) zone_size);
                ret = -EINVAL;
                goto close;
@@ -559,7 +585,7 @@ static int zbd_init_zone_info(struct thread_data *td, struct fio_file *file)
 
        ret = zbd_create_zone_info(td, file);
        if (ret < 0)
-               td_verror(td, -ret, "BLKREPORTZONE failed");
+               td_verror(td, -ret, "zbd_create_zone_info() failed");
        return ret;
 }
 
@@ -1219,6 +1245,65 @@ bool zbd_unaligned_write(int error_code)
        return false;
 }
 
+/**
+ * setup_zbd_zone_mode - handle zoneskip as necessary for ZBD drives
+ * @td: FIO thread data.
+ * @io_u: FIO I/O unit.
+ *
+ * For sequential workloads, change the file offset to skip zoneskip bytes when
+ * no more IO can be performed in the current zone.
+ * - For read workloads, zoneskip is applied when the io has reached the end of
+ *   the zone or the zone write position (when td->o.read_beyond_wp is false).
+ * - For write workloads, zoneskip is applied when the zone is full.
+ * This applies only to read and write operations.
+ */
+void setup_zbd_zone_mode(struct thread_data *td, struct io_u *io_u)
+{
+       struct fio_file *f = io_u->file;
+       enum fio_ddir ddir = io_u->ddir;
+       struct fio_zone_info *z;
+       uint32_t zone_idx;
+
+       assert(td->o.zone_mode == ZONE_MODE_ZBD);
+       assert(td->o.zone_size);
+
+       /*
+        * zone_skip is valid only for sequential workloads.
+        */
+       if (td_random(td) || !td->o.zone_skip)
+               return;
+
+       /*
+        * It is time to switch to a new zone if:
+        * - zone_bytes == zone_size bytes have already been accessed
+        * - The last position reached the end of the current zone.
+        * - For reads with td->o.read_beyond_wp == false, the last position
+        *   reached the zone write pointer.
+        */
+       zone_idx = zbd_zone_idx(f, f->last_pos[ddir]);
+       z = &f->zbd_info->zone_info[zone_idx];
+
+       if (td->zone_bytes >= td->o.zone_size ||
+           f->last_pos[ddir] >= (z+1)->start ||
+           (ddir == DDIR_READ &&
+            (!td->o.read_beyond_wp) && f->last_pos[ddir] >= z->wp)) {
+               /*
+                * Skip zones.
+                */
+               td->zone_bytes = 0;
+               f->file_offset += td->o.zone_size + td->o.zone_skip;
+
+               /*
+                * Wrap from the beginning, if we exceed the file size
+                */
+               if (f->file_offset >= f->real_file_size)
+                       f->file_offset = get_start_offset(td, f);
+
+               f->last_pos[ddir] = f->file_offset;
+               td->io_skip_bytes += td->o.zone_skip;
+       }
+}
+
 /**
  * zbd_adjust_block - adjust the offset and length as necessary for ZBD drives
  * @td: FIO thread data.