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