#include "idletime.h"
#include "filelock.h"
-#include "lib/getopt.h"
-#include "lib/strcasestr.h"
+#include "oslib/getopt.h"
+#include "oslib/strcasestr.h"
#include "crc/test.h"
static int nr_job_sections;
int exitall_on_terminate = 0;
+int exitall_on_terminate_error = 0;
int output_format = FIO_OUTPUT_NORMAL;
-int append_terse_output = 0;
int eta_print = FIO_ETA_AUTO;
int eta_new_line = 0;
FILE *f_out = NULL;
char *trigger_cmd = NULL;
char *trigger_remote_cmd = NULL;
+char *aux_path = NULL;
+
static int prev_group_jobs;
unsigned long fio_debug = 0;
.has_arg = required_argument,
.val = 'J',
},
+ {
+ .name = (char *) "aux-path",
+ .has_arg = required_argument,
+ .val = 'K',
+ },
{
.name = NULL,
},
o->timeout = def_timeout;
}
+static void dump_print_option(struct print_option *p)
+{
+ const char *delim;
+
+ if (!strcmp("description", p->name))
+ delim = "\"";
+ else
+ delim = "";
+
+ log_info("--%s%s", p->name, p->value ? "" : " ");
+ if (p->value)
+ log_info("=%s%s%s ", delim, p->value, delim);
+}
+
+static void dump_opt_list(struct thread_data *td)
+{
+ struct flist_head *entry;
+ struct print_option *p;
+
+ if (flist_empty(&td->opt_list))
+ return;
+
+ flist_for_each(entry, &td->opt_list) {
+ p = flist_entry(entry, struct print_option, list);
+ dump_print_option(p);
+ }
+}
+
+static void fio_dump_options_free(struct thread_data *td)
+{
+ while (!flist_empty(&td->opt_list)) {
+ struct print_option *p;
+
+ p = flist_first_entry(&td->opt_list, struct print_option, list);
+ flist_del_init(&p->list);
+ free(p->name);
+ free(p->value);
+ free(p);
+ }
+}
+
+static void copy_opt_list(struct thread_data *dst, struct thread_data *src)
+{
+ struct flist_head *entry;
+
+ if (flist_empty(&src->opt_list))
+ return;
+
+ flist_for_each(entry, &src->opt_list) {
+ struct print_option *srcp, *dstp;
+
+ srcp = flist_entry(entry, struct print_option, list);
+ dstp = malloc(sizeof(*dstp));
+ dstp->name = strdup(srcp->name);
+ if (srcp->value)
+ dstp->value = strdup(srcp->value);
+ else
+ dstp->value = NULL;
+ flist_add_tail(&dstp->list, &dst->opt_list);
+ }
+}
+
/*
* Return a free job structure.
*/
td = &threads[thread_number++];
*td = *parent;
+ INIT_FLIST_HEAD(&td->opt_list);
+ if (parent != &def_thread)
+ copy_opt_list(td, parent);
+
td->io_ops = NULL;
if (!preserve_eo)
td->eo = NULL;
if (jobname)
td->o.name = strdup(jobname);
- if (!parent->o.group_reporting)
+ if (!parent->o.group_reporting || parent == &def_thread)
stat_number++;
set_cmd_options(td);
log_info("fio: %s\n", td->verror);
fio_options_free(td);
+ fio_dump_options_free(td);
if (td->io_ops)
free_ioengine(td);
if (td->o.rate[ddir])
td->rate_bps[ddir] = td->o.rate[ddir];
else
- td->rate_bps[ddir] = td->o.rate_iops[ddir] * bs;
+ td->rate_bps[ddir] = (uint64_t) td->o.rate_iops[ddir] * bs;
if (!td->rate_bps[ddir]) {
log_err("rate lower than supported\n");
return -1;
}
- td->rate_pending_usleep[ddir] = 0;
+ td->rate_next_io_time[ddir] = 0;
+ td->rate_io_issue_bytes[ddir] = 0;
+ td->last_usec = 0;
return 0;
}
static unsigned long long get_rand_start_delay(struct thread_data *td)
{
unsigned long long delayrange;
+ uint64_t frand_max;
unsigned long r;
delayrange = td->o.start_delay_high - td->o.start_delay;
+ frand_max = rand_max(&td->delay_state);
r = __rand(&td->delay_state);
- delayrange = (unsigned long long) ((double) delayrange * (r / (FRAND_MAX + 1.0)));
+ delayrange = (unsigned long long) ((double) delayrange * (r / (frand_max + 1.0)));
delayrange += td->o.start_delay;
return delayrange;
if (o->norandommap && o->verify != VERIFY_NONE
&& !fixed_block_size(o)) {
log_err("fio: norandommap given for variable block sizes, "
- "verify disabled\n");
- o->verify = VERIFY_NONE;
+ "verify limited\n");
ret = warnings_fatal;
}
if (o->bs_unaligned && (o->odirect || td->io_ops->flags & FIO_RAWIO))
if (o->iodepth_batch > o->iodepth || !o->iodepth_batch)
o->iodepth_batch = o->iodepth;
+ /*
+ * If max batch complete number isn't set or set incorrectly,
+ * default to the same as iodepth_batch_complete_min
+ */
+ if (o->iodepth_batch_complete_min > o->iodepth_batch_complete_max)
+ o->iodepth_batch_complete_max = o->iodepth_batch_complete_min;
+
if (o->nr_files > td->files_index)
o->nr_files = td->files_index;
log_err("fio: rate and rate_iops are mutually exclusive\n");
ret = 1;
}
- if ((o->rate[DDIR_READ] < o->ratemin[DDIR_READ]) ||
- (o->rate[DDIR_WRITE] < o->ratemin[DDIR_WRITE]) ||
- (o->rate[DDIR_TRIM] < o->ratemin[DDIR_TRIM]) ||
- (o->rate_iops[DDIR_READ] < o->rate_iops_min[DDIR_READ]) ||
- (o->rate_iops[DDIR_WRITE] < o->rate_iops_min[DDIR_WRITE]) ||
- (o->rate_iops[DDIR_TRIM] < o->rate_iops_min[DDIR_TRIM])) {
+ if ((o->rate[DDIR_READ] && (o->rate[DDIR_READ] < o->ratemin[DDIR_READ])) ||
+ (o->rate[DDIR_WRITE] && (o->rate[DDIR_WRITE] < o->ratemin[DDIR_WRITE])) ||
+ (o->rate[DDIR_TRIM] && (o->rate[DDIR_TRIM] < o->ratemin[DDIR_TRIM])) ||
+ (o->rate_iops[DDIR_READ] && (o->rate_iops[DDIR_READ] < o->rate_iops_min[DDIR_READ])) ||
+ (o->rate_iops[DDIR_WRITE] && (o->rate_iops[DDIR_WRITE] < o->rate_iops_min[DDIR_WRITE])) ||
+ (o->rate_iops[DDIR_TRIM] && (o->rate_iops[DDIR_TRIM] < o->rate_iops_min[DDIR_TRIM]))) {
log_err("fio: minimum rate exceeds rate\n");
ret = 1;
}
ret = warnings_fatal;
}
- o->refill_buffers = 1;
+ if (!fio_option_is_set(o, refill_buffers))
+ o->refill_buffers = 1;
+
if (o->max_bs[DDIR_WRITE] != o->min_bs[DDIR_WRITE] &&
!o->verify_interval)
o->verify_interval = o->min_bs[DDIR_WRITE];
/*
* For fully compressible data, just zero them at init time.
- * It's faster than repeatedly filling it.
+ * It's faster than repeatedly filling it. For non-zero
+ * compression, we should have refill_buffers set. Set it, unless
+ * the job file already changed it.
*/
- if (td->o.compress_percentage == 100) {
- td->o.zero_buffers = 1;
- td->o.compress_percentage = 0;
+ if (o->compress_percentage) {
+ if (o->compress_percentage == 100) {
+ o->zero_buffers = 1;
+ o->compress_percentage = 0;
+ } else if (!fio_option_is_set(o, refill_buffers))
+ o->refill_buffers = 1;
}
/*
/*
* If randseed is set, that overrides randrepeat
*/
- if (td->o.rand_seed)
+ if (fio_option_is_set(&td->o, rand_seed))
td->o.rand_repeatable = 0;
if ((td->io_ops->flags & FIO_NOEXTEND) && td->o.file_append) {
fio_gtod_offload = 1;
}
+ td->loops = o->loops;
+ if (!td->loops)
+ td->loops = 1;
+
+ if (td->o.block_error_hist && td->o.nr_files != 1) {
+ log_err("fio: block error histogram only available with "
+ "with a single file per job, but %d files "
+ "provided\n", td->o.nr_files);
+ ret = 1;
+ }
+
return ret;
}
return 1;
}
-static void td_fill_rand_seeds_internal(struct thread_data *td)
+static void td_fill_rand_seeds_internal(struct thread_data *td, bool use64)
{
- init_rand_seed(&td->bsrange_state, td->rand_seeds[FIO_RAND_BS_OFF]);
- init_rand_seed(&td->verify_state, td->rand_seeds[FIO_RAND_VER_OFF]);
- init_rand_seed(&td->rwmix_state, td->rand_seeds[FIO_RAND_MIX_OFF]);
+ int i;
+
+ init_rand_seed(&td->bsrange_state, td->rand_seeds[FIO_RAND_BS_OFF], use64);
+ init_rand_seed(&td->verify_state, td->rand_seeds[FIO_RAND_VER_OFF], use64);
+ init_rand_seed(&td->rwmix_state, td->rand_seeds[FIO_RAND_MIX_OFF], false);
if (td->o.file_service_type == FIO_FSERVICE_RANDOM)
- init_rand_seed(&td->next_file_state, td->rand_seeds[FIO_RAND_FILE_OFF]);
+ init_rand_seed(&td->next_file_state, td->rand_seeds[FIO_RAND_FILE_OFF], use64);
- init_rand_seed(&td->file_size_state, td->rand_seeds[FIO_RAND_FILE_SIZE_OFF]);
- init_rand_seed(&td->trim_state, td->rand_seeds[FIO_RAND_TRIM_OFF]);
- init_rand_seed(&td->delay_state, td->rand_seeds[FIO_RAND_START_DELAY]);
+ init_rand_seed(&td->file_size_state, td->rand_seeds[FIO_RAND_FILE_SIZE_OFF], use64);
+ init_rand_seed(&td->trim_state, td->rand_seeds[FIO_RAND_TRIM_OFF], use64);
+ init_rand_seed(&td->delay_state, td->rand_seeds[FIO_RAND_START_DELAY], use64);
+ init_rand_seed(&td->poisson_state, td->rand_seeds[FIO_RAND_POISSON_OFF], 0);
+ init_rand_seed(&td->dedupe_state, td->rand_seeds[FIO_DEDUPE_OFF], false);
+ init_rand_seed(&td->zone_state, td->rand_seeds[FIO_RAND_ZONE_OFF], false);
if (!td_random(td))
return;
if (td->o.rand_repeatable)
td->rand_seeds[FIO_RAND_BLOCK_OFF] = FIO_RANDSEED * td->thread_number;
- init_rand_seed(&td->random_state, td->rand_seeds[FIO_RAND_BLOCK_OFF]);
- init_rand_seed(&td->seq_rand_state[DDIR_READ], td->rand_seeds[FIO_RAND_SEQ_RAND_READ_OFF]);
- init_rand_seed(&td->seq_rand_state[DDIR_WRITE], td->rand_seeds[FIO_RAND_SEQ_RAND_WRITE_OFF]);
- init_rand_seed(&td->seq_rand_state[DDIR_TRIM], td->rand_seeds[FIO_RAND_SEQ_RAND_TRIM_OFF]);
+ init_rand_seed(&td->random_state, td->rand_seeds[FIO_RAND_BLOCK_OFF], use64);
+
+ for (i = 0; i < DDIR_RWDIR_CNT; i++) {
+ struct frand_state *s = &td->seq_rand_state[i];
+
+ init_rand_seed(s, td->rand_seeds[FIO_RAND_SEQ_RAND_READ_OFF], false);
+ }
}
void td_fill_rand_seeds(struct thread_data *td)
{
+ bool use64;
+
if (td->o.allrand_repeatable) {
unsigned int i;
+ i;
}
- td_fill_rand_seeds_internal(td);
+ if (td->o.random_generator == FIO_RAND_GEN_TAUSWORTHE64)
+ use64 = 1;
+ else
+ use64 = 0;
- init_rand_seed(&td->buf_state, td->rand_seeds[FIO_RAND_BUF_OFF]);
- frand_copy(&td->buf_state_prev, &td->buf_state);
+ td_fill_rand_seeds_internal(td, use64);
- init_rand_seed(&td->dedupe_state, td->rand_seeds[FIO_DEDUPE_OFF]);
+ init_rand_seed(&td->buf_state, td->rand_seeds[FIO_RAND_BUF_OFF], use64);
+ frand_copy(&td->buf_state_prev, &td->buf_state);
}
/*
td->flags |= TD_F_SCRAMBLE_BUFFERS;
if (o->verify != VERIFY_NONE)
td->flags |= TD_F_VER_NONE;
+
+ if (o->verify_async || o->io_submit_mode == IO_MODE_OFFLOAD)
+ td->flags |= TD_F_NEED_LOCK;
}
static int setup_random_seeds(struct thread_data *td)
unsigned long seed;
unsigned int i;
- if (!td->o.rand_repeatable && !td->o.rand_seed)
+ if (!td->o.rand_repeatable && !fio_option_is_set(&td->o, rand_seed))
return init_random_state(td, td->rand_seeds, sizeof(td->rand_seeds));
- if (!td->o.rand_seed)
- seed = 0x89;
- else
- seed = td->o.rand_seed;
-
+ seed = td->o.rand_seed;
for (i = 0; i < 4; i++)
seed *= 0x9e370001UL;
for (i = 0; i < FIO_RAND_NR_OFFS; i++) {
- td->rand_seeds[i] = seed;
+ td->rand_seeds[i] = seed * td->thread_number + i;
seed *= 0x9e370001UL;
}
return dump_cmdline || parse_only;
}
+static void gen_log_name(char *name, size_t size, const char *logtype,
+ const char *logname, unsigned int num,
+ const char *suf, int per_job)
+{
+ if (per_job)
+ snprintf(name, size, "%s_%s.%d.%s", logname, logtype, num, suf);
+ else
+ snprintf(name, size, "%s_%s.%s", logname, logtype, suf);
+}
+
+static int check_waitees(char *waitee)
+{
+ struct thread_data *td;
+ int i, ret = 0;
+
+ for_each_td(td, i) {
+ if (td->subjob_number)
+ continue;
+
+ ret += !strcmp(td->o.name, waitee);
+ }
+
+ return ret;
+}
+
+static bool wait_for_ok(const char *jobname, struct thread_options *o)
+{
+ int nw;
+
+ if (!o->wait_for)
+ return true;
+
+ if (!strcmp(jobname, o->wait_for)) {
+ log_err("%s: a job cannot wait for itself (wait_for=%s).\n",
+ jobname, o->wait_for);
+ return false;
+ }
+
+ if (!(nw = check_waitees(o->wait_for))) {
+ log_err("%s: waitee job %s unknown.\n", jobname, o->wait_for);
+ return false;
+ }
+
+ if (nw > 1) {
+ log_err("%s: multiple waitees %s found,\n"
+ "please avoid duplicates when using wait_for option.\n",
+ jobname, o->wait_for);
+ return false;
+ }
+
+ return true;
+}
+
/*
* Adds a job to the list of things todo. Sanitizes the various options
* to make sure we don't have conflicts, and initializes various
if (fixup_options(td))
goto err;
+ /*
+ * Belongs to fixup_options, but o->name is not necessarily set as yet
+ */
+ if (!wait_for_ok(jobname, o))
+ goto err;
+
flow_init_job(td);
/*
if ((o->stonewall || o->new_group) && prev_group_jobs) {
prev_group_jobs = 0;
groupid++;
+ if (groupid == INT_MAX) {
+ log_err("fio: too many groups defined\n");
+ goto err;
+ }
}
td->groupid = groupid;
else
suf = "log";
- snprintf(logname, sizeof(logname), "%s_lat.%d.%s",
- o->lat_log_file, td->thread_number, suf);
+ gen_log_name(logname, sizeof(logname), "lat", o->lat_log_file,
+ td->thread_number, suf, o->per_job_logs);
setup_log(&td->lat_log, &p, logname);
- snprintf(logname, sizeof(logname), "%s_slat.%d.%s",
- o->lat_log_file, td->thread_number, suf);
+
+ gen_log_name(logname, sizeof(logname), "slat", o->lat_log_file,
+ td->thread_number, suf, o->per_job_logs);
setup_log(&td->slat_log, &p, logname);
- snprintf(logname, sizeof(logname), "%s_clat.%d.%s",
- o->lat_log_file, td->thread_number, suf);
+
+ gen_log_name(logname, sizeof(logname), "clat", o->lat_log_file,
+ td->thread_number, suf, o->per_job_logs);
setup_log(&td->clat_log, &p, logname);
}
if (o->bw_log_file) {
else
suf = "log";
- snprintf(logname, sizeof(logname), "%s_bw.%d.%s",
- o->bw_log_file, td->thread_number, suf);
+ gen_log_name(logname, sizeof(logname), "bw", o->bw_log_file,
+ td->thread_number, suf, o->per_job_logs);
setup_log(&td->bw_log, &p, logname);
}
if (o->iops_log_file) {
else
suf = "log";
- snprintf(logname, sizeof(logname), "%s_iops.%d.%s",
- o->iops_log_file, td->thread_number, suf);
+ gen_log_name(logname, sizeof(logname), "iops", o->iops_log_file,
+ td->thread_number, suf, o->per_job_logs);
setup_log(&td->iops_log, &p, logname);
}
if (!o->name)
o->name = strdup(jobname);
- if (output_format == FIO_OUTPUT_NORMAL) {
+ if (output_format & FIO_OUTPUT_NORMAL) {
if (!job_add_num) {
if (is_backend && !recursed)
fio_server_send_add_job(td);
td = get_new_job(0, td_parent, 0, jobname);
}
if (in_global)
- fio_options_parse(td_parent, (char **) &o[i], 1, 0);
+ fio_options_parse(td_parent, (char **) &o[i], 1);
else
- fio_options_parse(td, (char **) &o[i], 1, 0);
+ fio_options_parse(td, (char **) &o[i], 1);
i++;
}
strip_blank_end(p);
if (!strncmp(p, "include", strlen("include"))) {
- char *filename = p + strlen("include") + 1;
+ char *filename = p + strlen("include") + 1,
+ *ts, *full_fn = NULL;
+
+ /*
+ * Allow for the include filename
+ * specification to be relative.
+ */
+ if (access(filename, F_OK) &&
+ (ts = strrchr(file, '/'))) {
+ int len = ts - file +
+ strlen(filename) + 2;
+
+ if (!(full_fn = calloc(1, len))) {
+ ret = ENOMEM;
+ break;
+ }
- if ((ret = __parse_jobs_ini(td, filename,
- is_buf, stonewall_flag, type, 1,
- name, &opts, &alloc_opts, &num_opts))) {
- log_err("Error %d while parsing include file %s\n",
+ strncpy(full_fn,
+ file, (ts - file) + 1);
+ strncpy(full_fn + (ts - file) + 1,
+ filename, strlen(filename));
+ full_fn[len - 1] = 0;
+ filename = full_fn;
+ }
+
+ ret = __parse_jobs_ini(td, filename, is_buf,
+ stonewall_flag, type, 1,
+ name, &opts,
+ &alloc_opts, &num_opts);
+
+ if (ret) {
+ log_err("Error %d while parsing "
+ "include file %s\n",
ret, filename);
- break;
}
+
+ if (full_fn)
+ free(full_fn);
+
+ if (ret)
+ break;
+
continue;
}
goto out;
}
- ret = fio_options_parse(td, opts, num_opts, dump_cmdline);
- if (!ret)
+ ret = fio_options_parse(td, opts, num_opts);
+ if (!ret) {
+ if (dump_cmdline)
+ dump_opt_list(td);
+
ret = add_job(td, name, 0, 0, type);
- else {
+ } else {
log_err("fio: job %s dropped\n", name);
put_job(td);
}
static int fill_def_thread(void)
{
memset(&def_thread, 0, sizeof(def_thread));
+ INIT_FLIST_HEAD(&def_thread.opt_list);
fio_getaffinity(getpid(), &def_thread.o.cpumask);
def_thread.o.error_dump = 1;
return 0;
}
+static void show_debug_categories(void)
+{
+#ifdef FIO_INC_DEBUG
+ struct debug_level *dl = &debug_levels[0];
+ int curlen, first = 1;
+
+ curlen = 0;
+ while (dl->name) {
+ int has_next = (dl + 1)->name != NULL;
+
+ if (first || curlen + strlen(dl->name) >= 80) {
+ if (!first) {
+ printf("\n");
+ curlen = 0;
+ }
+ curlen += printf("\t\t\t%s", dl->name);
+ curlen += 3 * (8 - 1);
+ if (has_next)
+ curlen += printf(",");
+ } else {
+ curlen += printf("%s", dl->name);
+ if (has_next)
+ curlen += printf(",");
+ }
+ dl++;
+ first = 0;
+ }
+ printf("\n");
+#endif
+}
+
static void usage(const char *name)
{
printf("%s\n", fio_version_string);
printf("%s [options] [job options] <job file(s)>\n", name);
- printf(" --debug=options\tEnable debug logging. May be one/more of:\n"
- "\t\t\tprocess,file,io,mem,blktrace,verify,random,parse,\n"
- "\t\t\tdiskutil,job,mutex,profile,time,net,rate,compress\n");
+ printf(" --debug=options\tEnable debug logging. May be one/more of:\n");
+ show_debug_categories();
printf(" --parse-only\t\tParse options only, don't start any IO\n");
printf(" --output\t\tWrite output to file\n");
printf(" --runtime\t\tRuntime in seconds\n");
printf(" --bandwidth-log\tGenerate per-job bandwidth logs\n");
printf(" --minimal\t\tMinimal (terse) output\n");
- printf(" --output-format=x\tOutput format (terse,json,normal)\n");
+ printf(" --output-format=x\tOutput format (terse,json,json+,normal)\n");
printf(" --terse-version=x\tSet terse version output format to 'x'\n");
printf(" --version\t\tPrint version info and exit\n");
printf(" --help\t\tPrint this page\n");
printf(" --trigger-timeout=t\tExecute trigger af this time\n");
printf(" --trigger=cmd\t\tSet this command as local trigger\n");
printf(" --trigger-remote=cmd\tSet this command as remote trigger\n");
+ printf(" --aux-path=path\tUse this path for fio state generated files\n");
printf("\nFio was written by Jens Axboe <jens.axboe@oracle.com>");
printf("\n Jens Axboe <jaxboe@fusionio.com>");
printf("\n Jens Axboe <axboe@fb.com>\n");
char *opt;
int i;
+ if (!string)
+ return 0;
+
if (!strcmp(string, "?") || !strcmp(string, "help")) {
log_info("fio: dumping debug options:");
for (i = 0; debug_levels[i].name; i++) {
i++;
}
- if (best_option != -1)
+ if (best_option != -1 && string_distance_ok(name, best_distance))
log_err("Did you mean %s?\n", l_opts[best_option].name);
}
+static int parse_output_format(const char *optarg)
+{
+ char *p, *orig, *opt;
+ int ret = 0;
+
+ p = orig = strdup(optarg);
+
+ output_format = 0;
+
+ while ((opt = strsep(&p, ",")) != NULL) {
+ if (!strcmp(opt, "minimal") ||
+ !strcmp(opt, "terse") ||
+ !strcmp(opt, "csv"))
+ output_format |= FIO_OUTPUT_TERSE;
+ else if (!strcmp(opt, "json"))
+ output_format |= FIO_OUTPUT_JSON;
+ else if (!strcmp(opt, "json+"))
+ output_format |= (FIO_OUTPUT_JSON | FIO_OUTPUT_JSON_PLUS);
+ else if (!strcmp(opt, "normal"))
+ output_format |= FIO_OUTPUT_NORMAL;
+ else {
+ log_err("fio: invalid output format %s\n", opt);
+ ret = 1;
+ break;
+ }
+ }
+
+ free(orig);
+ return ret;
+}
+
int parse_cmd_line(int argc, char *argv[], int client_type)
{
struct thread_data *td = NULL;
do_exit++;
break;
}
- if (!strcmp(optarg, "minimal") ||
- !strcmp(optarg, "terse") ||
- !strcmp(optarg, "csv"))
- output_format = FIO_OUTPUT_TERSE;
- else if (!strcmp(optarg, "json"))
- output_format = FIO_OUTPUT_JSON;
- else
- output_format = FIO_OUTPUT_NORMAL;
+ if (parse_output_format(optarg)) {
+ log_err("fio: failed parsing output-format\n");
+ exit_val = 1;
+ do_exit++;
+ break;
+ }
break;
case 'f':
- append_terse_output = 1;
+ output_format |= FIO_OUTPUT_TERSE;
break;
case 'h':
did_arg = 1;
td = NULL;
}
do_exit++;
+ exit_val = 1;
break;
}
fio_options_set_ioengine_opts(l_opts, td);
td = NULL;
}
do_exit++;
+ exit_val = 1;
}
if (!ret && !strcmp(opt, "ioengine")) {
put_job(td);
td = NULL;
do_exit++;
+ exit_val = 1;
break;
}
fio_options_set_ioengine_opts(l_opts, td);
exit_val = 1;
break;
}
+ /* if --client parameter contains a pathname */
+ if (0 == access(optarg, R_OK)) {
+ /* file contains a list of host addrs or names */
+ char hostaddr[PATH_MAX] = {0};
+ char formatstr[8];
+ FILE * hostf = fopen(optarg, "r");
+ if (!hostf) {
+ log_err("fio: could not open client list file %s for read\n", optarg);
+ do_exit++;
+ exit_val = 1;
+ break;
+ }
+ sprintf(formatstr, "%%%ds", PATH_MAX - 1);
+ /*
+ * read at most PATH_MAX-1 chars from each
+ * record in this file
+ */
+ while (fscanf(hostf, formatstr, hostaddr) == 1) {
+ /* expect EVERY host in file to be valid */
+ if (fio_client_add(&fio_client_ops, hostaddr, &cur_client)) {
+ log_err("fio: failed adding client %s from file %s\n", hostaddr, optarg);
+ do_exit++;
+ exit_val = 1;
+ break;
+ }
+ }
+ fclose(hostf);
+ break; /* no possibility of job file for "this client only" */
+ }
if (fio_client_add(&fio_client_ops, optarg, &cur_client)) {
log_err("fio: failed adding client %s\n", optarg);
do_exit++;
break;
}
case 'W':
+ if (trigger_file)
+ free(trigger_file);
trigger_file = strdup(optarg);
break;
case 'H':
+ if (trigger_cmd)
+ free(trigger_cmd);
trigger_cmd = strdup(optarg);
break;
case 'J':
+ if (trigger_remote_cmd)
+ free(trigger_remote_cmd);
trigger_remote_cmd = strdup(optarg);
break;
+ case 'K':
+ if (aux_path)
+ free(aux_path);
+ aux_path = strdup(optarg);
+ break;
case 'B':
if (check_str_time(optarg, &trigger_timeout, 1)) {
log_err("fio: failed parsing time %s\n", optarg);
return 0;
}
- if (output_format == FIO_OUTPUT_NORMAL)
+ if (output_format & FIO_OUTPUT_NORMAL)
log_info("%s\n", fio_version_string);
return 0;
{
memcpy(o, &def_thread.o, sizeof(*o));
}
+
+struct thread_data *get_global_options(void)
+{
+ return &def_thread;
+}