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