+ for_each_file(td, f, i) {
+ struct zoned_block_device_info *zbd = f->zbd_info;
+ struct fio_zone_info *z;
+ int zi;
+
+ assert(zbd);
+
+ f->min_zone = zbd_zone_idx(f, f->file_offset);
+ f->max_zone = zbd_zone_idx(f, f->file_offset + f->io_size);
+
+ /*
+ * When all zones in the I/O range are conventional, io_size
+ * can be smaller than zone size, making min_zone the same
+ * as max_zone. This is why the assert below needs to be made
+ * conditional.
+ */
+ if (zbd_is_seq_job(f))
+ assert(f->min_zone < f->max_zone);
+
+ if (td->o.max_open_zones > 0 &&
+ zbd->max_open_zones != td->o.max_open_zones) {
+ log_err("Different 'max_open_zones' values\n");
+ return 1;
+ }
+
+ /*
+ * The per job max open zones limit cannot be used without a
+ * global max open zones limit. (As the tracking of open zones
+ * is disabled when there is no global max open zones limit.)
+ */
+ if (td->o.job_max_open_zones && !zbd->max_open_zones) {
+ log_err("'job_max_open_zones' cannot be used without a global open zones limit\n");
+ return 1;
+ }
+
+ /*
+ * zbd->max_open_zones is the global limit shared for all jobs
+ * that target the same zoned block device. Force sync the per
+ * thread global limit with the actual global limit. (The real
+ * per thread/job limit is stored in td->o.job_max_open_zones).
+ */
+ td->o.max_open_zones = zbd->max_open_zones;
+
+ for (zi = f->min_zone; zi < f->max_zone; zi++) {
+ z = &zbd->zone_info[zi];
+ if (z->cond != ZBD_ZONE_COND_IMP_OPEN &&
+ z->cond != ZBD_ZONE_COND_EXP_OPEN)
+ continue;
+ if (zbd_open_zone(td, f, zi))
+ continue;
+ /*
+ * If the number of open zones exceeds specified limits,
+ * reset all extra open zones.
+ */
+ if (zbd_reset_zone(td, f, z) < 0) {
+ log_err("Failed to reest zone %d\n", zi);
+ return 1;
+ }
+ }
+ }
+