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