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