options: check for dryrun in cpu mask setting
[fio.git] / options.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <unistd.h>
4 #include <ctype.h>
5 #include <string.h>
6 #include <assert.h>
7 #include <libgen.h>
8 #include <fcntl.h>
9 #include <sys/types.h>
10 #include <sys/stat.h>
11 #include <netinet/in.h>
12
13 #include "fio.h"
14 #include "verify.h"
15 #include "parse.h"
16 #include "lib/fls.h"
17 #include "lib/pattern.h"
18 #include "options.h"
19
20 #include "crc/crc32c.h"
21
22 char client_sockaddr_str[INET6_ADDRSTRLEN] = { 0 };
23
24 struct pattern_fmt_desc fmt_desc[] = {
25         {
26                 .fmt   = "%o",
27                 .len   = FIELD_SIZE(struct io_u *, offset),
28                 .paste = paste_blockoff
29         }
30 };
31
32 /*
33  * Check if mmap/mmaphuge has a :/foo/bar/file at the end. If so, return that.
34  */
35 static char *get_opt_postfix(const char *str)
36 {
37         char *p = strstr(str, ":");
38
39         if (!p)
40                 return NULL;
41
42         p++;
43         strip_blank_front(&p);
44         strip_blank_end(p);
45         return strdup(p);
46 }
47
48 static int bs_cmp(const void *p1, const void *p2)
49 {
50         const struct bssplit *bsp1 = p1;
51         const struct bssplit *bsp2 = p2;
52
53         return bsp1->perc < bsp2->perc;
54 }
55
56 static int bssplit_ddir(struct thread_options *o, int ddir, char *str)
57 {
58         struct bssplit *bssplit;
59         unsigned int i, perc, perc_missing;
60         unsigned int max_bs, min_bs;
61         long long val;
62         char *fname;
63
64         o->bssplit_nr[ddir] = 4;
65         bssplit = malloc(4 * sizeof(struct bssplit));
66
67         i = 0;
68         max_bs = 0;
69         min_bs = -1;
70         while ((fname = strsep(&str, ":")) != NULL) {
71                 char *perc_str;
72
73                 if (!strlen(fname))
74                         break;
75
76                 /*
77                  * grow struct buffer, if needed
78                  */
79                 if (i == o->bssplit_nr[ddir]) {
80                         o->bssplit_nr[ddir] <<= 1;
81                         bssplit = realloc(bssplit, o->bssplit_nr[ddir]
82                                                   * sizeof(struct bssplit));
83                 }
84
85                 perc_str = strstr(fname, "/");
86                 if (perc_str) {
87                         *perc_str = '\0';
88                         perc_str++;
89                         perc = atoi(perc_str);
90                         if (perc > 100)
91                                 perc = 100;
92                         else if (!perc)
93                                 perc = -1U;
94                 } else
95                         perc = -1U;
96
97                 if (str_to_decimal(fname, &val, 1, o, 0, 0)) {
98                         log_err("fio: bssplit conversion failed\n");
99                         free(bssplit);
100                         return 1;
101                 }
102
103                 if (val > max_bs)
104                         max_bs = val;
105                 if (val < min_bs)
106                         min_bs = val;
107
108                 bssplit[i].bs = val;
109                 bssplit[i].perc = perc;
110                 i++;
111         }
112
113         o->bssplit_nr[ddir] = i;
114
115         /*
116          * Now check if the percentages add up, and how much is missing
117          */
118         perc = perc_missing = 0;
119         for (i = 0; i < o->bssplit_nr[ddir]; i++) {
120                 struct bssplit *bsp = &bssplit[i];
121
122                 if (bsp->perc == -1U)
123                         perc_missing++;
124                 else
125                         perc += bsp->perc;
126         }
127
128         if (perc > 100 && perc_missing > 1) {
129                 log_err("fio: bssplit percentages add to more than 100%%\n");
130                 free(bssplit);
131                 return 1;
132         }
133
134         /*
135          * If values didn't have a percentage set, divide the remains between
136          * them.
137          */
138         if (perc_missing) {
139                 if (perc_missing == 1 && o->bssplit_nr[ddir] == 1)
140                         perc = 100;
141                 for (i = 0; i < o->bssplit_nr[ddir]; i++) {
142                         struct bssplit *bsp = &bssplit[i];
143
144                         if (bsp->perc == -1U)
145                                 bsp->perc = (100 - perc) / perc_missing;
146                 }
147         }
148
149         o->min_bs[ddir] = min_bs;
150         o->max_bs[ddir] = max_bs;
151
152         /*
153          * now sort based on percentages, for ease of lookup
154          */
155         qsort(bssplit, o->bssplit_nr[ddir], sizeof(struct bssplit), bs_cmp);
156         o->bssplit[ddir] = bssplit;
157         return 0;
158 }
159
160 static int str_bssplit_cb(void *data, const char *input)
161 {
162         struct thread_data *td = data;
163         char *str, *p, *odir, *ddir;
164         int ret = 0;
165
166         if (parse_dryrun())
167                 return 0;
168
169         p = str = strdup(input);
170
171         strip_blank_front(&str);
172         strip_blank_end(str);
173
174         odir = strchr(str, ',');
175         if (odir) {
176                 ddir = strchr(odir + 1, ',');
177                 if (ddir) {
178                         ret = bssplit_ddir(&td->o, DDIR_TRIM, ddir + 1);
179                         if (!ret)
180                                 *ddir = '\0';
181                 } else {
182                         char *op;
183
184                         op = strdup(odir + 1);
185                         ret = bssplit_ddir(&td->o, DDIR_TRIM, op);
186
187                         free(op);
188                 }
189                 if (!ret)
190                         ret = bssplit_ddir(&td->o, DDIR_WRITE, odir + 1);
191                 if (!ret) {
192                         *odir = '\0';
193                         ret = bssplit_ddir(&td->o, DDIR_READ, str);
194                 }
195         } else {
196                 char *op;
197
198                 op = strdup(str);
199                 ret = bssplit_ddir(&td->o, DDIR_WRITE, op);
200                 free(op);
201
202                 if (!ret) {
203                         op = strdup(str);
204                         ret = bssplit_ddir(&td->o, DDIR_TRIM, op);
205                         free(op);
206                 }
207                 if (!ret)
208                         ret = bssplit_ddir(&td->o, DDIR_READ, str);
209         }
210
211         free(p);
212         return ret;
213 }
214
215 static int str2error(char *str)
216 {
217         const char *err[] = { "EPERM", "ENOENT", "ESRCH", "EINTR", "EIO",
218                             "ENXIO", "E2BIG", "ENOEXEC", "EBADF",
219                             "ECHILD", "EAGAIN", "ENOMEM", "EACCES",
220                             "EFAULT", "ENOTBLK", "EBUSY", "EEXIST",
221                             "EXDEV", "ENODEV", "ENOTDIR", "EISDIR",
222                             "EINVAL", "ENFILE", "EMFILE", "ENOTTY",
223                             "ETXTBSY","EFBIG", "ENOSPC", "ESPIPE",
224                             "EROFS","EMLINK", "EPIPE", "EDOM", "ERANGE" };
225         int i = 0, num = sizeof(err) / sizeof(void *);
226
227         while (i < num) {
228                 if (!strcmp(err[i], str))
229                         return i + 1;
230                 i++;
231         }
232         return 0;
233 }
234
235 static int ignore_error_type(struct thread_data *td, int etype, char *str)
236 {
237         unsigned int i;
238         int *error;
239         char *fname;
240
241         if (etype >= ERROR_TYPE_CNT) {
242                 log_err("Illegal error type\n");
243                 return 1;
244         }
245
246         td->o.ignore_error_nr[etype] = 4;
247         error = malloc(4 * sizeof(struct bssplit));
248
249         i = 0;
250         while ((fname = strsep(&str, ":")) != NULL) {
251
252                 if (!strlen(fname))
253                         break;
254
255                 /*
256                  * grow struct buffer, if needed
257                  */
258                 if (i == td->o.ignore_error_nr[etype]) {
259                         td->o.ignore_error_nr[etype] <<= 1;
260                         error = realloc(error, td->o.ignore_error_nr[etype]
261                                                   * sizeof(int));
262                 }
263                 if (fname[0] == 'E') {
264                         error[i] = str2error(fname);
265                 } else {
266                         error[i] = atoi(fname);
267                         if (error[i] < 0)
268                                 error[i] = -error[i];
269                 }
270                 if (!error[i]) {
271                         log_err("Unknown error %s, please use number value \n",
272                                   fname);
273                         free(error);
274                         return 1;
275                 }
276                 i++;
277         }
278         if (i) {
279                 td->o.continue_on_error |= 1 << etype;
280                 td->o.ignore_error_nr[etype] = i;
281                 td->o.ignore_error[etype] = error;
282         } else
283                 free(error);
284
285         return 0;
286
287 }
288
289 static int str_ignore_error_cb(void *data, const char *input)
290 {
291         struct thread_data *td = data;
292         char *str, *p, *n;
293         int type = 0, ret = 1;
294
295         if (parse_dryrun())
296                 return 0;
297
298         p = str = strdup(input);
299
300         strip_blank_front(&str);
301         strip_blank_end(str);
302
303         while (p) {
304                 n = strchr(p, ',');
305                 if (n)
306                         *n++ = '\0';
307                 ret = ignore_error_type(td, type, p);
308                 if (ret)
309                         break;
310                 p = n;
311                 type++;
312         }
313         free(str);
314         return ret;
315 }
316
317 static int str_rw_cb(void *data, const char *str)
318 {
319         struct thread_data *td = data;
320         struct thread_options *o = &td->o;
321         char *nr;
322
323         if (parse_dryrun())
324                 return 0;
325
326         o->ddir_seq_nr = 1;
327         o->ddir_seq_add = 0;
328
329         nr = get_opt_postfix(str);
330         if (!nr)
331                 return 0;
332
333         if (td_random(td))
334                 o->ddir_seq_nr = atoi(nr);
335         else {
336                 long long val;
337
338                 if (str_to_decimal(nr, &val, 1, o, 0, 0)) {
339                         log_err("fio: rw postfix parsing failed\n");
340                         free(nr);
341                         return 1;
342                 }
343
344                 o->ddir_seq_add = val;
345         }
346
347         free(nr);
348         return 0;
349 }
350
351 static int str_mem_cb(void *data, const char *mem)
352 {
353         struct thread_data *td = data;
354
355         if (td->o.mem_type == MEM_MMAPHUGE || td->o.mem_type == MEM_MMAP ||
356             td->o.mem_type == MEM_MMAPSHARED)
357                 td->o.mmapfile = get_opt_postfix(mem);
358
359         return 0;
360 }
361
362 static int fio_clock_source_cb(void *data, const char *str)
363 {
364         struct thread_data *td = data;
365
366         fio_clock_source = td->o.clocksource;
367         fio_clock_source_set = 1;
368         fio_clock_init();
369         return 0;
370 }
371
372 static int str_rwmix_read_cb(void *data, unsigned long long *val)
373 {
374         struct thread_data *td = data;
375
376         td->o.rwmix[DDIR_READ] = *val;
377         td->o.rwmix[DDIR_WRITE] = 100 - *val;
378         return 0;
379 }
380
381 static int str_rwmix_write_cb(void *data, unsigned long long *val)
382 {
383         struct thread_data *td = data;
384
385         td->o.rwmix[DDIR_WRITE] = *val;
386         td->o.rwmix[DDIR_READ] = 100 - *val;
387         return 0;
388 }
389
390 static int str_exitall_cb(void)
391 {
392         exitall_on_terminate = 1;
393         return 0;
394 }
395
396 #ifdef FIO_HAVE_CPU_AFFINITY
397 int fio_cpus_split(os_cpu_mask_t *mask, unsigned int cpu_index)
398 {
399         unsigned int i, index, cpus_in_mask;
400         const long max_cpu = cpus_online();
401
402         cpus_in_mask = fio_cpu_count(mask);
403         cpu_index = cpu_index % cpus_in_mask;
404
405         index = 0;
406         for (i = 0; i < max_cpu; i++) {
407                 if (!fio_cpu_isset(mask, i))
408                         continue;
409
410                 if (cpu_index != index)
411                         fio_cpu_clear(mask, i);
412
413                 index++;
414         }
415
416         return fio_cpu_count(mask);
417 }
418
419 static int str_cpumask_cb(void *data, unsigned long long *val)
420 {
421         struct thread_data *td = data;
422         unsigned int i;
423         long max_cpu;
424         int ret;
425
426         if (parse_dryrun())
427                 return 0;
428
429         ret = fio_cpuset_init(&td->o.cpumask);
430         if (ret < 0) {
431                 log_err("fio: cpuset_init failed\n");
432                 td_verror(td, ret, "fio_cpuset_init");
433                 return 1;
434         }
435
436         max_cpu = cpus_online();
437
438         for (i = 0; i < sizeof(int) * 8; i++) {
439                 if ((1 << i) & *val) {
440                         if (i >= max_cpu) {
441                                 log_err("fio: CPU %d too large (max=%ld)\n", i,
442                                                                 max_cpu - 1);
443                                 return 1;
444                         }
445                         dprint(FD_PARSE, "set cpu allowed %d\n", i);
446                         fio_cpu_set(&td->o.cpumask, i);
447                 }
448         }
449
450         return 0;
451 }
452
453 static int set_cpus_allowed(struct thread_data *td, os_cpu_mask_t *mask,
454                             const char *input)
455 {
456         char *cpu, *str, *p;
457         long max_cpu;
458         int ret = 0;
459
460         ret = fio_cpuset_init(mask);
461         if (ret < 0) {
462                 log_err("fio: cpuset_init failed\n");
463                 td_verror(td, ret, "fio_cpuset_init");
464                 return 1;
465         }
466
467         p = str = strdup(input);
468
469         strip_blank_front(&str);
470         strip_blank_end(str);
471
472         max_cpu = cpus_online();
473
474         while ((cpu = strsep(&str, ",")) != NULL) {
475                 char *str2, *cpu2;
476                 int icpu, icpu2;
477
478                 if (!strlen(cpu))
479                         break;
480
481                 str2 = cpu;
482                 icpu2 = -1;
483                 while ((cpu2 = strsep(&str2, "-")) != NULL) {
484                         if (!strlen(cpu2))
485                                 break;
486
487                         icpu2 = atoi(cpu2);
488                 }
489
490                 icpu = atoi(cpu);
491                 if (icpu2 == -1)
492                         icpu2 = icpu;
493                 while (icpu <= icpu2) {
494                         if (icpu >= FIO_MAX_CPUS) {
495                                 log_err("fio: your OS only supports up to"
496                                         " %d CPUs\n", (int) FIO_MAX_CPUS);
497                                 ret = 1;
498                                 break;
499                         }
500                         if (icpu >= max_cpu) {
501                                 log_err("fio: CPU %d too large (max=%ld)\n",
502                                                         icpu, max_cpu - 1);
503                                 ret = 1;
504                                 break;
505                         }
506
507                         dprint(FD_PARSE, "set cpu allowed %d\n", icpu);
508                         fio_cpu_set(mask, icpu);
509                         icpu++;
510                 }
511                 if (ret)
512                         break;
513         }
514
515         free(p);
516         return ret;
517 }
518
519 static int str_cpus_allowed_cb(void *data, const char *input)
520 {
521         struct thread_data *td = data;
522
523         if (parse_dryrun())
524                 return 0;
525
526         return set_cpus_allowed(td, &td->o.cpumask, input);
527 }
528
529 static int str_verify_cpus_allowed_cb(void *data, const char *input)
530 {
531         struct thread_data *td = data;
532
533         if (parse_dryrun())
534                 return 0;
535
536         return set_cpus_allowed(td, &td->o.verify_cpumask, input);
537 }
538 #endif
539
540 #ifdef CONFIG_LIBNUMA
541 static int str_numa_cpunodes_cb(void *data, char *input)
542 {
543         struct thread_data *td = data;
544         struct bitmask *verify_bitmask;
545
546         if (parse_dryrun())
547                 return 0;
548
549         /* numa_parse_nodestring() parses a character string list
550          * of nodes into a bit mask. The bit mask is allocated by
551          * numa_allocate_nodemask(), so it should be freed by
552          * numa_free_nodemask().
553          */
554         verify_bitmask = numa_parse_nodestring(input);
555         if (verify_bitmask == NULL) {
556                 log_err("fio: numa_parse_nodestring failed\n");
557                 td_verror(td, 1, "str_numa_cpunodes_cb");
558                 return 1;
559         }
560         numa_free_nodemask(verify_bitmask);
561
562         td->o.numa_cpunodes = strdup(input);
563         return 0;
564 }
565
566 static int str_numa_mpol_cb(void *data, char *input)
567 {
568         struct thread_data *td = data;
569         const char * const policy_types[] =
570                 { "default", "prefer", "bind", "interleave", "local", NULL };
571         int i;
572         char *nodelist;
573         struct bitmask *verify_bitmask;
574
575         if (parse_dryrun())
576                 return 0;
577
578         nodelist = strchr(input, ':');
579         if (nodelist) {
580                 /* NUL-terminate mode */
581                 *nodelist++ = '\0';
582         }
583
584         for (i = 0; i <= MPOL_LOCAL; i++) {
585                 if (!strcmp(input, policy_types[i])) {
586                         td->o.numa_mem_mode = i;
587                         break;
588                 }
589         }
590         if (i > MPOL_LOCAL) {
591                 log_err("fio: memory policy should be: default, prefer, bind, interleave, local\n");
592                 goto out;
593         }
594
595         switch (td->o.numa_mem_mode) {
596         case MPOL_PREFERRED:
597                 /*
598                  * Insist on a nodelist of one node only
599                  */
600                 if (nodelist) {
601                         char *rest = nodelist;
602                         while (isdigit(*rest))
603                                 rest++;
604                         if (*rest) {
605                                 log_err("fio: one node only for \'prefer\'\n");
606                                 goto out;
607                         }
608                 } else {
609                         log_err("fio: one node is needed for \'prefer\'\n");
610                         goto out;
611                 }
612                 break;
613         case MPOL_INTERLEAVE:
614                 /*
615                  * Default to online nodes with memory if no nodelist
616                  */
617                 if (!nodelist)
618                         nodelist = strdup("all");
619                 break;
620         case MPOL_LOCAL:
621         case MPOL_DEFAULT:
622                 /*
623                  * Don't allow a nodelist
624                  */
625                 if (nodelist) {
626                         log_err("fio: NO nodelist for \'local\'\n");
627                         goto out;
628                 }
629                 break;
630         case MPOL_BIND:
631                 /*
632                  * Insist on a nodelist
633                  */
634                 if (!nodelist) {
635                         log_err("fio: a nodelist is needed for \'bind\'\n");
636                         goto out;
637                 }
638                 break;
639         }
640
641
642         /* numa_parse_nodestring() parses a character string list
643          * of nodes into a bit mask. The bit mask is allocated by
644          * numa_allocate_nodemask(), so it should be freed by
645          * numa_free_nodemask().
646          */
647         switch (td->o.numa_mem_mode) {
648         case MPOL_PREFERRED:
649                 td->o.numa_mem_prefer_node = atoi(nodelist);
650                 break;
651         case MPOL_INTERLEAVE:
652         case MPOL_BIND:
653                 verify_bitmask = numa_parse_nodestring(nodelist);
654                 if (verify_bitmask == NULL) {
655                         log_err("fio: numa_parse_nodestring failed\n");
656                         td_verror(td, 1, "str_numa_memnodes_cb");
657                         return 1;
658                 }
659                 td->o.numa_memnodes = strdup(nodelist);
660                 numa_free_nodemask(verify_bitmask);
661
662                 break;
663         case MPOL_LOCAL:
664         case MPOL_DEFAULT:
665         default:
666                 break;
667         }
668
669         return 0;
670 out:
671         return 1;
672 }
673 #endif
674
675 static int str_fst_cb(void *data, const char *str)
676 {
677         struct thread_data *td = data;
678         char *nr = get_opt_postfix(str);
679
680         td->file_service_nr = 1;
681         if (nr) {
682                 td->file_service_nr = atoi(nr);
683                 free(nr);
684         }
685
686         return 0;
687 }
688
689 #ifdef CONFIG_SYNC_FILE_RANGE
690 static int str_sfr_cb(void *data, const char *str)
691 {
692         struct thread_data *td = data;
693         char *nr = get_opt_postfix(str);
694
695         td->sync_file_range_nr = 1;
696         if (nr) {
697                 td->sync_file_range_nr = atoi(nr);
698                 free(nr);
699         }
700
701         return 0;
702 }
703 #endif
704
705 static int str_random_distribution_cb(void *data, const char *str)
706 {
707         struct thread_data *td = data;
708         double val;
709         char *nr;
710
711         if (parse_dryrun())
712                 return 0;
713
714         if (td->o.random_distribution == FIO_RAND_DIST_ZIPF)
715                 val = FIO_DEF_ZIPF;
716         else if (td->o.random_distribution == FIO_RAND_DIST_PARETO)
717                 val = FIO_DEF_PARETO;
718         else if (td->o.random_distribution == FIO_RAND_DIST_GAUSS)
719                 val = 0.0;
720         else
721                 return 0;
722
723         nr = get_opt_postfix(str);
724         if (nr && !str_to_float(nr, &val, 0)) {
725                 log_err("fio: random postfix parsing failed\n");
726                 free(nr);
727                 return 1;
728         }
729
730         free(nr);
731
732         if (td->o.random_distribution == FIO_RAND_DIST_ZIPF) {
733                 if (val == 1.00) {
734                         log_err("fio: zipf theta must different than 1.0\n");
735                         return 1;
736                 }
737                 td->o.zipf_theta.u.f = val;
738         } else if (td->o.random_distribution == FIO_RAND_DIST_PARETO) {
739                 if (val <= 0.00 || val >= 1.00) {
740                         log_err("fio: pareto input out of range (0 < input < 1.0)\n");
741                         return 1;
742                 }
743                 td->o.pareto_h.u.f = val;
744         } else {
745                 if (val <= 0.00 || val >= 100.0) {
746                         log_err("fio: normal deviation out of range (0 < input < 100.0)\n");
747                         return 1;
748                 }
749                 td->o.gauss_dev.u.f = val;
750         }
751
752         return 0;
753 }
754
755 /*
756  * Return next name in the string. Files are separated with ':'. If the ':'
757  * is escaped with a '\', then that ':' is part of the filename and does not
758  * indicate a new file.
759  */
760 static char *get_next_name(char **ptr)
761 {
762         char *str = *ptr;
763         char *p, *start;
764
765         if (!str || !strlen(str))
766                 return NULL;
767
768         start = str;
769         do {
770                 /*
771                  * No colon, we are done
772                  */
773                 p = strchr(str, ':');
774                 if (!p) {
775                         *ptr = NULL;
776                         break;
777                 }
778
779                 /*
780                  * We got a colon, but it's the first character. Skip and
781                  * continue
782                  */
783                 if (p == start) {
784                         str = ++start;
785                         continue;
786                 }
787
788                 if (*(p - 1) != '\\') {
789                         *p = '\0';
790                         *ptr = p + 1;
791                         break;
792                 }
793
794                 memmove(p - 1, p, strlen(p) + 1);
795                 str = p;
796         } while (1);
797
798         return start;
799 }
800
801
802 static int get_max_name_idx(char *input)
803 {
804         unsigned int cur_idx;
805         char *str, *p;
806
807         p = str = strdup(input);
808         for (cur_idx = 0; ; cur_idx++)
809                 if (get_next_name(&str) == NULL)
810                         break;
811
812         free(p);
813         return cur_idx;
814 }
815
816 /*
817  * Returns the directory at the index, indexes > entires will be
818  * assigned via modulo division of the index
819  */
820 int set_name_idx(char *target, size_t tlen, char *input, int index)
821 {
822         unsigned int cur_idx;
823         int len;
824         char *fname, *str, *p;
825
826         p = str = strdup(input);
827
828         index %= get_max_name_idx(input);
829         for (cur_idx = 0; cur_idx <= index; cur_idx++)
830                 fname = get_next_name(&str);
831
832         if (client_sockaddr_str[0]) {
833                 len = snprintf(target, tlen, "%s/%s.", fname,
834                                 client_sockaddr_str);
835         } else
836                 len = snprintf(target, tlen, "%s/", fname);
837
838         target[tlen - 1] = '\0';
839         free(p);
840
841         return len;
842 }
843
844 static int str_filename_cb(void *data, const char *input)
845 {
846         struct thread_data *td = data;
847         char *fname, *str, *p;
848
849         p = str = strdup(input);
850
851         strip_blank_front(&str);
852         strip_blank_end(str);
853
854         if (!td->files_index)
855                 td->o.nr_files = 0;
856
857         while ((fname = get_next_name(&str)) != NULL) {
858                 if (!strlen(fname))
859                         break;
860                 add_file(td, fname, 0, 1);
861         }
862
863         free(p);
864         return 0;
865 }
866
867 static int str_directory_cb(void *data, const char fio_unused *unused)
868 {
869         struct thread_data *td = data;
870         struct stat sb;
871         char *dirname, *str, *p;
872         int ret = 0;
873
874         if (parse_dryrun())
875                 return 0;
876
877         p = str = strdup(td->o.directory);
878         while ((dirname = get_next_name(&str)) != NULL) {
879                 if (lstat(dirname, &sb) < 0) {
880                         ret = errno;
881
882                         log_err("fio: %s is not a directory\n", dirname);
883                         td_verror(td, ret, "lstat");
884                         goto out;
885                 }
886                 if (!S_ISDIR(sb.st_mode)) {
887                         log_err("fio: %s is not a directory\n", dirname);
888                         ret = 1;
889                         goto out;
890                 }
891         }
892
893 out:
894         free(p);
895         return ret;
896 }
897
898 static int str_opendir_cb(void *data, const char fio_unused *str)
899 {
900         struct thread_data *td = data;
901
902         if (parse_dryrun())
903                 return 0;
904
905         if (!td->files_index)
906                 td->o.nr_files = 0;
907
908         return add_dir_files(td, td->o.opendir);
909 }
910
911 static int str_buffer_pattern_cb(void *data, const char *input)
912 {
913         struct thread_data *td = data;
914         int ret;
915
916         /* FIXME: for now buffer pattern does not support formats */
917         ret = parse_and_fill_pattern(input, strlen(input), td->o.buffer_pattern,
918                                      MAX_PATTERN_SIZE, NULL, 0, NULL, NULL);
919         if (ret < 0)
920                 return 1;
921
922         assert(ret != 0);
923         td->o.buffer_pattern_bytes = ret;
924         if (!td->o.compress_percentage)
925                 td->o.refill_buffers = 0;
926         td->o.scramble_buffers = 0;
927         td->o.zero_buffers = 0;
928
929         return 0;
930 }
931
932 static int str_buffer_compress_cb(void *data, unsigned long long *il)
933 {
934         struct thread_data *td = data;
935
936         td->flags |= TD_F_COMPRESS;
937         td->o.compress_percentage = *il;
938         return 0;
939 }
940
941 static int str_dedupe_cb(void *data, unsigned long long *il)
942 {
943         struct thread_data *td = data;
944
945         td->flags |= TD_F_COMPRESS;
946         td->o.dedupe_percentage = *il;
947         td->o.refill_buffers = 1;
948         return 0;
949 }
950
951 static int str_verify_pattern_cb(void *data, const char *input)
952 {
953         struct thread_data *td = data;
954         int ret;
955
956         td->o.verify_fmt_sz = ARRAY_SIZE(td->o.verify_fmt);
957         ret = parse_and_fill_pattern(input, strlen(input), td->o.verify_pattern,
958                                      MAX_PATTERN_SIZE, fmt_desc, sizeof(fmt_desc),
959                                      td->o.verify_fmt, &td->o.verify_fmt_sz);
960         if (ret < 0)
961                 return 1;
962
963         assert(ret != 0);
964         td->o.verify_pattern_bytes = ret;
965         /*
966          * VERIFY_* could already be set
967          */
968         if (!fio_option_is_set(&td->o, verify))
969                 td->o.verify = VERIFY_PATTERN;
970
971         return 0;
972 }
973
974 static int str_gtod_reduce_cb(void *data, int *il)
975 {
976         struct thread_data *td = data;
977         int val = *il;
978
979         td->o.disable_lat = !!val;
980         td->o.disable_clat = !!val;
981         td->o.disable_slat = !!val;
982         td->o.disable_bw = !!val;
983         td->o.clat_percentiles = !val;
984         if (val)
985                 td->tv_cache_mask = 63;
986
987         return 0;
988 }
989
990 static int str_size_cb(void *data, unsigned long long *__val)
991 {
992         struct thread_data *td = data;
993         unsigned long long v = *__val;
994
995         if (parse_is_percent(v)) {
996                 td->o.size = 0;
997                 td->o.size_percent = -1ULL - v;
998         } else
999                 td->o.size = v;
1000
1001         return 0;
1002 }
1003
1004 static int rw_verify(struct fio_option *o, void *data)
1005 {
1006         struct thread_data *td = data;
1007
1008         if (read_only && td_write(td)) {
1009                 log_err("fio: job <%s> has write bit set, but fio is in"
1010                         " read-only mode\n", td->o.name);
1011                 return 1;
1012         }
1013
1014         return 0;
1015 }
1016
1017 static int gtod_cpu_verify(struct fio_option *o, void *data)
1018 {
1019 #ifndef FIO_HAVE_CPU_AFFINITY
1020         struct thread_data *td = data;
1021
1022         if (td->o.gtod_cpu) {
1023                 log_err("fio: platform must support CPU affinity for"
1024                         "gettimeofday() offloading\n");
1025                 return 1;
1026         }
1027 #endif
1028
1029         return 0;
1030 }
1031
1032 /*
1033  * Option grouping
1034  */
1035 static struct opt_group fio_opt_groups[] = {
1036         {
1037                 .name   = "General",
1038                 .mask   = FIO_OPT_C_GENERAL,
1039         },
1040         {
1041                 .name   = "I/O",
1042                 .mask   = FIO_OPT_C_IO,
1043         },
1044         {
1045                 .name   = "File",
1046                 .mask   = FIO_OPT_C_FILE,
1047         },
1048         {
1049                 .name   = "Statistics",
1050                 .mask   = FIO_OPT_C_STAT,
1051         },
1052         {
1053                 .name   = "Logging",
1054                 .mask   = FIO_OPT_C_LOG,
1055         },
1056         {
1057                 .name   = "Profiles",
1058                 .mask   = FIO_OPT_C_PROFILE,
1059         },
1060         {
1061                 .name   = NULL,
1062         },
1063 };
1064
1065 static struct opt_group *__opt_group_from_mask(struct opt_group *ogs, unsigned int *mask,
1066                                                unsigned int inv_mask)
1067 {
1068         struct opt_group *og;
1069         int i;
1070
1071         if (*mask == inv_mask || !*mask)
1072                 return NULL;
1073
1074         for (i = 0; ogs[i].name; i++) {
1075                 og = &ogs[i];
1076
1077                 if (*mask & og->mask) {
1078                         *mask &= ~(og->mask);
1079                         return og;
1080                 }
1081         }
1082
1083         return NULL;
1084 }
1085
1086 struct opt_group *opt_group_from_mask(unsigned int *mask)
1087 {
1088         return __opt_group_from_mask(fio_opt_groups, mask, FIO_OPT_C_INVALID);
1089 }
1090
1091 static struct opt_group fio_opt_cat_groups[] = {
1092         {
1093                 .name   = "Latency profiling",
1094                 .mask   = FIO_OPT_G_LATPROF,
1095         },
1096         {
1097                 .name   = "Rate",
1098                 .mask   = FIO_OPT_G_RATE,
1099         },
1100         {
1101                 .name   = "Zone",
1102                 .mask   = FIO_OPT_G_ZONE,
1103         },
1104         {
1105                 .name   = "Read/write mix",
1106                 .mask   = FIO_OPT_G_RWMIX,
1107         },
1108         {
1109                 .name   = "Verify",
1110                 .mask   = FIO_OPT_G_VERIFY,
1111         },
1112         {
1113                 .name   = "Trim",
1114                 .mask   = FIO_OPT_G_TRIM,
1115         },
1116         {
1117                 .name   = "I/O Logging",
1118                 .mask   = FIO_OPT_G_IOLOG,
1119         },
1120         {
1121                 .name   = "I/O Depth",
1122                 .mask   = FIO_OPT_G_IO_DEPTH,
1123         },
1124         {
1125                 .name   = "I/O Flow",
1126                 .mask   = FIO_OPT_G_IO_FLOW,
1127         },
1128         {
1129                 .name   = "Description",
1130                 .mask   = FIO_OPT_G_DESC,
1131         },
1132         {
1133                 .name   = "Filename",
1134                 .mask   = FIO_OPT_G_FILENAME,
1135         },
1136         {
1137                 .name   = "General I/O",
1138                 .mask   = FIO_OPT_G_IO_BASIC,
1139         },
1140         {
1141                 .name   = "Cgroups",
1142                 .mask   = FIO_OPT_G_CGROUP,
1143         },
1144         {
1145                 .name   = "Runtime",
1146                 .mask   = FIO_OPT_G_RUNTIME,
1147         },
1148         {
1149                 .name   = "Process",
1150                 .mask   = FIO_OPT_G_PROCESS,
1151         },
1152         {
1153                 .name   = "Job credentials / priority",
1154                 .mask   = FIO_OPT_G_CRED,
1155         },
1156         {
1157                 .name   = "Clock settings",
1158                 .mask   = FIO_OPT_G_CLOCK,
1159         },
1160         {
1161                 .name   = "I/O Type",
1162                 .mask   = FIO_OPT_G_IO_TYPE,
1163         },
1164         {
1165                 .name   = "I/O Thinktime",
1166                 .mask   = FIO_OPT_G_THINKTIME,
1167         },
1168         {
1169                 .name   = "Randomizations",
1170                 .mask   = FIO_OPT_G_RANDOM,
1171         },
1172         {
1173                 .name   = "I/O buffers",
1174                 .mask   = FIO_OPT_G_IO_BUF,
1175         },
1176         {
1177                 .name   = "Tiobench profile",
1178                 .mask   = FIO_OPT_G_TIOBENCH,
1179         },
1180         {
1181                 .name   = "MTD",
1182                 .mask   = FIO_OPT_G_MTD,
1183         },
1184
1185         {
1186                 .name   = NULL,
1187         }
1188 };
1189
1190 struct opt_group *opt_group_cat_from_mask(unsigned int *mask)
1191 {
1192         return __opt_group_from_mask(fio_opt_cat_groups, mask, FIO_OPT_G_INVALID);
1193 }
1194
1195 /*
1196  * Map of job/command line options
1197  */
1198 struct fio_option fio_options[FIO_MAX_OPTS] = {
1199         {
1200                 .name   = "description",
1201                 .lname  = "Description of job",
1202                 .type   = FIO_OPT_STR_STORE,
1203                 .off1   = td_var_offset(description),
1204                 .help   = "Text job description",
1205                 .category = FIO_OPT_C_GENERAL,
1206                 .group  = FIO_OPT_G_DESC,
1207         },
1208         {
1209                 .name   = "name",
1210                 .lname  = "Job name",
1211                 .type   = FIO_OPT_STR_STORE,
1212                 .off1   = td_var_offset(name),
1213                 .help   = "Name of this job",
1214                 .category = FIO_OPT_C_GENERAL,
1215                 .group  = FIO_OPT_G_DESC,
1216         },
1217         {
1218                 .name   = "filename",
1219                 .lname  = "Filename(s)",
1220                 .type   = FIO_OPT_STR_STORE,
1221                 .off1   = td_var_offset(filename),
1222                 .cb     = str_filename_cb,
1223                 .prio   = -1, /* must come after "directory" */
1224                 .help   = "File(s) to use for the workload",
1225                 .category = FIO_OPT_C_FILE,
1226                 .group  = FIO_OPT_G_FILENAME,
1227         },
1228         {
1229                 .name   = "directory",
1230                 .lname  = "Directory",
1231                 .type   = FIO_OPT_STR_STORE,
1232                 .off1   = td_var_offset(directory),
1233                 .cb     = str_directory_cb,
1234                 .help   = "Directory to store files in",
1235                 .category = FIO_OPT_C_FILE,
1236                 .group  = FIO_OPT_G_FILENAME,
1237         },
1238         {
1239                 .name   = "filename_format",
1240                 .type   = FIO_OPT_STR_STORE,
1241                 .off1   = td_var_offset(filename_format),
1242                 .prio   = -1, /* must come after "directory" */
1243                 .help   = "Override default $jobname.$jobnum.$filenum naming",
1244                 .def    = "$jobname.$jobnum.$filenum",
1245                 .category = FIO_OPT_C_FILE,
1246                 .group  = FIO_OPT_G_FILENAME,
1247         },
1248         {
1249                 .name   = "lockfile",
1250                 .lname  = "Lockfile",
1251                 .type   = FIO_OPT_STR,
1252                 .off1   = td_var_offset(file_lock_mode),
1253                 .help   = "Lock file when doing IO to it",
1254                 .prio   = 1,
1255                 .parent = "filename",
1256                 .hide   = 0,
1257                 .def    = "none",
1258                 .category = FIO_OPT_C_FILE,
1259                 .group  = FIO_OPT_G_FILENAME,
1260                 .posval = {
1261                           { .ival = "none",
1262                             .oval = FILE_LOCK_NONE,
1263                             .help = "No file locking",
1264                           },
1265                           { .ival = "exclusive",
1266                             .oval = FILE_LOCK_EXCLUSIVE,
1267                             .help = "Exclusive file lock",
1268                           },
1269                           {
1270                             .ival = "readwrite",
1271                             .oval = FILE_LOCK_READWRITE,
1272                             .help = "Read vs write lock",
1273                           },
1274                 },
1275         },
1276         {
1277                 .name   = "opendir",
1278                 .lname  = "Open directory",
1279                 .type   = FIO_OPT_STR_STORE,
1280                 .off1   = td_var_offset(opendir),
1281                 .cb     = str_opendir_cb,
1282                 .help   = "Recursively add files from this directory and down",
1283                 .category = FIO_OPT_C_FILE,
1284                 .group  = FIO_OPT_G_FILENAME,
1285         },
1286         {
1287                 .name   = "rw",
1288                 .lname  = "Read/write",
1289                 .alias  = "readwrite",
1290                 .type   = FIO_OPT_STR,
1291                 .cb     = str_rw_cb,
1292                 .off1   = td_var_offset(td_ddir),
1293                 .help   = "IO direction",
1294                 .def    = "read",
1295                 .verify = rw_verify,
1296                 .category = FIO_OPT_C_IO,
1297                 .group  = FIO_OPT_G_IO_BASIC,
1298                 .posval = {
1299                           { .ival = "read",
1300                             .oval = TD_DDIR_READ,
1301                             .help = "Sequential read",
1302                           },
1303                           { .ival = "write",
1304                             .oval = TD_DDIR_WRITE,
1305                             .help = "Sequential write",
1306                           },
1307                           { .ival = "trim",
1308                             .oval = TD_DDIR_TRIM,
1309                             .help = "Sequential trim",
1310                           },
1311                           { .ival = "randread",
1312                             .oval = TD_DDIR_RANDREAD,
1313                             .help = "Random read",
1314                           },
1315                           { .ival = "randwrite",
1316                             .oval = TD_DDIR_RANDWRITE,
1317                             .help = "Random write",
1318                           },
1319                           { .ival = "randtrim",
1320                             .oval = TD_DDIR_RANDTRIM,
1321                             .help = "Random trim",
1322                           },
1323                           { .ival = "rw",
1324                             .oval = TD_DDIR_RW,
1325                             .help = "Sequential read and write mix",
1326                           },
1327                           { .ival = "readwrite",
1328                             .oval = TD_DDIR_RW,
1329                             .help = "Sequential read and write mix",
1330                           },
1331                           { .ival = "randrw",
1332                             .oval = TD_DDIR_RANDRW,
1333                             .help = "Random read and write mix"
1334                           },
1335                           { .ival = "trimwrite",
1336                             .oval = TD_DDIR_TRIMWRITE,
1337                             .help = "Trim and write mix, trims preceding writes"
1338                           },
1339                 },
1340         },
1341         {
1342                 .name   = "rw_sequencer",
1343                 .lname  = "RW Sequencer",
1344                 .type   = FIO_OPT_STR,
1345                 .off1   = td_var_offset(rw_seq),
1346                 .help   = "IO offset generator modifier",
1347                 .def    = "sequential",
1348                 .category = FIO_OPT_C_IO,
1349                 .group  = FIO_OPT_G_IO_BASIC,
1350                 .posval = {
1351                           { .ival = "sequential",
1352                             .oval = RW_SEQ_SEQ,
1353                             .help = "Generate sequential offsets",
1354                           },
1355                           { .ival = "identical",
1356                             .oval = RW_SEQ_IDENT,
1357                             .help = "Generate identical offsets",
1358                           },
1359                 },
1360         },
1361
1362         {
1363                 .name   = "ioengine",
1364                 .lname  = "IO Engine",
1365                 .type   = FIO_OPT_STR_STORE,
1366                 .off1   = td_var_offset(ioengine),
1367                 .help   = "IO engine to use",
1368                 .def    = FIO_PREFERRED_ENGINE,
1369                 .category = FIO_OPT_C_IO,
1370                 .group  = FIO_OPT_G_IO_BASIC,
1371                 .posval = {
1372                           { .ival = "sync",
1373                             .help = "Use read/write",
1374                           },
1375                           { .ival = "psync",
1376                             .help = "Use pread/pwrite",
1377                           },
1378                           { .ival = "vsync",
1379                             .help = "Use readv/writev",
1380                           },
1381 #ifdef CONFIG_PWRITEV
1382                           { .ival = "pvsync",
1383                             .help = "Use preadv/pwritev",
1384                           },
1385 #endif
1386 #ifdef CONFIG_LIBAIO
1387                           { .ival = "libaio",
1388                             .help = "Linux native asynchronous IO",
1389                           },
1390 #endif
1391 #ifdef CONFIG_POSIXAIO
1392                           { .ival = "posixaio",
1393                             .help = "POSIX asynchronous IO",
1394                           },
1395 #endif
1396 #ifdef CONFIG_SOLARISAIO
1397                           { .ival = "solarisaio",
1398                             .help = "Solaris native asynchronous IO",
1399                           },
1400 #endif
1401 #ifdef CONFIG_WINDOWSAIO
1402                           { .ival = "windowsaio",
1403                             .help = "Windows native asynchronous IO"
1404                           },
1405 #endif
1406 #ifdef CONFIG_RBD
1407                           { .ival = "rbd",
1408                             .help = "Rados Block Device asynchronous IO"
1409                           },
1410 #endif
1411                           { .ival = "mmap",
1412                             .help = "Memory mapped IO"
1413                           },
1414 #ifdef CONFIG_LINUX_SPLICE
1415                           { .ival = "splice",
1416                             .help = "splice/vmsplice based IO",
1417                           },
1418                           { .ival = "netsplice",
1419                             .help = "splice/vmsplice to/from the network",
1420                           },
1421 #endif
1422 #ifdef FIO_HAVE_SGIO
1423                           { .ival = "sg",
1424                             .help = "SCSI generic v3 IO",
1425                           },
1426 #endif
1427                           { .ival = "null",
1428                             .help = "Testing engine (no data transfer)",
1429                           },
1430                           { .ival = "net",
1431                             .help = "Network IO",
1432                           },
1433                           { .ival = "cpuio",
1434                             .help = "CPU cycle burner engine",
1435                           },
1436 #ifdef CONFIG_GUASI
1437                           { .ival = "guasi",
1438                             .help = "GUASI IO engine",
1439                           },
1440 #endif
1441 #ifdef FIO_HAVE_BINJECT
1442                           { .ival = "binject",
1443                             .help = "binject direct inject block engine",
1444                           },
1445 #endif
1446 #ifdef CONFIG_RDMA
1447                           { .ival = "rdma",
1448                             .help = "RDMA IO engine",
1449                           },
1450 #endif
1451 #ifdef CONFIG_FUSION_AW
1452                           { .ival = "fusion-aw-sync",
1453                             .help = "Fusion-io atomic write engine",
1454                           },
1455 #endif
1456 #ifdef CONFIG_LINUX_EXT4_MOVE_EXTENT
1457                           { .ival = "e4defrag",
1458                             .help = "ext4 defrag engine",
1459                           },
1460 #endif
1461 #ifdef CONFIG_LINUX_FALLOCATE
1462                           { .ival = "falloc",
1463                             .help = "fallocate() file based engine",
1464                           },
1465 #endif
1466 #ifdef CONFIG_GFAPI
1467                           { .ival = "gfapi",
1468                             .help = "Glusterfs libgfapi(sync) based engine"
1469                           },
1470                           { .ival = "gfapi_async",
1471                             .help = "Glusterfs libgfapi(async) based engine"
1472                           },
1473 #endif
1474 #ifdef CONFIG_LIBHDFS
1475                           { .ival = "libhdfs",
1476                             .help = "Hadoop Distributed Filesystem (HDFS) engine"
1477                           },
1478 #endif
1479                           { .ival = "external",
1480                             .help = "Load external engine (append name)",
1481                           },
1482                 },
1483         },
1484         {
1485                 .name   = "iodepth",
1486                 .lname  = "IO Depth",
1487                 .type   = FIO_OPT_INT,
1488                 .off1   = td_var_offset(iodepth),
1489                 .help   = "Number of IO buffers to keep in flight",
1490                 .minval = 1,
1491                 .interval = 1,
1492                 .def    = "1",
1493                 .category = FIO_OPT_C_IO,
1494                 .group  = FIO_OPT_G_IO_BASIC,
1495         },
1496         {
1497                 .name   = "iodepth_batch",
1498                 .lname  = "IO Depth batch",
1499                 .alias  = "iodepth_batch_submit",
1500                 .type   = FIO_OPT_INT,
1501                 .off1   = td_var_offset(iodepth_batch),
1502                 .help   = "Number of IO buffers to submit in one go",
1503                 .parent = "iodepth",
1504                 .hide   = 1,
1505                 .minval = 1,
1506                 .interval = 1,
1507                 .def    = "1",
1508                 .category = FIO_OPT_C_IO,
1509                 .group  = FIO_OPT_G_IO_BASIC,
1510         },
1511         {
1512                 .name   = "iodepth_batch_complete_min",
1513                 .lname  = "Min IO depth batch complete",
1514                 .alias  = "iodepth_batch_complete",
1515                 .type   = FIO_OPT_INT,
1516                 .off1   = td_var_offset(iodepth_batch_complete_min),
1517                 .help   = "Min number of IO buffers to retrieve in one go",
1518                 .parent = "iodepth",
1519                 .hide   = 1,
1520                 .minval = 0,
1521                 .interval = 1,
1522                 .def    = "1",
1523                 .category = FIO_OPT_C_IO,
1524                 .group  = FIO_OPT_G_IO_BASIC,
1525         },
1526         {
1527                 .name   = "iodepth_batch_complete_max",
1528                 .lname  = "Max IO depth batch complete",
1529                 .type   = FIO_OPT_INT,
1530                 .off1   = td_var_offset(iodepth_batch_complete_max),
1531                 .help   = "Max number of IO buffers to retrieve in one go",
1532                 .parent = "iodepth",
1533                 .hide   = 1,
1534                 .minval = 0,
1535                 .interval = 1,
1536                 .category = FIO_OPT_C_IO,
1537                 .group  = FIO_OPT_G_IO_BASIC,
1538         },
1539         {
1540                 .name   = "iodepth_low",
1541                 .lname  = "IO Depth batch low",
1542                 .type   = FIO_OPT_INT,
1543                 .off1   = td_var_offset(iodepth_low),
1544                 .help   = "Low water mark for queuing depth",
1545                 .parent = "iodepth",
1546                 .hide   = 1,
1547                 .interval = 1,
1548                 .category = FIO_OPT_C_IO,
1549                 .group  = FIO_OPT_G_IO_BASIC,
1550         },
1551         {
1552                 .name   = "io_submit_mode",
1553                 .lname  = "IO submit mode",
1554                 .type   = FIO_OPT_STR,
1555                 .off1   = td_var_offset(io_submit_mode),
1556                 .help   = "How IO submissions and completions are done",
1557                 .def    = "inline",
1558                 .category = FIO_OPT_C_IO,
1559                 .group  = FIO_OPT_G_IO_BASIC,
1560                 .posval = {
1561                           { .ival = "inline",
1562                             .oval = IO_MODE_INLINE,
1563                             .help = "Submit and complete IO inline",
1564                           },
1565                           { .ival = "offload",
1566                             .oval = IO_MODE_OFFLOAD,
1567                             .help = "Offload submit and complete to threads",
1568                           },
1569                 },
1570         },
1571         {
1572                 .name   = "size",
1573                 .lname  = "Size",
1574                 .type   = FIO_OPT_STR_VAL,
1575                 .cb     = str_size_cb,
1576                 .off1   = td_var_offset(size),
1577                 .help   = "Total size of device or files",
1578                 .interval = 1024 * 1024,
1579                 .category = FIO_OPT_C_IO,
1580                 .group  = FIO_OPT_G_INVALID,
1581         },
1582         {
1583                 .name   = "io_size",
1584                 .alias  = "io_limit",
1585                 .lname  = "IO Size",
1586                 .type   = FIO_OPT_STR_VAL,
1587                 .off1   = td_var_offset(io_limit),
1588                 .interval = 1024 * 1024,
1589                 .category = FIO_OPT_C_IO,
1590                 .group  = FIO_OPT_G_INVALID,
1591         },
1592         {
1593                 .name   = "fill_device",
1594                 .lname  = "Fill device",
1595                 .alias  = "fill_fs",
1596                 .type   = FIO_OPT_BOOL,
1597                 .off1   = td_var_offset(fill_device),
1598                 .help   = "Write until an ENOSPC error occurs",
1599                 .def    = "0",
1600                 .category = FIO_OPT_C_FILE,
1601                 .group  = FIO_OPT_G_INVALID,
1602         },
1603         {
1604                 .name   = "filesize",
1605                 .lname  = "File size",
1606                 .type   = FIO_OPT_STR_VAL,
1607                 .off1   = td_var_offset(file_size_low),
1608                 .off2   = td_var_offset(file_size_high),
1609                 .minval = 1,
1610                 .help   = "Size of individual files",
1611                 .interval = 1024 * 1024,
1612                 .category = FIO_OPT_C_FILE,
1613                 .group  = FIO_OPT_G_INVALID,
1614         },
1615         {
1616                 .name   = "file_append",
1617                 .lname  = "File append",
1618                 .type   = FIO_OPT_BOOL,
1619                 .off1   = td_var_offset(file_append),
1620                 .help   = "IO will start at the end of the file(s)",
1621                 .def    = "0",
1622                 .category = FIO_OPT_C_FILE,
1623                 .group  = FIO_OPT_G_INVALID,
1624         },
1625         {
1626                 .name   = "offset",
1627                 .lname  = "IO offset",
1628                 .alias  = "fileoffset",
1629                 .type   = FIO_OPT_STR_VAL,
1630                 .off1   = td_var_offset(start_offset),
1631                 .help   = "Start IO from this offset",
1632                 .def    = "0",
1633                 .interval = 1024 * 1024,
1634                 .category = FIO_OPT_C_IO,
1635                 .group  = FIO_OPT_G_INVALID,
1636         },
1637         {
1638                 .name   = "offset_increment",
1639                 .lname  = "IO offset increment",
1640                 .type   = FIO_OPT_STR_VAL,
1641                 .off1   = td_var_offset(offset_increment),
1642                 .help   = "What is the increment from one offset to the next",
1643                 .parent = "offset",
1644                 .hide   = 1,
1645                 .def    = "0",
1646                 .interval = 1024 * 1024,
1647                 .category = FIO_OPT_C_IO,
1648                 .group  = FIO_OPT_G_INVALID,
1649         },
1650         {
1651                 .name   = "number_ios",
1652                 .lname  = "Number of IOs to perform",
1653                 .type   = FIO_OPT_STR_VAL,
1654                 .off1   = td_var_offset(number_ios),
1655                 .help   = "Force job completion after this number of IOs",
1656                 .def    = "0",
1657                 .category = FIO_OPT_C_IO,
1658                 .group  = FIO_OPT_G_INVALID,
1659         },
1660         {
1661                 .name   = "bs",
1662                 .lname  = "Block size",
1663                 .alias  = "blocksize",
1664                 .type   = FIO_OPT_INT,
1665                 .off1   = td_var_offset(bs[DDIR_READ]),
1666                 .off2   = td_var_offset(bs[DDIR_WRITE]),
1667                 .off3   = td_var_offset(bs[DDIR_TRIM]),
1668                 .minval = 1,
1669                 .help   = "Block size unit",
1670                 .def    = "4k",
1671                 .parent = "rw",
1672                 .hide   = 1,
1673                 .interval = 512,
1674                 .category = FIO_OPT_C_IO,
1675                 .group  = FIO_OPT_G_INVALID,
1676         },
1677         {
1678                 .name   = "ba",
1679                 .lname  = "Block size align",
1680                 .alias  = "blockalign",
1681                 .type   = FIO_OPT_INT,
1682                 .off1   = td_var_offset(ba[DDIR_READ]),
1683                 .off2   = td_var_offset(ba[DDIR_WRITE]),
1684                 .off3   = td_var_offset(ba[DDIR_TRIM]),
1685                 .minval = 1,
1686                 .help   = "IO block offset alignment",
1687                 .parent = "rw",
1688                 .hide   = 1,
1689                 .interval = 512,
1690                 .category = FIO_OPT_C_IO,
1691                 .group  = FIO_OPT_G_INVALID,
1692         },
1693         {
1694                 .name   = "bsrange",
1695                 .lname  = "Block size range",
1696                 .alias  = "blocksize_range",
1697                 .type   = FIO_OPT_RANGE,
1698                 .off1   = td_var_offset(min_bs[DDIR_READ]),
1699                 .off2   = td_var_offset(max_bs[DDIR_READ]),
1700                 .off3   = td_var_offset(min_bs[DDIR_WRITE]),
1701                 .off4   = td_var_offset(max_bs[DDIR_WRITE]),
1702                 .off5   = td_var_offset(min_bs[DDIR_TRIM]),
1703                 .off6   = td_var_offset(max_bs[DDIR_TRIM]),
1704                 .minval = 1,
1705                 .help   = "Set block size range (in more detail than bs)",
1706                 .parent = "rw",
1707                 .hide   = 1,
1708                 .interval = 4096,
1709                 .category = FIO_OPT_C_IO,
1710                 .group  = FIO_OPT_G_INVALID,
1711         },
1712         {
1713                 .name   = "bssplit",
1714                 .lname  = "Block size split",
1715                 .type   = FIO_OPT_STR,
1716                 .cb     = str_bssplit_cb,
1717                 .off1   = td_var_offset(bssplit),
1718                 .help   = "Set a specific mix of block sizes",
1719                 .parent = "rw",
1720                 .hide   = 1,
1721                 .category = FIO_OPT_C_IO,
1722                 .group  = FIO_OPT_G_INVALID,
1723         },
1724         {
1725                 .name   = "bs_unaligned",
1726                 .lname  = "Block size unaligned",
1727                 .alias  = "blocksize_unaligned",
1728                 .type   = FIO_OPT_STR_SET,
1729                 .off1   = td_var_offset(bs_unaligned),
1730                 .help   = "Don't sector align IO buffer sizes",
1731                 .parent = "rw",
1732                 .hide   = 1,
1733                 .category = FIO_OPT_C_IO,
1734                 .group  = FIO_OPT_G_INVALID,
1735         },
1736         {
1737                 .name   = "bs_is_seq_rand",
1738                 .lname  = "Block size division is seq/random (not read/write)",
1739                 .type   = FIO_OPT_BOOL,
1740                 .off1   = td_var_offset(bs_is_seq_rand),
1741                 .help   = "Consider any blocksize setting to be sequential,random",
1742                 .def    = "0",
1743                 .parent = "blocksize",
1744                 .category = FIO_OPT_C_IO,
1745                 .group  = FIO_OPT_G_INVALID,
1746         },
1747         {
1748                 .name   = "randrepeat",
1749                 .lname  = "Random repeatable",
1750                 .type   = FIO_OPT_BOOL,
1751                 .off1   = td_var_offset(rand_repeatable),
1752                 .help   = "Use repeatable random IO pattern",
1753                 .def    = "1",
1754                 .parent = "rw",
1755                 .hide   = 1,
1756                 .category = FIO_OPT_C_IO,
1757                 .group  = FIO_OPT_G_RANDOM,
1758         },
1759         {
1760                 .name   = "randseed",
1761                 .lname  = "The random generator seed",
1762                 .type   = FIO_OPT_STR_VAL,
1763                 .off1   = td_var_offset(rand_seed),
1764                 .help   = "Set the random generator seed value",
1765                 .def    = "0x89",
1766                 .parent = "rw",
1767                 .category = FIO_OPT_C_IO,
1768                 .group  = FIO_OPT_G_RANDOM,
1769         },
1770         {
1771                 .name   = "use_os_rand",
1772                 .lname  = "Use OS random",
1773                 .type   = FIO_OPT_DEPRECATED,
1774                 .off1   = td_var_offset(dep_use_os_rand),
1775                 .category = FIO_OPT_C_IO,
1776                 .group  = FIO_OPT_G_RANDOM,
1777         },
1778         {
1779                 .name   = "norandommap",
1780                 .lname  = "No randommap",
1781                 .type   = FIO_OPT_STR_SET,
1782                 .off1   = td_var_offset(norandommap),
1783                 .help   = "Accept potential duplicate random blocks",
1784                 .parent = "rw",
1785                 .hide   = 1,
1786                 .hide_on_set = 1,
1787                 .category = FIO_OPT_C_IO,
1788                 .group  = FIO_OPT_G_RANDOM,
1789         },
1790         {
1791                 .name   = "softrandommap",
1792                 .lname  = "Soft randommap",
1793                 .type   = FIO_OPT_BOOL,
1794                 .off1   = td_var_offset(softrandommap),
1795                 .help   = "Set norandommap if randommap allocation fails",
1796                 .parent = "norandommap",
1797                 .hide   = 1,
1798                 .def    = "0",
1799                 .category = FIO_OPT_C_IO,
1800                 .group  = FIO_OPT_G_RANDOM,
1801         },
1802         {
1803                 .name   = "random_generator",
1804                 .type   = FIO_OPT_STR,
1805                 .off1   = td_var_offset(random_generator),
1806                 .help   = "Type of random number generator to use",
1807                 .def    = "tausworthe",
1808                 .posval = {
1809                           { .ival = "tausworthe",
1810                             .oval = FIO_RAND_GEN_TAUSWORTHE,
1811                             .help = "Strong Tausworthe generator",
1812                           },
1813                           { .ival = "lfsr",
1814                             .oval = FIO_RAND_GEN_LFSR,
1815                             .help = "Variable length LFSR",
1816                           },
1817                           {
1818                             .ival = "tausworthe64",
1819                             .oval = FIO_RAND_GEN_TAUSWORTHE64,
1820                             .help = "64-bit Tausworthe variant",
1821                           },
1822                 },
1823                 .category = FIO_OPT_C_IO,
1824                 .group  = FIO_OPT_G_RANDOM,
1825         },
1826         {
1827                 .name   = "random_distribution",
1828                 .type   = FIO_OPT_STR,
1829                 .off1   = td_var_offset(random_distribution),
1830                 .cb     = str_random_distribution_cb,
1831                 .help   = "Random offset distribution generator",
1832                 .def    = "random",
1833                 .posval = {
1834                           { .ival = "random",
1835                             .oval = FIO_RAND_DIST_RANDOM,
1836                             .help = "Completely random",
1837                           },
1838                           { .ival = "zipf",
1839                             .oval = FIO_RAND_DIST_ZIPF,
1840                             .help = "Zipf distribution",
1841                           },
1842                           { .ival = "pareto",
1843                             .oval = FIO_RAND_DIST_PARETO,
1844                             .help = "Pareto distribution",
1845                           },
1846                           { .ival = "normal",
1847                             .oval = FIO_RAND_DIST_GAUSS,
1848                             .help = "Normal (gaussian) distribution",
1849                           },
1850                 },
1851                 .category = FIO_OPT_C_IO,
1852                 .group  = FIO_OPT_G_RANDOM,
1853         },
1854         {
1855                 .name   = "percentage_random",
1856                 .lname  = "Percentage Random",
1857                 .type   = FIO_OPT_INT,
1858                 .off1   = td_var_offset(perc_rand[DDIR_READ]),
1859                 .off2   = td_var_offset(perc_rand[DDIR_WRITE]),
1860                 .off3   = td_var_offset(perc_rand[DDIR_TRIM]),
1861                 .maxval = 100,
1862                 .help   = "Percentage of seq/random mix that should be random",
1863                 .def    = "100,100,100",
1864                 .interval = 5,
1865                 .inverse = "percentage_sequential",
1866                 .category = FIO_OPT_C_IO,
1867                 .group  = FIO_OPT_G_RANDOM,
1868         },
1869         {
1870                 .name   = "percentage_sequential",
1871                 .lname  = "Percentage Sequential",
1872                 .type   = FIO_OPT_DEPRECATED,
1873                 .category = FIO_OPT_C_IO,
1874                 .group  = FIO_OPT_G_RANDOM,
1875         },
1876         {
1877                 .name   = "allrandrepeat",
1878                 .type   = FIO_OPT_BOOL,
1879                 .off1   = td_var_offset(allrand_repeatable),
1880                 .help   = "Use repeatable random numbers for everything",
1881                 .def    = "0",
1882                 .category = FIO_OPT_C_IO,
1883                 .group  = FIO_OPT_G_RANDOM,
1884         },
1885         {
1886                 .name   = "nrfiles",
1887                 .lname  = "Number of files",
1888                 .alias  = "nr_files",
1889                 .type   = FIO_OPT_INT,
1890                 .off1   = td_var_offset(nr_files),
1891                 .help   = "Split job workload between this number of files",
1892                 .def    = "1",
1893                 .interval = 1,
1894                 .category = FIO_OPT_C_FILE,
1895                 .group  = FIO_OPT_G_INVALID,
1896         },
1897         {
1898                 .name   = "openfiles",
1899                 .lname  = "Number of open files",
1900                 .type   = FIO_OPT_INT,
1901                 .off1   = td_var_offset(open_files),
1902                 .help   = "Number of files to keep open at the same time",
1903                 .category = FIO_OPT_C_FILE,
1904                 .group  = FIO_OPT_G_INVALID,
1905         },
1906         {
1907                 .name   = "file_service_type",
1908                 .lname  = "File service type",
1909                 .type   = FIO_OPT_STR,
1910                 .cb     = str_fst_cb,
1911                 .off1   = td_var_offset(file_service_type),
1912                 .help   = "How to select which file to service next",
1913                 .def    = "roundrobin",
1914                 .category = FIO_OPT_C_FILE,
1915                 .group  = FIO_OPT_G_INVALID,
1916                 .posval = {
1917                           { .ival = "random",
1918                             .oval = FIO_FSERVICE_RANDOM,
1919                             .help = "Choose a file at random",
1920                           },
1921                           { .ival = "roundrobin",
1922                             .oval = FIO_FSERVICE_RR,
1923                             .help = "Round robin select files",
1924                           },
1925                           { .ival = "sequential",
1926                             .oval = FIO_FSERVICE_SEQ,
1927                             .help = "Finish one file before moving to the next",
1928                           },
1929                 },
1930                 .parent = "nrfiles",
1931                 .hide   = 1,
1932         },
1933 #ifdef CONFIG_POSIX_FALLOCATE
1934         {
1935                 .name   = "fallocate",
1936                 .lname  = "Fallocate",
1937                 .type   = FIO_OPT_STR,
1938                 .off1   = td_var_offset(fallocate_mode),
1939                 .help   = "Whether pre-allocation is performed when laying out files",
1940                 .def    = "posix",
1941                 .category = FIO_OPT_C_FILE,
1942                 .group  = FIO_OPT_G_INVALID,
1943                 .posval = {
1944                           { .ival = "none",
1945                             .oval = FIO_FALLOCATE_NONE,
1946                             .help = "Do not pre-allocate space",
1947                           },
1948                           { .ival = "posix",
1949                             .oval = FIO_FALLOCATE_POSIX,
1950                             .help = "Use posix_fallocate()",
1951                           },
1952 #ifdef CONFIG_LINUX_FALLOCATE
1953                           { .ival = "keep",
1954                             .oval = FIO_FALLOCATE_KEEP_SIZE,
1955                             .help = "Use fallocate(..., FALLOC_FL_KEEP_SIZE, ...)",
1956                           },
1957 #endif
1958                           /* Compatibility with former boolean values */
1959                           { .ival = "0",
1960                             .oval = FIO_FALLOCATE_NONE,
1961                             .help = "Alias for 'none'",
1962                           },
1963                           { .ival = "1",
1964                             .oval = FIO_FALLOCATE_POSIX,
1965                             .help = "Alias for 'posix'",
1966                           },
1967                 },
1968         },
1969 #endif  /* CONFIG_POSIX_FALLOCATE */
1970         {
1971                 .name   = "fadvise_hint",
1972                 .lname  = "Fadvise hint",
1973                 .type   = FIO_OPT_BOOL,
1974                 .off1   = td_var_offset(fadvise_hint),
1975                 .help   = "Use fadvise() to advise the kernel on IO pattern",
1976                 .def    = "1",
1977                 .category = FIO_OPT_C_FILE,
1978                 .group  = FIO_OPT_G_INVALID,
1979         },
1980 #ifdef FIO_HAVE_STREAMID
1981         {
1982                 .name   = "fadvise_stream",
1983                 .lname  = "Fadvise stream",
1984                 .type   = FIO_OPT_INT,
1985                 .off1   = td_var_offset(fadvise_stream),
1986                 .help   = "Use fadvise() to set stream ID",
1987                 .category = FIO_OPT_C_FILE,
1988                 .group  = FIO_OPT_G_INVALID,
1989         },
1990 #endif
1991         {
1992                 .name   = "fsync",
1993                 .lname  = "Fsync",
1994                 .type   = FIO_OPT_INT,
1995                 .off1   = td_var_offset(fsync_blocks),
1996                 .help   = "Issue fsync for writes every given number of blocks",
1997                 .def    = "0",
1998                 .interval = 1,
1999                 .category = FIO_OPT_C_FILE,
2000                 .group  = FIO_OPT_G_INVALID,
2001         },
2002         {
2003                 .name   = "fdatasync",
2004                 .lname  = "Fdatasync",
2005                 .type   = FIO_OPT_INT,
2006                 .off1   = td_var_offset(fdatasync_blocks),
2007                 .help   = "Issue fdatasync for writes every given number of blocks",
2008                 .def    = "0",
2009                 .interval = 1,
2010                 .category = FIO_OPT_C_FILE,
2011                 .group  = FIO_OPT_G_INVALID,
2012         },
2013         {
2014                 .name   = "write_barrier",
2015                 .lname  = "Write barrier",
2016                 .type   = FIO_OPT_INT,
2017                 .off1   = td_var_offset(barrier_blocks),
2018                 .help   = "Make every Nth write a barrier write",
2019                 .def    = "0",
2020                 .interval = 1,
2021                 .category = FIO_OPT_C_IO,
2022                 .group  = FIO_OPT_G_INVALID,
2023         },
2024 #ifdef CONFIG_SYNC_FILE_RANGE
2025         {
2026                 .name   = "sync_file_range",
2027                 .lname  = "Sync file range",
2028                 .posval = {
2029                           { .ival = "wait_before",
2030                             .oval = SYNC_FILE_RANGE_WAIT_BEFORE,
2031                             .help = "SYNC_FILE_RANGE_WAIT_BEFORE",
2032                             .orval  = 1,
2033                           },
2034                           { .ival = "write",
2035                             .oval = SYNC_FILE_RANGE_WRITE,
2036                             .help = "SYNC_FILE_RANGE_WRITE",
2037                             .orval  = 1,
2038                           },
2039                           {
2040                             .ival = "wait_after",
2041                             .oval = SYNC_FILE_RANGE_WAIT_AFTER,
2042                             .help = "SYNC_FILE_RANGE_WAIT_AFTER",
2043                             .orval  = 1,
2044                           },
2045                 },
2046                 .type   = FIO_OPT_STR_MULTI,
2047                 .cb     = str_sfr_cb,
2048                 .off1   = td_var_offset(sync_file_range),
2049                 .help   = "Use sync_file_range()",
2050                 .category = FIO_OPT_C_FILE,
2051                 .group  = FIO_OPT_G_INVALID,
2052         },
2053 #endif
2054         {
2055                 .name   = "direct",
2056                 .lname  = "Direct I/O",
2057                 .type   = FIO_OPT_BOOL,
2058                 .off1   = td_var_offset(odirect),
2059                 .help   = "Use O_DIRECT IO (negates buffered)",
2060                 .def    = "0",
2061                 .inverse = "buffered",
2062                 .category = FIO_OPT_C_IO,
2063                 .group  = FIO_OPT_G_IO_TYPE,
2064         },
2065         {
2066                 .name   = "atomic",
2067                 .lname  = "Atomic I/O",
2068                 .type   = FIO_OPT_BOOL,
2069                 .off1   = td_var_offset(oatomic),
2070                 .help   = "Use Atomic IO with O_DIRECT (implies O_DIRECT)",
2071                 .def    = "0",
2072                 .category = FIO_OPT_C_IO,
2073                 .group  = FIO_OPT_G_IO_TYPE,
2074         },
2075         {
2076                 .name   = "buffered",
2077                 .lname  = "Buffered I/O",
2078                 .type   = FIO_OPT_BOOL,
2079                 .off1   = td_var_offset(odirect),
2080                 .neg    = 1,
2081                 .help   = "Use buffered IO (negates direct)",
2082                 .def    = "1",
2083                 .inverse = "direct",
2084                 .category = FIO_OPT_C_IO,
2085                 .group  = FIO_OPT_G_IO_TYPE,
2086         },
2087         {
2088                 .name   = "overwrite",
2089                 .lname  = "Overwrite",
2090                 .type   = FIO_OPT_BOOL,
2091                 .off1   = td_var_offset(overwrite),
2092                 .help   = "When writing, set whether to overwrite current data",
2093                 .def    = "0",
2094                 .category = FIO_OPT_C_FILE,
2095                 .group  = FIO_OPT_G_INVALID,
2096         },
2097         {
2098                 .name   = "loops",
2099                 .lname  = "Loops",
2100                 .type   = FIO_OPT_INT,
2101                 .off1   = td_var_offset(loops),
2102                 .help   = "Number of times to run the job",
2103                 .def    = "1",
2104                 .interval = 1,
2105                 .category = FIO_OPT_C_GENERAL,
2106                 .group  = FIO_OPT_G_RUNTIME,
2107         },
2108         {
2109                 .name   = "numjobs",
2110                 .lname  = "Number of jobs",
2111                 .type   = FIO_OPT_INT,
2112                 .off1   = td_var_offset(numjobs),
2113                 .help   = "Duplicate this job this many times",
2114                 .def    = "1",
2115                 .interval = 1,
2116                 .category = FIO_OPT_C_GENERAL,
2117                 .group  = FIO_OPT_G_RUNTIME,
2118         },
2119         {
2120                 .name   = "startdelay",
2121                 .lname  = "Start delay",
2122                 .type   = FIO_OPT_STR_VAL_TIME,
2123                 .off1   = td_var_offset(start_delay),
2124                 .off2   = td_var_offset(start_delay_high),
2125                 .help   = "Only start job when this period has passed",
2126                 .def    = "0",
2127                 .is_seconds = 1,
2128                 .is_time = 1,
2129                 .category = FIO_OPT_C_GENERAL,
2130                 .group  = FIO_OPT_G_RUNTIME,
2131         },
2132         {
2133                 .name   = "runtime",
2134                 .lname  = "Runtime",
2135                 .alias  = "timeout",
2136                 .type   = FIO_OPT_STR_VAL_TIME,
2137                 .off1   = td_var_offset(timeout),
2138                 .help   = "Stop workload when this amount of time has passed",
2139                 .def    = "0",
2140                 .is_seconds = 1,
2141                 .is_time = 1,
2142                 .category = FIO_OPT_C_GENERAL,
2143                 .group  = FIO_OPT_G_RUNTIME,
2144         },
2145         {
2146                 .name   = "time_based",
2147                 .lname  = "Time based",
2148                 .type   = FIO_OPT_STR_SET,
2149                 .off1   = td_var_offset(time_based),
2150                 .help   = "Keep running until runtime/timeout is met",
2151                 .category = FIO_OPT_C_GENERAL,
2152                 .group  = FIO_OPT_G_RUNTIME,
2153         },
2154         {
2155                 .name   = "verify_only",
2156                 .lname  = "Verify only",
2157                 .type   = FIO_OPT_STR_SET,
2158                 .off1   = td_var_offset(verify_only),
2159                 .help   = "Verifies previously written data is still valid",
2160                 .category = FIO_OPT_C_GENERAL,
2161                 .group  = FIO_OPT_G_RUNTIME,
2162         },
2163         {
2164                 .name   = "ramp_time",
2165                 .lname  = "Ramp time",
2166                 .type   = FIO_OPT_STR_VAL_TIME,
2167                 .off1   = td_var_offset(ramp_time),
2168                 .help   = "Ramp up time before measuring performance",
2169                 .is_seconds = 1,
2170                 .is_time = 1,
2171                 .category = FIO_OPT_C_GENERAL,
2172                 .group  = FIO_OPT_G_RUNTIME,
2173         },
2174         {
2175                 .name   = "clocksource",
2176                 .lname  = "Clock source",
2177                 .type   = FIO_OPT_STR,
2178                 .cb     = fio_clock_source_cb,
2179                 .off1   = td_var_offset(clocksource),
2180                 .help   = "What type of timing source to use",
2181                 .category = FIO_OPT_C_GENERAL,
2182                 .group  = FIO_OPT_G_CLOCK,
2183                 .posval = {
2184 #ifdef CONFIG_GETTIMEOFDAY
2185                           { .ival = "gettimeofday",
2186                             .oval = CS_GTOD,
2187                             .help = "Use gettimeofday(2) for timing",
2188                           },
2189 #endif
2190 #ifdef CONFIG_CLOCK_GETTIME
2191                           { .ival = "clock_gettime",
2192                             .oval = CS_CGETTIME,
2193                             .help = "Use clock_gettime(2) for timing",
2194                           },
2195 #endif
2196 #ifdef ARCH_HAVE_CPU_CLOCK
2197                           { .ival = "cpu",
2198                             .oval = CS_CPUCLOCK,
2199                             .help = "Use CPU private clock",
2200                           },
2201 #endif
2202                 },
2203         },
2204         {
2205                 .name   = "mem",
2206                 .alias  = "iomem",
2207                 .lname  = "I/O Memory",
2208                 .type   = FIO_OPT_STR,
2209                 .cb     = str_mem_cb,
2210                 .off1   = td_var_offset(mem_type),
2211                 .help   = "Backing type for IO buffers",
2212                 .def    = "malloc",
2213                 .category = FIO_OPT_C_IO,
2214                 .group  = FIO_OPT_G_INVALID,
2215                 .posval = {
2216                           { .ival = "malloc",
2217                             .oval = MEM_MALLOC,
2218                             .help = "Use malloc(3) for IO buffers",
2219                           },
2220 #ifndef CONFIG_NO_SHM
2221                           { .ival = "shm",
2222                             .oval = MEM_SHM,
2223                             .help = "Use shared memory segments for IO buffers",
2224                           },
2225 #ifdef FIO_HAVE_HUGETLB
2226                           { .ival = "shmhuge",
2227                             .oval = MEM_SHMHUGE,
2228                             .help = "Like shm, but use huge pages",
2229                           },
2230 #endif
2231 #endif
2232                           { .ival = "mmap",
2233                             .oval = MEM_MMAP,
2234                             .help = "Use mmap(2) (file or anon) for IO buffers",
2235                           },
2236                           { .ival = "mmapshared",
2237                             .oval = MEM_MMAPSHARED,
2238                             .help = "Like mmap, but use the shared flag",
2239                           },
2240 #ifdef FIO_HAVE_HUGETLB
2241                           { .ival = "mmaphuge",
2242                             .oval = MEM_MMAPHUGE,
2243                             .help = "Like mmap, but use huge pages",
2244                           },
2245 #endif
2246                   },
2247         },
2248         {
2249                 .name   = "iomem_align",
2250                 .alias  = "mem_align",
2251                 .lname  = "I/O memory alignment",
2252                 .type   = FIO_OPT_INT,
2253                 .off1   = td_var_offset(mem_align),
2254                 .minval = 0,
2255                 .help   = "IO memory buffer offset alignment",
2256                 .def    = "0",
2257                 .parent = "iomem",
2258                 .hide   = 1,
2259                 .category = FIO_OPT_C_IO,
2260                 .group  = FIO_OPT_G_INVALID,
2261         },
2262         {
2263                 .name   = "verify",
2264                 .lname  = "Verify",
2265                 .type   = FIO_OPT_STR,
2266                 .off1   = td_var_offset(verify),
2267                 .help   = "Verify data written",
2268                 .def    = "0",
2269                 .category = FIO_OPT_C_IO,
2270                 .group  = FIO_OPT_G_VERIFY,
2271                 .posval = {
2272                           { .ival = "0",
2273                             .oval = VERIFY_NONE,
2274                             .help = "Don't do IO verification",
2275                           },
2276                           { .ival = "md5",
2277                             .oval = VERIFY_MD5,
2278                             .help = "Use md5 checksums for verification",
2279                           },
2280                           { .ival = "crc64",
2281                             .oval = VERIFY_CRC64,
2282                             .help = "Use crc64 checksums for verification",
2283                           },
2284                           { .ival = "crc32",
2285                             .oval = VERIFY_CRC32,
2286                             .help = "Use crc32 checksums for verification",
2287                           },
2288                           { .ival = "crc32c-intel",
2289                             .oval = VERIFY_CRC32C,
2290                             .help = "Use crc32c checksums for verification (hw assisted, if available)",
2291                           },
2292                           { .ival = "crc32c",
2293                             .oval = VERIFY_CRC32C,
2294                             .help = "Use crc32c checksums for verification (hw assisted, if available)",
2295                           },
2296                           { .ival = "crc16",
2297                             .oval = VERIFY_CRC16,
2298                             .help = "Use crc16 checksums for verification",
2299                           },
2300                           { .ival = "crc7",
2301                             .oval = VERIFY_CRC7,
2302                             .help = "Use crc7 checksums for verification",
2303                           },
2304                           { .ival = "sha1",
2305                             .oval = VERIFY_SHA1,
2306                             .help = "Use sha1 checksums for verification",
2307                           },
2308                           { .ival = "sha256",
2309                             .oval = VERIFY_SHA256,
2310                             .help = "Use sha256 checksums for verification",
2311                           },
2312                           { .ival = "sha512",
2313                             .oval = VERIFY_SHA512,
2314                             .help = "Use sha512 checksums for verification",
2315                           },
2316                           { .ival = "xxhash",
2317                             .oval = VERIFY_XXHASH,
2318                             .help = "Use xxhash checksums for verification",
2319                           },
2320                           /* Meta information was included into verify_header,
2321                            * 'meta' verification is implied by default. */
2322                           { .ival = "meta",
2323                             .oval = VERIFY_HDR_ONLY,
2324                             .help = "Use io information for verification. "
2325                                     "Now is implied by default, thus option is obsolete, "
2326                                     "don't use it",
2327                           },
2328                           { .ival = "pattern",
2329                             .oval = VERIFY_PATTERN_NO_HDR,
2330                             .help = "Verify strict pattern",
2331                           },
2332                           {
2333                             .ival = "null",
2334                             .oval = VERIFY_NULL,
2335                             .help = "Pretend to verify",
2336                           },
2337                 },
2338         },
2339         {
2340                 .name   = "do_verify",
2341                 .lname  = "Perform verify step",
2342                 .type   = FIO_OPT_BOOL,
2343                 .off1   = td_var_offset(do_verify),
2344                 .help   = "Run verification stage after write",
2345                 .def    = "1",
2346                 .parent = "verify",
2347                 .hide   = 1,
2348                 .category = FIO_OPT_C_IO,
2349                 .group  = FIO_OPT_G_VERIFY,
2350         },
2351         {
2352                 .name   = "verifysort",
2353                 .lname  = "Verify sort",
2354                 .type   = FIO_OPT_BOOL,
2355                 .off1   = td_var_offset(verifysort),
2356                 .help   = "Sort written verify blocks for read back",
2357                 .def    = "1",
2358                 .parent = "verify",
2359                 .hide   = 1,
2360                 .category = FIO_OPT_C_IO,
2361                 .group  = FIO_OPT_G_VERIFY,
2362         },
2363         {
2364                 .name   = "verifysort_nr",
2365                 .type   = FIO_OPT_INT,
2366                 .off1   = td_var_offset(verifysort_nr),
2367                 .help   = "Pre-load and sort verify blocks for a read workload",
2368                 .minval = 0,
2369                 .maxval = 131072,
2370                 .def    = "1024",
2371                 .parent = "verify",
2372                 .category = FIO_OPT_C_IO,
2373                 .group  = FIO_OPT_G_VERIFY,
2374         },
2375         {
2376                 .name   = "verify_interval",
2377                 .lname  = "Verify interval",
2378                 .type   = FIO_OPT_INT,
2379                 .off1   = td_var_offset(verify_interval),
2380                 .minval = 2 * sizeof(struct verify_header),
2381                 .help   = "Store verify buffer header every N bytes",
2382                 .parent = "verify",
2383                 .hide   = 1,
2384                 .interval = 2 * sizeof(struct verify_header),
2385                 .category = FIO_OPT_C_IO,
2386                 .group  = FIO_OPT_G_VERIFY,
2387         },
2388         {
2389                 .name   = "verify_offset",
2390                 .lname  = "Verify offset",
2391                 .type   = FIO_OPT_INT,
2392                 .help   = "Offset verify header location by N bytes",
2393                 .off1   = td_var_offset(verify_offset),
2394                 .minval = sizeof(struct verify_header),
2395                 .parent = "verify",
2396                 .hide   = 1,
2397                 .category = FIO_OPT_C_IO,
2398                 .group  = FIO_OPT_G_VERIFY,
2399         },
2400         {
2401                 .name   = "verify_pattern",
2402                 .lname  = "Verify pattern",
2403                 .type   = FIO_OPT_STR,
2404                 .cb     = str_verify_pattern_cb,
2405                 .off1   = td_var_offset(verify_pattern),
2406                 .help   = "Fill pattern for IO buffers",
2407                 .parent = "verify",
2408                 .hide   = 1,
2409                 .category = FIO_OPT_C_IO,
2410                 .group  = FIO_OPT_G_VERIFY,
2411         },
2412         {
2413                 .name   = "verify_fatal",
2414                 .lname  = "Verify fatal",
2415                 .type   = FIO_OPT_BOOL,
2416                 .off1   = td_var_offset(verify_fatal),
2417                 .def    = "0",
2418                 .help   = "Exit on a single verify failure, don't continue",
2419                 .parent = "verify",
2420                 .hide   = 1,
2421                 .category = FIO_OPT_C_IO,
2422                 .group  = FIO_OPT_G_VERIFY,
2423         },
2424         {
2425                 .name   = "verify_dump",
2426                 .lname  = "Verify dump",
2427                 .type   = FIO_OPT_BOOL,
2428                 .off1   = td_var_offset(verify_dump),
2429                 .def    = "0",
2430                 .help   = "Dump contents of good and bad blocks on failure",
2431                 .parent = "verify",
2432                 .hide   = 1,
2433                 .category = FIO_OPT_C_IO,
2434                 .group  = FIO_OPT_G_VERIFY,
2435         },
2436         {
2437                 .name   = "verify_async",
2438                 .lname  = "Verify asynchronously",
2439                 .type   = FIO_OPT_INT,
2440                 .off1   = td_var_offset(verify_async),
2441                 .def    = "0",
2442                 .help   = "Number of async verifier threads to use",
2443                 .parent = "verify",
2444                 .hide   = 1,
2445                 .category = FIO_OPT_C_IO,
2446                 .group  = FIO_OPT_G_VERIFY,
2447         },
2448         {
2449                 .name   = "verify_backlog",
2450                 .lname  = "Verify backlog",
2451                 .type   = FIO_OPT_STR_VAL,
2452                 .off1   = td_var_offset(verify_backlog),
2453                 .help   = "Verify after this number of blocks are written",
2454                 .parent = "verify",
2455                 .hide   = 1,
2456                 .category = FIO_OPT_C_IO,
2457                 .group  = FIO_OPT_G_VERIFY,
2458         },
2459         {
2460                 .name   = "verify_backlog_batch",
2461                 .lname  = "Verify backlog batch",
2462                 .type   = FIO_OPT_INT,
2463                 .off1   = td_var_offset(verify_batch),
2464                 .help   = "Verify this number of IO blocks",
2465                 .parent = "verify",
2466                 .hide   = 1,
2467                 .category = FIO_OPT_C_IO,
2468                 .group  = FIO_OPT_G_VERIFY,
2469         },
2470 #ifdef FIO_HAVE_CPU_AFFINITY
2471         {
2472                 .name   = "verify_async_cpus",
2473                 .lname  = "Async verify CPUs",
2474                 .type   = FIO_OPT_STR,
2475                 .cb     = str_verify_cpus_allowed_cb,
2476                 .off1   = td_var_offset(verify_cpumask),
2477                 .help   = "Set CPUs allowed for async verify threads",
2478                 .parent = "verify_async",
2479                 .hide   = 1,
2480                 .category = FIO_OPT_C_IO,
2481                 .group  = FIO_OPT_G_VERIFY,
2482         },
2483 #endif
2484         {
2485                 .name   = "experimental_verify",
2486                 .off1   = td_var_offset(experimental_verify),
2487                 .type   = FIO_OPT_BOOL,
2488                 .help   = "Enable experimental verification",
2489                 .parent = "verify",
2490                 .category = FIO_OPT_C_IO,
2491                 .group  = FIO_OPT_G_VERIFY,
2492         },
2493         {
2494                 .name   = "verify_state_load",
2495                 .lname  = "Load verify state",
2496                 .off1   = td_var_offset(verify_state),
2497                 .type   = FIO_OPT_BOOL,
2498                 .help   = "Load verify termination state",
2499                 .parent = "verify",
2500                 .category = FIO_OPT_C_IO,
2501                 .group  = FIO_OPT_G_VERIFY,
2502         },
2503         {
2504                 .name   = "verify_state_save",
2505                 .lname  = "Save verify state",
2506                 .off1   = td_var_offset(verify_state_save),
2507                 .type   = FIO_OPT_BOOL,
2508                 .def    = "1",
2509                 .help   = "Save verify state on termination",
2510                 .parent = "verify",
2511                 .category = FIO_OPT_C_IO,
2512                 .group  = FIO_OPT_G_VERIFY,
2513         },
2514 #ifdef FIO_HAVE_TRIM
2515         {
2516                 .name   = "trim_percentage",
2517                 .lname  = "Trim percentage",
2518                 .type   = FIO_OPT_INT,
2519                 .off1   = td_var_offset(trim_percentage),
2520                 .minval = 0,
2521                 .maxval = 100,
2522                 .help   = "Number of verify blocks to discard/trim",
2523                 .parent = "verify",
2524                 .def    = "0",
2525                 .interval = 1,
2526                 .hide   = 1,
2527                 .category = FIO_OPT_C_IO,
2528                 .group  = FIO_OPT_G_TRIM,
2529         },
2530         {
2531                 .name   = "trim_verify_zero",
2532                 .lname  = "Verify trim zero",
2533                 .type   = FIO_OPT_BOOL,
2534                 .help   = "Verify that trim/discarded blocks are returned as zeroes",
2535                 .off1   = td_var_offset(trim_zero),
2536                 .parent = "trim_percentage",
2537                 .hide   = 1,
2538                 .def    = "1",
2539                 .category = FIO_OPT_C_IO,
2540                 .group  = FIO_OPT_G_TRIM,
2541         },
2542         {
2543                 .name   = "trim_backlog",
2544                 .lname  = "Trim backlog",
2545                 .type   = FIO_OPT_STR_VAL,
2546                 .off1   = td_var_offset(trim_backlog),
2547                 .help   = "Trim after this number of blocks are written",
2548                 .parent = "trim_percentage",
2549                 .hide   = 1,
2550                 .interval = 1,
2551                 .category = FIO_OPT_C_IO,
2552                 .group  = FIO_OPT_G_TRIM,
2553         },
2554         {
2555                 .name   = "trim_backlog_batch",
2556                 .lname  = "Trim backlog batch",
2557                 .type   = FIO_OPT_INT,
2558                 .off1   = td_var_offset(trim_batch),
2559                 .help   = "Trim this number of IO blocks",
2560                 .parent = "trim_percentage",
2561                 .hide   = 1,
2562                 .interval = 1,
2563                 .category = FIO_OPT_C_IO,
2564                 .group  = FIO_OPT_G_TRIM,
2565         },
2566 #endif
2567         {
2568                 .name   = "write_iolog",
2569                 .lname  = "Write I/O log",
2570                 .type   = FIO_OPT_STR_STORE,
2571                 .off1   = td_var_offset(write_iolog_file),
2572                 .help   = "Store IO pattern to file",
2573                 .category = FIO_OPT_C_IO,
2574                 .group  = FIO_OPT_G_IOLOG,
2575         },
2576         {
2577                 .name   = "read_iolog",
2578                 .lname  = "Read I/O log",
2579                 .type   = FIO_OPT_STR_STORE,
2580                 .off1   = td_var_offset(read_iolog_file),
2581                 .help   = "Playback IO pattern from file",
2582                 .category = FIO_OPT_C_IO,
2583                 .group  = FIO_OPT_G_IOLOG,
2584         },
2585         {
2586                 .name   = "replay_no_stall",
2587                 .lname  = "Don't stall on replay",
2588                 .type   = FIO_OPT_BOOL,
2589                 .off1   = td_var_offset(no_stall),
2590                 .def    = "0",
2591                 .parent = "read_iolog",
2592                 .hide   = 1,
2593                 .help   = "Playback IO pattern file as fast as possible without stalls",
2594                 .category = FIO_OPT_C_IO,
2595                 .group  = FIO_OPT_G_IOLOG,
2596         },
2597         {
2598                 .name   = "replay_redirect",
2599                 .lname  = "Redirect device for replay",
2600                 .type   = FIO_OPT_STR_STORE,
2601                 .off1   = td_var_offset(replay_redirect),
2602                 .parent = "read_iolog",
2603                 .hide   = 1,
2604                 .help   = "Replay all I/O onto this device, regardless of trace device",
2605                 .category = FIO_OPT_C_IO,
2606                 .group  = FIO_OPT_G_IOLOG,
2607         },
2608         {
2609                 .name   = "replay_scale",
2610                 .lname  = "Replace offset scale factor",
2611                 .type   = FIO_OPT_INT,
2612                 .off1   = td_var_offset(replay_scale),
2613                 .parent = "read_iolog",
2614                 .def    = "1",
2615                 .help   = "Align offsets to this blocksize",
2616                 .category = FIO_OPT_C_IO,
2617                 .group  = FIO_OPT_G_IOLOG,
2618         },
2619         {
2620                 .name   = "replay_align",
2621                 .lname  = "Replace alignment",
2622                 .type   = FIO_OPT_INT,
2623                 .off1   = td_var_offset(replay_align),
2624                 .parent = "read_iolog",
2625                 .help   = "Scale offset down by this factor",
2626                 .category = FIO_OPT_C_IO,
2627                 .group  = FIO_OPT_G_IOLOG,
2628                 .pow2   = 1,
2629         },
2630         {
2631                 .name   = "exec_prerun",
2632                 .lname  = "Pre-execute runnable",
2633                 .type   = FIO_OPT_STR_STORE,
2634                 .off1   = td_var_offset(exec_prerun),
2635                 .help   = "Execute this file prior to running job",
2636                 .category = FIO_OPT_C_GENERAL,
2637                 .group  = FIO_OPT_G_INVALID,
2638         },
2639         {
2640                 .name   = "exec_postrun",
2641                 .lname  = "Post-execute runnable",
2642                 .type   = FIO_OPT_STR_STORE,
2643                 .off1   = td_var_offset(exec_postrun),
2644                 .help   = "Execute this file after running job",
2645                 .category = FIO_OPT_C_GENERAL,
2646                 .group  = FIO_OPT_G_INVALID,
2647         },
2648 #ifdef FIO_HAVE_IOSCHED_SWITCH
2649         {
2650                 .name   = "ioscheduler",
2651                 .lname  = "I/O scheduler",
2652                 .type   = FIO_OPT_STR_STORE,
2653                 .off1   = td_var_offset(ioscheduler),
2654                 .help   = "Use this IO scheduler on the backing device",
2655                 .category = FIO_OPT_C_FILE,
2656                 .group  = FIO_OPT_G_INVALID,
2657         },
2658 #endif
2659         {
2660                 .name   = "zonesize",
2661                 .lname  = "Zone size",
2662                 .type   = FIO_OPT_STR_VAL,
2663                 .off1   = td_var_offset(zone_size),
2664                 .help   = "Amount of data to read per zone",
2665                 .def    = "0",
2666                 .interval = 1024 * 1024,
2667                 .category = FIO_OPT_C_IO,
2668                 .group  = FIO_OPT_G_ZONE,
2669         },
2670         {
2671                 .name   = "zonerange",
2672                 .lname  = "Zone range",
2673                 .type   = FIO_OPT_STR_VAL,
2674                 .off1   = td_var_offset(zone_range),
2675                 .help   = "Give size of an IO zone",
2676                 .def    = "0",
2677                 .interval = 1024 * 1024,
2678                 .category = FIO_OPT_C_IO,
2679                 .group  = FIO_OPT_G_ZONE,
2680         },
2681         {
2682                 .name   = "zoneskip",
2683                 .lname  = "Zone skip",
2684                 .type   = FIO_OPT_STR_VAL,
2685                 .off1   = td_var_offset(zone_skip),
2686                 .help   = "Space between IO zones",
2687                 .def    = "0",
2688                 .interval = 1024 * 1024,
2689                 .category = FIO_OPT_C_IO,
2690                 .group  = FIO_OPT_G_ZONE,
2691         },
2692         {
2693                 .name   = "lockmem",
2694                 .lname  = "Lock memory",
2695                 .type   = FIO_OPT_STR_VAL,
2696                 .off1   = td_var_offset(lockmem),
2697                 .help   = "Lock down this amount of memory (per worker)",
2698                 .def    = "0",
2699                 .interval = 1024 * 1024,
2700                 .category = FIO_OPT_C_GENERAL,
2701                 .group  = FIO_OPT_G_INVALID,
2702         },
2703         {
2704                 .name   = "rwmixread",
2705                 .lname  = "Read/write mix read",
2706                 .type   = FIO_OPT_INT,
2707                 .cb     = str_rwmix_read_cb,
2708                 .off1   = td_var_offset(rwmix[DDIR_READ]),
2709                 .maxval = 100,
2710                 .help   = "Percentage of mixed workload that is reads",
2711                 .def    = "50",
2712                 .interval = 5,
2713                 .inverse = "rwmixwrite",
2714                 .category = FIO_OPT_C_IO,
2715                 .group  = FIO_OPT_G_RWMIX,
2716         },
2717         {
2718                 .name   = "rwmixwrite",
2719                 .lname  = "Read/write mix write",
2720                 .type   = FIO_OPT_INT,
2721                 .cb     = str_rwmix_write_cb,
2722                 .off1   = td_var_offset(rwmix[DDIR_WRITE]),
2723                 .maxval = 100,
2724                 .help   = "Percentage of mixed workload that is writes",
2725                 .def    = "50",
2726                 .interval = 5,
2727                 .inverse = "rwmixread",
2728                 .category = FIO_OPT_C_IO,
2729                 .group  = FIO_OPT_G_RWMIX,
2730         },
2731         {
2732                 .name   = "rwmixcycle",
2733                 .lname  = "Read/write mix cycle",
2734                 .type   = FIO_OPT_DEPRECATED,
2735                 .category = FIO_OPT_C_IO,
2736                 .group  = FIO_OPT_G_RWMIX,
2737         },
2738         {
2739                 .name   = "nice",
2740                 .lname  = "Nice",
2741                 .type   = FIO_OPT_INT,
2742                 .off1   = td_var_offset(nice),
2743                 .help   = "Set job CPU nice value",
2744                 .minval = -19,
2745                 .maxval = 20,
2746                 .def    = "0",
2747                 .interval = 1,
2748                 .category = FIO_OPT_C_GENERAL,
2749                 .group  = FIO_OPT_G_CRED,
2750         },
2751 #ifdef FIO_HAVE_IOPRIO
2752         {
2753                 .name   = "prio",
2754                 .lname  = "I/O nice priority",
2755                 .type   = FIO_OPT_INT,
2756                 .off1   = td_var_offset(ioprio),
2757                 .help   = "Set job IO priority value",
2758                 .minval = 0,
2759                 .maxval = 7,
2760                 .interval = 1,
2761                 .category = FIO_OPT_C_GENERAL,
2762                 .group  = FIO_OPT_G_CRED,
2763         },
2764         {
2765                 .name   = "prioclass",
2766                 .lname  = "I/O nice priority class",
2767                 .type   = FIO_OPT_INT,
2768                 .off1   = td_var_offset(ioprio_class),
2769                 .help   = "Set job IO priority class",
2770                 .minval = 0,
2771                 .maxval = 3,
2772                 .interval = 1,
2773                 .category = FIO_OPT_C_GENERAL,
2774                 .group  = FIO_OPT_G_CRED,
2775         },
2776 #endif
2777         {
2778                 .name   = "thinktime",
2779                 .lname  = "Thinktime",
2780                 .type   = FIO_OPT_INT,
2781                 .off1   = td_var_offset(thinktime),
2782                 .help   = "Idle time between IO buffers (usec)",
2783                 .def    = "0",
2784                 .is_time = 1,
2785                 .category = FIO_OPT_C_IO,
2786                 .group  = FIO_OPT_G_THINKTIME,
2787         },
2788         {
2789                 .name   = "thinktime_spin",
2790                 .lname  = "Thinktime spin",
2791                 .type   = FIO_OPT_INT,
2792                 .off1   = td_var_offset(thinktime_spin),
2793                 .help   = "Start think time by spinning this amount (usec)",
2794                 .def    = "0",
2795                 .is_time = 1,
2796                 .parent = "thinktime",
2797                 .hide   = 1,
2798                 .category = FIO_OPT_C_IO,
2799                 .group  = FIO_OPT_G_THINKTIME,
2800         },
2801         {
2802                 .name   = "thinktime_blocks",
2803                 .lname  = "Thinktime blocks",
2804                 .type   = FIO_OPT_INT,
2805                 .off1   = td_var_offset(thinktime_blocks),
2806                 .help   = "IO buffer period between 'thinktime'",
2807                 .def    = "1",
2808                 .parent = "thinktime",
2809                 .hide   = 1,
2810                 .category = FIO_OPT_C_IO,
2811                 .group  = FIO_OPT_G_THINKTIME,
2812         },
2813         {
2814                 .name   = "rate",
2815                 .lname  = "I/O rate",
2816                 .type   = FIO_OPT_INT,
2817                 .off1   = td_var_offset(rate[DDIR_READ]),
2818                 .off2   = td_var_offset(rate[DDIR_WRITE]),
2819                 .off3   = td_var_offset(rate[DDIR_TRIM]),
2820                 .help   = "Set bandwidth rate",
2821                 .category = FIO_OPT_C_IO,
2822                 .group  = FIO_OPT_G_RATE,
2823         },
2824         {
2825                 .name   = "rate_min",
2826                 .alias  = "ratemin",
2827                 .lname  = "I/O min rate",
2828                 .type   = FIO_OPT_INT,
2829                 .off1   = td_var_offset(ratemin[DDIR_READ]),
2830                 .off2   = td_var_offset(ratemin[DDIR_WRITE]),
2831                 .off3   = td_var_offset(ratemin[DDIR_TRIM]),
2832                 .help   = "Job must meet this rate or it will be shutdown",
2833                 .parent = "rate",
2834                 .hide   = 1,
2835                 .category = FIO_OPT_C_IO,
2836                 .group  = FIO_OPT_G_RATE,
2837         },
2838         {
2839                 .name   = "rate_iops",
2840                 .lname  = "I/O rate IOPS",
2841                 .type   = FIO_OPT_INT,
2842                 .off1   = td_var_offset(rate_iops[DDIR_READ]),
2843                 .off2   = td_var_offset(rate_iops[DDIR_WRITE]),
2844                 .off3   = td_var_offset(rate_iops[DDIR_TRIM]),
2845                 .help   = "Limit IO used to this number of IO operations/sec",
2846                 .hide   = 1,
2847                 .category = FIO_OPT_C_IO,
2848                 .group  = FIO_OPT_G_RATE,
2849         },
2850         {
2851                 .name   = "rate_iops_min",
2852                 .lname  = "I/O min rate IOPS",
2853                 .type   = FIO_OPT_INT,
2854                 .off1   = td_var_offset(rate_iops_min[DDIR_READ]),
2855                 .off2   = td_var_offset(rate_iops_min[DDIR_WRITE]),
2856                 .off3   = td_var_offset(rate_iops_min[DDIR_TRIM]),
2857                 .help   = "Job must meet this rate or it will be shut down",
2858                 .parent = "rate_iops",
2859                 .hide   = 1,
2860                 .category = FIO_OPT_C_IO,
2861                 .group  = FIO_OPT_G_RATE,
2862         },
2863         {
2864                 .name   = "rate_process",
2865                 .lname  = "Rate Process",
2866                 .type   = FIO_OPT_STR,
2867                 .off1   = td_var_offset(rate_process),
2868                 .help   = "What process controls how rated IO is managed",
2869                 .def    = "linear",
2870                 .category = FIO_OPT_C_IO,
2871                 .group  = FIO_OPT_G_RATE,
2872                 .posval = {
2873                           { .ival = "linear",
2874                             .oval = RATE_PROCESS_LINEAR,
2875                             .help = "Linear rate of IO",
2876                           },
2877                           {
2878                             .ival = "poisson",
2879                             .oval = RATE_PROCESS_POISSON,
2880                             .help = "Rate follows Poisson process",
2881                           },
2882                 },
2883                 .parent = "rate",
2884         },
2885         {
2886                 .name   = "rate_cycle",
2887                 .alias  = "ratecycle",
2888                 .lname  = "I/O rate cycle",
2889                 .type   = FIO_OPT_INT,
2890                 .off1   = td_var_offset(ratecycle),
2891                 .help   = "Window average for rate limits (msec)",
2892                 .def    = "1000",
2893                 .parent = "rate",
2894                 .hide   = 1,
2895                 .category = FIO_OPT_C_IO,
2896                 .group  = FIO_OPT_G_RATE,
2897         },
2898         {
2899                 .name   = "max_latency",
2900                 .type   = FIO_OPT_INT,
2901                 .off1   = td_var_offset(max_latency),
2902                 .help   = "Maximum tolerated IO latency (usec)",
2903                 .is_time = 1,
2904                 .category = FIO_OPT_C_IO,
2905                 .group = FIO_OPT_G_LATPROF,
2906         },
2907         {
2908                 .name   = "latency_target",
2909                 .lname  = "Latency Target (usec)",
2910                 .type   = FIO_OPT_STR_VAL_TIME,
2911                 .off1   = td_var_offset(latency_target),
2912                 .help   = "Ramp to max queue depth supporting this latency",
2913                 .is_time = 1,
2914                 .category = FIO_OPT_C_IO,
2915                 .group  = FIO_OPT_G_LATPROF,
2916         },
2917         {
2918                 .name   = "latency_window",
2919                 .lname  = "Latency Window (usec)",
2920                 .type   = FIO_OPT_STR_VAL_TIME,
2921                 .off1   = td_var_offset(latency_window),
2922                 .help   = "Time to sustain latency_target",
2923                 .is_time = 1,
2924                 .category = FIO_OPT_C_IO,
2925                 .group  = FIO_OPT_G_LATPROF,
2926         },
2927         {
2928                 .name   = "latency_percentile",
2929                 .lname  = "Latency Percentile",
2930                 .type   = FIO_OPT_FLOAT_LIST,
2931                 .off1   = td_var_offset(latency_percentile),
2932                 .help   = "Percentile of IOs must be below latency_target",
2933                 .def    = "100",
2934                 .maxlen = 1,
2935                 .minfp  = 0.0,
2936                 .maxfp  = 100.0,
2937                 .category = FIO_OPT_C_IO,
2938                 .group  = FIO_OPT_G_LATPROF,
2939         },
2940         {
2941                 .name   = "invalidate",
2942                 .lname  = "Cache invalidate",
2943                 .type   = FIO_OPT_BOOL,
2944                 .off1   = td_var_offset(invalidate_cache),
2945                 .help   = "Invalidate buffer/page cache prior to running job",
2946                 .def    = "1",
2947                 .category = FIO_OPT_C_IO,
2948                 .group  = FIO_OPT_G_IO_TYPE,
2949         },
2950         {
2951                 .name   = "sync",
2952                 .lname  = "Synchronous I/O",
2953                 .type   = FIO_OPT_BOOL,
2954                 .off1   = td_var_offset(sync_io),
2955                 .help   = "Use O_SYNC for buffered writes",
2956                 .def    = "0",
2957                 .parent = "buffered",
2958                 .hide   = 1,
2959                 .category = FIO_OPT_C_IO,
2960                 .group  = FIO_OPT_G_IO_TYPE,
2961         },
2962         {
2963                 .name   = "create_serialize",
2964                 .lname  = "Create serialize",
2965                 .type   = FIO_OPT_BOOL,
2966                 .off1   = td_var_offset(create_serialize),
2967                 .help   = "Serialize creating of job files",
2968                 .def    = "1",
2969                 .category = FIO_OPT_C_FILE,
2970                 .group  = FIO_OPT_G_INVALID,
2971         },
2972         {
2973                 .name   = "create_fsync",
2974                 .lname  = "Create fsync",
2975                 .type   = FIO_OPT_BOOL,
2976                 .off1   = td_var_offset(create_fsync),
2977                 .help   = "fsync file after creation",
2978                 .def    = "1",
2979                 .category = FIO_OPT_C_FILE,
2980                 .group  = FIO_OPT_G_INVALID,
2981         },
2982         {
2983                 .name   = "create_on_open",
2984                 .lname  = "Create on open",
2985                 .type   = FIO_OPT_BOOL,
2986                 .off1   = td_var_offset(create_on_open),
2987                 .help   = "Create files when they are opened for IO",
2988                 .def    = "0",
2989                 .category = FIO_OPT_C_FILE,
2990                 .group  = FIO_OPT_G_INVALID,
2991         },
2992         {
2993                 .name   = "create_only",
2994                 .type   = FIO_OPT_BOOL,
2995                 .off1   = td_var_offset(create_only),
2996                 .help   = "Only perform file creation phase",
2997                 .category = FIO_OPT_C_FILE,
2998                 .def    = "0",
2999         },
3000         {
3001                 .name   = "allow_file_create",
3002                 .lname  = "Allow file create",
3003                 .type   = FIO_OPT_BOOL,
3004                 .off1   = td_var_offset(allow_create),
3005                 .help   = "Permit fio to create files, if they don't exist",
3006                 .def    = "1",
3007                 .category = FIO_OPT_C_FILE,
3008                 .group  = FIO_OPT_G_FILENAME,
3009         },
3010         {
3011                 .name   = "allow_mounted_write",
3012                 .lname  = "Allow mounted write",
3013                 .type   = FIO_OPT_BOOL,
3014                 .off1   = td_var_offset(allow_mounted_write),
3015                 .help   = "Allow writes to a mounted partition",
3016                 .def    = "0",
3017                 .category = FIO_OPT_C_FILE,
3018                 .group  = FIO_OPT_G_FILENAME,
3019         },
3020         {
3021                 .name   = "pre_read",
3022                 .lname  = "Pre-read files",
3023                 .type   = FIO_OPT_BOOL,
3024                 .off1   = td_var_offset(pre_read),
3025                 .help   = "Pre-read files before starting official testing",
3026                 .def    = "0",
3027                 .category = FIO_OPT_C_FILE,
3028                 .group  = FIO_OPT_G_INVALID,
3029         },
3030 #ifdef FIO_HAVE_CPU_AFFINITY
3031         {
3032                 .name   = "cpumask",
3033                 .lname  = "CPU mask",
3034                 .type   = FIO_OPT_INT,
3035                 .cb     = str_cpumask_cb,
3036                 .off1   = td_var_offset(cpumask),
3037                 .help   = "CPU affinity mask",
3038                 .category = FIO_OPT_C_GENERAL,
3039                 .group  = FIO_OPT_G_CRED,
3040         },
3041         {
3042                 .name   = "cpus_allowed",
3043                 .lname  = "CPUs allowed",
3044                 .type   = FIO_OPT_STR,
3045                 .cb     = str_cpus_allowed_cb,
3046                 .off1   = td_var_offset(cpumask),
3047                 .help   = "Set CPUs allowed",
3048                 .category = FIO_OPT_C_GENERAL,
3049                 .group  = FIO_OPT_G_CRED,
3050         },
3051         {
3052                 .name   = "cpus_allowed_policy",
3053                 .lname  = "CPUs allowed distribution policy",
3054                 .type   = FIO_OPT_STR,
3055                 .off1   = td_var_offset(cpus_allowed_policy),
3056                 .help   = "Distribution policy for cpus_allowed",
3057                 .parent = "cpus_allowed",
3058                 .prio   = 1,
3059                 .posval = {
3060                           { .ival = "shared",
3061                             .oval = FIO_CPUS_SHARED,
3062                             .help = "Mask shared between threads",
3063                           },
3064                           { .ival = "split",
3065                             .oval = FIO_CPUS_SPLIT,
3066                             .help = "Mask split between threads",
3067                           },
3068                 },
3069                 .category = FIO_OPT_C_GENERAL,
3070                 .group  = FIO_OPT_G_CRED,
3071         },
3072 #endif
3073 #ifdef CONFIG_LIBNUMA
3074         {
3075                 .name   = "numa_cpu_nodes",
3076                 .type   = FIO_OPT_STR,
3077                 .cb     = str_numa_cpunodes_cb,
3078                 .off1   = td_var_offset(numa_cpunodes),
3079                 .help   = "NUMA CPU nodes bind",
3080                 .category = FIO_OPT_C_GENERAL,
3081                 .group  = FIO_OPT_G_INVALID,
3082         },
3083         {
3084                 .name   = "numa_mem_policy",
3085                 .type   = FIO_OPT_STR,
3086                 .cb     = str_numa_mpol_cb,
3087                 .off1   = td_var_offset(numa_memnodes),
3088                 .help   = "NUMA memory policy setup",
3089                 .category = FIO_OPT_C_GENERAL,
3090                 .group  = FIO_OPT_G_INVALID,
3091         },
3092 #endif
3093         {
3094                 .name   = "end_fsync",
3095                 .lname  = "End fsync",
3096                 .type   = FIO_OPT_BOOL,
3097                 .off1   = td_var_offset(end_fsync),
3098                 .help   = "Include fsync at the end of job",
3099                 .def    = "0",
3100                 .category = FIO_OPT_C_FILE,
3101                 .group  = FIO_OPT_G_INVALID,
3102         },
3103         {
3104                 .name   = "fsync_on_close",
3105                 .lname  = "Fsync on close",
3106                 .type   = FIO_OPT_BOOL,
3107                 .off1   = td_var_offset(fsync_on_close),
3108                 .help   = "fsync files on close",
3109                 .def    = "0",
3110                 .category = FIO_OPT_C_FILE,
3111                 .group  = FIO_OPT_G_INVALID,
3112         },
3113         {
3114                 .name   = "unlink",
3115                 .lname  = "Unlink file",
3116                 .type   = FIO_OPT_BOOL,
3117                 .off1   = td_var_offset(unlink),
3118                 .help   = "Unlink created files after job has completed",
3119                 .def    = "0",
3120                 .category = FIO_OPT_C_FILE,
3121                 .group  = FIO_OPT_G_INVALID,
3122         },
3123         {
3124                 .name   = "exitall",
3125                 .lname  = "Exit-all on terminate",
3126                 .type   = FIO_OPT_STR_SET,
3127                 .cb     = str_exitall_cb,
3128                 .help   = "Terminate all jobs when one exits",
3129                 .category = FIO_OPT_C_GENERAL,
3130                 .group  = FIO_OPT_G_PROCESS,
3131         },
3132         {
3133                 .name   = "stonewall",
3134                 .lname  = "Wait for previous",
3135                 .alias  = "wait_for_previous",
3136                 .type   = FIO_OPT_STR_SET,
3137                 .off1   = td_var_offset(stonewall),
3138                 .help   = "Insert a hard barrier between this job and previous",
3139                 .category = FIO_OPT_C_GENERAL,
3140                 .group  = FIO_OPT_G_PROCESS,
3141         },
3142         {
3143                 .name   = "new_group",
3144                 .lname  = "New group",
3145                 .type   = FIO_OPT_STR_SET,
3146                 .off1   = td_var_offset(new_group),
3147                 .help   = "Mark the start of a new group (for reporting)",
3148                 .category = FIO_OPT_C_GENERAL,
3149                 .group  = FIO_OPT_G_PROCESS,
3150         },
3151         {
3152                 .name   = "thread",
3153                 .lname  = "Thread",
3154                 .type   = FIO_OPT_STR_SET,
3155                 .off1   = td_var_offset(use_thread),
3156                 .help   = "Use threads instead of processes",
3157 #ifdef CONFIG_NO_SHM
3158                 .def    = "1",
3159                 .no_warn_def = 1,
3160 #endif
3161                 .category = FIO_OPT_C_GENERAL,
3162                 .group  = FIO_OPT_G_PROCESS,
3163         },
3164         {
3165                 .name   = "per_job_logs",
3166                 .type   = FIO_OPT_BOOL,
3167                 .off1   = td_var_offset(per_job_logs),
3168                 .help   = "Include job number in generated log files or not",
3169                 .def    = "1",
3170                 .category = FIO_OPT_C_LOG,
3171                 .group  = FIO_OPT_G_INVALID,
3172         },
3173         {
3174                 .name   = "write_bw_log",
3175                 .lname  = "Write bandwidth log",
3176                 .type   = FIO_OPT_STR_STORE,
3177                 .off1   = td_var_offset(bw_log_file),
3178                 .help   = "Write log of bandwidth during run",
3179                 .category = FIO_OPT_C_LOG,
3180                 .group  = FIO_OPT_G_INVALID,
3181         },
3182         {
3183                 .name   = "write_lat_log",
3184                 .lname  = "Write latency log",
3185                 .type   = FIO_OPT_STR_STORE,
3186                 .off1   = td_var_offset(lat_log_file),
3187                 .help   = "Write log of latency during run",
3188                 .category = FIO_OPT_C_LOG,
3189                 .group  = FIO_OPT_G_INVALID,
3190         },
3191         {
3192                 .name   = "write_iops_log",
3193                 .lname  = "Write IOPS log",
3194                 .type   = FIO_OPT_STR_STORE,
3195                 .off1   = td_var_offset(iops_log_file),
3196                 .help   = "Write log of IOPS during run",
3197                 .category = FIO_OPT_C_LOG,
3198                 .group  = FIO_OPT_G_INVALID,
3199         },
3200         {
3201                 .name   = "log_avg_msec",
3202                 .lname  = "Log averaging (msec)",
3203                 .type   = FIO_OPT_INT,
3204                 .off1   = td_var_offset(log_avg_msec),
3205                 .help   = "Average bw/iops/lat logs over this period of time",
3206                 .def    = "0",
3207                 .category = FIO_OPT_C_LOG,
3208                 .group  = FIO_OPT_G_INVALID,
3209         },
3210         {
3211                 .name   = "log_offset",
3212                 .lname  = "Log offset of IO",
3213                 .type   = FIO_OPT_BOOL,
3214                 .off1   = td_var_offset(log_offset),
3215                 .help   = "Include offset of IO for each log entry",
3216                 .def    = "0",
3217                 .category = FIO_OPT_C_LOG,
3218                 .group  = FIO_OPT_G_INVALID,
3219         },
3220 #ifdef CONFIG_ZLIB
3221         {
3222                 .name   = "log_compression",
3223                 .lname  = "Log compression",
3224                 .type   = FIO_OPT_INT,
3225                 .off1   = td_var_offset(log_gz),
3226                 .help   = "Log in compressed chunks of this size",
3227                 .minval = 1024ULL,
3228                 .maxval = 512 * 1024 * 1024ULL,
3229                 .category = FIO_OPT_C_LOG,
3230                 .group  = FIO_OPT_G_INVALID,
3231         },
3232         {
3233                 .name   = "log_store_compressed",
3234                 .lname  = "Log store compressed",
3235                 .type   = FIO_OPT_BOOL,
3236                 .off1   = td_var_offset(log_gz_store),
3237                 .help   = "Store logs in a compressed format",
3238                 .category = FIO_OPT_C_LOG,
3239                 .group  = FIO_OPT_G_INVALID,
3240         },
3241 #endif
3242         {
3243                 .name   = "block_error_percentiles",
3244                 .lname  = "Block error percentiles",
3245                 .type   = FIO_OPT_BOOL,
3246                 .off1   = td_var_offset(block_error_hist),
3247                 .help   = "Record trim block errors and make a histogram",
3248                 .def    = "0",
3249                 .category = FIO_OPT_C_LOG,
3250                 .group  = FIO_OPT_G_INVALID,
3251         },
3252         {
3253                 .name   = "bwavgtime",
3254                 .lname  = "Bandwidth average time",
3255                 .type   = FIO_OPT_INT,
3256                 .off1   = td_var_offset(bw_avg_time),
3257                 .help   = "Time window over which to calculate bandwidth"
3258                           " (msec)",
3259                 .def    = "500",
3260                 .parent = "write_bw_log",
3261                 .hide   = 1,
3262                 .interval = 100,
3263                 .category = FIO_OPT_C_LOG,
3264                 .group  = FIO_OPT_G_INVALID,
3265         },
3266         {
3267                 .name   = "iopsavgtime",
3268                 .lname  = "IOPS average time",
3269                 .type   = FIO_OPT_INT,
3270                 .off1   = td_var_offset(iops_avg_time),
3271                 .help   = "Time window over which to calculate IOPS (msec)",
3272                 .def    = "500",
3273                 .parent = "write_iops_log",
3274                 .hide   = 1,
3275                 .interval = 100,
3276                 .category = FIO_OPT_C_LOG,
3277                 .group  = FIO_OPT_G_INVALID,
3278         },
3279         {
3280                 .name   = "group_reporting",
3281                 .lname  = "Group reporting",
3282                 .type   = FIO_OPT_STR_SET,
3283                 .off1   = td_var_offset(group_reporting),
3284                 .help   = "Do reporting on a per-group basis",
3285                 .category = FIO_OPT_C_STAT,
3286                 .group  = FIO_OPT_G_INVALID,
3287         },
3288         {
3289                 .name   = "zero_buffers",
3290                 .lname  = "Zero I/O buffers",
3291                 .type   = FIO_OPT_STR_SET,
3292                 .off1   = td_var_offset(zero_buffers),
3293                 .help   = "Init IO buffers to all zeroes",
3294                 .category = FIO_OPT_C_IO,
3295                 .group  = FIO_OPT_G_IO_BUF,
3296         },
3297         {
3298                 .name   = "refill_buffers",
3299                 .lname  = "Refill I/O buffers",
3300                 .type   = FIO_OPT_STR_SET,
3301                 .off1   = td_var_offset(refill_buffers),
3302                 .help   = "Refill IO buffers on every IO submit",
3303                 .category = FIO_OPT_C_IO,
3304                 .group  = FIO_OPT_G_IO_BUF,
3305         },
3306         {
3307                 .name   = "scramble_buffers",
3308                 .lname  = "Scramble I/O buffers",
3309                 .type   = FIO_OPT_BOOL,
3310                 .off1   = td_var_offset(scramble_buffers),
3311                 .help   = "Slightly scramble buffers on every IO submit",
3312                 .def    = "1",
3313                 .category = FIO_OPT_C_IO,
3314                 .group  = FIO_OPT_G_IO_BUF,
3315         },
3316         {
3317                 .name   = "buffer_pattern",
3318                 .lname  = "Buffer pattern",
3319                 .type   = FIO_OPT_STR,
3320                 .cb     = str_buffer_pattern_cb,
3321                 .off1   = td_var_offset(buffer_pattern),
3322                 .help   = "Fill pattern for IO buffers",
3323                 .category = FIO_OPT_C_IO,
3324                 .group  = FIO_OPT_G_IO_BUF,
3325         },
3326         {
3327                 .name   = "buffer_compress_percentage",
3328                 .lname  = "Buffer compression percentage",
3329                 .type   = FIO_OPT_INT,
3330                 .cb     = str_buffer_compress_cb,
3331                 .off1   = td_var_offset(compress_percentage),
3332                 .maxval = 100,
3333                 .minval = 0,
3334                 .help   = "How compressible the buffer is (approximately)",
3335                 .interval = 5,
3336                 .category = FIO_OPT_C_IO,
3337                 .group  = FIO_OPT_G_IO_BUF,
3338         },
3339         {
3340                 .name   = "buffer_compress_chunk",
3341                 .lname  = "Buffer compression chunk size",
3342                 .type   = FIO_OPT_INT,
3343                 .off1   = td_var_offset(compress_chunk),
3344                 .parent = "buffer_compress_percentage",
3345                 .hide   = 1,
3346                 .help   = "Size of compressible region in buffer",
3347                 .interval = 256,
3348                 .category = FIO_OPT_C_IO,
3349                 .group  = FIO_OPT_G_IO_BUF,
3350         },
3351         {
3352                 .name   = "dedupe_percentage",
3353                 .lname  = "Dedupe percentage",
3354                 .type   = FIO_OPT_INT,
3355                 .cb     = str_dedupe_cb,
3356                 .off1   = td_var_offset(dedupe_percentage),
3357                 .maxval = 100,
3358                 .minval = 0,
3359                 .help   = "Percentage of buffers that are dedupable",
3360                 .interval = 1,
3361                 .category = FIO_OPT_C_IO,
3362                 .group  = FIO_OPT_G_IO_BUF,
3363         },
3364         {
3365                 .name   = "clat_percentiles",
3366                 .lname  = "Completion latency percentiles",
3367                 .type   = FIO_OPT_BOOL,
3368                 .off1   = td_var_offset(clat_percentiles),
3369                 .help   = "Enable the reporting of completion latency percentiles",
3370                 .def    = "1",
3371                 .category = FIO_OPT_C_STAT,
3372                 .group  = FIO_OPT_G_INVALID,
3373         },
3374         {
3375                 .name   = "percentile_list",
3376                 .lname  = "Percentile list",
3377                 .type   = FIO_OPT_FLOAT_LIST,
3378                 .off1   = td_var_offset(percentile_list),
3379                 .off2   = td_var_offset(percentile_precision),
3380                 .help   = "Specify a custom list of percentiles to report for "
3381                           "completion latency and block errors",
3382                 .def    = "1:5:10:20:30:40:50:60:70:80:90:95:99:99.5:99.9:99.95:99.99",
3383                 .maxlen = FIO_IO_U_LIST_MAX_LEN,
3384                 .minfp  = 0.0,
3385                 .maxfp  = 100.0,
3386                 .category = FIO_OPT_C_STAT,
3387                 .group  = FIO_OPT_G_INVALID,
3388         },
3389
3390 #ifdef FIO_HAVE_DISK_UTIL
3391         {
3392                 .name   = "disk_util",
3393                 .lname  = "Disk utilization",
3394                 .type   = FIO_OPT_BOOL,
3395                 .off1   = td_var_offset(do_disk_util),
3396                 .help   = "Log disk utilization statistics",
3397                 .def    = "1",
3398                 .category = FIO_OPT_C_STAT,
3399                 .group  = FIO_OPT_G_INVALID,
3400         },
3401 #endif
3402         {
3403                 .name   = "gtod_reduce",
3404                 .lname  = "Reduce gettimeofday() calls",
3405                 .type   = FIO_OPT_BOOL,
3406                 .help   = "Greatly reduce number of gettimeofday() calls",
3407                 .cb     = str_gtod_reduce_cb,
3408                 .def    = "0",
3409                 .hide_on_set = 1,
3410                 .category = FIO_OPT_C_STAT,
3411                 .group  = FIO_OPT_G_INVALID,
3412         },
3413         {
3414                 .name   = "disable_lat",
3415                 .lname  = "Disable all latency stats",
3416                 .type   = FIO_OPT_BOOL,
3417                 .off1   = td_var_offset(disable_lat),
3418                 .help   = "Disable latency numbers",
3419                 .parent = "gtod_reduce",
3420                 .hide   = 1,
3421                 .def    = "0",
3422                 .category = FIO_OPT_C_STAT,
3423                 .group  = FIO_OPT_G_INVALID,
3424         },
3425         {
3426                 .name   = "disable_clat",
3427                 .lname  = "Disable completion latency stats",
3428                 .type   = FIO_OPT_BOOL,
3429                 .off1   = td_var_offset(disable_clat),
3430                 .help   = "Disable completion latency numbers",
3431                 .parent = "gtod_reduce",
3432                 .hide   = 1,
3433                 .def    = "0",
3434                 .category = FIO_OPT_C_STAT,
3435                 .group  = FIO_OPT_G_INVALID,
3436         },
3437         {
3438                 .name   = "disable_slat",
3439                 .lname  = "Disable submission latency stats",
3440                 .type   = FIO_OPT_BOOL,
3441                 .off1   = td_var_offset(disable_slat),
3442                 .help   = "Disable submission latency numbers",
3443                 .parent = "gtod_reduce",
3444                 .hide   = 1,
3445                 .def    = "0",
3446                 .category = FIO_OPT_C_STAT,
3447                 .group  = FIO_OPT_G_INVALID,
3448         },
3449         {
3450                 .name   = "disable_bw_measurement",
3451                 .lname  = "Disable bandwidth stats",
3452                 .type   = FIO_OPT_BOOL,
3453                 .off1   = td_var_offset(disable_bw),
3454                 .help   = "Disable bandwidth logging",
3455                 .parent = "gtod_reduce",
3456                 .hide   = 1,
3457                 .def    = "0",
3458                 .category = FIO_OPT_C_STAT,
3459                 .group  = FIO_OPT_G_INVALID,
3460         },
3461         {
3462                 .name   = "gtod_cpu",
3463                 .lname  = "Dedicated gettimeofday() CPU",
3464                 .type   = FIO_OPT_INT,
3465                 .off1   = td_var_offset(gtod_cpu),
3466                 .help   = "Set up dedicated gettimeofday() thread on this CPU",
3467                 .verify = gtod_cpu_verify,
3468                 .category = FIO_OPT_C_GENERAL,
3469                 .group  = FIO_OPT_G_CLOCK,
3470         },
3471         {
3472                 .name   = "unified_rw_reporting",
3473                 .type   = FIO_OPT_BOOL,
3474                 .off1   = td_var_offset(unified_rw_rep),
3475                 .help   = "Unify reporting across data direction",
3476                 .def    = "0",
3477                 .category = FIO_OPT_C_GENERAL,
3478                 .group  = FIO_OPT_G_INVALID,
3479         },
3480         {
3481                 .name   = "continue_on_error",
3482                 .lname  = "Continue on error",
3483                 .type   = FIO_OPT_STR,
3484                 .off1   = td_var_offset(continue_on_error),
3485                 .help   = "Continue on non-fatal errors during IO",
3486                 .def    = "none",
3487                 .category = FIO_OPT_C_GENERAL,
3488                 .group  = FIO_OPT_G_ERR,
3489                 .posval = {
3490                           { .ival = "none",
3491                             .oval = ERROR_TYPE_NONE,
3492                             .help = "Exit when an error is encountered",
3493                           },
3494                           { .ival = "read",
3495                             .oval = ERROR_TYPE_READ,
3496                             .help = "Continue on read errors only",
3497                           },
3498                           { .ival = "write",
3499                             .oval = ERROR_TYPE_WRITE,
3500                             .help = "Continue on write errors only",
3501                           },
3502                           { .ival = "io",
3503                             .oval = ERROR_TYPE_READ | ERROR_TYPE_WRITE,
3504                             .help = "Continue on any IO errors",
3505                           },
3506                           { .ival = "verify",
3507                             .oval = ERROR_TYPE_VERIFY,
3508                             .help = "Continue on verify errors only",
3509                           },
3510                           { .ival = "all",
3511                             .oval = ERROR_TYPE_ANY,
3512                             .help = "Continue on all io and verify errors",
3513                           },
3514                           { .ival = "0",
3515                             .oval = ERROR_TYPE_NONE,
3516                             .help = "Alias for 'none'",
3517                           },
3518                           { .ival = "1",
3519                             .oval = ERROR_TYPE_ANY,
3520                             .help = "Alias for 'all'",
3521                           },
3522                 },
3523         },
3524         {
3525                 .name   = "ignore_error",
3526                 .type   = FIO_OPT_STR,
3527                 .cb     = str_ignore_error_cb,
3528                 .off1   = td_var_offset(ignore_error_nr),
3529                 .help   = "Set a specific list of errors to ignore",
3530                 .parent = "rw",
3531                 .category = FIO_OPT_C_GENERAL,
3532                 .group  = FIO_OPT_G_ERR,
3533         },
3534         {
3535                 .name   = "error_dump",
3536                 .type   = FIO_OPT_BOOL,
3537                 .off1   = td_var_offset(error_dump),
3538                 .def    = "0",
3539                 .help   = "Dump info on each error",
3540                 .category = FIO_OPT_C_GENERAL,
3541                 .group  = FIO_OPT_G_ERR,
3542         },
3543         {
3544                 .name   = "profile",
3545                 .lname  = "Profile",
3546                 .type   = FIO_OPT_STR_STORE,
3547                 .off1   = td_var_offset(profile),
3548                 .help   = "Select a specific builtin performance test",
3549                 .category = FIO_OPT_C_PROFILE,
3550                 .group  = FIO_OPT_G_INVALID,
3551         },
3552         {
3553                 .name   = "cgroup",
3554                 .lname  = "Cgroup",
3555                 .type   = FIO_OPT_STR_STORE,
3556                 .off1   = td_var_offset(cgroup),
3557                 .help   = "Add job to cgroup of this name",
3558                 .category = FIO_OPT_C_GENERAL,
3559                 .group  = FIO_OPT_G_CGROUP,
3560         },
3561         {
3562                 .name   = "cgroup_nodelete",
3563                 .lname  = "Cgroup no-delete",
3564                 .type   = FIO_OPT_BOOL,
3565                 .off1   = td_var_offset(cgroup_nodelete),
3566                 .help   = "Do not delete cgroups after job completion",
3567                 .def    = "0",
3568                 .parent = "cgroup",
3569                 .category = FIO_OPT_C_GENERAL,
3570                 .group  = FIO_OPT_G_CGROUP,
3571         },
3572         {
3573                 .name   = "cgroup_weight",
3574                 .lname  = "Cgroup weight",
3575                 .type   = FIO_OPT_INT,
3576                 .off1   = td_var_offset(cgroup_weight),
3577                 .help   = "Use given weight for cgroup",
3578                 .minval = 100,
3579                 .maxval = 1000,
3580                 .parent = "cgroup",
3581                 .category = FIO_OPT_C_GENERAL,
3582                 .group  = FIO_OPT_G_CGROUP,
3583         },
3584         {
3585                 .name   = "uid",
3586                 .lname  = "User ID",
3587                 .type   = FIO_OPT_INT,
3588                 .off1   = td_var_offset(uid),
3589                 .help   = "Run job with this user ID",
3590                 .category = FIO_OPT_C_GENERAL,
3591                 .group  = FIO_OPT_G_CRED,
3592         },
3593         {
3594                 .name   = "gid",
3595                 .lname  = "Group ID",
3596                 .type   = FIO_OPT_INT,
3597                 .off1   = td_var_offset(gid),
3598                 .help   = "Run job with this group ID",
3599                 .category = FIO_OPT_C_GENERAL,
3600                 .group  = FIO_OPT_G_CRED,
3601         },
3602         {
3603                 .name   = "kb_base",
3604                 .lname  = "KB Base",
3605                 .type   = FIO_OPT_INT,
3606                 .off1   = td_var_offset(kb_base),
3607                 .prio   = 1,
3608                 .def    = "1024",
3609                 .posval = {
3610                           { .ival = "1024",
3611                             .oval = 1024,
3612                             .help = "Use 1024 as the K base",
3613                           },
3614                           { .ival = "1000",
3615                             .oval = 1000,
3616                             .help = "Use 1000 as the K base",
3617                           },
3618                 },
3619                 .help   = "How many bytes per KB for reporting (1000 or 1024)",
3620                 .category = FIO_OPT_C_GENERAL,
3621                 .group  = FIO_OPT_G_INVALID,
3622         },
3623         {
3624                 .name   = "unit_base",
3625                 .lname  = "Base unit for reporting (Bits or Bytes)",
3626                 .type   = FIO_OPT_INT,
3627                 .off1   = td_var_offset(unit_base),
3628                 .prio   = 1,
3629                 .posval = {
3630                           { .ival = "0",
3631                             .oval = 0,
3632                             .help = "Auto-detect",
3633                           },
3634                           { .ival = "8",
3635                             .oval = 8,
3636                             .help = "Normal (byte based)",
3637                           },
3638                           { .ival = "1",
3639                             .oval = 1,
3640                             .help = "Bit based",
3641                           },
3642                 },
3643                 .help   = "Bit multiple of result summary data (8 for byte, 1 for bit)",
3644                 .category = FIO_OPT_C_GENERAL,
3645                 .group  = FIO_OPT_G_INVALID,
3646         },
3647         {
3648                 .name   = "hugepage-size",
3649                 .lname  = "Hugepage size",
3650                 .type   = FIO_OPT_INT,
3651                 .off1   = td_var_offset(hugepage_size),
3652                 .help   = "When using hugepages, specify size of each page",
3653                 .def    = __fio_stringify(FIO_HUGE_PAGE),
3654                 .interval = 1024 * 1024,
3655                 .category = FIO_OPT_C_GENERAL,
3656                 .group  = FIO_OPT_G_INVALID,
3657         },
3658         {
3659                 .name   = "flow_id",
3660                 .lname  = "I/O flow ID",
3661                 .type   = FIO_OPT_INT,
3662                 .off1   = td_var_offset(flow_id),
3663                 .help   = "The flow index ID to use",
3664                 .def    = "0",
3665                 .category = FIO_OPT_C_IO,
3666                 .group  = FIO_OPT_G_IO_FLOW,
3667         },
3668         {
3669                 .name   = "flow",
3670                 .lname  = "I/O flow weight",
3671                 .type   = FIO_OPT_INT,
3672                 .off1   = td_var_offset(flow),
3673                 .help   = "Weight for flow control of this job",
3674                 .parent = "flow_id",
3675                 .hide   = 1,
3676                 .def    = "0",
3677                 .category = FIO_OPT_C_IO,
3678                 .group  = FIO_OPT_G_IO_FLOW,
3679         },
3680         {
3681                 .name   = "flow_watermark",
3682                 .lname  = "I/O flow watermark",
3683                 .type   = FIO_OPT_INT,
3684                 .off1   = td_var_offset(flow_watermark),
3685                 .help   = "High watermark for flow control. This option"
3686                         " should be set to the same value for all threads"
3687                         " with non-zero flow.",
3688                 .parent = "flow_id",
3689                 .hide   = 1,
3690                 .def    = "1024",
3691                 .category = FIO_OPT_C_IO,
3692                 .group  = FIO_OPT_G_IO_FLOW,
3693         },
3694         {
3695                 .name   = "flow_sleep",
3696                 .lname  = "I/O flow sleep",
3697                 .type   = FIO_OPT_INT,
3698                 .off1   = td_var_offset(flow_sleep),
3699                 .help   = "How many microseconds to sleep after being held"
3700                         " back by the flow control mechanism",
3701                 .parent = "flow_id",
3702                 .hide   = 1,
3703                 .def    = "0",
3704                 .category = FIO_OPT_C_IO,
3705                 .group  = FIO_OPT_G_IO_FLOW,
3706         },
3707         {
3708                 .name   = "skip_bad",
3709                 .lname  = "Skip operations against bad blocks",
3710                 .type   = FIO_OPT_BOOL,
3711                 .off1   = td_var_offset(skip_bad),
3712                 .help   = "Skip operations against known bad blocks.",
3713                 .hide   = 1,
3714                 .def    = "0",
3715                 .category = FIO_OPT_C_IO,
3716                 .group  = FIO_OPT_G_MTD,
3717         },
3718         {
3719                 .name = NULL,
3720         },
3721 };
3722
3723 static void add_to_lopt(struct option *lopt, struct fio_option *o,
3724                         const char *name, int val)
3725 {
3726         lopt->name = (char *) name;
3727         lopt->val = val;
3728         if (o->type == FIO_OPT_STR_SET)
3729                 lopt->has_arg = optional_argument;
3730         else
3731                 lopt->has_arg = required_argument;
3732 }
3733
3734 static void options_to_lopts(struct fio_option *opts,
3735                               struct option *long_options,
3736                               int i, int option_type)
3737 {
3738         struct fio_option *o = &opts[0];
3739         while (o->name) {
3740                 add_to_lopt(&long_options[i], o, o->name, option_type);
3741                 if (o->alias) {
3742                         i++;
3743                         add_to_lopt(&long_options[i], o, o->alias, option_type);
3744                 }
3745
3746                 i++;
3747                 o++;
3748                 assert(i < FIO_NR_OPTIONS);
3749         }
3750 }
3751
3752 void fio_options_set_ioengine_opts(struct option *long_options,
3753                                    struct thread_data *td)
3754 {
3755         unsigned int i;
3756
3757         i = 0;
3758         while (long_options[i].name) {
3759                 if (long_options[i].val == FIO_GETOPT_IOENGINE) {
3760                         memset(&long_options[i], 0, sizeof(*long_options));
3761                         break;
3762                 }
3763                 i++;
3764         }
3765
3766         /*
3767          * Just clear out the prior ioengine options.
3768          */
3769         if (!td || !td->eo)
3770                 return;
3771
3772         options_to_lopts(td->io_ops->options, long_options, i,
3773                          FIO_GETOPT_IOENGINE);
3774 }
3775
3776 void fio_options_dup_and_init(struct option *long_options)
3777 {
3778         unsigned int i;
3779
3780         options_init(fio_options);
3781
3782         i = 0;
3783         while (long_options[i].name)
3784                 i++;
3785
3786         options_to_lopts(fio_options, long_options, i, FIO_GETOPT_JOB);
3787 }
3788
3789 struct fio_keyword {
3790         const char *word;
3791         const char *desc;
3792         char *replace;
3793 };
3794
3795 static struct fio_keyword fio_keywords[] = {
3796         {
3797                 .word   = "$pagesize",
3798                 .desc   = "Page size in the system",
3799         },
3800         {
3801                 .word   = "$mb_memory",
3802                 .desc   = "Megabytes of memory online",
3803         },
3804         {
3805                 .word   = "$ncpus",
3806                 .desc   = "Number of CPUs online in the system",
3807         },
3808         {
3809                 .word   = NULL,
3810         },
3811 };
3812
3813 void fio_keywords_exit(void)
3814 {
3815         struct fio_keyword *kw;
3816
3817         kw = &fio_keywords[0];
3818         while (kw->word) {
3819                 free(kw->replace);
3820                 kw->replace = NULL;
3821                 kw++;
3822         }
3823 }
3824
3825 void fio_keywords_init(void)
3826 {
3827         unsigned long long mb_memory;
3828         char buf[128];
3829         long l;
3830
3831         sprintf(buf, "%lu", (unsigned long) page_size);
3832         fio_keywords[0].replace = strdup(buf);
3833
3834         mb_memory = os_phys_mem() / (1024 * 1024);
3835         sprintf(buf, "%llu", mb_memory);
3836         fio_keywords[1].replace = strdup(buf);
3837
3838         l = cpus_online();
3839         sprintf(buf, "%lu", l);
3840         fio_keywords[2].replace = strdup(buf);
3841 }
3842
3843 #define BC_APP          "bc"
3844
3845 static char *bc_calc(char *str)
3846 {
3847         char buf[128], *tmp;
3848         FILE *f;
3849         int ret;
3850
3851         /*
3852          * No math, just return string
3853          */
3854         if ((!strchr(str, '+') && !strchr(str, '-') && !strchr(str, '*') &&
3855              !strchr(str, '/')) || strchr(str, '\''))
3856                 return str;
3857
3858         /*
3859          * Split option from value, we only need to calculate the value
3860          */
3861         tmp = strchr(str, '=');
3862         if (!tmp)
3863                 return str;
3864
3865         tmp++;
3866
3867         /*
3868          * Prevent buffer overflows; such a case isn't reasonable anyway
3869          */
3870         if (strlen(str) >= 128 || strlen(tmp) > 100)
3871                 return str;
3872
3873         sprintf(buf, "which %s > /dev/null", BC_APP);
3874         if (system(buf)) {
3875                 log_err("fio: bc is needed for performing math\n");
3876                 return NULL;
3877         }
3878
3879         sprintf(buf, "echo '%s' | %s", tmp, BC_APP);
3880         f = popen(buf, "r");
3881         if (!f)
3882                 return NULL;
3883
3884         ret = fread(&buf[tmp - str], 1, 128 - (tmp - str), f);
3885         if (ret <= 0) {
3886                 pclose(f);
3887                 return NULL;
3888         }
3889
3890         pclose(f);
3891         buf[(tmp - str) + ret - 1] = '\0';
3892         memcpy(buf, str, tmp - str);
3893         free(str);
3894         return strdup(buf);
3895 }
3896
3897 /*
3898  * Return a copy of the input string with substrings of the form ${VARNAME}
3899  * substituted with the value of the environment variable VARNAME.  The
3900  * substitution always occurs, even if VARNAME is empty or the corresponding
3901  * environment variable undefined.
3902  */
3903 static char *option_dup_subs(const char *opt)
3904 {
3905         char out[OPT_LEN_MAX+1];
3906         char in[OPT_LEN_MAX+1];
3907         char *outptr = out;
3908         char *inptr = in;
3909         char *ch1, *ch2, *env;
3910         ssize_t nchr = OPT_LEN_MAX;
3911         size_t envlen;
3912
3913         if (strlen(opt) + 1 > OPT_LEN_MAX) {
3914                 log_err("OPT_LEN_MAX (%d) is too small\n", OPT_LEN_MAX);
3915                 return NULL;
3916         }
3917
3918         in[OPT_LEN_MAX] = '\0';
3919         strncpy(in, opt, OPT_LEN_MAX);
3920
3921         while (*inptr && nchr > 0) {
3922                 if (inptr[0] == '$' && inptr[1] == '{') {
3923                         ch2 = strchr(inptr, '}');
3924                         if (ch2 && inptr+1 < ch2) {
3925                                 ch1 = inptr+2;
3926                                 inptr = ch2+1;
3927                                 *ch2 = '\0';
3928
3929                                 env = getenv(ch1);
3930                                 if (env) {
3931                                         envlen = strlen(env);
3932                                         if (envlen <= nchr) {
3933                                                 memcpy(outptr, env, envlen);
3934                                                 outptr += envlen;
3935                                                 nchr -= envlen;
3936                                         }
3937                                 }
3938
3939                                 continue;
3940                         }
3941                 }
3942
3943                 *outptr++ = *inptr++;
3944                 --nchr;
3945         }
3946
3947         *outptr = '\0';
3948         return strdup(out);
3949 }
3950
3951 /*
3952  * Look for reserved variable names and replace them with real values
3953  */
3954 static char *fio_keyword_replace(char *opt)
3955 {
3956         char *s;
3957         int i;
3958         int docalc = 0;
3959
3960         for (i = 0; fio_keywords[i].word != NULL; i++) {
3961                 struct fio_keyword *kw = &fio_keywords[i];
3962
3963                 while ((s = strstr(opt, kw->word)) != NULL) {
3964                         char *new = malloc(strlen(opt) + 1);
3965                         char *o_org = opt;
3966                         int olen = s - opt;
3967                         int len;
3968
3969                         /*
3970                          * Copy part of the string before the keyword and
3971                          * sprintf() the replacement after it.
3972                          */
3973                         memcpy(new, opt, olen);
3974                         len = sprintf(new + olen, "%s", kw->replace);
3975
3976                         /*
3977                          * If there's more in the original string, copy that
3978                          * in too
3979                          */
3980                         opt += strlen(kw->word) + olen;
3981                         if (strlen(opt))
3982                                 memcpy(new + olen + len, opt, opt - o_org - 1);
3983
3984                         /*
3985                          * replace opt and free the old opt
3986                          */
3987                         opt = new;
3988                         free(o_org);
3989
3990                         docalc = 1;
3991                 }
3992         }
3993
3994         /*
3995          * Check for potential math and invoke bc, if possible
3996          */
3997         if (docalc)
3998                 opt = bc_calc(opt);
3999
4000         return opt;
4001 }
4002
4003 static char **dup_and_sub_options(char **opts, int num_opts)
4004 {
4005         int i;
4006         char **opts_copy = malloc(num_opts * sizeof(*opts));
4007         for (i = 0; i < num_opts; i++) {
4008                 opts_copy[i] = option_dup_subs(opts[i]);
4009                 if (!opts_copy[i])
4010                         continue;
4011                 opts_copy[i] = fio_keyword_replace(opts_copy[i]);
4012         }
4013         return opts_copy;
4014 }
4015
4016 static void show_closest_option(const char *opt)
4017 {
4018         int best_option, best_distance;
4019         int i, distance;
4020         char *name;
4021
4022         if (!strlen(opt))
4023                 return;
4024
4025         name = strdup(opt);
4026         i = 0;
4027         while (name[i] != '\0' && name[i] != '=')
4028                 i++;
4029         name[i] = '\0';
4030
4031         best_option = -1;
4032         best_distance = INT_MAX;
4033         i = 0;
4034         while (fio_options[i].name) {
4035                 distance = string_distance(name, fio_options[i].name);
4036                 if (distance < best_distance) {
4037                         best_distance = distance;
4038                         best_option = i;
4039                 }
4040                 i++;
4041         }
4042
4043         if (best_option != -1 && string_distance_ok(name, best_distance))
4044                 log_err("Did you mean %s?\n", fio_options[best_option].name);
4045
4046         free(name);
4047 }
4048
4049 int fio_options_parse(struct thread_data *td, char **opts, int num_opts,
4050                         int dump_cmdline)
4051 {
4052         int i, ret, unknown;
4053         char **opts_copy;
4054
4055         sort_options(opts, fio_options, num_opts);
4056         opts_copy = dup_and_sub_options(opts, num_opts);
4057
4058         for (ret = 0, i = 0, unknown = 0; i < num_opts; i++) {
4059                 struct fio_option *o;
4060                 int newret = parse_option(opts_copy[i], opts[i], fio_options,
4061                                                 &o, td, dump_cmdline);
4062
4063                 if (!newret && o)
4064                         fio_option_mark_set(&td->o, o);
4065
4066                 if (opts_copy[i]) {
4067                         if (newret && !o) {
4068                                 unknown++;
4069                                 continue;
4070                         }
4071                         free(opts_copy[i]);
4072                         opts_copy[i] = NULL;
4073                 }
4074
4075                 ret |= newret;
4076         }
4077
4078         if (unknown) {
4079                 ret |= ioengine_load(td);
4080                 if (td->eo) {
4081                         sort_options(opts_copy, td->io_ops->options, num_opts);
4082                         opts = opts_copy;
4083                 }
4084                 for (i = 0; i < num_opts; i++) {
4085                         struct fio_option *o = NULL;
4086                         int newret = 1;
4087
4088                         if (!opts_copy[i])
4089                                 continue;
4090
4091                         if (td->eo)
4092                                 newret = parse_option(opts_copy[i], opts[i],
4093                                                       td->io_ops->options, &o,
4094                                                       td->eo, dump_cmdline);
4095
4096                         ret |= newret;
4097                         if (!o) {
4098                                 log_err("Bad option <%s>\n", opts[i]);
4099                                 show_closest_option(opts[i]);
4100                         }
4101                         free(opts_copy[i]);
4102                         opts_copy[i] = NULL;
4103                 }
4104         }
4105
4106         free(opts_copy);
4107         return ret;
4108 }
4109
4110 int fio_cmd_option_parse(struct thread_data *td, const char *opt, char *val)
4111 {
4112         int ret;
4113
4114         ret = parse_cmd_option(opt, val, fio_options, td);
4115         if (!ret) {
4116                 struct fio_option *o;
4117
4118                 o = find_option(fio_options, opt);
4119                 if (o)
4120                         fio_option_mark_set(&td->o, o);
4121         }
4122
4123         return ret;
4124 }
4125
4126 int fio_cmd_ioengine_option_parse(struct thread_data *td, const char *opt,
4127                                 char *val)
4128 {
4129         return parse_cmd_option(opt, val, td->io_ops->options, td->eo);
4130 }
4131
4132 void fio_fill_default_options(struct thread_data *td)
4133 {
4134         td->o.magic = OPT_MAGIC;
4135         fill_default_options(td, fio_options);
4136 }
4137
4138 int fio_show_option_help(const char *opt)
4139 {
4140         return show_cmd_help(fio_options, opt);
4141 }
4142
4143 void options_mem_dupe(void *data, struct fio_option *options)
4144 {
4145         struct fio_option *o;
4146         char **ptr;
4147
4148         for (o = &options[0]; o->name; o++) {
4149                 if (o->type != FIO_OPT_STR_STORE)
4150                         continue;
4151
4152                 ptr = td_var(data, o, o->off1);
4153                 if (*ptr)
4154                         *ptr = strdup(*ptr);
4155         }
4156 }
4157
4158 /*
4159  * dupe FIO_OPT_STR_STORE options
4160  */
4161 void fio_options_mem_dupe(struct thread_data *td)
4162 {
4163         options_mem_dupe(&td->o, fio_options);
4164
4165         if (td->eo && td->io_ops) {
4166                 void *oldeo = td->eo;
4167
4168                 td->eo = malloc(td->io_ops->option_struct_size);
4169                 memcpy(td->eo, oldeo, td->io_ops->option_struct_size);
4170                 options_mem_dupe(td->eo, td->io_ops->options);
4171         }
4172 }
4173
4174 unsigned int fio_get_kb_base(void *data)
4175 {
4176         struct thread_options *o = data;
4177         unsigned int kb_base = 0;
4178
4179         /*
4180          * This is a hack... For private options, *data is not holding
4181          * a pointer to the thread_options, but to private data. This means
4182          * we can't safely dereference it, but magic is first so mem wise
4183          * it is valid. But this also means that if the job first sets
4184          * kb_base and expects that to be honored by private options,
4185          * it will be disappointed. We will return the global default
4186          * for this.
4187          */
4188         if (o && o->magic == OPT_MAGIC)
4189                 kb_base = o->kb_base;
4190         if (!kb_base)
4191                 kb_base = 1024;
4192
4193         return kb_base;
4194 }
4195
4196 int add_option(struct fio_option *o)
4197 {
4198         struct fio_option *__o;
4199         int opt_index = 0;
4200
4201         __o = fio_options;
4202         while (__o->name) {
4203                 opt_index++;
4204                 __o++;
4205         }
4206
4207         if (opt_index + 1 == FIO_MAX_OPTS) {
4208                 log_err("fio: FIO_MAX_OPTS is too small\n");
4209                 return 1;
4210         }
4211
4212         memcpy(&fio_options[opt_index], o, sizeof(*o));
4213         fio_options[opt_index + 1].name = NULL;
4214         return 0;
4215 }
4216
4217 void invalidate_profile_options(const char *prof_name)
4218 {
4219         struct fio_option *o;
4220
4221         o = fio_options;
4222         while (o->name) {
4223                 if (o->prof_name && !strcmp(o->prof_name, prof_name)) {
4224                         o->type = FIO_OPT_INVALID;
4225                         o->prof_name = NULL;
4226                 }
4227                 o++;
4228         }
4229 }
4230
4231 void add_opt_posval(const char *optname, const char *ival, const char *help)
4232 {
4233         struct fio_option *o;
4234         unsigned int i;
4235
4236         o = find_option(fio_options, optname);
4237         if (!o)
4238                 return;
4239
4240         for (i = 0; i < PARSE_MAX_VP; i++) {
4241                 if (o->posval[i].ival)
4242                         continue;
4243
4244                 o->posval[i].ival = ival;
4245                 o->posval[i].help = help;
4246                 break;
4247         }
4248 }
4249
4250 void del_opt_posval(const char *optname, const char *ival)
4251 {
4252         struct fio_option *o;
4253         unsigned int i;
4254
4255         o = find_option(fio_options, optname);
4256         if (!o)
4257                 return;
4258
4259         for (i = 0; i < PARSE_MAX_VP; i++) {
4260                 if (!o->posval[i].ival)
4261                         continue;
4262                 if (strcmp(o->posval[i].ival, ival))
4263                         continue;
4264
4265                 o->posval[i].ival = NULL;
4266                 o->posval[i].help = NULL;
4267         }
4268 }
4269
4270 void fio_options_free(struct thread_data *td)
4271 {
4272         options_free(fio_options, td);
4273         if (td->eo && td->io_ops && td->io_ops->options) {
4274                 options_free(td->io_ops->options, td->eo);
4275                 free(td->eo);
4276                 td->eo = NULL;
4277         }
4278 }
4279
4280 struct fio_option *fio_option_find(const char *name)
4281 {
4282         return find_option(fio_options, name);
4283 }
4284
4285 static struct fio_option *find_next_opt(struct thread_options *o,
4286                                         struct fio_option *from,
4287                                         unsigned int off1)
4288 {
4289         struct fio_option *opt;
4290
4291         if (!from)
4292                 from = &fio_options[0];
4293         else
4294                 from++;
4295
4296         opt = NULL;
4297         do {
4298                 if (off1 == from->off1) {
4299                         opt = from;
4300                         break;
4301                 }
4302                 from++;
4303         } while (from->name);
4304
4305         return opt;
4306 }
4307
4308 static int opt_is_set(struct thread_options *o, struct fio_option *opt)
4309 {
4310         unsigned int opt_off, index, offset;
4311
4312         opt_off = opt - &fio_options[0];
4313         index = opt_off / (8 * sizeof(uint64_t));
4314         offset = opt_off & ((8 * sizeof(uint64_t)) - 1);
4315         return (o->set_options[index] & ((uint64_t)1 << offset)) != 0;
4316 }
4317
4318 int __fio_option_is_set(struct thread_options *o, unsigned int off1)
4319 {
4320         struct fio_option *opt, *next;
4321
4322         next = NULL;
4323         while ((opt = find_next_opt(o, next, off1)) != NULL) {
4324                 if (opt_is_set(o, opt))
4325                         return 1;
4326
4327                 next = opt;
4328         }
4329
4330         return 0;
4331 }
4332
4333 void fio_option_mark_set(struct thread_options *o, struct fio_option *opt)
4334 {
4335         unsigned int opt_off, index, offset;
4336
4337         opt_off = opt - &fio_options[0];
4338         index = opt_off / (8 * sizeof(uint64_t));
4339         offset = opt_off & ((8 * sizeof(uint64_t)) - 1);
4340         o->set_options[index] |= (uint64_t)1 << offset;
4341 }