engines/io_uring: add new I/O engine for uring passthrough support
[fio.git] / options.c
index 102bcf5661a0c0fbffd54a61ad85281809250d3a..2b183c60d01b4cf8f5b320a66d8afc43caac79af 100644 (file)
--- a/options.c
+++ b/options.c
@@ -278,6 +278,128 @@ static int str_bssplit_cb(void *data, const char *input)
        return ret;
 }
 
+static int parse_cmdprio_bssplit_entry(struct thread_options *o,
+                                      struct split_prio *entry, char *str)
+{
+       int matches = 0;
+       char *bs_str = NULL;
+       long long bs_val;
+       unsigned int perc = 0, class, level;
+
+       /*
+        * valid entry formats:
+        * bs/ - %s/ - set perc to 0, prio to -1.
+        * bs/perc - %s/%u - set prio to -1.
+        * bs/perc/class/level - %s/%u/%u/%u
+        */
+       matches = sscanf(str, "%m[^/]/%u/%u/%u", &bs_str, &perc, &class, &level);
+       if (matches < 1) {
+               log_err("fio: invalid cmdprio_bssplit format\n");
+               return 1;
+       }
+
+       if (str_to_decimal(bs_str, &bs_val, 1, o, 0, 0)) {
+               log_err("fio: split conversion failed\n");
+               free(bs_str);
+               return 1;
+       }
+       free(bs_str);
+
+       entry->bs = bs_val;
+       entry->perc = min(perc, 100u);
+       entry->prio = -1;
+       switch (matches) {
+       case 1: /* bs/ case */
+       case 2: /* bs/perc case */
+               break;
+       case 4: /* bs/perc/class/level case */
+               class = min(class, (unsigned int) IOPRIO_MAX_PRIO_CLASS);
+               level = min(level, (unsigned int) IOPRIO_MAX_PRIO);
+               entry->prio = ioprio_value(class, level);
+               break;
+       default:
+               log_err("fio: invalid cmdprio_bssplit format\n");
+               return 1;
+       }
+
+       return 0;
+}
+
+/*
+ * Returns a negative integer if the first argument should be before the second
+ * argument in the sorted list. A positive integer if the first argument should
+ * be after the second argument in the sorted list. A zero if they are equal.
+ */
+static int fio_split_prio_cmp(const void *p1, const void *p2)
+{
+       const struct split_prio *tmp1 = p1;
+       const struct split_prio *tmp2 = p2;
+
+       if (tmp1->bs > tmp2->bs)
+               return 1;
+       if (tmp1->bs < tmp2->bs)
+               return -1;
+       return 0;
+}
+
+int split_parse_prio_ddir(struct thread_options *o, struct split_prio **entries,
+                         int *nr_entries, char *str)
+{
+       struct split_prio *tmp_entries;
+       unsigned int nr_bssplits;
+       char *str_cpy, *p, *fname;
+
+       /* strsep modifies the string, dup it so that we can use strsep twice */
+       p = str_cpy = strdup(str);
+       if (!p)
+               return 1;
+
+       nr_bssplits = 0;
+       while ((fname = strsep(&str_cpy, ":")) != NULL) {
+               if (!strlen(fname))
+                       break;
+               nr_bssplits++;
+       }
+       free(p);
+
+       if (nr_bssplits > BSSPLIT_MAX) {
+               log_err("fio: too many cmdprio_bssplit entries\n");
+               return 1;
+       }
+
+       tmp_entries = calloc(nr_bssplits, sizeof(*tmp_entries));
+       if (!tmp_entries)
+               return 1;
+
+       nr_bssplits = 0;
+       while ((fname = strsep(&str, ":")) != NULL) {
+               struct split_prio *entry;
+
+               if (!strlen(fname))
+                       break;
+
+               entry = &tmp_entries[nr_bssplits];
+
+               if (parse_cmdprio_bssplit_entry(o, entry, fname)) {
+                       log_err("fio: failed to parse cmdprio_bssplit entry\n");
+                       free(tmp_entries);
+                       return 1;
+               }
+
+               /* skip zero perc entries, they provide no useful information */
+               if (entry->perc)
+                       nr_bssplits++;
+       }
+
+       qsort(tmp_entries, nr_bssplits, sizeof(*tmp_entries),
+             fio_split_prio_cmp);
+
+       *entries = tmp_entries;
+       *nr_entries = nr_bssplits;
+
+       return 0;
+}
+
 static int str2error(char *str)
 {
        const char *err[] = { "EPERM", "ENOENT", "ESRCH", "EINTR", "EIO",
@@ -1244,7 +1366,7 @@ int get_max_str_idx(char *input)
 }
 
 /*
- * Returns the directory at the index, indexes > entires will be
+ * Returns the directory at the index, indexes > entries will be
  * assigned via modulo division of the index
  */
 int set_name_idx(char *target, size_t tlen, char *input, int index,
@@ -1438,7 +1560,7 @@ static int str_gtod_reduce_cb(void *data, int *il)
        int val = *il;
 
        /*
-        * Only modfiy options if gtod_reduce==1
+        * Only modify options if gtod_reduce==1
         * Otherwise leave settings alone.
         */
        if (val) {
@@ -2022,6 +2144,11 @@ struct fio_option fio_options[FIO_MAX_OPTS] = {
                          { .ival = "nfs",
                            .help = "NFS IO engine",
                          },
+#endif
+#ifdef CONFIG_LIBXNVME
+                         { .ival = "xnvme",
+                           .help = "XNVME IO engine",
+                         },
 #endif
                },
        },
@@ -4392,6 +4519,24 @@ struct fio_option fio_options[FIO_MAX_OPTS] = {
                .category = FIO_OPT_C_LOG,
                .group = FIO_OPT_G_INVALID,
        },
+       {
+               .name = "log_alternate_epoch",
+               .lname = "Log epoch alternate",
+               .type = FIO_OPT_BOOL,
+               .off1 = offsetof(struct thread_options, log_alternate_epoch),
+               .help = "Use alternate epoch time in log files. Uses the same epoch as that is used by clock_gettime with specified log_alternate_epoch_clock_id.",
+               .category = FIO_OPT_C_LOG,
+               .group = FIO_OPT_G_INVALID,
+       },
+       {
+               .name = "log_alternate_epoch_clock_id",
+               .lname = "Log alternate epoch clock_id",
+               .type = FIO_OPT_INT,
+               .off1 = offsetof(struct thread_options, log_alternate_epoch_clock_id),
+               .help = "If log_alternate_epoch or log_unix_epoch is true, this option specifies the clock_id from clock_gettime whose epoch should be used. If neither of those is true, this option has no effect. Default value is 0, or CLOCK_REALTIME",
+               .category = FIO_OPT_C_LOG,
+               .group = FIO_OPT_G_INVALID,
+       },
        {
                .name   = "block_error_percentiles",
                .lname  = "Block error percentiles",
@@ -4525,6 +4670,16 @@ struct fio_option fio_options[FIO_MAX_OPTS] = {
                .category = FIO_OPT_C_IO,
                .group  = FIO_OPT_G_IO_BUF,
        },
+       {
+               .name   = "dedupe_global",
+               .lname  = "Global deduplication",
+               .type   = FIO_OPT_BOOL,
+               .off1   = offsetof(struct thread_options, dedupe_global),
+               .help   = "Share deduplication buffers across jobs",
+               .def    = "0",
+               .category = FIO_OPT_C_IO,
+               .group  = FIO_OPT_G_IO_BUF,
+       },
        {
                .name   = "dedupe_mode",
                .lname  = "Dedupe mode",