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