Fix keyword replacement leaks
[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 .parent = "rw",
1849 .category = FIO_OPT_C_IO,
1850 .group = FIO_OPT_G_RANDOM,
1851 },
1852 {
1853 .name = "use_os_rand",
1854 .lname = "Use OS random",
1855 .type = FIO_OPT_DEPRECATED,
1856 .off1 = td_var_offset(dep_use_os_rand),
1857 .category = FIO_OPT_C_IO,
1858 .group = FIO_OPT_G_RANDOM,
1859 },
1860 {
1861 .name = "norandommap",
1862 .lname = "No randommap",
1863 .type = FIO_OPT_STR_SET,
1864 .off1 = td_var_offset(norandommap),
1865 .help = "Accept potential duplicate random blocks",
1866 .parent = "rw",
1867 .hide = 1,
1868 .hide_on_set = 1,
1869 .category = FIO_OPT_C_IO,
1870 .group = FIO_OPT_G_RANDOM,
1871 },
1872 {
1873 .name = "softrandommap",
1874 .lname = "Soft randommap",
1875 .type = FIO_OPT_BOOL,
1876 .off1 = td_var_offset(softrandommap),
1877 .help = "Set norandommap if randommap allocation fails",
1878 .parent = "norandommap",
1879 .hide = 1,
1880 .def = "0",
1881 .category = FIO_OPT_C_IO,
1882 .group = FIO_OPT_G_RANDOM,
1883 },
1884 {
1885 .name = "random_generator",
1886 .type = FIO_OPT_STR,
1887 .off1 = td_var_offset(random_generator),
1888 .help = "Type of random number generator to use",
1889 .def = "tausworthe",
1890 .posval = {
1891 { .ival = "tausworthe",
1892 .oval = FIO_RAND_GEN_TAUSWORTHE,
1893 .help = "Strong Tausworthe generator",
1894 },
1895 { .ival = "lfsr",
1896 .oval = FIO_RAND_GEN_LFSR,
1897 .help = "Variable length LFSR",
1898 },
1899 },
1900 .category = FIO_OPT_C_IO,
1901 .group = FIO_OPT_G_RANDOM,
1902 },
1903 {
1904 .name = "random_distribution",
1905 .type = FIO_OPT_STR,
1906 .off1 = td_var_offset(random_distribution),
1907 .cb = str_random_distribution_cb,
1908 .help = "Random offset distribution generator",
1909 .def = "random",
1910 .posval = {
1911 { .ival = "random",
1912 .oval = FIO_RAND_DIST_RANDOM,
1913 .help = "Completely random",
1914 },
1915 { .ival = "zipf",
1916 .oval = FIO_RAND_DIST_ZIPF,
1917 .help = "Zipf distribution",
1918 },
1919 { .ival = "pareto",
1920 .oval = FIO_RAND_DIST_PARETO,
1921 .help = "Pareto distribution",
1922 },
1923 { .ival = "normal",
1924 .oval = FIO_RAND_DIST_GAUSS,
1925 .help = "Normal (gaussian) distribution",
1926 },
1927 },
1928 .category = FIO_OPT_C_IO,
1929 .group = FIO_OPT_G_RANDOM,
1930 },
1931 {
1932 .name = "percentage_random",
1933 .lname = "Percentage Random",
1934 .type = FIO_OPT_INT,
1935 .off1 = td_var_offset(perc_rand[DDIR_READ]),
1936 .off2 = td_var_offset(perc_rand[DDIR_WRITE]),
1937 .off3 = td_var_offset(perc_rand[DDIR_TRIM]),
1938 .maxval = 100,
1939 .help = "Percentage of seq/random mix that should be random",
1940 .def = "100,100,100",
1941 .interval = 5,
1942 .inverse = "percentage_sequential",
1943 .category = FIO_OPT_C_IO,
1944 .group = FIO_OPT_G_RANDOM,
1945 },
1946 {
1947 .name = "percentage_sequential",
1948 .lname = "Percentage Sequential",
1949 .type = FIO_OPT_DEPRECATED,
1950 .category = FIO_OPT_C_IO,
1951 .group = FIO_OPT_G_RANDOM,
1952 },
1953 {
1954 .name = "allrandrepeat",
1955 .type = FIO_OPT_BOOL,
1956 .off1 = td_var_offset(allrand_repeatable),
1957 .help = "Use repeatable random numbers for everything",
1958 .def = "0",
1959 .category = FIO_OPT_C_IO,
1960 .group = FIO_OPT_G_RANDOM,
1961 },
1962 {
1963 .name = "nrfiles",
1964 .lname = "Number of files",
1965 .alias = "nr_files",
1966 .type = FIO_OPT_INT,
1967 .off1 = td_var_offset(nr_files),
1968 .help = "Split job workload between this number of files",
1969 .def = "1",
1970 .interval = 1,
1971 .category = FIO_OPT_C_FILE,
1972 .group = FIO_OPT_G_INVALID,
1973 },
1974 {
1975 .name = "openfiles",
1976 .lname = "Number of open files",
1977 .type = FIO_OPT_INT,
1978 .off1 = td_var_offset(open_files),
1979 .help = "Number of files to keep open at the same time",
1980 .category = FIO_OPT_C_FILE,
1981 .group = FIO_OPT_G_INVALID,
1982 },
1983 {
1984 .name = "file_service_type",
1985 .lname = "File service type",
1986 .type = FIO_OPT_STR,
1987 .cb = str_fst_cb,
1988 .off1 = td_var_offset(file_service_type),
1989 .help = "How to select which file to service next",
1990 .def = "roundrobin",
1991 .category = FIO_OPT_C_FILE,
1992 .group = FIO_OPT_G_INVALID,
1993 .posval = {
1994 { .ival = "random",
1995 .oval = FIO_FSERVICE_RANDOM,
1996 .help = "Choose a file at random",
1997 },
1998 { .ival = "roundrobin",
1999 .oval = FIO_FSERVICE_RR,
2000 .help = "Round robin select files",
2001 },
2002 { .ival = "sequential",
2003 .oval = FIO_FSERVICE_SEQ,
2004 .help = "Finish one file before moving to the next",
2005 },
2006 },
2007 .parent = "nrfiles",
2008 .hide = 1,
2009 },
2010#ifdef CONFIG_POSIX_FALLOCATE
2011 {
2012 .name = "fallocate",
2013 .lname = "Fallocate",
2014 .type = FIO_OPT_STR,
2015 .off1 = td_var_offset(fallocate_mode),
2016 .help = "Whether pre-allocation is performed when laying out files",
2017 .def = "posix",
2018 .category = FIO_OPT_C_FILE,
2019 .group = FIO_OPT_G_INVALID,
2020 .posval = {
2021 { .ival = "none",
2022 .oval = FIO_FALLOCATE_NONE,
2023 .help = "Do not pre-allocate space",
2024 },
2025 { .ival = "posix",
2026 .oval = FIO_FALLOCATE_POSIX,
2027 .help = "Use posix_fallocate()",
2028 },
2029#ifdef CONFIG_LINUX_FALLOCATE
2030 { .ival = "keep",
2031 .oval = FIO_FALLOCATE_KEEP_SIZE,
2032 .help = "Use fallocate(..., FALLOC_FL_KEEP_SIZE, ...)",
2033 },
2034#endif
2035 /* Compatibility with former boolean values */
2036 { .ival = "0",
2037 .oval = FIO_FALLOCATE_NONE,
2038 .help = "Alias for 'none'",
2039 },
2040 { .ival = "1",
2041 .oval = FIO_FALLOCATE_POSIX,
2042 .help = "Alias for 'posix'",
2043 },
2044 },
2045 },
2046#endif /* CONFIG_POSIX_FALLOCATE */
2047 {
2048 .name = "fadvise_hint",
2049 .lname = "Fadvise hint",
2050 .type = FIO_OPT_BOOL,
2051 .off1 = td_var_offset(fadvise_hint),
2052 .help = "Use fadvise() to advise the kernel on IO pattern",
2053 .def = "1",
2054 .category = FIO_OPT_C_FILE,
2055 .group = FIO_OPT_G_INVALID,
2056 },
2057#ifdef FIO_HAVE_STREAMID
2058 {
2059 .name = "fadvise_stream",
2060 .lname = "Fadvise stream",
2061 .type = FIO_OPT_INT,
2062 .off1 = td_var_offset(fadvise_stream),
2063 .help = "Use fadvise() to set stream ID",
2064 .category = FIO_OPT_C_FILE,
2065 .group = FIO_OPT_G_INVALID,
2066 },
2067#endif
2068 {
2069 .name = "fsync",
2070 .lname = "Fsync",
2071 .type = FIO_OPT_INT,
2072 .off1 = td_var_offset(fsync_blocks),
2073 .help = "Issue fsync for writes every given number of blocks",
2074 .def = "0",
2075 .interval = 1,
2076 .category = FIO_OPT_C_FILE,
2077 .group = FIO_OPT_G_INVALID,
2078 },
2079 {
2080 .name = "fdatasync",
2081 .lname = "Fdatasync",
2082 .type = FIO_OPT_INT,
2083 .off1 = td_var_offset(fdatasync_blocks),
2084 .help = "Issue fdatasync for writes every given number of blocks",
2085 .def = "0",
2086 .interval = 1,
2087 .category = FIO_OPT_C_FILE,
2088 .group = FIO_OPT_G_INVALID,
2089 },
2090 {
2091 .name = "write_barrier",
2092 .lname = "Write barrier",
2093 .type = FIO_OPT_INT,
2094 .off1 = td_var_offset(barrier_blocks),
2095 .help = "Make every Nth write a barrier write",
2096 .def = "0",
2097 .interval = 1,
2098 .category = FIO_OPT_C_IO,
2099 .group = FIO_OPT_G_INVALID,
2100 },
2101#ifdef CONFIG_SYNC_FILE_RANGE
2102 {
2103 .name = "sync_file_range",
2104 .lname = "Sync file range",
2105 .posval = {
2106 { .ival = "wait_before",
2107 .oval = SYNC_FILE_RANGE_WAIT_BEFORE,
2108 .help = "SYNC_FILE_RANGE_WAIT_BEFORE",
2109 .orval = 1,
2110 },
2111 { .ival = "write",
2112 .oval = SYNC_FILE_RANGE_WRITE,
2113 .help = "SYNC_FILE_RANGE_WRITE",
2114 .orval = 1,
2115 },
2116 {
2117 .ival = "wait_after",
2118 .oval = SYNC_FILE_RANGE_WAIT_AFTER,
2119 .help = "SYNC_FILE_RANGE_WAIT_AFTER",
2120 .orval = 1,
2121 },
2122 },
2123 .type = FIO_OPT_STR_MULTI,
2124 .cb = str_sfr_cb,
2125 .off1 = td_var_offset(sync_file_range),
2126 .help = "Use sync_file_range()",
2127 .category = FIO_OPT_C_FILE,
2128 .group = FIO_OPT_G_INVALID,
2129 },
2130#endif
2131 {
2132 .name = "direct",
2133 .lname = "Direct I/O",
2134 .type = FIO_OPT_BOOL,
2135 .off1 = td_var_offset(odirect),
2136 .help = "Use O_DIRECT IO (negates buffered)",
2137 .def = "0",
2138 .inverse = "buffered",
2139 .category = FIO_OPT_C_IO,
2140 .group = FIO_OPT_G_IO_TYPE,
2141 },
2142 {
2143 .name = "atomic",
2144 .lname = "Atomic I/O",
2145 .type = FIO_OPT_BOOL,
2146 .off1 = td_var_offset(oatomic),
2147 .help = "Use Atomic IO with O_DIRECT (implies O_DIRECT)",
2148 .def = "0",
2149 .category = FIO_OPT_C_IO,
2150 .group = FIO_OPT_G_IO_TYPE,
2151 },
2152 {
2153 .name = "buffered",
2154 .lname = "Buffered I/O",
2155 .type = FIO_OPT_BOOL,
2156 .off1 = td_var_offset(odirect),
2157 .neg = 1,
2158 .help = "Use buffered IO (negates direct)",
2159 .def = "1",
2160 .inverse = "direct",
2161 .category = FIO_OPT_C_IO,
2162 .group = FIO_OPT_G_IO_TYPE,
2163 },
2164 {
2165 .name = "overwrite",
2166 .lname = "Overwrite",
2167 .type = FIO_OPT_BOOL,
2168 .off1 = td_var_offset(overwrite),
2169 .help = "When writing, set whether to overwrite current data",
2170 .def = "0",
2171 .category = FIO_OPT_C_FILE,
2172 .group = FIO_OPT_G_INVALID,
2173 },
2174 {
2175 .name = "loops",
2176 .lname = "Loops",
2177 .type = FIO_OPT_INT,
2178 .off1 = td_var_offset(loops),
2179 .help = "Number of times to run the job",
2180 .def = "1",
2181 .interval = 1,
2182 .category = FIO_OPT_C_GENERAL,
2183 .group = FIO_OPT_G_RUNTIME,
2184 },
2185 {
2186 .name = "numjobs",
2187 .lname = "Number of jobs",
2188 .type = FIO_OPT_INT,
2189 .off1 = td_var_offset(numjobs),
2190 .help = "Duplicate this job this many times",
2191 .def = "1",
2192 .interval = 1,
2193 .category = FIO_OPT_C_GENERAL,
2194 .group = FIO_OPT_G_RUNTIME,
2195 },
2196 {
2197 .name = "startdelay",
2198 .lname = "Start delay",
2199 .type = FIO_OPT_STR_VAL_TIME,
2200 .off1 = td_var_offset(start_delay),
2201 .off2 = td_var_offset(start_delay_high),
2202 .help = "Only start job when this period has passed",
2203 .def = "0",
2204 .is_seconds = 1,
2205 .is_time = 1,
2206 .category = FIO_OPT_C_GENERAL,
2207 .group = FIO_OPT_G_RUNTIME,
2208 },
2209 {
2210 .name = "runtime",
2211 .lname = "Runtime",
2212 .alias = "timeout",
2213 .type = FIO_OPT_STR_VAL_TIME,
2214 .off1 = td_var_offset(timeout),
2215 .help = "Stop workload when this amount of time has passed",
2216 .def = "0",
2217 .is_seconds = 1,
2218 .is_time = 1,
2219 .category = FIO_OPT_C_GENERAL,
2220 .group = FIO_OPT_G_RUNTIME,
2221 },
2222 {
2223 .name = "time_based",
2224 .lname = "Time based",
2225 .type = FIO_OPT_STR_SET,
2226 .off1 = td_var_offset(time_based),
2227 .help = "Keep running until runtime/timeout is met",
2228 .category = FIO_OPT_C_GENERAL,
2229 .group = FIO_OPT_G_RUNTIME,
2230 },
2231 {
2232 .name = "verify_only",
2233 .lname = "Verify only",
2234 .type = FIO_OPT_STR_SET,
2235 .off1 = td_var_offset(verify_only),
2236 .help = "Verifies previously written data is still valid",
2237 .category = FIO_OPT_C_GENERAL,
2238 .group = FIO_OPT_G_RUNTIME,
2239 },
2240 {
2241 .name = "ramp_time",
2242 .lname = "Ramp time",
2243 .type = FIO_OPT_STR_VAL_TIME,
2244 .off1 = td_var_offset(ramp_time),
2245 .help = "Ramp up time before measuring performance",
2246 .is_seconds = 1,
2247 .is_time = 1,
2248 .category = FIO_OPT_C_GENERAL,
2249 .group = FIO_OPT_G_RUNTIME,
2250 },
2251 {
2252 .name = "clocksource",
2253 .lname = "Clock source",
2254 .type = FIO_OPT_STR,
2255 .cb = fio_clock_source_cb,
2256 .off1 = td_var_offset(clocksource),
2257 .help = "What type of timing source to use",
2258 .category = FIO_OPT_C_GENERAL,
2259 .group = FIO_OPT_G_CLOCK,
2260 .posval = {
2261#ifdef CONFIG_GETTIMEOFDAY
2262 { .ival = "gettimeofday",
2263 .oval = CS_GTOD,
2264 .help = "Use gettimeofday(2) for timing",
2265 },
2266#endif
2267#ifdef CONFIG_CLOCK_GETTIME
2268 { .ival = "clock_gettime",
2269 .oval = CS_CGETTIME,
2270 .help = "Use clock_gettime(2) for timing",
2271 },
2272#endif
2273#ifdef ARCH_HAVE_CPU_CLOCK
2274 { .ival = "cpu",
2275 .oval = CS_CPUCLOCK,
2276 .help = "Use CPU private clock",
2277 },
2278#endif
2279 },
2280 },
2281 {
2282 .name = "mem",
2283 .alias = "iomem",
2284 .lname = "I/O Memory",
2285 .type = FIO_OPT_STR,
2286 .cb = str_mem_cb,
2287 .off1 = td_var_offset(mem_type),
2288 .help = "Backing type for IO buffers",
2289 .def = "malloc",
2290 .category = FIO_OPT_C_IO,
2291 .group = FIO_OPT_G_INVALID,
2292 .posval = {
2293 { .ival = "malloc",
2294 .oval = MEM_MALLOC,
2295 .help = "Use malloc(3) for IO buffers",
2296 },
2297#ifndef CONFIG_NO_SHM
2298 { .ival = "shm",
2299 .oval = MEM_SHM,
2300 .help = "Use shared memory segments for IO buffers",
2301 },
2302#ifdef FIO_HAVE_HUGETLB
2303 { .ival = "shmhuge",
2304 .oval = MEM_SHMHUGE,
2305 .help = "Like shm, but use huge pages",
2306 },
2307#endif
2308#endif
2309 { .ival = "mmap",
2310 .oval = MEM_MMAP,
2311 .help = "Use mmap(2) (file or anon) for IO buffers",
2312 },
2313#ifdef FIO_HAVE_HUGETLB
2314 { .ival = "mmaphuge",
2315 .oval = MEM_MMAPHUGE,
2316 .help = "Like mmap, but use huge pages",
2317 },
2318#endif
2319 },
2320 },
2321 {
2322 .name = "iomem_align",
2323 .alias = "mem_align",
2324 .lname = "I/O memory alignment",
2325 .type = FIO_OPT_INT,
2326 .off1 = td_var_offset(mem_align),
2327 .minval = 0,
2328 .help = "IO memory buffer offset alignment",
2329 .def = "0",
2330 .parent = "iomem",
2331 .hide = 1,
2332 .category = FIO_OPT_C_IO,
2333 .group = FIO_OPT_G_INVALID,
2334 },
2335 {
2336 .name = "verify",
2337 .lname = "Verify",
2338 .type = FIO_OPT_STR,
2339 .off1 = td_var_offset(verify),
2340 .help = "Verify data written",
2341 .def = "0",
2342 .category = FIO_OPT_C_IO,
2343 .group = FIO_OPT_G_VERIFY,
2344 .posval = {
2345 { .ival = "0",
2346 .oval = VERIFY_NONE,
2347 .help = "Don't do IO verification",
2348 },
2349 { .ival = "md5",
2350 .oval = VERIFY_MD5,
2351 .help = "Use md5 checksums for verification",
2352 },
2353 { .ival = "crc64",
2354 .oval = VERIFY_CRC64,
2355 .help = "Use crc64 checksums for verification",
2356 },
2357 { .ival = "crc32",
2358 .oval = VERIFY_CRC32,
2359 .help = "Use crc32 checksums for verification",
2360 },
2361 { .ival = "crc32c-intel",
2362 .oval = VERIFY_CRC32C,
2363 .help = "Use crc32c checksums for verification (hw assisted, if available)",
2364 },
2365 { .ival = "crc32c",
2366 .oval = VERIFY_CRC32C,
2367 .help = "Use crc32c checksums for verification (hw assisted, if available)",
2368 },
2369 { .ival = "crc16",
2370 .oval = VERIFY_CRC16,
2371 .help = "Use crc16 checksums for verification",
2372 },
2373 { .ival = "crc7",
2374 .oval = VERIFY_CRC7,
2375 .help = "Use crc7 checksums for verification",
2376 },
2377 { .ival = "sha1",
2378 .oval = VERIFY_SHA1,
2379 .help = "Use sha1 checksums for verification",
2380 },
2381 { .ival = "sha256",
2382 .oval = VERIFY_SHA256,
2383 .help = "Use sha256 checksums for verification",
2384 },
2385 { .ival = "sha512",
2386 .oval = VERIFY_SHA512,
2387 .help = "Use sha512 checksums for verification",
2388 },
2389 { .ival = "xxhash",
2390 .oval = VERIFY_XXHASH,
2391 .help = "Use xxhash checksums for verification",
2392 },
2393 { .ival = "meta",
2394 .oval = VERIFY_META,
2395 .help = "Use io information",
2396 },
2397 {
2398 .ival = "null",
2399 .oval = VERIFY_NULL,
2400 .help = "Pretend to verify",
2401 },
2402 },
2403 },
2404 {
2405 .name = "do_verify",
2406 .lname = "Perform verify step",
2407 .type = FIO_OPT_BOOL,
2408 .off1 = td_var_offset(do_verify),
2409 .help = "Run verification stage after write",
2410 .def = "1",
2411 .parent = "verify",
2412 .hide = 1,
2413 .category = FIO_OPT_C_IO,
2414 .group = FIO_OPT_G_VERIFY,
2415 },
2416 {
2417 .name = "verifysort",
2418 .lname = "Verify sort",
2419 .type = FIO_OPT_BOOL,
2420 .off1 = td_var_offset(verifysort),
2421 .help = "Sort written verify blocks for read back",
2422 .def = "1",
2423 .parent = "verify",
2424 .hide = 1,
2425 .category = FIO_OPT_C_IO,
2426 .group = FIO_OPT_G_VERIFY,
2427 },
2428 {
2429 .name = "verifysort_nr",
2430 .type = FIO_OPT_INT,
2431 .off1 = td_var_offset(verifysort_nr),
2432 .help = "Pre-load and sort verify blocks for a read workload",
2433 .minval = 0,
2434 .maxval = 131072,
2435 .def = "1024",
2436 .parent = "verify",
2437 .category = FIO_OPT_C_IO,
2438 .group = FIO_OPT_G_VERIFY,
2439 },
2440 {
2441 .name = "verify_interval",
2442 .lname = "Verify interval",
2443 .type = FIO_OPT_INT,
2444 .off1 = td_var_offset(verify_interval),
2445 .minval = 2 * sizeof(struct verify_header),
2446 .help = "Store verify buffer header every N bytes",
2447 .parent = "verify",
2448 .hide = 1,
2449 .interval = 2 * sizeof(struct verify_header),
2450 .category = FIO_OPT_C_IO,
2451 .group = FIO_OPT_G_VERIFY,
2452 },
2453 {
2454 .name = "verify_offset",
2455 .lname = "Verify offset",
2456 .type = FIO_OPT_INT,
2457 .help = "Offset verify header location by N bytes",
2458 .off1 = td_var_offset(verify_offset),
2459 .minval = sizeof(struct verify_header),
2460 .parent = "verify",
2461 .hide = 1,
2462 .category = FIO_OPT_C_IO,
2463 .group = FIO_OPT_G_VERIFY,
2464 },
2465 {
2466 .name = "verify_pattern",
2467 .lname = "Verify pattern",
2468 .type = FIO_OPT_STR,
2469 .cb = str_verify_pattern_cb,
2470 .off1 = td_var_offset(verify_pattern),
2471 .help = "Fill pattern for IO buffers",
2472 .parent = "verify",
2473 .hide = 1,
2474 .category = FIO_OPT_C_IO,
2475 .group = FIO_OPT_G_VERIFY,
2476 },
2477 {
2478 .name = "verify_fatal",
2479 .lname = "Verify fatal",
2480 .type = FIO_OPT_BOOL,
2481 .off1 = td_var_offset(verify_fatal),
2482 .def = "0",
2483 .help = "Exit on a single verify failure, don't continue",
2484 .parent = "verify",
2485 .hide = 1,
2486 .category = FIO_OPT_C_IO,
2487 .group = FIO_OPT_G_VERIFY,
2488 },
2489 {
2490 .name = "verify_dump",
2491 .lname = "Verify dump",
2492 .type = FIO_OPT_BOOL,
2493 .off1 = td_var_offset(verify_dump),
2494 .def = "0",
2495 .help = "Dump contents of good and bad blocks on failure",
2496 .parent = "verify",
2497 .hide = 1,
2498 .category = FIO_OPT_C_IO,
2499 .group = FIO_OPT_G_VERIFY,
2500 },
2501 {
2502 .name = "verify_async",
2503 .lname = "Verify asynchronously",
2504 .type = FIO_OPT_INT,
2505 .off1 = td_var_offset(verify_async),
2506 .def = "0",
2507 .help = "Number of async verifier threads to use",
2508 .parent = "verify",
2509 .hide = 1,
2510 .category = FIO_OPT_C_IO,
2511 .group = FIO_OPT_G_VERIFY,
2512 },
2513 {
2514 .name = "verify_backlog",
2515 .lname = "Verify backlog",
2516 .type = FIO_OPT_STR_VAL,
2517 .off1 = td_var_offset(verify_backlog),
2518 .help = "Verify after this number of blocks are written",
2519 .parent = "verify",
2520 .hide = 1,
2521 .category = FIO_OPT_C_IO,
2522 .group = FIO_OPT_G_VERIFY,
2523 },
2524 {
2525 .name = "verify_backlog_batch",
2526 .lname = "Verify backlog batch",
2527 .type = FIO_OPT_INT,
2528 .off1 = td_var_offset(verify_batch),
2529 .help = "Verify this number of IO blocks",
2530 .parent = "verify",
2531 .hide = 1,
2532 .category = FIO_OPT_C_IO,
2533 .group = FIO_OPT_G_VERIFY,
2534 },
2535#ifdef FIO_HAVE_CPU_AFFINITY
2536 {
2537 .name = "verify_async_cpus",
2538 .lname = "Async verify CPUs",
2539 .type = FIO_OPT_STR,
2540 .cb = str_verify_cpus_allowed_cb,
2541 .off1 = td_var_offset(verify_cpumask),
2542 .help = "Set CPUs allowed for async verify threads",
2543 .parent = "verify_async",
2544 .hide = 1,
2545 .category = FIO_OPT_C_IO,
2546 .group = FIO_OPT_G_VERIFY,
2547 },
2548#endif
2549 {
2550 .name = "experimental_verify",
2551 .off1 = td_var_offset(experimental_verify),
2552 .type = FIO_OPT_BOOL,
2553 .help = "Enable experimental verification",
2554 .parent = "verify",
2555 .category = FIO_OPT_C_IO,
2556 .group = FIO_OPT_G_VERIFY,
2557 },
2558 {
2559 .name = "verify_state_load",
2560 .lname = "Load verify state",
2561 .off1 = td_var_offset(verify_state),
2562 .type = FIO_OPT_BOOL,
2563 .help = "Load verify termination state",
2564 .parent = "verify",
2565 .category = FIO_OPT_C_IO,
2566 .group = FIO_OPT_G_VERIFY,
2567 },
2568 {
2569 .name = "verify_state_save",
2570 .lname = "Save verify state",
2571 .off1 = td_var_offset(verify_state_save),
2572 .type = FIO_OPT_BOOL,
2573 .def = "1",
2574 .help = "Save verify state on termination",
2575 .parent = "verify",
2576 .category = FIO_OPT_C_IO,
2577 .group = FIO_OPT_G_VERIFY,
2578 },
2579#ifdef FIO_HAVE_TRIM
2580 {
2581 .name = "trim_percentage",
2582 .lname = "Trim percentage",
2583 .type = FIO_OPT_INT,
2584 .off1 = td_var_offset(trim_percentage),
2585 .minval = 0,
2586 .maxval = 100,
2587 .help = "Number of verify blocks to discard/trim",
2588 .parent = "verify",
2589 .def = "0",
2590 .interval = 1,
2591 .hide = 1,
2592 .category = FIO_OPT_C_IO,
2593 .group = FIO_OPT_G_TRIM,
2594 },
2595 {
2596 .name = "trim_verify_zero",
2597 .lname = "Verify trim zero",
2598 .type = FIO_OPT_BOOL,
2599 .help = "Verify that trim/discarded blocks are returned as zeroes",
2600 .off1 = td_var_offset(trim_zero),
2601 .parent = "trim_percentage",
2602 .hide = 1,
2603 .def = "1",
2604 .category = FIO_OPT_C_IO,
2605 .group = FIO_OPT_G_TRIM,
2606 },
2607 {
2608 .name = "trim_backlog",
2609 .lname = "Trim backlog",
2610 .type = FIO_OPT_STR_VAL,
2611 .off1 = td_var_offset(trim_backlog),
2612 .help = "Trim after this number of blocks are written",
2613 .parent = "trim_percentage",
2614 .hide = 1,
2615 .interval = 1,
2616 .category = FIO_OPT_C_IO,
2617 .group = FIO_OPT_G_TRIM,
2618 },
2619 {
2620 .name = "trim_backlog_batch",
2621 .lname = "Trim backlog batch",
2622 .type = FIO_OPT_INT,
2623 .off1 = td_var_offset(trim_batch),
2624 .help = "Trim this number of IO blocks",
2625 .parent = "trim_percentage",
2626 .hide = 1,
2627 .interval = 1,
2628 .category = FIO_OPT_C_IO,
2629 .group = FIO_OPT_G_TRIM,
2630 },
2631#endif
2632 {
2633 .name = "write_iolog",
2634 .lname = "Write I/O log",
2635 .type = FIO_OPT_STR_STORE,
2636 .off1 = td_var_offset(write_iolog_file),
2637 .help = "Store IO pattern to file",
2638 .category = FIO_OPT_C_IO,
2639 .group = FIO_OPT_G_IOLOG,
2640 },
2641 {
2642 .name = "read_iolog",
2643 .lname = "Read I/O log",
2644 .type = FIO_OPT_STR_STORE,
2645 .off1 = td_var_offset(read_iolog_file),
2646 .help = "Playback IO pattern from file",
2647 .category = FIO_OPT_C_IO,
2648 .group = FIO_OPT_G_IOLOG,
2649 },
2650 {
2651 .name = "replay_no_stall",
2652 .lname = "Don't stall on replay",
2653 .type = FIO_OPT_BOOL,
2654 .off1 = td_var_offset(no_stall),
2655 .def = "0",
2656 .parent = "read_iolog",
2657 .hide = 1,
2658 .help = "Playback IO pattern file as fast as possible without stalls",
2659 .category = FIO_OPT_C_IO,
2660 .group = FIO_OPT_G_IOLOG,
2661 },
2662 {
2663 .name = "replay_redirect",
2664 .lname = "Redirect device for replay",
2665 .type = FIO_OPT_STR_STORE,
2666 .off1 = td_var_offset(replay_redirect),
2667 .parent = "read_iolog",
2668 .hide = 1,
2669 .help = "Replay all I/O onto this device, regardless of trace device",
2670 .category = FIO_OPT_C_IO,
2671 .group = FIO_OPT_G_IOLOG,
2672 },
2673 {
2674 .name = "replay_scale",
2675 .lname = "Replace offset scale factor",
2676 .type = FIO_OPT_INT,
2677 .off1 = td_var_offset(replay_scale),
2678 .parent = "read_iolog",
2679 .def = "1",
2680 .help = "Align offsets to this blocksize",
2681 .category = FIO_OPT_C_IO,
2682 .group = FIO_OPT_G_IOLOG,
2683 },
2684 {
2685 .name = "replay_align",
2686 .lname = "Replace alignment",
2687 .type = FIO_OPT_INT,
2688 .off1 = td_var_offset(replay_align),
2689 .parent = "read_iolog",
2690 .help = "Scale offset down by this factor",
2691 .category = FIO_OPT_C_IO,
2692 .group = FIO_OPT_G_IOLOG,
2693 .pow2 = 1,
2694 },
2695 {
2696 .name = "exec_prerun",
2697 .lname = "Pre-execute runnable",
2698 .type = FIO_OPT_STR_STORE,
2699 .off1 = td_var_offset(exec_prerun),
2700 .help = "Execute this file prior to running job",
2701 .category = FIO_OPT_C_GENERAL,
2702 .group = FIO_OPT_G_INVALID,
2703 },
2704 {
2705 .name = "exec_postrun",
2706 .lname = "Post-execute runnable",
2707 .type = FIO_OPT_STR_STORE,
2708 .off1 = td_var_offset(exec_postrun),
2709 .help = "Execute this file after running job",
2710 .category = FIO_OPT_C_GENERAL,
2711 .group = FIO_OPT_G_INVALID,
2712 },
2713#ifdef FIO_HAVE_IOSCHED_SWITCH
2714 {
2715 .name = "ioscheduler",
2716 .lname = "I/O scheduler",
2717 .type = FIO_OPT_STR_STORE,
2718 .off1 = td_var_offset(ioscheduler),
2719 .help = "Use this IO scheduler on the backing device",
2720 .category = FIO_OPT_C_FILE,
2721 .group = FIO_OPT_G_INVALID,
2722 },
2723#endif
2724 {
2725 .name = "zonesize",
2726 .lname = "Zone size",
2727 .type = FIO_OPT_STR_VAL,
2728 .off1 = td_var_offset(zone_size),
2729 .help = "Amount of data to read per zone",
2730 .def = "0",
2731 .interval = 1024 * 1024,
2732 .category = FIO_OPT_C_IO,
2733 .group = FIO_OPT_G_ZONE,
2734 },
2735 {
2736 .name = "zonerange",
2737 .lname = "Zone range",
2738 .type = FIO_OPT_STR_VAL,
2739 .off1 = td_var_offset(zone_range),
2740 .help = "Give size of an IO zone",
2741 .def = "0",
2742 .interval = 1024 * 1024,
2743 .category = FIO_OPT_C_IO,
2744 .group = FIO_OPT_G_ZONE,
2745 },
2746 {
2747 .name = "zoneskip",
2748 .lname = "Zone skip",
2749 .type = FIO_OPT_STR_VAL,
2750 .off1 = td_var_offset(zone_skip),
2751 .help = "Space between IO zones",
2752 .def = "0",
2753 .interval = 1024 * 1024,
2754 .category = FIO_OPT_C_IO,
2755 .group = FIO_OPT_G_ZONE,
2756 },
2757 {
2758 .name = "lockmem",
2759 .lname = "Lock memory",
2760 .type = FIO_OPT_STR_VAL,
2761 .off1 = td_var_offset(lockmem),
2762 .help = "Lock down this amount of memory (per worker)",
2763 .def = "0",
2764 .interval = 1024 * 1024,
2765 .category = FIO_OPT_C_GENERAL,
2766 .group = FIO_OPT_G_INVALID,
2767 },
2768 {
2769 .name = "rwmixread",
2770 .lname = "Read/write mix read",
2771 .type = FIO_OPT_INT,
2772 .cb = str_rwmix_read_cb,
2773 .off1 = td_var_offset(rwmix[DDIR_READ]),
2774 .maxval = 100,
2775 .help = "Percentage of mixed workload that is reads",
2776 .def = "50",
2777 .interval = 5,
2778 .inverse = "rwmixwrite",
2779 .category = FIO_OPT_C_IO,
2780 .group = FIO_OPT_G_RWMIX,
2781 },
2782 {
2783 .name = "rwmixwrite",
2784 .lname = "Read/write mix write",
2785 .type = FIO_OPT_INT,
2786 .cb = str_rwmix_write_cb,
2787 .off1 = td_var_offset(rwmix[DDIR_WRITE]),
2788 .maxval = 100,
2789 .help = "Percentage of mixed workload that is writes",
2790 .def = "50",
2791 .interval = 5,
2792 .inverse = "rwmixread",
2793 .category = FIO_OPT_C_IO,
2794 .group = FIO_OPT_G_RWMIX,
2795 },
2796 {
2797 .name = "rwmixcycle",
2798 .lname = "Read/write mix cycle",
2799 .type = FIO_OPT_DEPRECATED,
2800 .category = FIO_OPT_C_IO,
2801 .group = FIO_OPT_G_RWMIX,
2802 },
2803 {
2804 .name = "nice",
2805 .lname = "Nice",
2806 .type = FIO_OPT_INT,
2807 .off1 = td_var_offset(nice),
2808 .help = "Set job CPU nice value",
2809 .minval = -19,
2810 .maxval = 20,
2811 .def = "0",
2812 .interval = 1,
2813 .category = FIO_OPT_C_GENERAL,
2814 .group = FIO_OPT_G_CRED,
2815 },
2816#ifdef FIO_HAVE_IOPRIO
2817 {
2818 .name = "prio",
2819 .lname = "I/O nice priority",
2820 .type = FIO_OPT_INT,
2821 .off1 = td_var_offset(ioprio),
2822 .help = "Set job IO priority value",
2823 .minval = 0,
2824 .maxval = 7,
2825 .interval = 1,
2826 .category = FIO_OPT_C_GENERAL,
2827 .group = FIO_OPT_G_CRED,
2828 },
2829 {
2830 .name = "prioclass",
2831 .lname = "I/O nice priority class",
2832 .type = FIO_OPT_INT,
2833 .off1 = td_var_offset(ioprio_class),
2834 .help = "Set job IO priority class",
2835 .minval = 0,
2836 .maxval = 3,
2837 .interval = 1,
2838 .category = FIO_OPT_C_GENERAL,
2839 .group = FIO_OPT_G_CRED,
2840 },
2841#endif
2842 {
2843 .name = "thinktime",
2844 .lname = "Thinktime",
2845 .type = FIO_OPT_INT,
2846 .off1 = td_var_offset(thinktime),
2847 .help = "Idle time between IO buffers (usec)",
2848 .def = "0",
2849 .is_time = 1,
2850 .category = FIO_OPT_C_IO,
2851 .group = FIO_OPT_G_THINKTIME,
2852 },
2853 {
2854 .name = "thinktime_spin",
2855 .lname = "Thinktime spin",
2856 .type = FIO_OPT_INT,
2857 .off1 = td_var_offset(thinktime_spin),
2858 .help = "Start think time by spinning this amount (usec)",
2859 .def = "0",
2860 .is_time = 1,
2861 .parent = "thinktime",
2862 .hide = 1,
2863 .category = FIO_OPT_C_IO,
2864 .group = FIO_OPT_G_THINKTIME,
2865 },
2866 {
2867 .name = "thinktime_blocks",
2868 .lname = "Thinktime blocks",
2869 .type = FIO_OPT_INT,
2870 .off1 = td_var_offset(thinktime_blocks),
2871 .help = "IO buffer period between 'thinktime'",
2872 .def = "1",
2873 .parent = "thinktime",
2874 .hide = 1,
2875 .category = FIO_OPT_C_IO,
2876 .group = FIO_OPT_G_THINKTIME,
2877 },
2878 {
2879 .name = "rate",
2880 .lname = "I/O rate",
2881 .type = FIO_OPT_INT,
2882 .off1 = td_var_offset(rate[DDIR_READ]),
2883 .off2 = td_var_offset(rate[DDIR_WRITE]),
2884 .off3 = td_var_offset(rate[DDIR_TRIM]),
2885 .help = "Set bandwidth rate",
2886 .category = FIO_OPT_C_IO,
2887 .group = FIO_OPT_G_RATE,
2888 },
2889 {
2890 .name = "ratemin",
2891 .lname = "I/O min rate",
2892 .type = FIO_OPT_INT,
2893 .off1 = td_var_offset(ratemin[DDIR_READ]),
2894 .off2 = td_var_offset(ratemin[DDIR_WRITE]),
2895 .off3 = td_var_offset(ratemin[DDIR_TRIM]),
2896 .help = "Job must meet this rate or it will be shutdown",
2897 .parent = "rate",
2898 .hide = 1,
2899 .category = FIO_OPT_C_IO,
2900 .group = FIO_OPT_G_RATE,
2901 },
2902 {
2903 .name = "rate_iops",
2904 .lname = "I/O rate IOPS",
2905 .type = FIO_OPT_INT,
2906 .off1 = td_var_offset(rate_iops[DDIR_READ]),
2907 .off2 = td_var_offset(rate_iops[DDIR_WRITE]),
2908 .off3 = td_var_offset(rate_iops[DDIR_TRIM]),
2909 .help = "Limit IO used to this number of IO operations/sec",
2910 .hide = 1,
2911 .category = FIO_OPT_C_IO,
2912 .group = FIO_OPT_G_RATE,
2913 },
2914 {
2915 .name = "rate_iops_min",
2916 .lname = "I/O min rate IOPS",
2917 .type = FIO_OPT_INT,
2918 .off1 = td_var_offset(rate_iops_min[DDIR_READ]),
2919 .off2 = td_var_offset(rate_iops_min[DDIR_WRITE]),
2920 .off3 = td_var_offset(rate_iops_min[DDIR_TRIM]),
2921 .help = "Job must meet this rate or it will be shut down",
2922 .parent = "rate_iops",
2923 .hide = 1,
2924 .category = FIO_OPT_C_IO,
2925 .group = FIO_OPT_G_RATE,
2926 },
2927 {
2928 .name = "ratecycle",
2929 .lname = "I/O rate cycle",
2930 .type = FIO_OPT_INT,
2931 .off1 = td_var_offset(ratecycle),
2932 .help = "Window average for rate limits (msec)",
2933 .def = "1000",
2934 .parent = "rate",
2935 .hide = 1,
2936 .category = FIO_OPT_C_IO,
2937 .group = FIO_OPT_G_RATE,
2938 },
2939 {
2940 .name = "max_latency",
2941 .type = FIO_OPT_INT,
2942 .off1 = td_var_offset(max_latency),
2943 .help = "Maximum tolerated IO latency (usec)",
2944 .is_time = 1,
2945 .category = FIO_OPT_C_IO,
2946 .group = FIO_OPT_G_LATPROF,
2947 },
2948 {
2949 .name = "latency_target",
2950 .lname = "Latency Target (usec)",
2951 .type = FIO_OPT_STR_VAL_TIME,
2952 .off1 = td_var_offset(latency_target),
2953 .help = "Ramp to max queue depth supporting this latency",
2954 .is_time = 1,
2955 .category = FIO_OPT_C_IO,
2956 .group = FIO_OPT_G_LATPROF,
2957 },
2958 {
2959 .name = "latency_window",
2960 .lname = "Latency Window (usec)",
2961 .type = FIO_OPT_STR_VAL_TIME,
2962 .off1 = td_var_offset(latency_window),
2963 .help = "Time to sustain latency_target",
2964 .is_time = 1,
2965 .category = FIO_OPT_C_IO,
2966 .group = FIO_OPT_G_LATPROF,
2967 },
2968 {
2969 .name = "latency_percentile",
2970 .lname = "Latency Percentile",
2971 .type = FIO_OPT_FLOAT_LIST,
2972 .off1 = td_var_offset(latency_percentile),
2973 .help = "Percentile of IOs must be below latency_target",
2974 .def = "100",
2975 .maxlen = 1,
2976 .minfp = 0.0,
2977 .maxfp = 100.0,
2978 .category = FIO_OPT_C_IO,
2979 .group = FIO_OPT_G_LATPROF,
2980 },
2981 {
2982 .name = "invalidate",
2983 .lname = "Cache invalidate",
2984 .type = FIO_OPT_BOOL,
2985 .off1 = td_var_offset(invalidate_cache),
2986 .help = "Invalidate buffer/page cache prior to running job",
2987 .def = "1",
2988 .category = FIO_OPT_C_IO,
2989 .group = FIO_OPT_G_IO_TYPE,
2990 },
2991 {
2992 .name = "sync",
2993 .lname = "Synchronous I/O",
2994 .type = FIO_OPT_BOOL,
2995 .off1 = td_var_offset(sync_io),
2996 .help = "Use O_SYNC for buffered writes",
2997 .def = "0",
2998 .parent = "buffered",
2999 .hide = 1,
3000 .category = FIO_OPT_C_IO,
3001 .group = FIO_OPT_G_IO_TYPE,
3002 },
3003 {
3004 .name = "create_serialize",
3005 .lname = "Create serialize",
3006 .type = FIO_OPT_BOOL,
3007 .off1 = td_var_offset(create_serialize),
3008 .help = "Serialize creating of job files",
3009 .def = "1",
3010 .category = FIO_OPT_C_FILE,
3011 .group = FIO_OPT_G_INVALID,
3012 },
3013 {
3014 .name = "create_fsync",
3015 .lname = "Create fsync",
3016 .type = FIO_OPT_BOOL,
3017 .off1 = td_var_offset(create_fsync),
3018 .help = "fsync file after creation",
3019 .def = "1",
3020 .category = FIO_OPT_C_FILE,
3021 .group = FIO_OPT_G_INVALID,
3022 },
3023 {
3024 .name = "create_on_open",
3025 .lname = "Create on open",
3026 .type = FIO_OPT_BOOL,
3027 .off1 = td_var_offset(create_on_open),
3028 .help = "Create files when they are opened for IO",
3029 .def = "0",
3030 .category = FIO_OPT_C_FILE,
3031 .group = FIO_OPT_G_INVALID,
3032 },
3033 {
3034 .name = "create_only",
3035 .type = FIO_OPT_BOOL,
3036 .off1 = td_var_offset(create_only),
3037 .help = "Only perform file creation phase",
3038 .category = FIO_OPT_C_FILE,
3039 .def = "0",
3040 },
3041 {
3042 .name = "pre_read",
3043 .lname = "Pre-read files",
3044 .type = FIO_OPT_BOOL,
3045 .off1 = td_var_offset(pre_read),
3046 .help = "Pre-read files before starting official testing",
3047 .def = "0",
3048 .category = FIO_OPT_C_FILE,
3049 .group = FIO_OPT_G_INVALID,
3050 },
3051#ifdef FIO_HAVE_CPU_AFFINITY
3052 {
3053 .name = "cpumask",
3054 .lname = "CPU mask",
3055 .type = FIO_OPT_INT,
3056 .cb = str_cpumask_cb,
3057 .off1 = td_var_offset(cpumask),
3058 .help = "CPU affinity mask",
3059 .category = FIO_OPT_C_GENERAL,
3060 .group = FIO_OPT_G_CRED,
3061 },
3062 {
3063 .name = "cpus_allowed",
3064 .lname = "CPUs allowed",
3065 .type = FIO_OPT_STR,
3066 .cb = str_cpus_allowed_cb,
3067 .off1 = td_var_offset(cpumask),
3068 .help = "Set CPUs allowed",
3069 .category = FIO_OPT_C_GENERAL,
3070 .group = FIO_OPT_G_CRED,
3071 },
3072 {
3073 .name = "cpus_allowed_policy",
3074 .lname = "CPUs allowed distribution policy",
3075 .type = FIO_OPT_STR,
3076 .off1 = td_var_offset(cpus_allowed_policy),
3077 .help = "Distribution policy for cpus_allowed",
3078 .parent = "cpus_allowed",
3079 .prio = 1,
3080 .posval = {
3081 { .ival = "shared",
3082 .oval = FIO_CPUS_SHARED,
3083 .help = "Mask shared between threads",
3084 },
3085 { .ival = "split",
3086 .oval = FIO_CPUS_SPLIT,
3087 .help = "Mask split between threads",
3088 },
3089 },
3090 .category = FIO_OPT_C_GENERAL,
3091 .group = FIO_OPT_G_CRED,
3092 },
3093#endif
3094#ifdef CONFIG_LIBNUMA
3095 {
3096 .name = "numa_cpu_nodes",
3097 .type = FIO_OPT_STR,
3098 .cb = str_numa_cpunodes_cb,
3099 .off1 = td_var_offset(numa_cpunodes),
3100 .help = "NUMA CPU nodes bind",
3101 .category = FIO_OPT_C_GENERAL,
3102 .group = FIO_OPT_G_INVALID,
3103 },
3104 {
3105 .name = "numa_mem_policy",
3106 .type = FIO_OPT_STR,
3107 .cb = str_numa_mpol_cb,
3108 .off1 = td_var_offset(numa_memnodes),
3109 .help = "NUMA memory policy setup",
3110 .category = FIO_OPT_C_GENERAL,
3111 .group = FIO_OPT_G_INVALID,
3112 },
3113#endif
3114 {
3115 .name = "end_fsync",
3116 .lname = "End fsync",
3117 .type = FIO_OPT_BOOL,
3118 .off1 = td_var_offset(end_fsync),
3119 .help = "Include fsync at the end of job",
3120 .def = "0",
3121 .category = FIO_OPT_C_FILE,
3122 .group = FIO_OPT_G_INVALID,
3123 },
3124 {
3125 .name = "fsync_on_close",
3126 .lname = "Fsync on close",
3127 .type = FIO_OPT_BOOL,
3128 .off1 = td_var_offset(fsync_on_close),
3129 .help = "fsync files on close",
3130 .def = "0",
3131 .category = FIO_OPT_C_FILE,
3132 .group = FIO_OPT_G_INVALID,
3133 },
3134 {
3135 .name = "unlink",
3136 .lname = "Unlink file",
3137 .type = FIO_OPT_BOOL,
3138 .off1 = td_var_offset(unlink),
3139 .help = "Unlink created files after job has completed",
3140 .def = "0",
3141 .category = FIO_OPT_C_FILE,
3142 .group = FIO_OPT_G_INVALID,
3143 },
3144 {
3145 .name = "exitall",
3146 .lname = "Exit-all on terminate",
3147 .type = FIO_OPT_STR_SET,
3148 .cb = str_exitall_cb,
3149 .help = "Terminate all jobs when one exits",
3150 .category = FIO_OPT_C_GENERAL,
3151 .group = FIO_OPT_G_PROCESS,
3152 },
3153 {
3154 .name = "stonewall",
3155 .lname = "Wait for previous",
3156 .alias = "wait_for_previous",
3157 .type = FIO_OPT_STR_SET,
3158 .off1 = td_var_offset(stonewall),
3159 .help = "Insert a hard barrier between this job and previous",
3160 .category = FIO_OPT_C_GENERAL,
3161 .group = FIO_OPT_G_PROCESS,
3162 },
3163 {
3164 .name = "new_group",
3165 .lname = "New group",
3166 .type = FIO_OPT_STR_SET,
3167 .off1 = td_var_offset(new_group),
3168 .help = "Mark the start of a new group (for reporting)",
3169 .category = FIO_OPT_C_GENERAL,
3170 .group = FIO_OPT_G_PROCESS,
3171 },
3172 {
3173 .name = "thread",
3174 .lname = "Thread",
3175 .type = FIO_OPT_STR_SET,
3176 .off1 = td_var_offset(use_thread),
3177 .help = "Use threads instead of processes",
3178#ifdef CONFIG_NO_SHM
3179 .def = "1",
3180 .no_warn_def = 1,
3181#endif
3182 .category = FIO_OPT_C_GENERAL,
3183 .group = FIO_OPT_G_PROCESS,
3184 },
3185 {
3186 .name = "write_bw_log",
3187 .lname = "Write bandwidth log",
3188 .type = FIO_OPT_STR_STORE,
3189 .off1 = td_var_offset(bw_log_file),
3190 .help = "Write log of bandwidth during run",
3191 .category = FIO_OPT_C_LOG,
3192 .group = FIO_OPT_G_INVALID,
3193 },
3194 {
3195 .name = "write_lat_log",
3196 .lname = "Write latency log",
3197 .type = FIO_OPT_STR_STORE,
3198 .off1 = td_var_offset(lat_log_file),
3199 .help = "Write log of latency during run",
3200 .category = FIO_OPT_C_LOG,
3201 .group = FIO_OPT_G_INVALID,
3202 },
3203 {
3204 .name = "write_iops_log",
3205 .lname = "Write IOPS log",
3206 .type = FIO_OPT_STR_STORE,
3207 .off1 = td_var_offset(iops_log_file),
3208 .help = "Write log of IOPS during run",
3209 .category = FIO_OPT_C_LOG,
3210 .group = FIO_OPT_G_INVALID,
3211 },
3212 {
3213 .name = "log_avg_msec",
3214 .lname = "Log averaging (msec)",
3215 .type = FIO_OPT_INT,
3216 .off1 = td_var_offset(log_avg_msec),
3217 .help = "Average bw/iops/lat logs over this period of time",
3218 .def = "0",
3219 .category = FIO_OPT_C_LOG,
3220 .group = FIO_OPT_G_INVALID,
3221 },
3222 {
3223 .name = "log_offset",
3224 .lname = "Log offset of IO",
3225 .type = FIO_OPT_BOOL,
3226 .off1 = td_var_offset(log_offset),
3227 .help = "Include offset of IO for each log entry",
3228 .def = "0",
3229 .category = FIO_OPT_C_LOG,
3230 .group = FIO_OPT_G_INVALID,
3231 },
3232#ifdef CONFIG_ZLIB
3233 {
3234 .name = "log_compression",
3235 .lname = "Log compression",
3236 .type = FIO_OPT_INT,
3237 .off1 = td_var_offset(log_gz),
3238 .help = "Log in compressed chunks of this size",
3239 .minval = 32 * 1024 * 1024ULL,
3240 .maxval = 512 * 1024 * 1024ULL,
3241 .category = FIO_OPT_C_LOG,
3242 .group = FIO_OPT_G_INVALID,
3243 },
3244 {
3245 .name = "log_store_compressed",
3246 .lname = "Log store compressed",
3247 .type = FIO_OPT_BOOL,
3248 .off1 = td_var_offset(log_gz_store),
3249 .help = "Store logs in a compressed format",
3250 .category = FIO_OPT_C_LOG,
3251 .group = FIO_OPT_G_INVALID,
3252 },
3253#endif
3254 {
3255 .name = "block_error_percentiles",
3256 .lname = "Block error percentiles",
3257 .type = FIO_OPT_BOOL,
3258 .off1 = td_var_offset(block_error_hist),
3259 .help = "Record trim block errors and make a histogram",
3260 .def = "0",
3261 .category = FIO_OPT_C_LOG,
3262 .group = FIO_OPT_G_INVALID,
3263 },
3264 {
3265 .name = "bwavgtime",
3266 .lname = "Bandwidth average time",
3267 .type = FIO_OPT_INT,
3268 .off1 = td_var_offset(bw_avg_time),
3269 .help = "Time window over which to calculate bandwidth"
3270 " (msec)",
3271 .def = "500",
3272 .parent = "write_bw_log",
3273 .hide = 1,
3274 .interval = 100,
3275 .category = FIO_OPT_C_LOG,
3276 .group = FIO_OPT_G_INVALID,
3277 },
3278 {
3279 .name = "iopsavgtime",
3280 .lname = "IOPS average time",
3281 .type = FIO_OPT_INT,
3282 .off1 = td_var_offset(iops_avg_time),
3283 .help = "Time window over which to calculate IOPS (msec)",
3284 .def = "500",
3285 .parent = "write_iops_log",
3286 .hide = 1,
3287 .interval = 100,
3288 .category = FIO_OPT_C_LOG,
3289 .group = FIO_OPT_G_INVALID,
3290 },
3291 {
3292 .name = "group_reporting",
3293 .lname = "Group reporting",
3294 .type = FIO_OPT_STR_SET,
3295 .off1 = td_var_offset(group_reporting),
3296 .help = "Do reporting on a per-group basis",
3297 .category = FIO_OPT_C_STAT,
3298 .group = FIO_OPT_G_INVALID,
3299 },
3300 {
3301 .name = "zero_buffers",
3302 .lname = "Zero I/O buffers",
3303 .type = FIO_OPT_STR_SET,
3304 .off1 = td_var_offset(zero_buffers),
3305 .help = "Init IO buffers to all zeroes",
3306 .category = FIO_OPT_C_IO,
3307 .group = FIO_OPT_G_IO_BUF,
3308 },
3309 {
3310 .name = "refill_buffers",
3311 .lname = "Refill I/O buffers",
3312 .type = FIO_OPT_STR_SET,
3313 .off1 = td_var_offset(refill_buffers),
3314 .help = "Refill IO buffers on every IO submit",
3315 .category = FIO_OPT_C_IO,
3316 .group = FIO_OPT_G_IO_BUF,
3317 },
3318 {
3319 .name = "scramble_buffers",
3320 .lname = "Scramble I/O buffers",
3321 .type = FIO_OPT_BOOL,
3322 .off1 = td_var_offset(scramble_buffers),
3323 .help = "Slightly scramble buffers on every IO submit",
3324 .def = "1",
3325 .category = FIO_OPT_C_IO,
3326 .group = FIO_OPT_G_IO_BUF,
3327 },
3328 {
3329 .name = "buffer_pattern",
3330 .lname = "Buffer pattern",
3331 .type = FIO_OPT_STR,
3332 .cb = str_buffer_pattern_cb,
3333 .off1 = td_var_offset(buffer_pattern),
3334 .help = "Fill pattern for IO buffers",
3335 .category = FIO_OPT_C_IO,
3336 .group = FIO_OPT_G_IO_BUF,
3337 },
3338 {
3339 .name = "buffer_compress_percentage",
3340 .lname = "Buffer compression percentage",
3341 .type = FIO_OPT_INT,
3342 .cb = str_buffer_compress_cb,
3343 .off1 = td_var_offset(compress_percentage),
3344 .maxval = 100,
3345 .minval = 0,
3346 .help = "How compressible the buffer is (approximately)",
3347 .interval = 5,
3348 .category = FIO_OPT_C_IO,
3349 .group = FIO_OPT_G_IO_BUF,
3350 },
3351 {
3352 .name = "buffer_compress_chunk",
3353 .lname = "Buffer compression chunk size",
3354 .type = FIO_OPT_INT,
3355 .off1 = td_var_offset(compress_chunk),
3356 .parent = "buffer_compress_percentage",
3357 .hide = 1,
3358 .help = "Size of compressible region in buffer",
3359 .interval = 256,
3360 .category = FIO_OPT_C_IO,
3361 .group = FIO_OPT_G_IO_BUF,
3362 },
3363 {
3364 .name = "dedupe_percentage",
3365 .lname = "Dedupe percentage",
3366 .type = FIO_OPT_INT,
3367 .cb = str_dedupe_cb,
3368 .off1 = td_var_offset(dedupe_percentage),
3369 .maxval = 100,
3370 .minval = 0,
3371 .help = "Percentage of buffers that are dedupable",
3372 .interval = 1,
3373 .category = FIO_OPT_C_IO,
3374 .group = FIO_OPT_G_IO_BUF,
3375 },
3376 {
3377 .name = "clat_percentiles",
3378 .lname = "Completion latency percentiles",
3379 .type = FIO_OPT_BOOL,
3380 .off1 = td_var_offset(clat_percentiles),
3381 .help = "Enable the reporting of completion latency percentiles",
3382 .def = "1",
3383 .category = FIO_OPT_C_STAT,
3384 .group = FIO_OPT_G_INVALID,
3385 },
3386 {
3387 .name = "percentile_list",
3388 .lname = "Percentile list",
3389 .type = FIO_OPT_FLOAT_LIST,
3390 .off1 = td_var_offset(percentile_list),
3391 .off2 = td_var_offset(percentile_precision),
3392 .help = "Specify a custom list of percentiles to report for "
3393 "completion latency and block errors",
3394 .def = "1:5:10:20:30:40:50:60:70:80:90:95:99:99.5:99.9:99.95:99.99",
3395 .maxlen = FIO_IO_U_LIST_MAX_LEN,
3396 .minfp = 0.0,
3397 .maxfp = 100.0,
3398 .category = FIO_OPT_C_STAT,
3399 .group = FIO_OPT_G_INVALID,
3400 },
3401
3402#ifdef FIO_HAVE_DISK_UTIL
3403 {
3404 .name = "disk_util",
3405 .lname = "Disk utilization",
3406 .type = FIO_OPT_BOOL,
3407 .off1 = td_var_offset(do_disk_util),
3408 .help = "Log disk utilization statistics",
3409 .def = "1",
3410 .category = FIO_OPT_C_STAT,
3411 .group = FIO_OPT_G_INVALID,
3412 },
3413#endif
3414 {
3415 .name = "gtod_reduce",
3416 .lname = "Reduce gettimeofday() calls",
3417 .type = FIO_OPT_BOOL,
3418 .help = "Greatly reduce number of gettimeofday() calls",
3419 .cb = str_gtod_reduce_cb,
3420 .def = "0",
3421 .hide_on_set = 1,
3422 .category = FIO_OPT_C_STAT,
3423 .group = FIO_OPT_G_INVALID,
3424 },
3425 {
3426 .name = "disable_lat",
3427 .lname = "Disable all latency stats",
3428 .type = FIO_OPT_BOOL,
3429 .off1 = td_var_offset(disable_lat),
3430 .help = "Disable latency numbers",
3431 .parent = "gtod_reduce",
3432 .hide = 1,
3433 .def = "0",
3434 .category = FIO_OPT_C_STAT,
3435 .group = FIO_OPT_G_INVALID,
3436 },
3437 {
3438 .name = "disable_clat",
3439 .lname = "Disable completion latency stats",
3440 .type = FIO_OPT_BOOL,
3441 .off1 = td_var_offset(disable_clat),
3442 .help = "Disable completion latency numbers",
3443 .parent = "gtod_reduce",
3444 .hide = 1,
3445 .def = "0",
3446 .category = FIO_OPT_C_STAT,
3447 .group = FIO_OPT_G_INVALID,
3448 },
3449 {
3450 .name = "disable_slat",
3451 .lname = "Disable submission latency stats",
3452 .type = FIO_OPT_BOOL,
3453 .off1 = td_var_offset(disable_slat),
3454 .help = "Disable submission latency numbers",
3455 .parent = "gtod_reduce",
3456 .hide = 1,
3457 .def = "0",
3458 .category = FIO_OPT_C_STAT,
3459 .group = FIO_OPT_G_INVALID,
3460 },
3461 {
3462 .name = "disable_bw_measurement",
3463 .lname = "Disable bandwidth stats",
3464 .type = FIO_OPT_BOOL,
3465 .off1 = td_var_offset(disable_bw),
3466 .help = "Disable bandwidth logging",
3467 .parent = "gtod_reduce",
3468 .hide = 1,
3469 .def = "0",
3470 .category = FIO_OPT_C_STAT,
3471 .group = FIO_OPT_G_INVALID,
3472 },
3473 {
3474 .name = "gtod_cpu",
3475 .lname = "Dedicated gettimeofday() CPU",
3476 .type = FIO_OPT_INT,
3477 .off1 = td_var_offset(gtod_cpu),
3478 .help = "Set up dedicated gettimeofday() thread on this CPU",
3479 .verify = gtod_cpu_verify,
3480 .category = FIO_OPT_C_GENERAL,
3481 .group = FIO_OPT_G_CLOCK,
3482 },
3483 {
3484 .name = "unified_rw_reporting",
3485 .type = FIO_OPT_BOOL,
3486 .off1 = td_var_offset(unified_rw_rep),
3487 .help = "Unify reporting across data direction",
3488 .def = "0",
3489 .category = FIO_OPT_C_GENERAL,
3490 .group = FIO_OPT_G_INVALID,
3491 },
3492 {
3493 .name = "continue_on_error",
3494 .lname = "Continue on error",
3495 .type = FIO_OPT_STR,
3496 .off1 = td_var_offset(continue_on_error),
3497 .help = "Continue on non-fatal errors during IO",
3498 .def = "none",
3499 .category = FIO_OPT_C_GENERAL,
3500 .group = FIO_OPT_G_ERR,
3501 .posval = {
3502 { .ival = "none",
3503 .oval = ERROR_TYPE_NONE,
3504 .help = "Exit when an error is encountered",
3505 },
3506 { .ival = "read",
3507 .oval = ERROR_TYPE_READ,
3508 .help = "Continue on read errors only",
3509 },
3510 { .ival = "write",
3511 .oval = ERROR_TYPE_WRITE,
3512 .help = "Continue on write errors only",
3513 },
3514 { .ival = "io",
3515 .oval = ERROR_TYPE_READ | ERROR_TYPE_WRITE,
3516 .help = "Continue on any IO errors",
3517 },
3518 { .ival = "verify",
3519 .oval = ERROR_TYPE_VERIFY,
3520 .help = "Continue on verify errors only",
3521 },
3522 { .ival = "all",
3523 .oval = ERROR_TYPE_ANY,
3524 .help = "Continue on all io and verify errors",
3525 },
3526 { .ival = "0",
3527 .oval = ERROR_TYPE_NONE,
3528 .help = "Alias for 'none'",
3529 },
3530 { .ival = "1",
3531 .oval = ERROR_TYPE_ANY,
3532 .help = "Alias for 'all'",
3533 },
3534 },
3535 },
3536 {
3537 .name = "ignore_error",
3538 .type = FIO_OPT_STR,
3539 .cb = str_ignore_error_cb,
3540 .off1 = td_var_offset(ignore_error_nr),
3541 .help = "Set a specific list of errors to ignore",
3542 .parent = "rw",
3543 .category = FIO_OPT_C_GENERAL,
3544 .group = FIO_OPT_G_ERR,
3545 },
3546 {
3547 .name = "error_dump",
3548 .type = FIO_OPT_BOOL,
3549 .off1 = td_var_offset(error_dump),
3550 .def = "0",
3551 .help = "Dump info on each error",
3552 .category = FIO_OPT_C_GENERAL,
3553 .group = FIO_OPT_G_ERR,
3554 },
3555 {
3556 .name = "profile",
3557 .lname = "Profile",
3558 .type = FIO_OPT_STR_STORE,
3559 .off1 = td_var_offset(profile),
3560 .help = "Select a specific builtin performance test",
3561 .category = FIO_OPT_C_PROFILE,
3562 .group = FIO_OPT_G_INVALID,
3563 },
3564 {
3565 .name = "cgroup",
3566 .lname = "Cgroup",
3567 .type = FIO_OPT_STR_STORE,
3568 .off1 = td_var_offset(cgroup),
3569 .help = "Add job to cgroup of this name",
3570 .category = FIO_OPT_C_GENERAL,
3571 .group = FIO_OPT_G_CGROUP,
3572 },
3573 {
3574 .name = "cgroup_nodelete",
3575 .lname = "Cgroup no-delete",
3576 .type = FIO_OPT_BOOL,
3577 .off1 = td_var_offset(cgroup_nodelete),
3578 .help = "Do not delete cgroups after job completion",
3579 .def = "0",
3580 .parent = "cgroup",
3581 .category = FIO_OPT_C_GENERAL,
3582 .group = FIO_OPT_G_CGROUP,
3583 },
3584 {
3585 .name = "cgroup_weight",
3586 .lname = "Cgroup weight",
3587 .type = FIO_OPT_INT,
3588 .off1 = td_var_offset(cgroup_weight),
3589 .help = "Use given weight for cgroup",
3590 .minval = 100,
3591 .maxval = 1000,
3592 .parent = "cgroup",
3593 .category = FIO_OPT_C_GENERAL,
3594 .group = FIO_OPT_G_CGROUP,
3595 },
3596 {
3597 .name = "uid",
3598 .lname = "User ID",
3599 .type = FIO_OPT_INT,
3600 .off1 = td_var_offset(uid),
3601 .help = "Run job with this user ID",
3602 .category = FIO_OPT_C_GENERAL,
3603 .group = FIO_OPT_G_CRED,
3604 },
3605 {
3606 .name = "gid",
3607 .lname = "Group ID",
3608 .type = FIO_OPT_INT,
3609 .off1 = td_var_offset(gid),
3610 .help = "Run job with this group ID",
3611 .category = FIO_OPT_C_GENERAL,
3612 .group = FIO_OPT_G_CRED,
3613 },
3614 {
3615 .name = "kb_base",
3616 .lname = "KB Base",
3617 .type = FIO_OPT_INT,
3618 .off1 = td_var_offset(kb_base),
3619 .prio = 1,
3620 .def = "1024",
3621 .posval = {
3622 { .ival = "1024",
3623 .oval = 1024,
3624 .help = "Use 1024 as the K base",
3625 },
3626 { .ival = "1000",
3627 .oval = 1000,
3628 .help = "Use 1000 as the K base",
3629 },
3630 },
3631 .help = "How many bytes per KB for reporting (1000 or 1024)",
3632 .category = FIO_OPT_C_GENERAL,
3633 .group = FIO_OPT_G_INVALID,
3634 },
3635 {
3636 .name = "unit_base",
3637 .lname = "Base unit for reporting (Bits or Bytes)",
3638 .type = FIO_OPT_INT,
3639 .off1 = td_var_offset(unit_base),
3640 .prio = 1,
3641 .posval = {
3642 { .ival = "0",
3643 .oval = 0,
3644 .help = "Auto-detect",
3645 },
3646 { .ival = "8",
3647 .oval = 8,
3648 .help = "Normal (byte based)",
3649 },
3650 { .ival = "1",
3651 .oval = 1,
3652 .help = "Bit based",
3653 },
3654 },
3655 .help = "Bit multiple of result summary data (8 for byte, 1 for bit)",
3656 .category = FIO_OPT_C_GENERAL,
3657 .group = FIO_OPT_G_INVALID,
3658 },
3659 {
3660 .name = "hugepage-size",
3661 .lname = "Hugepage size",
3662 .type = FIO_OPT_INT,
3663 .off1 = td_var_offset(hugepage_size),
3664 .help = "When using hugepages, specify size of each page",
3665 .def = __fio_stringify(FIO_HUGE_PAGE),
3666 .interval = 1024 * 1024,
3667 .category = FIO_OPT_C_GENERAL,
3668 .group = FIO_OPT_G_INVALID,
3669 },
3670 {
3671 .name = "flow_id",
3672 .lname = "I/O flow ID",
3673 .type = FIO_OPT_INT,
3674 .off1 = td_var_offset(flow_id),
3675 .help = "The flow index ID to use",
3676 .def = "0",
3677 .category = FIO_OPT_C_IO,
3678 .group = FIO_OPT_G_IO_FLOW,
3679 },
3680 {
3681 .name = "flow",
3682 .lname = "I/O flow weight",
3683 .type = FIO_OPT_INT,
3684 .off1 = td_var_offset(flow),
3685 .help = "Weight for flow control of this job",
3686 .parent = "flow_id",
3687 .hide = 1,
3688 .def = "0",
3689 .category = FIO_OPT_C_IO,
3690 .group = FIO_OPT_G_IO_FLOW,
3691 },
3692 {
3693 .name = "flow_watermark",
3694 .lname = "I/O flow watermark",
3695 .type = FIO_OPT_INT,
3696 .off1 = td_var_offset(flow_watermark),
3697 .help = "High watermark for flow control. This option"
3698 " should be set to the same value for all threads"
3699 " with non-zero flow.",
3700 .parent = "flow_id",
3701 .hide = 1,
3702 .def = "1024",
3703 .category = FIO_OPT_C_IO,
3704 .group = FIO_OPT_G_IO_FLOW,
3705 },
3706 {
3707 .name = "flow_sleep",
3708 .lname = "I/O flow sleep",
3709 .type = FIO_OPT_INT,
3710 .off1 = td_var_offset(flow_sleep),
3711 .help = "How many microseconds to sleep after being held"
3712 " back by the flow control mechanism",
3713 .parent = "flow_id",
3714 .hide = 1,
3715 .def = "0",
3716 .category = FIO_OPT_C_IO,
3717 .group = FIO_OPT_G_IO_FLOW,
3718 },
3719 {
3720 .name = "skip_bad",
3721 .lname = "Skip operations against bad blocks",
3722 .type = FIO_OPT_BOOL,
3723 .off1 = td_var_offset(skip_bad),
3724 .help = "Skip operations against known bad blocks.",
3725 .hide = 1,
3726 .def = "0",
3727 .category = FIO_OPT_C_IO,
3728 .group = FIO_OPT_G_MTD,
3729 },
3730 {
3731 .name = NULL,
3732 },
3733};
3734
3735static void add_to_lopt(struct option *lopt, struct fio_option *o,
3736 const char *name, int val)
3737{
3738 lopt->name = (char *) name;
3739 lopt->val = val;
3740 if (o->type == FIO_OPT_STR_SET)
3741 lopt->has_arg = optional_argument;
3742 else
3743 lopt->has_arg = required_argument;
3744}
3745
3746static void options_to_lopts(struct fio_option *opts,
3747 struct option *long_options,
3748 int i, int option_type)
3749{
3750 struct fio_option *o = &opts[0];
3751 while (o->name) {
3752 add_to_lopt(&long_options[i], o, o->name, option_type);
3753 if (o->alias) {
3754 i++;
3755 add_to_lopt(&long_options[i], o, o->alias, option_type);
3756 }
3757
3758 i++;
3759 o++;
3760 assert(i < FIO_NR_OPTIONS);
3761 }
3762}
3763
3764void fio_options_set_ioengine_opts(struct option *long_options,
3765 struct thread_data *td)
3766{
3767 unsigned int i;
3768
3769 i = 0;
3770 while (long_options[i].name) {
3771 if (long_options[i].val == FIO_GETOPT_IOENGINE) {
3772 memset(&long_options[i], 0, sizeof(*long_options));
3773 break;
3774 }
3775 i++;
3776 }
3777
3778 /*
3779 * Just clear out the prior ioengine options.
3780 */
3781 if (!td || !td->eo)
3782 return;
3783
3784 options_to_lopts(td->io_ops->options, long_options, i,
3785 FIO_GETOPT_IOENGINE);
3786}
3787
3788void fio_options_dup_and_init(struct option *long_options)
3789{
3790 unsigned int i;
3791
3792 options_init(fio_options);
3793
3794 i = 0;
3795 while (long_options[i].name)
3796 i++;
3797
3798 options_to_lopts(fio_options, long_options, i, FIO_GETOPT_JOB);
3799}
3800
3801struct fio_keyword {
3802 const char *word;
3803 const char *desc;
3804 char *replace;
3805};
3806
3807static struct fio_keyword fio_keywords[] = {
3808 {
3809 .word = "$pagesize",
3810 .desc = "Page size in the system",
3811 },
3812 {
3813 .word = "$mb_memory",
3814 .desc = "Megabytes of memory online",
3815 },
3816 {
3817 .word = "$ncpus",
3818 .desc = "Number of CPUs online in the system",
3819 },
3820 {
3821 .word = NULL,
3822 },
3823};
3824
3825void fio_keywords_exit(void)
3826{
3827 struct fio_keyword *kw;
3828
3829 kw = &fio_keywords[0];
3830 while (kw->word) {
3831 free(kw->replace);
3832 kw->replace = NULL;
3833 kw++;
3834 }
3835}
3836
3837void fio_keywords_init(void)
3838{
3839 unsigned long long mb_memory;
3840 char buf[128];
3841 long l;
3842
3843 sprintf(buf, "%lu", (unsigned long) page_size);
3844 fio_keywords[0].replace = strdup(buf);
3845
3846 mb_memory = os_phys_mem() / (1024 * 1024);
3847 sprintf(buf, "%llu", mb_memory);
3848 fio_keywords[1].replace = strdup(buf);
3849
3850 l = cpus_online();
3851 sprintf(buf, "%lu", l);
3852 fio_keywords[2].replace = strdup(buf);
3853}
3854
3855#define BC_APP "bc"
3856
3857static char *bc_calc(char *str)
3858{
3859 char buf[128], *tmp;
3860 FILE *f;
3861 int ret;
3862
3863 /*
3864 * No math, just return string
3865 */
3866 if ((!strchr(str, '+') && !strchr(str, '-') && !strchr(str, '*') &&
3867 !strchr(str, '/')) || strchr(str, '\''))
3868 return str;
3869
3870 /*
3871 * Split option from value, we only need to calculate the value
3872 */
3873 tmp = strchr(str, '=');
3874 if (!tmp)
3875 return str;
3876
3877 tmp++;
3878
3879 /*
3880 * Prevent buffer overflows; such a case isn't reasonable anyway
3881 */
3882 if (strlen(str) >= 128 || strlen(tmp) > 100)
3883 return str;
3884
3885 sprintf(buf, "which %s > /dev/null", BC_APP);
3886 if (system(buf)) {
3887 log_err("fio: bc is needed for performing math\n");
3888 return NULL;
3889 }
3890
3891 sprintf(buf, "echo '%s' | %s", tmp, BC_APP);
3892 f = popen(buf, "r");
3893 if (!f)
3894 return NULL;
3895
3896 ret = fread(&buf[tmp - str], 1, 128 - (tmp - str), f);
3897 if (ret <= 0) {
3898 pclose(f);
3899 return NULL;
3900 }
3901
3902 pclose(f);
3903 buf[(tmp - str) + ret - 1] = '\0';
3904 memcpy(buf, str, tmp - str);
3905 free(str);
3906 return strdup(buf);
3907}
3908
3909/*
3910 * Return a copy of the input string with substrings of the form ${VARNAME}
3911 * substituted with the value of the environment variable VARNAME. The
3912 * substitution always occurs, even if VARNAME is empty or the corresponding
3913 * environment variable undefined.
3914 */
3915static char *option_dup_subs(const char *opt)
3916{
3917 char out[OPT_LEN_MAX+1];
3918 char in[OPT_LEN_MAX+1];
3919 char *outptr = out;
3920 char *inptr = in;
3921 char *ch1, *ch2, *env;
3922 ssize_t nchr = OPT_LEN_MAX;
3923 size_t envlen;
3924
3925 if (strlen(opt) + 1 > OPT_LEN_MAX) {
3926 log_err("OPT_LEN_MAX (%d) is too small\n", OPT_LEN_MAX);
3927 return NULL;
3928 }
3929
3930 in[OPT_LEN_MAX] = '\0';
3931 strncpy(in, opt, OPT_LEN_MAX);
3932
3933 while (*inptr && nchr > 0) {
3934 if (inptr[0] == '$' && inptr[1] == '{') {
3935 ch2 = strchr(inptr, '}');
3936 if (ch2 && inptr+1 < ch2) {
3937 ch1 = inptr+2;
3938 inptr = ch2+1;
3939 *ch2 = '\0';
3940
3941 env = getenv(ch1);
3942 if (env) {
3943 envlen = strlen(env);
3944 if (envlen <= nchr) {
3945 memcpy(outptr, env, envlen);
3946 outptr += envlen;
3947 nchr -= envlen;
3948 }
3949 }
3950
3951 continue;
3952 }
3953 }
3954
3955 *outptr++ = *inptr++;
3956 --nchr;
3957 }
3958
3959 *outptr = '\0';
3960 return strdup(out);
3961}
3962
3963/*
3964 * Look for reserved variable names and replace them with real values
3965 */
3966static char *fio_keyword_replace(char *opt)
3967{
3968 char *s;
3969 int i;
3970 int docalc = 0;
3971
3972 for (i = 0; fio_keywords[i].word != NULL; i++) {
3973 struct fio_keyword *kw = &fio_keywords[i];
3974
3975 while ((s = strstr(opt, kw->word)) != NULL) {
3976 char *new = malloc(strlen(opt) + 1);
3977 char *o_org = opt;
3978 int olen = s - opt;
3979 int len;
3980
3981 /*
3982 * Copy part of the string before the keyword and
3983 * sprintf() the replacement after it.
3984 */
3985 memcpy(new, opt, olen);
3986 len = sprintf(new + olen, "%s", kw->replace);
3987
3988 /*
3989 * If there's more in the original string, copy that
3990 * in too
3991 */
3992 opt += strlen(kw->word) + olen;
3993 if (strlen(opt))
3994 memcpy(new + olen + len, opt, opt - o_org - 1);
3995
3996 /*
3997 * replace opt and free the old opt
3998 */
3999 opt = new;
4000 free(o_org);
4001
4002 docalc = 1;
4003 }
4004 }
4005
4006 /*
4007 * Check for potential math and invoke bc, if possible
4008 */
4009 if (docalc)
4010 opt = bc_calc(opt);
4011
4012 return opt;
4013}
4014
4015static char **dup_and_sub_options(char **opts, int num_opts)
4016{
4017 int i;
4018 char **opts_copy = malloc(num_opts * sizeof(*opts));
4019 for (i = 0; i < num_opts; i++) {
4020 opts_copy[i] = option_dup_subs(opts[i]);
4021 if (!opts_copy[i])
4022 continue;
4023 opts_copy[i] = fio_keyword_replace(opts_copy[i]);
4024 }
4025 return opts_copy;
4026}
4027
4028static void show_closest_option(const char *opt)
4029{
4030 int best_option, best_distance;
4031 int i, distance;
4032 char *name;
4033
4034 if (!strlen(opt))
4035 return;
4036
4037 name = strdup(opt);
4038 i = 0;
4039 while (name[i] != '\0' && name[i] != '=')
4040 i++;
4041 name[i] = '\0';
4042
4043 best_option = -1;
4044 best_distance = INT_MAX;
4045 i = 0;
4046 while (fio_options[i].name) {
4047 distance = string_distance(name, fio_options[i].name);
4048 if (distance < best_distance) {
4049 best_distance = distance;
4050 best_option = i;
4051 }
4052 i++;
4053 }
4054
4055 if (best_option != -1)
4056 log_err("Did you mean %s?\n", fio_options[best_option].name);
4057
4058 free(name);
4059}
4060
4061int fio_options_parse(struct thread_data *td, char **opts, int num_opts,
4062 int dump_cmdline)
4063{
4064 int i, ret, unknown;
4065 char **opts_copy;
4066
4067 sort_options(opts, fio_options, num_opts);
4068 opts_copy = dup_and_sub_options(opts, num_opts);
4069
4070 for (ret = 0, i = 0, unknown = 0; i < num_opts; i++) {
4071 struct fio_option *o;
4072 int newret = parse_option(opts_copy[i], opts[i], fio_options,
4073 &o, td, dump_cmdline);
4074
4075 if (!newret && o)
4076 fio_option_mark_set(&td->o, o);
4077
4078 if (opts_copy[i]) {
4079 if (newret && !o) {
4080 unknown++;
4081 continue;
4082 }
4083 free(opts_copy[i]);
4084 opts_copy[i] = NULL;
4085 }
4086
4087 ret |= newret;
4088 }
4089
4090 if (unknown) {
4091 ret |= ioengine_load(td);
4092 if (td->eo) {
4093 sort_options(opts_copy, td->io_ops->options, num_opts);
4094 opts = opts_copy;
4095 }
4096 for (i = 0; i < num_opts; i++) {
4097 struct fio_option *o = NULL;
4098 int newret = 1;
4099
4100 if (!opts_copy[i])
4101 continue;
4102
4103 if (td->eo)
4104 newret = parse_option(opts_copy[i], opts[i],
4105 td->io_ops->options, &o,
4106 td->eo, dump_cmdline);
4107
4108 ret |= newret;
4109 if (!o) {
4110 log_err("Bad option <%s>\n", opts[i]);
4111 show_closest_option(opts[i]);
4112 }
4113 free(opts_copy[i]);
4114 opts_copy[i] = NULL;
4115 }
4116 }
4117
4118 free(opts_copy);
4119 return ret;
4120}
4121
4122int fio_cmd_option_parse(struct thread_data *td, const char *opt, char *val)
4123{
4124 int ret;
4125
4126 ret = parse_cmd_option(opt, val, fio_options, td);
4127 if (!ret) {
4128 struct fio_option *o;
4129
4130 o = find_option(fio_options, opt);
4131 if (o)
4132 fio_option_mark_set(&td->o, o);
4133 }
4134
4135 return ret;
4136}
4137
4138int fio_cmd_ioengine_option_parse(struct thread_data *td, const char *opt,
4139 char *val)
4140{
4141 return parse_cmd_option(opt, val, td->io_ops->options, td->eo);
4142}
4143
4144void fio_fill_default_options(struct thread_data *td)
4145{
4146 td->o.magic = OPT_MAGIC;
4147 fill_default_options(td, fio_options);
4148}
4149
4150int fio_show_option_help(const char *opt)
4151{
4152 return show_cmd_help(fio_options, opt);
4153}
4154
4155void options_mem_dupe(void *data, struct fio_option *options)
4156{
4157 struct fio_option *o;
4158 char **ptr;
4159
4160 for (o = &options[0]; o->name; o++) {
4161 if (o->type != FIO_OPT_STR_STORE)
4162 continue;
4163
4164 ptr = td_var(data, o, o->off1);
4165 if (*ptr)
4166 *ptr = strdup(*ptr);
4167 }
4168}
4169
4170/*
4171 * dupe FIO_OPT_STR_STORE options
4172 */
4173void fio_options_mem_dupe(struct thread_data *td)
4174{
4175 options_mem_dupe(&td->o, fio_options);
4176
4177 if (td->eo && td->io_ops) {
4178 void *oldeo = td->eo;
4179
4180 td->eo = malloc(td->io_ops->option_struct_size);
4181 memcpy(td->eo, oldeo, td->io_ops->option_struct_size);
4182 options_mem_dupe(td->eo, td->io_ops->options);
4183 }
4184}
4185
4186unsigned int fio_get_kb_base(void *data)
4187{
4188 struct thread_options *o = data;
4189 unsigned int kb_base = 0;
4190
4191 /*
4192 * This is a hack... For private options, *data is not holding
4193 * a pointer to the thread_options, but to private data. This means
4194 * we can't safely dereference it, but magic is first so mem wise
4195 * it is valid. But this also means that if the job first sets
4196 * kb_base and expects that to be honored by private options,
4197 * it will be disappointed. We will return the global default
4198 * for this.
4199 */
4200 if (o && o->magic == OPT_MAGIC)
4201 kb_base = o->kb_base;
4202 if (!kb_base)
4203 kb_base = 1024;
4204
4205 return kb_base;
4206}
4207
4208int add_option(struct fio_option *o)
4209{
4210 struct fio_option *__o;
4211 int opt_index = 0;
4212
4213 __o = fio_options;
4214 while (__o->name) {
4215 opt_index++;
4216 __o++;
4217 }
4218
4219 if (opt_index + 1 == FIO_MAX_OPTS) {
4220 log_err("fio: FIO_MAX_OPTS is too small\n");
4221 return 1;
4222 }
4223
4224 memcpy(&fio_options[opt_index], o, sizeof(*o));
4225 fio_options[opt_index + 1].name = NULL;
4226 return 0;
4227}
4228
4229void invalidate_profile_options(const char *prof_name)
4230{
4231 struct fio_option *o;
4232
4233 o = fio_options;
4234 while (o->name) {
4235 if (o->prof_name && !strcmp(o->prof_name, prof_name)) {
4236 o->type = FIO_OPT_INVALID;
4237 o->prof_name = NULL;
4238 }
4239 o++;
4240 }
4241}
4242
4243void add_opt_posval(const char *optname, const char *ival, const char *help)
4244{
4245 struct fio_option *o;
4246 unsigned int i;
4247
4248 o = find_option(fio_options, optname);
4249 if (!o)
4250 return;
4251
4252 for (i = 0; i < PARSE_MAX_VP; i++) {
4253 if (o->posval[i].ival)
4254 continue;
4255
4256 o->posval[i].ival = ival;
4257 o->posval[i].help = help;
4258 break;
4259 }
4260}
4261
4262void del_opt_posval(const char *optname, const char *ival)
4263{
4264 struct fio_option *o;
4265 unsigned int i;
4266
4267 o = find_option(fio_options, optname);
4268 if (!o)
4269 return;
4270
4271 for (i = 0; i < PARSE_MAX_VP; i++) {
4272 if (!o->posval[i].ival)
4273 continue;
4274 if (strcmp(o->posval[i].ival, ival))
4275 continue;
4276
4277 o->posval[i].ival = NULL;
4278 o->posval[i].help = NULL;
4279 }
4280}
4281
4282void fio_options_free(struct thread_data *td)
4283{
4284 options_free(fio_options, td);
4285 if (td->eo && td->io_ops && td->io_ops->options) {
4286 options_free(td->io_ops->options, td->eo);
4287 free(td->eo);
4288 td->eo = NULL;
4289 }
4290}
4291
4292struct fio_option *fio_option_find(const char *name)
4293{
4294 return find_option(fio_options, name);
4295}
4296
4297static struct fio_option *find_next_opt(struct thread_options *o,
4298 struct fio_option *from,
4299 unsigned int off1)
4300{
4301 struct fio_option *opt;
4302
4303 if (!from)
4304 from = &fio_options[0];
4305 else
4306 from++;
4307
4308 opt = NULL;
4309 do {
4310 if (off1 == from->off1) {
4311 opt = from;
4312 break;
4313 }
4314 from++;
4315 } while (from->name);
4316
4317 return opt;
4318}
4319
4320static int opt_is_set(struct thread_options *o, struct fio_option *opt)
4321{
4322 unsigned int opt_off, index, offset;
4323
4324 opt_off = opt - &fio_options[0];
4325 index = opt_off / (8 * sizeof(uint64_t));
4326 offset = opt_off & ((8 * sizeof(uint64_t)) - 1);
4327 return (o->set_options[index] & (1UL << offset)) != 0;
4328}
4329
4330int __fio_option_is_set(struct thread_options *o, unsigned int off1)
4331{
4332 struct fio_option *opt, *next;
4333
4334 next = NULL;
4335 while ((opt = find_next_opt(o, next, off1)) != NULL) {
4336 if (opt_is_set(o, opt))
4337 return 1;
4338
4339 next = opt;
4340 }
4341
4342 return 0;
4343}
4344
4345void fio_option_mark_set(struct thread_options *o, struct fio_option *opt)
4346{
4347 unsigned int opt_off, index, offset;
4348
4349 opt_off = opt - &fio_options[0];
4350 index = opt_off / (8 * sizeof(uint64_t));
4351 offset = opt_off & ((8 * sizeof(uint64_t)) - 1);
4352 o->set_options[index] |= 1UL << offset;
4353}