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