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