As a preparation to improve open zones accounting for devices with the max_active_zones limit, get the limit from the devices. In same manner as max_open_zones, call get_max_active_zones callback if the I/O engine supports it. Add the new call back to the I/O engine API and bump up FIO_IOOPS_VERSION. It is expected that io_uring and xnvme engines to support the callback later. When the callback is not available, refer max_active_zones sysfs attribute for block devices. When the limit value is not available, use zero value which means no limit. Keep the obtained limit value in the struct zoned_block_device_info. Signed-off-by: Shin'ichiro Kawasaki <shinichiro.kawasaki@xxxxxxx> --- ioengines.h | 4 +++- oslib/blkzoned.h | 9 +++++++++ oslib/linux-blkzoned.c | 23 +++++++++++++++++++++++ zbd.c | 29 +++++++++++++++++++++++++++++ zbd.h | 4 ++++ 5 files changed, 68 insertions(+), 1 deletion(-) diff --git a/ioengines.h b/ioengines.h index 9484265e..4391b31e 100644 --- a/ioengines.h +++ b/ioengines.h @@ -9,7 +9,7 @@ #include "zbd_types.h" #include "fdp.h" -#define FIO_IOOPS_VERSION 32 +#define FIO_IOOPS_VERSION 33 #ifndef CONFIG_DYNAMIC_ENGINES #define FIO_STATIC static @@ -62,6 +62,8 @@ struct ioengine_ops { uint64_t, uint64_t); int (*get_max_open_zones)(struct thread_data *, struct fio_file *, unsigned int *); + int (*get_max_active_zones)(struct thread_data *, struct fio_file *, + unsigned int *); int (*finish_zone)(struct thread_data *, struct fio_file *, uint64_t, uint64_t); int (*fdp_fetch_ruhs)(struct thread_data *, struct fio_file *, diff --git a/oslib/blkzoned.h b/oslib/blkzoned.h index 29fb034f..e598bd4f 100644 --- a/oslib/blkzoned.h +++ b/oslib/blkzoned.h @@ -18,6 +18,9 @@ extern int blkzoned_reset_wp(struct thread_data *td, struct fio_file *f, uint64_t offset, uint64_t length); extern int blkzoned_get_max_open_zones(struct thread_data *td, struct fio_file *f, unsigned int *max_open_zones); +extern int blkzoned_get_max_active_zones(struct thread_data *td, + struct fio_file *f, + unsigned int *max_active_zones); extern int blkzoned_finish_zone(struct thread_data *td, struct fio_file *f, uint64_t offset, uint64_t length); #else @@ -53,6 +56,12 @@ static inline int blkzoned_get_max_open_zones(struct thread_data *td, struct fio { return -EIO; } +static inline int blkzoned_get_max_active_zones(struct thread_data *td, + struct fio_file *f, + unsigned int *max_open_zones) +{ + return -EIO; +} static inline int blkzoned_finish_zone(struct thread_data *td, struct fio_file *f, uint64_t offset, uint64_t length) diff --git a/oslib/linux-blkzoned.c b/oslib/linux-blkzoned.c index 722e0992..2c3ecf33 100644 --- a/oslib/linux-blkzoned.c +++ b/oslib/linux-blkzoned.c @@ -186,6 +186,29 @@ int blkzoned_get_max_open_zones(struct thread_data *td, struct fio_file *f, return 0; } +int blkzoned_get_max_active_zones(struct thread_data *td, struct fio_file *f, + unsigned int *max_active_zones) +{ + char *max_active_str; + + if (f->filetype != FIO_TYPE_BLOCK) + return -EIO; + + max_active_str = blkzoned_get_sysfs_attr(f->file_name, "queue/max_active_zones"); + if (!max_active_str) { + *max_active_zones = 0; + return 0; + } + + dprint(FD_ZBD, "%s: max active zones supported by device: %s\n", + f->file_name, max_active_str); + *max_active_zones = atoll(max_active_str); + + free(max_active_str); + + return 0; +} + static uint64_t zone_capacity(struct blk_zone_report *hdr, struct blk_zone *blkz) { diff --git a/zbd.c b/zbd.c index d4565215..a5cb34d2 100644 --- a/zbd.c +++ b/zbd.c @@ -471,6 +471,34 @@ static int zbd_get_max_open_zones(struct thread_data *td, struct fio_file *f, return ret; } +/** + * zbd_get_max_active_zones - Get the maximum number of active zones + * @td: FIO thread data + * @f: FIO file for which to get max active zones + * + * Returns max_active_zones limit value of the target file if it is available. + * Otherwise return zero, which means no limit. + */ +static unsigned int zbd_get_max_active_zones(struct thread_data *td, + struct fio_file *f) +{ + unsigned int max_active_zones; + int ret; + + if (td->io_ops && td->io_ops->get_max_active_zones) + ret = td->io_ops->get_max_active_zones(td, f, + &max_active_zones); + else + ret = blkzoned_get_max_active_zones(td, f, &max_active_zones); + if (ret < 0) { + dprint(FD_ZBD, "%s: max_active_zones is not available\n", + f->file_name); + return 0; + } + + return max_active_zones; +} + /** * __zbd_write_zone_get - Add a zone to the array of write zones. * @td: fio thread data. @@ -927,6 +955,7 @@ static int parse_zone_info(struct thread_data *td, struct fio_file *f) f->zbd_info->zone_size_log2 = is_power_of_2(zone_size) ? ilog2(zone_size) : 0; f->zbd_info->nr_zones = nr_zones; + f->zbd_info->max_active_zones = zbd_get_max_active_zones(td, f); if (same_zone_cap) dprint(FD_ZBD, "Zone capacity = %"PRIu64" KB\n", diff --git a/zbd.h b/zbd.h index f0ac9876..a5cf59d1 100644 --- a/zbd.h +++ b/zbd.h @@ -52,6 +52,9 @@ struct fio_zone_info { * are simultaneously written. A zero value means unlimited zones of * simultaneous writes and that write target zones will not be tracked in * the write_zones array. + * @max_active_zones: device side limit on the number of sequential write zones + * in open or closed conditions. A zero value means unlimited number of + * zones in the conditions. * @mutex: Protects the modifiable members in this structure (refcount and * num_open_zones). * @zone_size: size of a single zone in bytes. @@ -75,6 +78,7 @@ struct fio_zone_info { struct zoned_block_device_info { enum zbd_zoned_model model; uint32_t max_write_zones; + uint32_t max_active_zones; pthread_mutex_t mutex; uint64_t zone_size; uint64_t wp_valid_data_bytes; -- 2.40.1