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