Unify the time handling
[fio.git] / options.c
index 57e9af5b4676296f22a1aee8a97fd379826afb53..535598297de43c32c8c07231b3407c016d83a698 100644 (file)
--- a/options.c
+++ b/options.c
@@ -102,7 +102,7 @@ static int bssplit_ddir(struct thread_options *o, int ddir, char *str)
                } else
                        perc = -1;
 
-               if (str_to_decimal(fname, &val, 1, o)) {
+               if (str_to_decimal(fname, &val, 1, o, 0)) {
                        log_err("fio: bssplit conversion failed\n");
                        free(bssplit);
                        return 1;
@@ -336,7 +336,7 @@ static int str_rw_cb(void *data, const char *str)
        else {
                long long val;
 
-               if (str_to_decimal(nr, &val, 1, o)) {
+               if (str_to_decimal(nr, &val, 1, o, 0)) {
                        log_err("fio: rw postfix parsing failed\n");
                        free(nr);
                        return 1;
@@ -729,11 +729,11 @@ static int str_random_distribution_cb(void *data, const char *str)
 }
 
 /*
- * Return next file in the string. Files are separated with ':'. If the ':'
+ * Return next name in the string. Files are separated with ':'. If the ':'
  * is escaped with a '\', then that ':' is part of the filename and does not
  * indicate a new file.
  */
-static char *get_next_file_name(char **ptr)
+static char *get_next_name(char **ptr)
 {
        char *str = *ptr;
        char *p, *start;
@@ -774,6 +774,43 @@ static char *get_next_file_name(char **ptr)
        return start;
 }
 
+
+static int get_max_name_idx(char *input)
+{
+       unsigned int cur_idx;
+       char *str, *p;
+
+       p = str = strdup(input);
+       for (cur_idx = 0; ; cur_idx++)
+               if (get_next_name(&str) == NULL)
+                       break;
+
+       free(p);
+       return cur_idx;
+}
+
+/*
+ * Returns the directory at the index, indexes > entires will be
+ * assigned via modulo division of the index
+ */
+int set_name_idx(char *target, char *input, int index)
+{
+       unsigned int cur_idx;
+       int len;
+       char *fname, *str, *p;
+
+       p = str = strdup(input);
+
+       index %= get_max_name_idx(input);
+       for (cur_idx = 0; cur_idx <= index; cur_idx++)
+               fname = get_next_name(&str);
+
+       len = sprintf(target, "%s/", fname);
+       free(p);
+
+       return len;
+}
+
 static int str_filename_cb(void *data, const char *input)
 {
        struct thread_data *td = data;
@@ -787,10 +824,10 @@ static int str_filename_cb(void *data, const char *input)
        if (!td->files_index)
                td->o.nr_files = 0;
 
-       while ((fname = get_next_file_name(&str)) != NULL) {
+       while ((fname = get_next_name(&str)) != NULL) {
                if (!strlen(fname))
                        break;
-               add_file(td, fname);
+               add_file(td, fname, 0);
                td->o.nr_files++;
        }
 
@@ -798,23 +835,43 @@ static int str_filename_cb(void *data, const char *input)
        return 0;
 }
 
-static int str_directory_cb(void *data, const char fio_unused *str)
+static int str_directory_cb(void *data, const char fio_unused *unused)
 {
        struct thread_data *td = data;
        struct stat sb;
+       char *dirname, *str, *p;
+       int ret = 0;
 
        if (parse_dryrun())
                return 0;
 
-       if (lstat(td->o.directory, &sb) < 0) {
-               int ret = errno;
+       p = str = strdup(td->o.directory);
+       while ((dirname = get_next_name(&str)) != NULL) {
+               if (lstat(dirname, &sb) < 0) {
+                       ret = errno;
 
-               log_err("fio: %s is not a directory\n", td->o.directory);
-               td_verror(td, ret, "lstat");
-               return 1;
+                       log_err("fio: %s is not a directory\n", dirname);
+                       td_verror(td, ret, "lstat");
+                       goto out;
+               }
+               if (!S_ISDIR(sb.st_mode)) {
+                       log_err("fio: %s is not a directory\n", dirname);
+                       ret = 1;
+                       goto out;
+               }
        }
-       if (!S_ISDIR(sb.st_mode)) {
-               log_err("fio: %s is not a directory\n", td->o.directory);
+
+out:
+       free(p);
+       return ret;
+}
+
+static int str_lockfile_cb(void *data, const char fio_unused *str)
+{
+       struct thread_data *td = data;
+
+       if (td->files_index) {
+               log_err("fio: lockfile= option must precede filename=\n");
                return 1;
        }
 
@@ -1231,6 +1288,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = {
                .parent = "filename",
                .hide   = 0,
                .def    = "none",
+               .cb     = str_lockfile_cb,
                .category = FIO_OPT_C_FILE,
                .group  = FIO_OPT_G_FILENAME,
                .posval = {
@@ -1374,6 +1432,11 @@ struct fio_option fio_options[FIO_MAX_OPTS] = {
                          { .ival = "windowsaio",
                            .help = "Windows native asynchronous IO"
                          },
+#endif
+#ifdef CONFIG_RBD
+                         { .ival = "rbd",
+                           .help = "Rados Block Device asynchronous IO"
+                         },
 #endif
                          { .ival = "mmap",
                            .help = "Memory mapped IO"
@@ -1765,6 +1828,15 @@ struct fio_option fio_options[FIO_MAX_OPTS] = {
                .category = FIO_OPT_C_IO,
                .group  = FIO_OPT_G_RANDOM,
        },
+       {
+               .name   = "allrandrepeat",
+               .type   = FIO_OPT_BOOL,
+               .off1   = td_var_offset(allrand_repeatable),
+               .help   = "Use repeatable random numbers for everything",
+               .def    = "0",
+               .category = FIO_OPT_C_IO,
+               .group  = FIO_OPT_G_RANDOM,
+       },
        {
                .name   = "nrfiles",
                .lname  = "Number of files",
@@ -1901,18 +1973,18 @@ struct fio_option fio_options[FIO_MAX_OPTS] = {
                          { .ival = "wait_before",
                            .oval = SYNC_FILE_RANGE_WAIT_BEFORE,
                            .help = "SYNC_FILE_RANGE_WAIT_BEFORE",
-                           .or   = 1,
+                           .orval  = 1,
                          },
                          { .ival = "write",
                            .oval = SYNC_FILE_RANGE_WRITE,
                            .help = "SYNC_FILE_RANGE_WRITE",
-                           .or   = 1,
+                           .orval  = 1,
                          },
                          {
                            .ival = "wait_after",
                            .oval = SYNC_FILE_RANGE_WAIT_AFTER,
                            .help = "SYNC_FILE_RANGE_WAIT_AFTER",
-                           .or   = 1,
+                           .orval  = 1,
                          },
                },
                .type   = FIO_OPT_STR_MULTI,
@@ -1993,8 +2065,10 @@ struct fio_option fio_options[FIO_MAX_OPTS] = {
                .lname  = "Start delay",
                .type   = FIO_OPT_STR_VAL_TIME,
                .off1   = td_var_offset(start_delay),
+               .off2   = td_var_offset(start_delay_high),
                .help   = "Only start job when this period has passed",
                .def    = "0",
+               .is_seconds = 1,
                .category = FIO_OPT_C_GENERAL,
                .group  = FIO_OPT_G_RUNTIME,
        },
@@ -2006,6 +2080,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = {
                .off1   = td_var_offset(timeout),
                .help   = "Stop workload when this amount of time has passed",
                .def    = "0",
+               .is_seconds = 1,
                .category = FIO_OPT_C_GENERAL,
                .group  = FIO_OPT_G_RUNTIME,
        },
@@ -2033,6 +2108,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = {
                .type   = FIO_OPT_STR_VAL_TIME,
                .off1   = td_var_offset(ramp_time),
                .help   = "Ramp up time before measuring performance",
+               .is_seconds = 1,
                .category = FIO_OPT_C_GENERAL,
                .group  = FIO_OPT_G_RUNTIME,
        },
@@ -2172,6 +2248,10 @@ struct fio_option fio_options[FIO_MAX_OPTS] = {
                            .oval = VERIFY_SHA512,
                            .help = "Use sha512 checksums for verification",
                          },
+                         { .ival = "xxhash",
+                           .oval = VERIFY_XXHASH,
+                           .help = "Use xxhash checksums for verification",
+                         },
                          { .ival = "meta",
                            .oval = VERIFY_META,
                            .help = "Use io information",
@@ -2998,7 +3078,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = {
                .type   = FIO_OPT_INT,
                .off1   = td_var_offset(compress_percentage),
                .maxval = 100,
-               .minval = 1,
+               .minval = 0,
                .help   = "How compressible the buffer is (approximately)",
                .interval = 5,
                .category = FIO_OPT_C_IO,
@@ -3727,7 +3807,7 @@ void options_mem_dupe(void *data, struct fio_option *options)
                if (o->type != FIO_OPT_STR_STORE)
                        continue;
 
-               ptr = td_var(data, o->off1);
+               ptr = td_var(data, o, o->off1);
                if (*ptr)
                        *ptr = strdup(*ptr);
        }
@@ -3773,7 +3853,13 @@ int add_option(struct fio_option *o)
                __o++;
        }
 
+       if (opt_index + 1 == FIO_MAX_OPTS) {
+               log_err("fio: FIO_MAX_OPTS is too small\n");
+               return 1;
+       }
+
        memcpy(&fio_options[opt_index], o, sizeof(*o));
+       fio_options[opt_index + 1].name = NULL;
        return 0;
 }