X-Git-Url: https://git.kernel.dk/?p=fio.git;a=blobdiff_plain;f=options.c;h=eab22a70d36eec90dc916a6649aa0a8e06639d63;hp=937a76e17cea9a518985a0d9973f1f6cdc062cf3;hb=481075983e3c71460b9f784ddfb14099857e444a;hpb=83ea422a62b8a42b14c362db61c2e7bf53862e80 diff --git a/options.c b/options.c index 937a76e1..eab22a70 100644 --- a/options.c +++ b/options.c @@ -165,7 +165,7 @@ static int bssplit_ddir(struct thread_options *o, int ddir, char *str) static int str_bssplit_cb(void *data, const char *input) { struct thread_data *td = data; - char *str, *p, *odir; + char *str, *p, *odir, *ddir; int ret = 0; p = str = strdup(input); @@ -175,7 +175,21 @@ static int str_bssplit_cb(void *data, const char *input) odir = strchr(str, ','); if (odir) { - ret = bssplit_ddir(&td->o, DDIR_WRITE, odir + 1); + ddir = strchr(odir + 1, ','); + if (ddir) { + ret = bssplit_ddir(&td->o, DDIR_TRIM, ddir + 1); + if (!ret) + *ddir = '\0'; + } else { + char *op; + + op = strdup(odir + 1); + ret = bssplit_ddir(&td->o, DDIR_TRIM, op); + + free(op); + } + if (!ret) + ret = bssplit_ddir(&td->o, DDIR_WRITE, odir + 1); if (!ret) { *odir = '\0'; ret = bssplit_ddir(&td->o, DDIR_READ, str); @@ -184,18 +198,116 @@ static int str_bssplit_cb(void *data, const char *input) char *op; op = strdup(str); + ret = bssplit_ddir(&td->o, DDIR_WRITE, op); + free(op); + if (!ret) { + op = strdup(str); + ret = bssplit_ddir(&td->o, DDIR_TRIM, op); + free(op); + } ret = bssplit_ddir(&td->o, DDIR_READ, str); - if (!ret) - ret = bssplit_ddir(&td->o, DDIR_WRITE, op); - - free(op); } free(p); return ret; } +static int str2error(char *str) +{ + const char *err[] = { "EPERM", "ENOENT", "ESRCH", "EINTR", "EIO", + "ENXIO", "E2BIG", "ENOEXEC", "EBADF", + "ECHILD", "EAGAIN", "ENOMEM", "EACCES", + "EFAULT", "ENOTBLK", "EBUSY", "EEXIST", + "EXDEV", "ENODEV", "ENOTDIR", "EISDIR", + "EINVAL", "ENFILE", "EMFILE", "ENOTTY", + "ETXTBSY","EFBIG", "ENOSPC", "ESPIPE", + "EROFS","EMLINK", "EPIPE", "EDOM", "ERANGE" }; + int i = 0, num = sizeof(err) / sizeof(void *); + + while (i < num) { + if (!strcmp(err[i], str)) + return i + 1; + i++; + } + return 0; +} + +static int ignore_error_type(struct thread_data *td, int etype, char *str) +{ + unsigned int i; + int *error; + char *fname; + + if (etype >= ERROR_TYPE_CNT) { + log_err("Illegal error type\n"); + return 1; + } + + td->o.ignore_error_nr[etype] = 4; + error = malloc(4 * sizeof(struct bssplit)); + + i = 0; + while ((fname = strsep(&str, ":")) != NULL) { + + if (!strlen(fname)) + break; + + /* + * grow struct buffer, if needed + */ + if (i == td->o.ignore_error_nr[etype]) { + td->o.ignore_error_nr[etype] <<= 1; + error = realloc(error, td->o.ignore_error_nr[etype] + * sizeof(int)); + } + if (fname[0] == 'E') { + error[i] = str2error(fname); + } else { + error[i] = atoi(fname); + if (error[i] < 0) + error[i] = error[i]; + } + if (!error[i]) { + log_err("Unknown error %s, please use number value \n", + fname); + return 1; + } + i++; + } + if (i) { + td->o.continue_on_error |= 1 << etype; + td->o.ignore_error_nr[etype] = i; + td->o.ignore_error[etype] = error; + } + return 0; + +} + +static int str_ignore_error_cb(void *data, const char *input) +{ + struct thread_data *td = data; + char *str, *p, *n; + int type = 0, ret = 1; + p = str = strdup(input); + + strip_blank_front(&str); + strip_blank_end(str); + + while (p) { + n = strchr(p, ','); + if (n) + *n++ = '\0'; + ret = ignore_error_type(td, type, p); + if (ret) + break; + p = n; + type++; + } + free(str); + return ret; +} + static int str_rw_cb(void *data, const char *str) { struct thread_data *td = data; @@ -251,12 +363,6 @@ static int fio_clock_source_cb(void *data, const char *str) return 0; } -static int str_lockmem_cb(void fio_unused *data, unsigned long long *val) -{ - mlock_size = *val; - return 0; -} - static int str_rwmix_read_cb(void *data, unsigned long long *val) { struct thread_data *td = data; @@ -275,40 +381,6 @@ static int str_rwmix_write_cb(void *data, unsigned long long *val) return 0; } -#ifdef FIO_HAVE_IOPRIO -static int str_prioclass_cb(void *data, unsigned long long *val) -{ - struct thread_data *td = data; - unsigned short mask; - - /* - * mask off old class bits, str_prio_cb() may have set a default class - */ - mask = (1 << IOPRIO_CLASS_SHIFT) - 1; - td->ioprio &= mask; - - td->ioprio |= *val << IOPRIO_CLASS_SHIFT; - td->ioprio_set = 1; - return 0; -} - -static int str_prio_cb(void *data, unsigned long long *val) -{ - struct thread_data *td = data; - - td->ioprio |= *val; - - /* - * If no class is set, assume BE - */ - if ((td->ioprio >> IOPRIO_CLASS_SHIFT) == 0) - td->ioprio |= IOPRIO_CLASS_BE << IOPRIO_CLASS_SHIFT; - - td->ioprio_set = 1; - return 0; -} -#endif - static int str_exitall_cb(void) { exitall_on_terminate = 1; @@ -441,13 +513,127 @@ static int str_verify_cpus_allowed_cb(void *data, const char *input) } #endif -#ifdef FIO_HAVE_TRIM -static int str_verify_trim_cb(void *data, unsigned long long *val) +#ifdef FIO_HAVE_LIBNUMA +static int str_numa_cpunodes_cb(void *data, char *input) +{ + struct thread_data *td = data; + + /* numa_parse_nodestring() parses a character string list + * of nodes into a bit mask. The bit mask is allocated by + * numa_allocate_nodemask(), so it should be freed by + * numa_free_nodemask(). + */ + td->o.numa_cpunodesmask = numa_parse_nodestring(input); + if (td->o.numa_cpunodesmask == NULL) { + log_err("fio: numa_parse_nodestring failed\n"); + td_verror(td, 1, "str_numa_cpunodes_cb"); + return 1; + } + + td->o.numa_cpumask_set = 1; + return 0; +} + +static int str_numa_mpol_cb(void *data, char *input) { struct thread_data *td = data; + const char * const policy_types[] = + { "default", "prefer", "bind", "interleave", "local" }; + int i; + + char *nodelist = strchr(input, ':'); + if (nodelist) { + /* NUL-terminate mode */ + *nodelist++ = '\0'; + } + + for (i = 0; i <= MPOL_LOCAL; i++) { + if (!strcmp(input, policy_types[i])) { + td->o.numa_mem_mode = i; + break; + } + } + if (i > MPOL_LOCAL) { + log_err("fio: memory policy should be: default, prefer, bind, interleave, local\n"); + goto out; + } + + switch (td->o.numa_mem_mode) { + case MPOL_PREFERRED: + /* + * Insist on a nodelist of one node only + */ + if (nodelist) { + char *rest = nodelist; + while (isdigit(*rest)) + rest++; + if (*rest) { + log_err("fio: one node only for \'prefer\'\n"); + goto out; + } + } else { + log_err("fio: one node is needed for \'prefer\'\n"); + goto out; + } + break; + case MPOL_INTERLEAVE: + /* + * Default to online nodes with memory if no nodelist + */ + if (!nodelist) + nodelist = strdup("all"); + break; + case MPOL_LOCAL: + case MPOL_DEFAULT: + /* + * Don't allow a nodelist + */ + if (nodelist) { + log_err("fio: NO nodelist for \'local\'\n"); + goto out; + } + break; + case MPOL_BIND: + /* + * Insist on a nodelist + */ + if (!nodelist) { + log_err("fio: a nodelist is needed for \'bind\'\n"); + goto out; + } + break; + } + + + /* numa_parse_nodestring() parses a character string list + * of nodes into a bit mask. The bit mask is allocated by + * numa_allocate_nodemask(), so it should be freed by + * numa_free_nodemask(). + */ + switch (td->o.numa_mem_mode) { + case MPOL_PREFERRED: + td->o.numa_mem_prefer_node = atoi(nodelist); + break; + case MPOL_INTERLEAVE: + case MPOL_BIND: + td->o.numa_memnodesmask = numa_parse_nodestring(nodelist); + if (td->o.numa_memnodesmask == NULL) { + log_err("fio: numa_parse_nodestring failed\n"); + td_verror(td, 1, "str_numa_memnodes_cb"); + return 1; + } + break; + case MPOL_LOCAL: + case MPOL_DEFAULT: + default: + break; + } - td->o.trim_percentage = *val; + td->o.numa_memmask_set = 1; return 0; + +out: + return 1; } #endif @@ -481,41 +667,41 @@ static int str_sfr_cb(void *data, const char *str) } #endif -static int check_dir(struct thread_data *td, char *fname) +static int str_random_distribution_cb(void *data, const char *str) { -#if 0 - char file[PATH_MAX], *dir; - int elen = 0; - - if (td->o.directory) { - strcpy(file, td->o.directory); - strcat(file, "/"); - elen = strlen(file); - } - - sprintf(file + elen, "%s", fname); - dir = dirname(file); + struct thread_data *td = data; + double val; + char *nr; - { - struct stat sb; - /* - * We can't do this on FIO_DISKLESSIO engines. The engine isn't loaded - * yet, so we can't do this check right here... - */ - if (lstat(dir, &sb) < 0) { - int ret = errno; + if (td->o.random_distribution == FIO_RAND_DIST_ZIPF) + val = 1.1; + else if (td->o.random_distribution == FIO_RAND_DIST_PARETO) + val = 0.2; + else + return 0; - log_err("fio: %s is not a directory\n", dir); - td_verror(td, ret, "lstat"); + nr = get_opt_postfix(str); + if (nr && !str_to_float(nr, &val)) { + log_err("fio: random postfix parsing failed\n"); + free(nr); return 1; } - if (!S_ISDIR(sb.st_mode)) { - log_err("fio: %s is not a directory\n", dir); - return 1; - } + free(nr); + + if (td->o.random_distribution == FIO_RAND_DIST_ZIPF) { + if (val == 1.00) { + log_err("fio: zipf theta must different than 1.0\n"); + return 1; + } + td->o.zipf_theta.u.f = val; + } else { + if (val <= 0.00 || val >= 1.00) { + log_err("fio: pareto input out of range (0 < input < 1.0)\n"); + return 1; + } + td->o.pareto_h.u.f = val; } -#endif return 0; } @@ -582,10 +768,6 @@ static int str_filename_cb(void *data, const char *input) while ((fname = get_next_file_name(&str)) != NULL) { if (!strlen(fname)) break; - if (check_dir(td, fname)) { - free(p); - return 1; - } add_file(td, fname); td->o.nr_files++; } @@ -624,19 +806,6 @@ static int str_opendir_cb(void *data, const char fio_unused *str) return add_dir_files(td, td->o.opendir); } -static int str_verify_offset_cb(void *data, unsigned long long *off) -{ - struct thread_data *td = data; - - if (*off && *off < sizeof(struct verify_header)) { - log_err("fio: verify_offset too small\n"); - return 1; - } - - td->o.verify_offset = *off; - return 0; -} - static int str_verify_pattern_cb(void *data, const char *input) { struct thread_data *td = data; @@ -718,39 +887,6 @@ static int str_lockfile_cb(void *data, const char *str) return 0; } -static int str_write_bw_log_cb(void *data, const char *str) -{ - struct thread_data *td = data; - - if (str) - td->o.bw_log_file = strdup(str); - - td->o.write_bw_log = 1; - return 0; -} - -static int str_write_lat_log_cb(void *data, const char *str) -{ - struct thread_data *td = data; - - if (str) - td->o.lat_log_file = strdup(str); - - td->o.write_lat_log = 1; - return 0; -} - -static int str_write_iops_log_cb(void *data, const char *str) -{ - struct thread_data *td = data; - - if (str) - td->o.iops_log_file = strdup(str); - - td->o.write_iops_log = 1; - return 0; -} - static int str_gtod_reduce_cb(void *data, int *il) { struct thread_data *td = data; @@ -856,6 +992,10 @@ static struct opt_group fio_opt_groups[] = { .name = "Logging", .mask = FIO_OPT_C_LOG, }, + { + .name = "Profiles", + .mask = FIO_OPT_C_PROFILE, + }, { .name = NULL, }, @@ -968,6 +1108,11 @@ static struct opt_group fio_opt_cat_groups[] = { .name = "I/O buffers", .mask = FIO_OPT_G_IO_BUF, }, + { + .name = "Tiobench profile", + .mask = FIO_OPT_G_TIOBENCH, + }, + { .name = NULL, } @@ -1080,6 +1225,10 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .oval = TD_DDIR_WRITE, .help = "Sequential write", }, + { .ival = "trim", + .oval = TD_DDIR_TRIM, + .help = "Sequential trim", + }, { .ival = "randread", .oval = TD_DDIR_RANDREAD, .help = "Random read", @@ -1088,10 +1237,18 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .oval = TD_DDIR_RANDWRITE, .help = "Random write", }, + { .ival = "randtrim", + .oval = TD_DDIR_RANDTRIM, + .help = "Random trim", + }, { .ival = "rw", .oval = TD_DDIR_RW, .help = "Sequential read and write mix", }, + { .ival = "readwrite", + .oval = TD_DDIR_RW, + .help = "Sequential read and write mix", + }, { .ival = "randrw", .oval = TD_DDIR_RANDRW, .help = "Random read and write mix" @@ -1202,6 +1359,21 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { { .ival = "rdma", .help = "RDMA IO engine", }, +#endif +#ifdef FIO_HAVE_FUSION_AW + { .ival = "fusion-aw-sync", + .help = "Fusion-io atomic write engine", + }, +#endif +#ifdef FIO_HAVE_E4_ENG + { .ival = "e4defrag", + .help = "ext4 defrag engine", + }, +#endif +#ifdef FIO_HAVE_FALLOC_ENG + { .ival = "falloc", + .help = "fallocate() file based engine", + }, #endif { .ival = "external", .help = "Load external engine (append name)", @@ -1326,6 +1498,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .type = FIO_OPT_INT, .off1 = td_var_offset(bs[DDIR_READ]), .off2 = td_var_offset(bs[DDIR_WRITE]), + .off3 = td_var_offset(bs[DDIR_TRIM]), .minval = 1, .help = "Block size unit", .def = "4k", @@ -1342,6 +1515,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .type = FIO_OPT_INT, .off1 = td_var_offset(ba[DDIR_READ]), .off2 = td_var_offset(ba[DDIR_WRITE]), + .off3 = td_var_offset(ba[DDIR_TRIM]), .minval = 1, .help = "IO block offset alignment", .parent = "rw", @@ -1359,6 +1533,8 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .off2 = td_var_offset(max_bs[DDIR_READ]), .off3 = td_var_offset(min_bs[DDIR_WRITE]), .off4 = td_var_offset(max_bs[DDIR_WRITE]), + .off5 = td_var_offset(min_bs[DDIR_TRIM]), + .off6 = td_var_offset(max_bs[DDIR_TRIM]), .minval = 1, .help = "Set block size range (in more detail than bs)", .parent = "rw", @@ -1438,6 +1614,49 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .category = FIO_OPT_C_IO, .group = FIO_OPT_G_RANDOM, }, + { + .name = "random_generator", + .type = FIO_OPT_STR, + .off1 = td_var_offset(random_generator), + .help = "Type of random number generator to use", + .def = "tausworthe", + .posval = { + { .ival = "tausworthe", + .oval = FIO_RAND_GEN_TAUSWORTHE, + .help = "Strong Tausworthe generator", + }, + { .ival = "lfsr", + .oval = FIO_RAND_GEN_LFSR, + .help = "Variable length LFSR", + }, + }, + .category = FIO_OPT_C_IO, + .group = FIO_OPT_G_RANDOM, + }, + { + .name = "random_distribution", + .type = FIO_OPT_STR, + .off1 = td_var_offset(random_distribution), + .cb = str_random_distribution_cb, + .help = "Random offset distribution generator", + .def = "random", + .posval = { + { .ival = "random", + .oval = FIO_RAND_DIST_RANDOM, + .help = "Completely random", + }, + { .ival = "zipf", + .oval = FIO_RAND_DIST_ZIPF, + .help = "Zipf distribution", + }, + { .ival = "pareto", + .oval = FIO_RAND_DIST_PARETO, + .help = "Pareto distribution", + }, + }, + .category = FIO_OPT_C_IO, + .group = FIO_OPT_G_RANDOM, + }, { .name = "nrfiles", .lname = "Number of files", @@ -1875,8 +2094,8 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .lname = "Verify offset", .type = FIO_OPT_INT, .help = "Offset verify header location by N bytes", - .def = "0", - .cb = str_verify_offset_cb, + .off1 = td_var_offset(verify_offset), + .minval = sizeof(struct verify_header), .parent = "verify", .hide = 1, .category = FIO_OPT_C_IO, @@ -1969,7 +2188,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "trim_percentage", .lname = "Trim percentage", .type = FIO_OPT_INT, - .cb = str_verify_trim_cb, + .off1 = td_var_offset(trim_percentage), .minval = 0, .maxval = 100, .help = "Number of verify blocks to discard/trim", @@ -2124,7 +2343,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "lockmem", .lname = "Lock memory", .type = FIO_OPT_STR_VAL, - .cb = str_lockmem_cb, + .off1 = td_var_offset(lockmem), .help = "Lock down this amount of memory", .def = "0", .interval = 1024 * 1024, @@ -2182,7 +2401,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "prio", .lname = "I/O nice priority", .type = FIO_OPT_INT, - .cb = str_prio_cb, + .off1 = td_var_offset(ioprio), .help = "Set job IO priority value", .minval = 0, .maxval = 7, @@ -2194,7 +2413,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "prioclass", .lname = "I/O nice priority class", .type = FIO_OPT_INT, - .cb = str_prioclass_cb, + .off1 = td_var_offset(ioprio_class), .help = "Set job IO priority class", .minval = 0, .maxval = 3, @@ -2241,8 +2460,9 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "rate", .lname = "I/O rate", .type = FIO_OPT_INT, - .off1 = td_var_offset(rate[0]), - .off2 = td_var_offset(rate[1]), + .off1 = td_var_offset(rate[DDIR_READ]), + .off2 = td_var_offset(rate[DDIR_WRITE]), + .off3 = td_var_offset(rate[DDIR_TRIM]), .help = "Set bandwidth rate", .category = FIO_OPT_C_IO, .group = FIO_OPT_G_RATE, @@ -2251,8 +2471,9 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "ratemin", .lname = "I/O min rate", .type = FIO_OPT_INT, - .off1 = td_var_offset(ratemin[0]), - .off2 = td_var_offset(ratemin[1]), + .off1 = td_var_offset(ratemin[DDIR_READ]), + .off2 = td_var_offset(ratemin[DDIR_WRITE]), + .off3 = td_var_offset(ratemin[DDIR_TRIM]), .help = "Job must meet this rate or it will be shutdown", .parent = "rate", .hide = 1, @@ -2263,8 +2484,9 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "rate_iops", .lname = "I/O rate IOPS", .type = FIO_OPT_INT, - .off1 = td_var_offset(rate_iops[0]), - .off2 = td_var_offset(rate_iops[1]), + .off1 = td_var_offset(rate_iops[DDIR_READ]), + .off2 = td_var_offset(rate_iops[DDIR_WRITE]), + .off3 = td_var_offset(rate_iops[DDIR_TRIM]), .help = "Limit IO used to this number of IO operations/sec", .hide = 1, .category = FIO_OPT_C_IO, @@ -2274,8 +2496,9 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "rate_iops_min", .lname = "I/O min rate IOPS", .type = FIO_OPT_INT, - .off1 = td_var_offset(rate_iops_min[0]), - .off2 = td_var_offset(rate_iops_min[1]), + .off1 = td_var_offset(rate_iops_min[DDIR_READ]), + .off2 = td_var_offset(rate_iops_min[DDIR_WRITE]), + .off3 = td_var_offset(rate_iops_min[DDIR_TRIM]), .help = "Job must meet this rate or it will be shut down", .parent = "rate_iops", .hide = 1, @@ -2294,6 +2517,14 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .category = FIO_OPT_C_IO, .group = FIO_OPT_G_RATE, }, + { + .name = "max_latency", + .type = FIO_OPT_INT, + .off1 = td_var_offset(max_latency), + .help = "Maximum tolerated IO latency (usec)", + .category = FIO_OPT_C_IO, + .group = FIO_OPT_G_RATE, + }, { .name = "invalidate", .lname = "Cache invalidate", @@ -2346,6 +2577,14 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .category = FIO_OPT_C_FILE, .group = FIO_OPT_G_INVALID, }, + { + .name = "create_only", + .type = FIO_OPT_BOOL, + .off1 = td_var_offset(create_only), + .help = "Only perform file creation phase", + .category = FIO_OPT_C_FILE, + .def = "0", + }, { .name = "pre_read", .lname = "Pre-read files", @@ -2375,6 +2614,20 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .category = FIO_OPT_C_GENERAL, .group = FIO_OPT_G_CRED, }, +#endif +#ifdef FIO_HAVE_LIBNUMA + { + .name = "numa_cpu_nodes", + .type = FIO_OPT_STR, + .cb = str_numa_cpunodes_cb, + .help = "NUMA CPU nodes bind", + }, + { + .name = "numa_mem_policy", + .type = FIO_OPT_STR, + .cb = str_numa_mpol_cb, + .help = "NUMA memory policy setup", + }, #endif { .name = "end_fsync", @@ -2446,9 +2699,8 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { { .name = "write_bw_log", .lname = "Write bandwidth log", - .type = FIO_OPT_STR, - .off1 = td_var_offset(write_bw_log), - .cb = str_write_bw_log_cb, + .type = FIO_OPT_STR_STORE, + .off1 = td_var_offset(bw_log_file), .help = "Write log of bandwidth during run", .category = FIO_OPT_C_LOG, .group = FIO_OPT_G_INVALID, @@ -2456,9 +2708,8 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { { .name = "write_lat_log", .lname = "Write latency log", - .type = FIO_OPT_STR, - .off1 = td_var_offset(write_lat_log), - .cb = str_write_lat_log_cb, + .type = FIO_OPT_STR_STORE, + .off1 = td_var_offset(lat_log_file), .help = "Write log of latency during run", .category = FIO_OPT_C_LOG, .group = FIO_OPT_G_INVALID, @@ -2467,8 +2718,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .name = "write_iops_log", .lname = "Write IOPS log", .type = FIO_OPT_STR, - .off1 = td_var_offset(write_iops_log), - .cb = str_write_iops_log_cb, + .off1 = td_var_offset(iops_log_file), .help = "Write log of IOPS during run", .category = FIO_OPT_C_LOG, .group = FIO_OPT_G_INVALID, @@ -2685,7 +2935,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .help = "Continue on non-fatal errors during IO", .def = "none", .category = FIO_OPT_C_GENERAL, - .group = FIO_OPT_G_INVALID, + .group = FIO_OPT_G_ERR, .posval = { { .ival = "none", .oval = ERROR_TYPE_NONE, @@ -2721,13 +2971,31 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { }, }, }, + { + .name = "ignore_error", + .type = FIO_OPT_STR, + .cb = str_ignore_error_cb, + .help = "Set a specific list of errors to ignore", + .parent = "rw", + .category = FIO_OPT_C_GENERAL, + .group = FIO_OPT_G_ERR, + }, + { + .name = "error_dump", + .type = FIO_OPT_BOOL, + .off1 = td_var_offset(error_dump), + .def = "0", + .help = "Dump info on each error", + .category = FIO_OPT_C_GENERAL, + .group = FIO_OPT_G_ERR, + }, { .name = "profile", .lname = "Profile", .type = FIO_OPT_STR_STORE, .off1 = td_var_offset(profile), .help = "Select a specific builtin performance test", - .category = FIO_OPT_C_GENERAL, + .category = FIO_OPT_C_PROFILE, .group = FIO_OPT_G_INVALID, }, { @@ -2953,7 +3221,7 @@ void fio_keywords_init(void) char buf[128]; long l; - sprintf(buf, "%lu", page_size); + sprintf(buf, "%lu", (unsigned long) page_size); fio_keywords[0].replace = strdup(buf); mb_memory = os_phys_mem() / (1024 * 1024);