Merge branch '2021-05-13/stat-fix-integer-overflow' of https://github.com/flx42/fio
authorJens Axboe <axboe@kernel.dk>
Fri, 14 May 2021 15:36:59 +0000 (09:36 -0600)
committerJens Axboe <axboe@kernel.dk>
Fri, 14 May 2021 15:36:59 +0000 (09:36 -0600)
* '2021-05-13/stat-fix-integer-overflow' of https://github.com/flx42/fio:
  stat: fix integer overflow in convert_agg_kbytes_percent

engines/libzbc.c
engines/skeleton_external.c
ioengines.h
oslib/blkzoned.h
oslib/linux-blkzoned.c
zbd.c

index 2aacf7bbebecd3ca0d2a5f11a5346ab26c429c86..3dde93db54713dbe884a2c6b9d2708ee1af4e01e 100644 (file)
@@ -19,6 +19,7 @@ struct libzbc_data {
        struct zbc_device       *zdev;
        enum zbc_dev_model      model;
        uint64_t                nr_sectors;
+       uint32_t                max_open_seq_req;
 };
 
 static int libzbc_get_dev_info(struct libzbc_data *ld, struct fio_file *f)
@@ -32,6 +33,7 @@ static int libzbc_get_dev_info(struct libzbc_data *ld, struct fio_file *f)
        zbc_get_device_info(ld->zdev, zinfo);
        ld->model = zinfo->zbd_model;
        ld->nr_sectors = zinfo->zbd_sectors;
+       ld->max_open_seq_req = zinfo->zbd_max_nr_open_seq_req;
 
        dprint(FD_ZBD, "%s: vendor_id:%s, type: %s, model: %s\n",
               f->file_name, zinfo->zbd_vendor_id,
@@ -335,6 +337,24 @@ err:
        return -ret;
 }
 
+static int libzbc_get_max_open_zones(struct thread_data *td, struct fio_file *f,
+                                    unsigned int *max_open_zones)
+{
+       struct libzbc_data *ld;
+       int ret;
+
+       ret = libzbc_open_dev(td, f, &ld);
+       if (ret)
+               return ret;
+
+       if (ld->max_open_seq_req == ZBC_NO_LIMIT)
+               *max_open_zones = 0;
+       else
+               *max_open_zones = ld->max_open_seq_req;
+
+       return 0;
+}
+
 ssize_t libzbc_rw(struct thread_data *td, struct io_u *io_u)
 {
        struct libzbc_data *ld = td->io_ops_data;
@@ -414,6 +434,7 @@ FIO_STATIC struct ioengine_ops ioengine = {
        .get_zoned_model        = libzbc_get_zoned_model,
        .report_zones           = libzbc_report_zones,
        .reset_wp               = libzbc_reset_wp,
+       .get_max_open_zones     = libzbc_get_max_open_zones,
        .queue                  = libzbc_queue,
        .flags                  = FIO_SYNCIO | FIO_NOEXTEND | FIO_RAWIO,
 };
index 7f3e4cb3a13c7d9cdb4fcee9b877f5a9b26e9e5d..c79b6f11146ff5ed7844f54da6ee03c3fbf971ac 100644 (file)
@@ -193,6 +193,18 @@ static int fio_skeleton_reset_wp(struct thread_data *td, struct fio_file *f,
        return 0;
 }
 
+/*
+ * Hook called for getting the maximum number of open zones for a
+ * ZBD_HOST_MANAGED zoned block device.
+ * A @max_open_zones value set to zero means no limit.
+ */
+static int fio_skeleton_get_max_open_zones(struct thread_data *td,
+                                          struct fio_file *f,
+                                          unsigned int *max_open_zones)
+{
+       return 0;
+}
+
 /*
  * Note that the structure is exported, so that fio can get it via
  * dlsym(..., "ioengine"); for (and only for) external engines.
@@ -212,6 +224,7 @@ struct ioengine_ops ioengine = {
        .get_zoned_model = fio_skeleton_get_zoned_model,
        .report_zones   = fio_skeleton_report_zones,
        .reset_wp       = fio_skeleton_reset_wp,
+       .get_max_open_zones = fio_skeleton_get_max_open_zones,
        .options        = options,
        .option_struct_size     = sizeof(struct fio_skeleton_options),
 };
index 1d01ab0a6d1345a71b04b0576f40fefca20062b9..b3f755b477de01f2ece25e93e9ad4d0edfa7bcda 100644 (file)
@@ -8,7 +8,7 @@
 #include "io_u.h"
 #include "zbd_types.h"
 
-#define FIO_IOOPS_VERSION      29
+#define FIO_IOOPS_VERSION      30
 
 #ifndef CONFIG_DYNAMIC_ENGINES
 #define FIO_STATIC     static
@@ -59,6 +59,8 @@ struct ioengine_ops {
                            uint64_t, struct zbd_zone *, unsigned int);
        int (*reset_wp)(struct thread_data *, struct fio_file *,
                        uint64_t, uint64_t);
+       int (*get_max_open_zones)(struct thread_data *, struct fio_file *,
+                                 unsigned int *);
        int option_struct_size;
        struct fio_option *options;
 };
index 4cc071dc6a61be64a257cd749e40cbd536cb9247..719b041d126adc03af9e30b9d2c9815b804a4518 100644 (file)
@@ -16,6 +16,8 @@ extern int blkzoned_report_zones(struct thread_data *td,
                                struct zbd_zone *zones, unsigned int nr_zones);
 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);
 #else
 /*
  * Define stubs for systems that do not have zoned block device support.
@@ -44,6 +46,11 @@ static inline int blkzoned_reset_wp(struct thread_data *td, struct fio_file *f,
 {
        return -EIO;
 }
+static inline int blkzoned_get_max_open_zones(struct thread_data *td, struct fio_file *f,
+                                             unsigned int *max_open_zones)
+{
+       return -EIO;
+}
 #endif
 
 #endif /* FIO_BLKZONED_H */
index 81e4e7f0d53544aa40c2ac95533763dfa7ee2c1f..6f89ec6f414e63c6a9bf6691a10dfc6723a29451 100644 (file)
@@ -74,12 +74,16 @@ static char *read_file(const char *path)
        return strdup(line);
 }
 
-int blkzoned_get_zoned_model(struct thread_data *td, struct fio_file *f,
-                            enum zbd_zoned_model *model)
+/*
+ * Get the value of a sysfs attribute for a block device.
+ *
+ * Returns NULL on failure.
+ * Returns a pointer to a string on success.
+ * The caller is responsible for freeing the memory.
+ */
+static char *blkzoned_get_sysfs_attr(const char *file_name, const char *attr)
 {
-       const char *file_name = f->file_name;
-       char *zoned_attr_path = NULL;
-       char *model_str = NULL;
+       char *attr_path = NULL;
        struct stat statbuf;
        char *sys_devno_path = NULL;
        char *part_attr_path = NULL;
@@ -87,13 +91,7 @@ int blkzoned_get_zoned_model(struct thread_data *td, struct fio_file *f,
        char sys_path[PATH_MAX];
        ssize_t sz;
        char *delim = NULL;
-
-       if (f->filetype != FIO_TYPE_BLOCK) {
-               *model = ZBD_IGNORE;
-               return 0;
-       }
-
-       *model = ZBD_NONE;
+       char *attr_str = NULL;
 
        if (stat(file_name, &statbuf) < 0)
                goto out;
@@ -123,24 +121,65 @@ int blkzoned_get_zoned_model(struct thread_data *td, struct fio_file *f,
                *delim = '\0';
        }
 
-       if (asprintf(&zoned_attr_path,
-                    "/sys/dev/block/%s/queue/zoned", sys_path) < 0)
+       if (asprintf(&attr_path,
+                    "/sys/dev/block/%s/%s", sys_path, attr) < 0)
                goto out;
 
-       model_str = read_file(zoned_attr_path);
+       attr_str = read_file(attr_path);
+out:
+       free(attr_path);
+       free(part_str);
+       free(part_attr_path);
+       free(sys_devno_path);
+
+       return attr_str;
+}
+
+int blkzoned_get_zoned_model(struct thread_data *td, struct fio_file *f,
+                            enum zbd_zoned_model *model)
+{
+       char *model_str = NULL;
+
+       if (f->filetype != FIO_TYPE_BLOCK) {
+               *model = ZBD_IGNORE;
+               return 0;
+       }
+
+       *model = ZBD_NONE;
+
+       model_str = blkzoned_get_sysfs_attr(f->file_name, "queue/zoned");
        if (!model_str)
-               goto out;
-       dprint(FD_ZBD, "%s: zbd model string: %s\n", file_name, model_str);
+               return 0;
+
+       dprint(FD_ZBD, "%s: zbd model string: %s\n", f->file_name, model_str);
        if (strcmp(model_str, "host-aware") == 0)
                *model = ZBD_HOST_AWARE;
        else if (strcmp(model_str, "host-managed") == 0)
                *model = ZBD_HOST_MANAGED;
-out:
+
        free(model_str);
-       free(zoned_attr_path);
-       free(part_str);
-       free(part_attr_path);
-       free(sys_devno_path);
+
+       return 0;
+}
+
+int blkzoned_get_max_open_zones(struct thread_data *td, struct fio_file *f,
+                               unsigned int *max_open_zones)
+{
+       char *max_open_str;
+
+       if (f->filetype != FIO_TYPE_BLOCK)
+               return -EIO;
+
+       max_open_str = blkzoned_get_sysfs_attr(f->file_name, "queue/max_open_zones");
+       if (!max_open_str)
+               return 0;
+
+       dprint(FD_ZBD, "%s: max open zones supported by device: %s\n",
+              f->file_name, max_open_str);
+       *max_open_zones = atoll(max_open_str);
+
+       free(max_open_str);
+
        return 0;
 }
 
diff --git a/zbd.c b/zbd.c
index eed796b3217d297eb94942b28b4cfbf0ab5113ab..68cd58e1b9db99dfa883dab39bc06daea6b972e8 100644 (file)
--- a/zbd.c
+++ b/zbd.c
@@ -113,6 +113,34 @@ int zbd_reset_wp(struct thread_data *td, struct fio_file *f,
        return ret;
 }
 
+/**
+ * zbd_get_max_open_zones - Get the maximum number of open zones
+ * @td: FIO thread data
+ * @f: FIO file for which to get max open zones
+ * @max_open_zones: Upon success, result will be stored here.
+ *
+ * A @max_open_zones value set to zero means no limit.
+ *
+ * Returns 0 upon success and a negative error code upon failure.
+ */
+int zbd_get_max_open_zones(struct thread_data *td, struct fio_file *f,
+                          unsigned int *max_open_zones)
+{
+       int ret;
+
+       if (td->io_ops && td->io_ops->get_max_open_zones)
+               ret = td->io_ops->get_max_open_zones(td, f, max_open_zones);
+       else
+               ret = blkzoned_get_max_open_zones(td, f, max_open_zones);
+       if (ret < 0) {
+               td_verror(td, errno, "get max open zones failed");
+               log_err("%s: get max open zones failed (%d).\n",
+                       f->file_name, errno);
+       }
+
+       return ret;
+}
+
 /**
  * zbd_zone_idx - convert an offset into a zone number
  * @f: file pointer.
@@ -554,6 +582,51 @@ out:
        return ret;
 }
 
+static int zbd_set_max_open_zones(struct thread_data *td, struct fio_file *f)
+{
+       struct zoned_block_device_info *zbd = f->zbd_info;
+       unsigned int max_open_zones;
+       int ret;
+
+       if (zbd->model != ZBD_HOST_MANAGED) {
+               /* Only host-managed devices have a max open limit */
+               zbd->max_open_zones = td->o.max_open_zones;
+               goto out;
+       }
+
+       /* If host-managed, get the max open limit */
+       ret = zbd_get_max_open_zones(td, f, &max_open_zones);
+       if (ret)
+               return ret;
+
+       if (!max_open_zones) {
+               /* No device limit */
+               zbd->max_open_zones = td->o.max_open_zones;
+       } else if (!td->o.max_open_zones) {
+               /* No user limit. Set limit to device limit */
+               zbd->max_open_zones = max_open_zones;
+       } else if (td->o.max_open_zones <= max_open_zones) {
+               /* Both user limit and dev limit. User limit not too large */
+               zbd->max_open_zones = td->o.max_open_zones;
+       } else {
+               /* Both user limit and dev limit. User limit too large */
+               td_verror(td, EINVAL,
+                         "Specified --max_open_zones is too large");
+               log_err("Specified --max_open_zones (%d) is larger than max (%u)\n",
+                       td->o.max_open_zones, max_open_zones);
+               return -EINVAL;
+       }
+
+out:
+       /* Ensure that the limit is not larger than FIO's internal limit */
+       zbd->max_open_zones = min_not_zero(zbd->max_open_zones,
+                                          (uint32_t) ZBD_MAX_OPEN_ZONES);
+       dprint(FD_ZBD, "%s: using max open zones limit: %"PRIu32"\n",
+              f->file_name, zbd->max_open_zones);
+
+       return 0;
+}
+
 /*
  * Allocate zone information and store it into f->zbd_info if zonemode=zbd.
  *
@@ -576,9 +649,13 @@ static int zbd_create_zone_info(struct thread_data *td, struct fio_file *f)
        case ZBD_HOST_AWARE:
        case ZBD_HOST_MANAGED:
                ret = parse_zone_info(td, f);
+               if (ret)
+                       return ret;
                break;
        case ZBD_NONE:
                ret = init_zone_info(td, f);
+               if (ret)
+                       return ret;
                break;
        default:
                td_verror(td, EINVAL, "Unsupported zoned model");
@@ -586,11 +663,15 @@ static int zbd_create_zone_info(struct thread_data *td, struct fio_file *f)
                return -EINVAL;
        }
 
-       if (ret == 0) {
-               f->zbd_info->model = zbd_model;
-               f->zbd_info->max_open_zones = td->o.max_open_zones;
+       f->zbd_info->model = zbd_model;
+
+       ret = zbd_set_max_open_zones(td, f);
+       if (ret) {
+               zbd_free_zone_info(f);
+               return ret;
        }
-       return ret;
+
+       return 0;
 }
 
 void zbd_free_zone_info(struct fio_file *f)
@@ -726,8 +807,6 @@ int zbd_setup_files(struct thread_data *td)
                if (zbd_is_seq_job(f))
                        assert(f->min_zone < f->max_zone);
 
-               zbd->max_open_zones = zbd->max_open_zones ?: ZBD_MAX_OPEN_ZONES;
-
                if (td->o.max_open_zones > 0 &&
                    zbd->max_open_zones != td->o.max_open_zones) {
                        log_err("Different 'max_open_zones' values\n");