options: unify the bssplit/zone split code
[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",