Merge branch 'master' of git://github.com/rootfs/fio
[fio.git] / options.c
index 87a443247a7f9e9d9005482670bc51be4b1441b2..d5bf00c38fbbccd00b394f1219bb0d0b63d84f6f 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;
@@ -269,7 +269,7 @@ static int ignore_error_type(struct thread_data *td, int etype, char *str)
                } else {
                        error[i] = atoi(fname);
                        if (error[i] < 0)
-                               error[i] = error[i];
+                               error[i] = -error[i];
                }
                if (!error[i]) {
                        log_err("Unknown error %s, please use number value \n",
@@ -283,7 +283,9 @@ static int ignore_error_type(struct thread_data *td, int etype, char *str)
                td->o.continue_on_error |= 1 << etype;
                td->o.ignore_error_nr[etype] = i;
                td->o.ignore_error[etype] = error;
-       }
+       } else
+               free(error);
+
        return 0;
 
 }
@@ -320,7 +322,7 @@ static int str_rw_cb(void *data, const char *str)
 {
        struct thread_data *td = data;
        struct thread_options *o = &td->o;
-       char *nr = get_opt_postfix(str);
+       char *nr;
 
        if (parse_dryrun())
                return 0;
@@ -328,6 +330,7 @@ static int str_rw_cb(void *data, const char *str)
        o->ddir_seq_nr = 1;
        o->ddir_seq_add = 0;
 
+       nr = get_opt_postfix(str);
        if (!nr)
                return 0;
 
@@ -336,7 +339,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;
@@ -394,6 +397,28 @@ static int str_exitall_cb(void)
 }
 
 #ifdef FIO_HAVE_CPU_AFFINITY
+int fio_cpus_split(os_cpu_mask_t *mask, unsigned int cpu_index)
+{
+       unsigned int i, index, cpus_in_mask;
+       const long max_cpu = cpus_online();
+
+       cpus_in_mask = fio_cpu_count(mask);
+       cpu_index = cpu_index % cpus_in_mask;
+
+       index = 0;
+       for (i = 0; i < max_cpu; i++) {
+               if (!fio_cpu_isset(mask, i))
+                       continue;
+
+               if (cpu_index != index)
+                       fio_cpu_clear(mask, i);
+
+               index++;
+       }
+
+       return fio_cpu_count(mask);
+}
+
 static int str_cpumask_cb(void *data, unsigned long long *val)
 {
        struct thread_data *td = data;
@@ -529,6 +554,7 @@ static int str_verify_cpus_allowed_cb(void *data, const char *input)
 static int str_numa_cpunodes_cb(void *data, char *input)
 {
        struct thread_data *td = data;
+       struct bitmask *verify_bitmask;
 
        if (parse_dryrun())
                return 0;
@@ -538,13 +564,15 @@ static int str_numa_cpunodes_cb(void *data, char *input)
         * numa_allocate_nodemask(), so it should be freed by
         * numa_free_nodemask().
         */
-       td->o.numa_cpunodesmask = numa_parse_nodestring(input);
-       if (td->o.numa_cpunodesmask == NULL) {
+       verify_bitmask = numa_parse_nodestring(input);
+       if (verify_bitmask == NULL) {
                log_err("fio: numa_parse_nodestring failed\n");
                td_verror(td, 1, "str_numa_cpunodes_cb");
                return 1;
        }
+       numa_free_nodemask(verify_bitmask);
 
+       td->o.numa_cpunodes = strdup(input);
        td->o.numa_cpumask_set = 1;
        return 0;
 }
@@ -556,6 +584,7 @@ static int str_numa_mpol_cb(void *data, char *input)
                { "default", "prefer", "bind", "interleave", "local", NULL };
        int i;
        char *nodelist;
+       struct bitmask *verify_bitmask;
 
        if (parse_dryrun())
                return 0;
@@ -635,12 +664,15 @@ static int str_numa_mpol_cb(void *data, char *input)
                break;
        case MPOL_INTERLEAVE:
        case MPOL_BIND:
-               td->o.numa_memnodesmask = numa_parse_nodestring(nodelist);
-               if (td->o.numa_memnodesmask == NULL) {
+               verify_bitmask = numa_parse_nodestring(nodelist);
+               if (verify_bitmask == NULL) {
                        log_err("fio: numa_parse_nodestring failed\n");
                        td_verror(td, 1, "str_numa_memnodes_cb");
                        return 1;
                }
+               td->o.numa_memnodes = strdup(nodelist);
+               numa_free_nodemask(verify_bitmask);
+                
                break;
        case MPOL_LOCAL:
        case MPOL_DEFAULT:
@@ -827,8 +859,7 @@ static int str_filename_cb(void *data, const char *input)
        while ((fname = get_next_name(&str)) != NULL) {
                if (!strlen(fname))
                        break;
-               add_file(td, fname, 0);
-               td->o.nr_files++;
+               add_file(td, fname, 0, 1);
        }
 
        free(p);
@@ -981,6 +1012,15 @@ static int str_buffer_pattern_cb(void *data, const char *input)
        return ret;
 }
 
+static int str_buffer_compress_cb(void *data, unsigned long long *il)
+{
+       struct thread_data *td = data;
+
+       td->flags |= TD_F_COMPRESS;
+       td->o.compress_percentage = *il;
+       return 0;
+}
+
 static int str_verify_pattern_cb(void *data, const char *input)
 {
        struct thread_data *td = data;
@@ -1493,6 +1533,15 @@ struct fio_option fio_options[FIO_MAX_OPTS] = {
                            .help = "fallocate() file based engine",
                          },
 #endif
+#ifdef CONFIG_GFAPI
+                         { .ival = "gfapi",
+                           .help = "Glusterfs libgfapi(sync) based engine"
+                         },
+                         { .ival = "gfapi_async",
+                           .help = "Glusterfs libgfapi(async) based engine"
+                         },
+#endif
+
                          { .ival = "external",
                            .help = "Load external engine (append name)",
                          },
@@ -1561,6 +1610,15 @@ struct fio_option fio_options[FIO_MAX_OPTS] = {
                .category = FIO_OPT_C_IO,
                .group  = FIO_OPT_G_INVALID,
        },
+       {
+               .name   = "io_limit",
+               .lname  = "IO Limit",
+               .type   = FIO_OPT_STR_VAL,
+               .off1   = td_var_offset(io_limit),
+               .interval = 1024 * 1024,
+               .category = FIO_OPT_C_IO,
+               .group  = FIO_OPT_G_INVALID,
+       },
        {
                .name   = "fill_device",
                .lname  = "Fill device",
@@ -1584,6 +1642,16 @@ struct fio_option fio_options[FIO_MAX_OPTS] = {
                .category = FIO_OPT_C_FILE,
                .group  = FIO_OPT_G_INVALID,
        },
+       {
+               .name   = "file_append",
+               .lname  = "File append",
+               .type   = FIO_OPT_BOOL,
+               .off1   = td_var_offset(file_append),
+               .help   = "IO will start at the end of the file(s)",
+               .def    = "0",
+               .category = FIO_OPT_C_FILE,
+               .group  = FIO_OPT_G_INVALID,
+       },
        {
                .name   = "offset",
                .lname  = "IO offset",
@@ -2068,6 +2136,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = {
                .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,
        },
@@ -2079,6 +2148,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,
        },
@@ -2106,6 +2176,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,
        },
@@ -2873,6 +2944,27 @@ struct fio_option fio_options[FIO_MAX_OPTS] = {
                .category = FIO_OPT_C_GENERAL,
                .group  = FIO_OPT_G_CRED,
        },
+       {
+               .name   = "cpus_allowed_policy",
+               .lname  = "CPUs allowed distribution policy",
+               .type   = FIO_OPT_STR,
+               .off1   = td_var_offset(cpus_allowed_policy),
+               .help   = "Distribution policy for cpus_allowed",
+               .parent = "cpus_allowed",
+               .prio   = 1,
+               .posval = {
+                         { .ival = "shared",
+                           .oval = FIO_CPUS_SHARED,
+                           .help = "Mask shared between threads",
+                         },
+                         { .ival = "split",
+                           .oval = FIO_CPUS_SPLIT,
+                           .help = "Mask split between threads",
+                         },
+               },
+               .category = FIO_OPT_C_GENERAL,
+               .group  = FIO_OPT_G_CRED,
+       },
 #endif
 #ifdef CONFIG_LIBNUMA
        {
@@ -3073,7 +3165,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = {
                .name   = "buffer_compress_percentage",
                .lname  = "Buffer compression percentage",
                .type   = FIO_OPT_INT,
-               .off1   = td_var_offset(compress_percentage),
+               .cb     = str_buffer_compress_cb,
                .maxval = 100,
                .minval = 0,
                .help   = "How compressible the buffer is (approximately)",
@@ -3589,8 +3681,10 @@ static char *bc_calc(char *str)
                return NULL;
 
        ret = fread(&buf[tmp - str], 1, 128 - (tmp - str), f);
-       if (ret <= 0)
+       if (ret <= 0) {
+               pclose(f);
                return NULL;
+       }
 
        pclose(f);
        buf[(tmp - str) + ret - 1] = '\0';
@@ -3787,6 +3881,7 @@ int fio_cmd_ioengine_option_parse(struct thread_data *td, const char *opt,
 
 void fio_fill_default_options(struct thread_data *td)
 {
+       td->o.magic = OPT_MAGIC;
        fill_default_options(td, fio_options);
 }
 
@@ -3831,7 +3926,16 @@ unsigned int fio_get_kb_base(void *data)
        struct thread_options *o = data;
        unsigned int kb_base = 0;
 
-       if (o)
+       /*
+        * This is a hack... For private options, *data is not holding
+        * a pointer to the thread_options, but to private data. This means
+        * we can't safely dereference it, but magic is first so mem wise
+        * it is valid. But this also means that if the job first sets
+        * kb_base and expects that to be honored by private options,
+        * it will be disappointed. We will return the global default
+        * for this.
+        */
+       if (o && o->magic == OPT_MAGIC)
                kb_base = o->kb_base;
        if (!kb_base)
                kb_base = 1024;