The following changes since commit ea66e04fe1a803f6a9ddf31cb999641d4396d67c: Fix issue with td->mutex being used-after-free (2014-02-10 13:57:09 -0700) are available in the git repository at: git://git.kernel.dk/fio.git master for you to fetch changes up to f0fdbcafc3a62b84250e5ccdcaec47e3ffa93a00: parse: cleanup difference between profile and normal options (2014-02-11 15:44:50 -0700) ---------------------------------------------------------------- Jens Axboe (6): Fix issue with openfiles= and file sizing Enfore that lockfile= must precede filename= Plug a free basic memory leaks parse: get rid of raw option offsets Fio 2.1.5 parse: cleanup difference between profile and normal options FIO-VERSION-GEN | 2 +- backend.c | 20 ++++++- cconv.c | 25 +++++++++ err.h | 44 +++++++++++++++ file.h | 1 + filesetup.c | 45 +++++++++++++-- goptions.c | 68 +++++++++++----------- init.c | 1 + io_u.c | 25 +++++++-- options.c | 21 ++++++- os/windows/install.wxs | 2 +- parse.c | 146 +++++++++++++++--------------------------------- parse.h | 14 ++++- profile.c | 1 + profile.h | 1 + profiles/act.c | 28 +++++++--- profiles/tiobench.c | 23 ++++++-- 17 files changed, 305 insertions(+), 162 deletions(-) create mode 100644 err.h --- Diff of recent changes: diff --git a/FIO-VERSION-GEN b/FIO-VERSION-GEN index 39e34b5..63ed948 100755 --- a/FIO-VERSION-GEN +++ b/FIO-VERSION-GEN @@ -1,7 +1,7 @@ #!/bin/sh GVF=FIO-VERSION-FILE -DEF_VER=fio-2.1.4 +DEF_VER=fio-2.1.5 LF=' ' diff --git a/backend.c b/backend.c index a607134..32bc265 100644 --- a/backend.c +++ b/backend.c @@ -52,6 +52,7 @@ #include "server.h" #include "lib/getrusage.h" #include "idletime.h" +#include "err.h" static pthread_t disk_util_thread; static struct fio_mutex *disk_thread_mutex; @@ -478,6 +479,12 @@ static void do_verify(struct thread_data *td, uint64_t verify_bytes) break; while ((io_u = get_io_u(td)) != NULL) { + if (IS_ERR(io_u)) { + io_u = NULL; + ret = FIO_Q_BUSY; + goto reap; + } + /* * We are only interested in the places where * we wrote or trimmed IOs. Turn those into @@ -574,6 +581,7 @@ sync_done: * completed io_u's first. Note that we can get BUSY even * without IO queued, if the system is resource starved. */ +reap: full = queue_full(td) || (ret == FIO_Q_BUSY && td->cur_depth); if (full || !td->o.iodepth_batch_complete) { min_events = min(td->o.iodepth_batch_complete, @@ -692,7 +700,14 @@ static uint64_t do_io(struct thread_data *td) break; io_u = get_io_u(td); - if (!io_u) { + if (IS_ERR_OR_NULL(io_u)) { + int err = PTR_ERR(io_u); + + io_u = NULL; + if (err == -EBUSY) { + ret = FIO_Q_BUSY; + goto reap; + } if (td->o.latency_target) goto reap; break; @@ -1124,6 +1139,9 @@ static int keep_running(struct thread_data *td) if (diff < td_max_bs(td)) return 0; + if (fio_files_done(td)) + return 0; + return 1; } diff --git a/cconv.c b/cconv.c index 0d30f07..b7d469e 100644 --- a/cconv.c +++ b/cconv.c @@ -18,6 +18,29 @@ static void string_to_net(uint8_t *dst, const char *src) dst[0] = '\0'; } +void free_thread_options_to_cpu(struct thread_options *o) +{ + free(o->description); + free(o->name); + free(o->directory); + free(o->filename); + free(o->filename_format); + free(o->opendir); + free(o->ioengine); + free(o->mmapfile); + free(o->read_iolog_file); + free(o->write_iolog_file); + free(o->bw_log_file); + free(o->lat_log_file); + free(o->iops_log_file); + free(o->replay_redirect); + free(o->exec_prerun); + free(o->exec_postrun); + free(o->ioscheduler); + free(o->profile); + free(o->cgroup); +} + void convert_thread_options_to_cpu(struct thread_options *o, struct thread_options_pack *top) { @@ -438,5 +461,7 @@ int fio_test_cconv(struct thread_options *__o) convert_thread_options_to_cpu(&o, &top1); convert_thread_options_to_net(&top2, &o); + free_thread_options_to_cpu(&o); + return memcmp(&top1, &top2, sizeof(top1)); } diff --git a/err.h b/err.h new file mode 100644 index 0000000..5c024ee --- /dev/null +++ b/err.h @@ -0,0 +1,44 @@ +#ifndef FIO_ERR_H +#define FIO_ERR_H + +/* + * Kernel pointers have redundant information, so we can use a + * scheme where we can return either an error code or a dentry + * pointer with the same return value. + * + * This should be a per-architecture thing, to allow different + * error and pointer decisions. + */ +#define MAX_ERRNO 4095 + +#define IS_ERR_VALUE(x) ((x) >= (unsigned long)-MAX_ERRNO) + +static inline void *ERR_PTR(long error) +{ + return (void *) error; +} + +static inline long PTR_ERR(const void *ptr) +{ + return (long) ptr; +} + +static inline long IS_ERR(const void *ptr) +{ + return IS_ERR_VALUE((unsigned long)ptr); +} + +static inline long IS_ERR_OR_NULL(const void *ptr) +{ + return !ptr || IS_ERR_VALUE((unsigned long)ptr); +} + +static inline int PTR_ERR_OR_ZERO(const void *ptr) +{ + if (IS_ERR(ptr)) + return PTR_ERR(ptr); + else + return 0; +} + +#endif diff --git a/file.h b/file.h index d7e05f4..19413fc 100644 --- a/file.h +++ b/file.h @@ -176,5 +176,6 @@ extern void dup_files(struct thread_data *, struct thread_data *); extern int get_fileno(struct thread_data *, const char *); extern void free_release_files(struct thread_data *); void fio_file_reset(struct thread_data *, struct fio_file *); +int fio_files_done(struct thread_data *); #endif diff --git a/filesetup.c b/filesetup.c index d1702e2..544ecb1 100644 --- a/filesetup.c +++ b/filesetup.c @@ -734,9 +734,11 @@ int setup_files(struct thread_data *td) unsigned long long total_size, extend_size; struct thread_options *o = &td->o; struct fio_file *f; - unsigned int i; + unsigned int i, nr_fs_extra = 0; int err = 0, need_extend; int old_state; + const unsigned int bs = td_min_bs(td); + uint64_t fs = 0; dprint(FD_FILE, "setup files\n"); @@ -786,6 +788,20 @@ int setup_files(struct thread_data *td) } /* + * Calculate per-file size and potential extra size for the + * first files, if needed. + */ + if (!o->file_size_low) { + uint64_t all_fs; + + fs = o->size / o->nr_files; + all_fs = fs * o->nr_files; + + if (all_fs < o->size) + nr_fs_extra = (o->size - all_fs) / bs; + } + + /* * now file sizes are known, so we can set ->io_size. if size= is * not given, ->io_size is just equal to ->real_file_size. if size * is given, ->io_size is size / nr_files. @@ -798,10 +814,17 @@ int setup_files(struct thread_data *td) if (!o->file_size_low) { /* * no file size range given, file size is equal to - * total size divided by number of files. if that is - * zero, set it to the real file size. + * total size divided by number of files. If that is + * zero, set it to the real file size. If the size + * doesn't divide nicely with the min blocksize, + * make the first files bigger. */ - f->io_size = o->size / o->nr_files; + f->io_size = fs; + if (nr_fs_extra) { + nr_fs_extra--; + f->io_size += bs; + } + if (!f->io_size) f->io_size = f->real_file_size - f->file_offset; } else if (f->real_file_size < o->file_size_low || @@ -1243,7 +1266,7 @@ void unlock_file(struct thread_data *td, struct fio_file *f) void unlock_file_all(struct thread_data *td, struct fio_file *f) { - if (td->o.file_lock_mode == FILE_LOCK_NONE) + if (td->o.file_lock_mode == FILE_LOCK_NONE || !td->file_locks) return; if (td->file_locks[f->fileno] != FILE_LOCK_NONE) unlock_file(td, f); @@ -1386,3 +1409,15 @@ void fio_file_reset(struct thread_data *td, struct fio_file *f) if (td->o.random_generator == FIO_RAND_GEN_LFSR) lfsr_reset(&f->lfsr, td->rand_seeds[FIO_RAND_BLOCK_OFF]); } + +int fio_files_done(struct thread_data *td) +{ + struct fio_file *f; + unsigned int i; + + for_each_file(td, f, i) + if (!fio_file_done(f)) + return 0; + + return 1; +} diff --git a/goptions.c b/goptions.c index 08b17ac..21d6427 100644 --- a/goptions.c +++ b/goptions.c @@ -874,7 +874,7 @@ static void gopt_set_option(struct gopt_job_view *gjv, struct fio_option *o, struct gopt_str_val *g; if (o->off1) - ullp = td_var(to, o->off1); + ullp = td_var(to, o, o->off1); g = container_of(gopt, struct gopt_str_val, gopt); if (ullp) @@ -886,7 +886,7 @@ static void gopt_set_option(struct gopt_job_view *gjv, struct fio_option *o, struct gopt_int *i; if (o->off1) - ullp = td_var(to, o->off1); + ullp = td_var(to, o, o->off1); i = container_of(gopt, struct gopt_int, gopt); if (ullp) @@ -899,7 +899,7 @@ static void gopt_set_option(struct gopt_job_view *gjv, struct fio_option *o, struct gopt_combo *c; if (o->off1) - ip = td_var(to, o->off1); + ip = td_var(to, o, o->off1); c = container_of(gopt, struct gopt_combo, gopt); if (ip) @@ -909,7 +909,7 @@ static void gopt_set_option(struct gopt_job_view *gjv, struct fio_option *o, struct gopt_int *i; if (o->off1) - ip = td_var(to, o->off1); + ip = td_var(to, o, o->off1); i = container_of(gopt, struct gopt_int, gopt); if (ip) @@ -922,7 +922,7 @@ static void gopt_set_option(struct gopt_job_view *gjv, struct fio_option *o, struct gopt_bool *b; if (o->off1) - ip = td_var(to, o->off1); + ip = td_var(to, o, o->off1); b = container_of(gopt, struct gopt_bool, gopt); if (ip) @@ -935,7 +935,7 @@ static void gopt_set_option(struct gopt_job_view *gjv, struct fio_option *o, struct gopt_combo *c; if (o->off1) - ip = td_var(to, o->off1); + ip = td_var(to, o, o->off1); c = container_of(gopt, struct gopt_combo, gopt); if (ip) @@ -945,7 +945,7 @@ static void gopt_set_option(struct gopt_job_view *gjv, struct fio_option *o, char *text = NULL; if (o->off1) { - char **p = td_var(to, o->off1); + char **p = td_var(to, o, o->off1); text = *p; } @@ -961,7 +961,7 @@ static void gopt_set_option(struct gopt_job_view *gjv, struct fio_option *o, char *text = NULL; if (o->off1) { - char **p = td_var(to, o->off1); + char **p = td_var(to, o, o->off1); text = *p; } @@ -983,10 +983,10 @@ static void gopt_set_option(struct gopt_job_view *gjv, struct fio_option *o, break; case FIO_OPT_RANGE: { struct gopt_range *r; - unsigned int *ip[4] = { td_var(to, o->off1), - td_var(to, o->off2), - td_var(to, o->off3), - td_var(to, o->off4) }; + unsigned int *ip[4] = { td_var(to, o, o->off1), + td_var(to, o, o->off2), + td_var(to, o, o->off3), + td_var(to, o, o->off4) }; r = container_of(gopt, struct gopt_range, gopt); gopt_int_range_set_val(r, *ip); @@ -1014,7 +1014,7 @@ static void gopt_add_option(struct gopt_job_view *gjv, GtkWidget *hbox, unsigned long long *ullp = NULL; if (o->off1) - ullp = td_var(to, o->off1); + ullp = td_var(to, o, o->off1); go = gopt_new_str_val(gjv, o, ullp, opt_index); break; @@ -1023,7 +1023,7 @@ static void gopt_add_option(struct gopt_job_view *gjv, GtkWidget *hbox, unsigned long long *ullp = NULL; if (o->off1) - ullp = td_var(to, o->off1); + ullp = td_var(to, o, o->off1); go = gopt_new_ullong(gjv, o, ullp, opt_index); break; @@ -1033,14 +1033,14 @@ static void gopt_add_option(struct gopt_job_view *gjv, GtkWidget *hbox, unsigned int *ip = NULL; if (o->off1) - ip = td_var(to, o->off1); + ip = td_var(to, o, o->off1); go = gopt_new_combo_int(gjv, o, ip, opt_index); } else { unsigned int *ip = NULL; if (o->off1) - ip = td_var(to, o->off1); + ip = td_var(to, o, o->off1); go = gopt_new_int(gjv, o, ip, opt_index); } @@ -1050,7 +1050,7 @@ static void gopt_add_option(struct gopt_job_view *gjv, GtkWidget *hbox, unsigned int *ip = NULL; if (o->off1) - ip = td_var(to, o->off1); + ip = td_var(to, o, o->off1); go = gopt_new_bool(gjv, o, ip, opt_index); break; @@ -1060,7 +1060,7 @@ static void gopt_add_option(struct gopt_job_view *gjv, GtkWidget *hbox, unsigned int *ip = NULL; if (o->off1) - ip = td_var(to, o->off1); + ip = td_var(to, o, o->off1); go = gopt_new_combo_int(gjv, o, ip, opt_index); } else { @@ -1074,7 +1074,7 @@ static void gopt_add_option(struct gopt_job_view *gjv, GtkWidget *hbox, char *text = NULL; if (o->off1) { - char **p = td_var(to, o->off1); + char **p = td_var(to, o, o->off1); text = *p; } @@ -1090,10 +1090,10 @@ static void gopt_add_option(struct gopt_job_view *gjv, GtkWidget *hbox, go = gopt_new_str_multi(gjv, o, opt_index); break; case FIO_OPT_RANGE: { - unsigned int *ip[4] = { td_var(to, o->off1), - td_var(to, o->off2), - td_var(to, o->off3), - td_var(to, o->off4) }; + unsigned int *ip[4] = { td_var(to, o, o->off1), + td_var(to, o, o->off2), + td_var(to, o, o->off3), + td_var(to, o, o->off4) }; go = gopt_new_int_range(gjv, o, ip, opt_index); break; @@ -1203,7 +1203,7 @@ static void gopt_handle_str_multi_changed(struct gopt_job_view *gjv, struct gopt_str_multi *m, struct fio_option *o) { - unsigned int *ip = td_var(gjv->o, o->off1); + unsigned int *ip = td_var(gjv->o, o, o->off1); struct value_pair *vp; gboolean set; guint val = 0; @@ -1233,10 +1233,10 @@ static void gopt_handle_range_changed(struct gopt_job_view *gjv, struct gopt_range *r, struct fio_option *o) { - unsigned int *ip[4] = { td_var(gjv->o, o->off1), - td_var(gjv->o, o->off2), - td_var(gjv->o, o->off3), - td_var(gjv->o, o->off4) }; + unsigned int *ip[4] = { td_var(gjv->o, o, o->off1), + td_var(gjv->o, o, o->off2), + td_var(gjv->o, o, o->off3), + td_var(gjv->o, o, o->off4) }; gint val; int i; @@ -1250,7 +1250,7 @@ static void gopt_handle_str_val_changed(struct gopt_job_view *gjv, struct gopt_str_val *s, struct fio_option *o) { - unsigned long long *ullp = td_var(gjv->o, o->off1); + unsigned long long *ullp = td_var(gjv->o, o, o->off1); GtkAdjustment *adj; gint index; @@ -1274,7 +1274,7 @@ static void gopt_handle_str_val_changed(struct gopt_job_view *gjv, static void gopt_handle_str_changed(struct gopt_job_view *gjv, struct gopt_str *s, struct fio_option *o) { - char **p = td_var(gjv->o, o->off1); + char **p = td_var(gjv->o, o, o->off1); if (*p) free(*p); @@ -1285,7 +1285,7 @@ static void gopt_handle_str_changed(struct gopt_job_view *gjv, static void gopt_handle_bool_changed(struct gopt_job_view *gjv, struct gopt_bool *b, struct fio_option *o) { - unsigned int *ip = td_var(gjv->o, o->off1); + unsigned int *ip = td_var(gjv->o, o, o->off1); gboolean set; set = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(b->check)); @@ -1295,7 +1295,7 @@ static void gopt_handle_bool_changed(struct gopt_job_view *gjv, static void gopt_handle_int_changed(struct gopt_job_view *gjv, struct gopt_int *i, struct fio_option *o) { - unsigned int *ip = td_var(gjv->o, o->off1); + unsigned int *ip = td_var(gjv->o, o, o->off1); GtkAdjustment *adj; guint val; @@ -1308,7 +1308,7 @@ static void gopt_handle_combo_str_changed(struct gopt_job_view *gjv, struct gopt_combo *c, struct fio_option *o) { - char **p = td_var(gjv->o, o->off1); + char **p = td_var(gjv->o, o, o->off1); if (*p) free(*p); @@ -1320,7 +1320,7 @@ static void gopt_handle_combo_int_changed(struct gopt_job_view *gjv, struct gopt_combo *c, struct fio_option *o) { - unsigned int *ip = td_var(gjv->o, o->off1); + unsigned int *ip = td_var(gjv->o, o, o->off1); gint index; index = gtk_combo_box_get_active(GTK_COMBO_BOX(c->combo)); diff --git a/init.c b/init.c index b26dc9f..fa1df8e 100644 --- a/init.c +++ b/init.c @@ -250,6 +250,7 @@ void free_shm(void) free_threads_shm(); } + options_free(fio_options, &def_thread); scleanup(); } diff --git a/io_u.c b/io_u.c index 64ff73c..acc1a7b 100644 --- a/io_u.c +++ b/io_u.c @@ -11,6 +11,7 @@ #include "trim.h" #include "lib/rand.h" #include "lib/axmap.h" +#include "err.h" struct io_completion_data { int nr; /* input */ @@ -985,6 +986,9 @@ static struct fio_file *get_next_file_rand(struct thread_data *td, if (!fio_file_open(f)) { int err; + if (td->nr_open_files >= td->o.open_files) + return ERR_PTR(-EBUSY); + err = td_io_open_file(td, f); if (err) continue; @@ -1027,6 +1031,9 @@ static struct fio_file *get_next_file_rr(struct thread_data *td, int goodf, if (!fio_file_open(f)) { int err; + if (td->nr_open_files >= td->o.open_files) + return ERR_PTR(-EBUSY); + err = td_io_open_file(td, f); if (err) { dprint(FD_FILE, "error %d on open of %s\n", @@ -1080,6 +1087,9 @@ static struct fio_file *__get_next_file(struct thread_data *td) else f = get_next_file_rand(td, FIO_FILE_open, FIO_FILE_closing); + if (IS_ERR(f)) + return f; + td->file_service_file = f; td->file_service_left = td->file_service_nr - 1; out: @@ -1099,14 +1109,14 @@ static struct fio_file *get_next_file(struct thread_data *td) return __get_next_file(td); } -static int set_io_u_file(struct thread_data *td, struct io_u *io_u) +static long set_io_u_file(struct thread_data *td, struct io_u *io_u) { struct fio_file *f; do { f = get_next_file(td); - if (!f) - return 1; + if (IS_ERR_OR_NULL(f)) + return PTR_ERR(f); io_u->file = f; get_file(f); @@ -1400,6 +1410,7 @@ struct io_u *get_io_u(struct thread_data *td) struct fio_file *f; struct io_u *io_u; int do_scramble = 0; + long ret = 0; io_u = __get_io_u(td); if (!io_u) { @@ -1425,11 +1436,17 @@ struct io_u *get_io_u(struct thread_data *td) if (read_iolog_get(td, io_u)) goto err_put; } else if (set_io_u_file(td, io_u)) { + ret = -EBUSY; dprint(FD_IO, "io_u %p, setting file failed\n", io_u); goto err_put; } f = io_u->file; + if (!f) { + dprint(FD_IO, "io_u %p, setting file failed\n", io_u); + goto err_put; + } + assert(fio_file_open(f)); if (ddir_rw(io_u->ddir)) { @@ -1478,7 +1495,7 @@ out: err_put: dprint(FD_IO, "get_io_u failed\n"); put_io_u(td, io_u); - return NULL; + return ERR_PTR(ret); } void io_u_log_error(struct thread_data *td, struct io_u *io_u) diff --git a/options.c b/options.c index 57e9af5..9f6bc8d 100644 --- a/options.c +++ b/options.c @@ -821,6 +821,18 @@ static int str_directory_cb(void *data, const char fio_unused *str) return 0; } +static int str_lockfile_cb(void *data, const char fio_unused *str) +{ + struct thread_data *td = data; + + if (td->files_index) { + log_err("fio: lockfile= option must precede filename=\n"); + return 1; + } + + return 0; +} + static int str_opendir_cb(void *data, const char fio_unused *str) { struct thread_data *td = data; @@ -1231,6 +1243,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .parent = "filename", .hide = 0, .def = "none", + .cb = str_lockfile_cb, .category = FIO_OPT_C_FILE, .group = FIO_OPT_G_FILENAME, .posval = { @@ -3727,7 +3740,7 @@ void options_mem_dupe(void *data, struct fio_option *options) if (o->type != FIO_OPT_STR_STORE) continue; - ptr = td_var(data, o->off1); + ptr = td_var(data, o, o->off1); if (*ptr) *ptr = strdup(*ptr); } @@ -3773,7 +3786,13 @@ int add_option(struct fio_option *o) __o++; } + if (opt_index + 1 == FIO_MAX_OPTS) { + log_err("fio: FIO_MAX_OPTS is too small\n"); + return 1; + } + memcpy(&fio_options[opt_index], o, sizeof(*o)); + fio_options[opt_index + 1].name = NULL; return 0; } diff --git a/os/windows/install.wxs b/os/windows/install.wxs index 599fe39..fd38041 100755 --- a/os/windows/install.wxs +++ b/os/windows/install.wxs @@ -10,7 +10,7 @@ <Product Id="*" Codepage="1252" Language="1033" Manufacturer="fio" Name="fio" - UpgradeCode="2338A332-5511-43CF-B9BD-5C60496CCFCC" Version="2.1.4"> + UpgradeCode="2338A332-5511-43CF-B9BD-5C60496CCFCC" Version="2.1.5"> <Package Description="Flexible IO Tester" InstallerVersion="301" Keywords="Installer,MSI,Database" diff --git a/parse.c b/parse.c index 6141c91..6121dfc 100644 --- a/parse.c +++ b/parse.c @@ -368,9 +368,9 @@ static int str_match_len(const struct value_pair *vp, const char *str) return max(strlen(vp->ival), opt_len(str)); } -#define val_store(ptr, val, off, or, data) \ +#define val_store(ptr, val, off, or, data, o) \ do { \ - ptr = td_var((data), (off)); \ + ptr = td_var((data), (o), (off)); \ if ((or)) \ *ptr |= (val); \ else \ @@ -414,16 +414,8 @@ static int __handle_option(struct fio_option *o, const char *ptr, void *data, all_skipped = 0; if (!strncmp(vp->ival, ptr, str_match_len(vp, ptr))) { ret = 0; - if (o->roff1) { - if (vp->or) - *(unsigned int *) o->roff1 |= vp->oval; - else - *(unsigned int *) o->roff1 = vp->oval; - } else { - if (!o->off1) - continue; - val_store(ilp, vp->oval, o->off1, vp->or, data); - } + if (o->off1) + val_store(ilp, vp->oval, o->off1, vp->or, data, o); continue; } } @@ -490,50 +482,32 @@ static int __handle_option(struct fio_option *o, const char *ptr, void *data, ret = fn(data, &ull); else { if (o->type == FIO_OPT_INT) { - if (first) { - if (o->roff1) - *(unsigned int *) o->roff1 = ull; - else - val_store(ilp, ull, o->off1, 0, data); - } + if (first) + val_store(ilp, ull, o->off1, 0, data, o); if (curr == 1) { - if (o->roff2) - *(unsigned int *) o->roff2 = ull; - else if (o->off2) - val_store(ilp, ull, o->off2, 0, data); + if (o->off2) + val_store(ilp, ull, o->off2, 0, data, o); } if (curr == 2) { - if (o->roff3) - *(unsigned int *) o->roff3 = ull; - else if (o->off3) - val_store(ilp, ull, o->off3, 0, data); + if (o->off3) + val_store(ilp, ull, o->off3, 0, data, o); } if (!more) { if (curr < 1) { - if (o->roff2) - *(unsigned int *) o->roff2 = ull; - else if (o->off2) - val_store(ilp, ull, o->off2, 0, data); + if (o->off2) + val_store(ilp, ull, o->off2, 0, data, o); } if (curr < 2) { - if (o->roff3) - *(unsigned int *) o->roff3 = ull; - else if (o->off3) - val_store(ilp, ull, o->off3, 0, data); + if (o->off3) + val_store(ilp, ull, o->off3, 0, data, o); } } } else { - if (first) { - if (o->roff1) - *(unsigned long long *) o->roff1 = ull; - else - val_store(ullp, ull, o->off1, 0, data); - } + if (first) + val_store(ullp, ull, o->off1, 0, data, o); if (!more) { - if (o->roff2) - *(unsigned long long *) o->roff2 = ull; - else if (o->off2) - val_store(ullp, ull, o->off2, 0, data); + if (o->off2) + val_store(ullp, ull, o->off2, 0, data, o); } } } @@ -549,11 +523,11 @@ static int __handle_option(struct fio_option *o, const char *ptr, void *data, */ if (o->off2) { ul2 = 0; - ilp = td_var(data, o->off2); + ilp = td_var(data, o, o->off2); *ilp = ul2; } - flp = td_var(data, o->off1); + flp = td_var(data, o, o->off1); for(i = 0; i < o->maxlen; i++) flp[i].u.f = 0.0; } @@ -577,7 +551,7 @@ static int __handle_option(struct fio_option *o, const char *ptr, void *data, return 1; } - flp = td_var(data, o->off1); + flp = td_var(data, o, o->off1); flp[curr].u.f = uf; dprint(FD_PARSE, " out=%f\n", uf); @@ -595,7 +569,7 @@ static int __handle_option(struct fio_option *o, const char *ptr, void *data, len++; if (o->off2) { - ilp = td_var(data, o->off2); + ilp = td_var(data, o, o->off2); if (len > *ilp) *ilp = len; } @@ -606,12 +580,8 @@ static int __handle_option(struct fio_option *o, const char *ptr, void *data, case FIO_OPT_STR_STORE: { fio_opt_str_fn *fn = o->cb; - if (o->roff1 || o->off1) { - if (o->roff1) - cp = (char **) o->roff1; - else if (o->off1) - cp = td_var(data, o->off1); - + if (o->off1) { + cp = td_var(data, o, o->off1); *cp = strdup(ptr); } @@ -691,50 +661,32 @@ static int __handle_option(struct fio_option *o, const char *ptr, void *data, } if (first) { - if (o->roff1) - *(unsigned int *) o->roff1 = ul1; - else - val_store(ilp, ul1, o->off1, 0, data); - if (o->roff2) - *(unsigned int *) o->roff2 = ul2; - else - val_store(ilp, ul2, o->off2, 0, data); + val_store(ilp, ul1, o->off1, 0, data, o); + val_store(ilp, ul2, o->off2, 0, data, o); } if (curr == 1) { - if (o->roff3 && o->roff4) { - *(unsigned int *) o->roff3 = ul1; - *(unsigned int *) o->roff4 = ul2; - } else if (o->off3 && o->off4) { - val_store(ilp, ul1, o->off3, 0, data); - val_store(ilp, ul2, o->off4, 0, data); + if (o->off3 && o->off4) { + val_store(ilp, ul1, o->off3, 0, data, o); + val_store(ilp, ul2, o->off4, 0, data, o); } } if (curr == 2) { - if (o->roff5 && o->roff6) { - *(unsigned int *) o->roff5 = ul1; - *(unsigned int *) o->roff6 = ul2; - } else if (o->off5 && o->off6) { - val_store(ilp, ul1, o->off5, 0, data); - val_store(ilp, ul2, o->off6, 0, data); + if (o->off5 && o->off6) { + val_store(ilp, ul1, o->off5, 0, data, o); + val_store(ilp, ul2, o->off6, 0, data, o); } } if (!more) { if (curr < 1) { - if (o->roff3 && o->roff4) { - *(unsigned int *) o->roff3 = ul1; - *(unsigned int *) o->roff4 = ul2; - } else if (o->off3 && o->off4) { - val_store(ilp, ul1, o->off3, 0, data); - val_store(ilp, ul2, o->off4, 0, data); + if (o->off3 && o->off4) { + val_store(ilp, ul1, o->off3, 0, data, o); + val_store(ilp, ul2, o->off4, 0, data, o); } } if (curr < 2) { - if (o->roff5 && o->roff6) { - *(unsigned int *) o->roff5 = ul1; - *(unsigned int *) o->roff6 = ul2; - } else if (o->off5 && o->off6) { - val_store(ilp, ul1, o->off5, 0, data); - val_store(ilp, ul2, o->off6, 0, data); + if (o->off5 && o->off6) { + val_store(ilp, ul1, o->off5, 0, data, o); + val_store(ilp, ul2, o->off6, 0, data, o); } } } @@ -775,17 +727,11 @@ static int __handle_option(struct fio_option *o, const char *ptr, void *data, if (fn) ret = fn(data, &il); else { - if (first) { - if (o->roff1) - *(unsigned int *)o->roff1 = il; - else - val_store(ilp, il, o->off1, 0, data); - } + if (first) + val_store(ilp, il, o->off1, 0, data, o); if (!more) { - if (o->roff2) - *(unsigned int *) o->roff2 = il; - else if (o->off2) - val_store(ilp, il, o->off2, 0, data); + if (o->off2) + val_store(ilp, il, o->off2, 0, data, o); } } break; @@ -1194,7 +1140,7 @@ void option_init(struct fio_option *o) log_err("Option %s: string set option with" " default will always be true\n", o->name); } - if (!o->cb && (!o->off1 && !o->roff1)) + if (!o->cb && !o->off1) log_err("Option %s: neither cb nor offset given\n", o->name); if (!o->category) { log_info("Option %s: no category defined. Setting to misc\n", o->name); @@ -1204,10 +1150,8 @@ void option_init(struct fio_option *o) if (o->type == FIO_OPT_STR || o->type == FIO_OPT_STR_STORE || o->type == FIO_OPT_STR_MULTI) return; - if (o->cb && ((o->off1 || o->off2 || o->off3 || o->off4) || - (o->roff1 || o->roff2 || o->roff3 || o->roff4))) { + if (o->cb && (o->off1 || o->off2 || o->off3 || o->off4)) log_err("Option %s: both cb and offset given\n", o->name); - } } /* @@ -1238,7 +1182,7 @@ void options_free(struct fio_option *options, void *data) if (o->type != FIO_OPT_STR_STORE || !o->off1) continue; - ptr = td_var(data, o->off1); + ptr = td_var(data, o, o->off1); if (*ptr) { free(*ptr); *ptr = NULL; diff --git a/parse.h b/parse.h index 34d99d4..8eefff9 100644 --- a/parse.h +++ b/parse.h @@ -49,7 +49,6 @@ struct fio_option { unsigned int off4; unsigned int off5; unsigned int off6; - void *roff1, *roff2, *roff3, *roff4, *roff5, *roff6; unsigned int maxval; /* max and min value */ int minval; double maxfp; /* max and min floating value */ @@ -69,6 +68,7 @@ struct fio_option { struct fio_option *inv_opt; /* cached lookup */ int (*verify)(struct fio_option *, void *); const char *prof_name; /* only valid for specific profile */ + void *prof_opts; unsigned int category; /* what type of option */ unsigned int group; /* who to group with */ void *gui_data; @@ -100,7 +100,17 @@ typedef int (fio_opt_str_val_fn)(void *, long long *); typedef int (fio_opt_int_fn)(void *, int *); typedef int (fio_opt_str_set_fn)(void *); -#define td_var(start, offset) ((void *) start + (offset)) +#define __td_var(start, offset) ((void *) start + (offset)) + +struct thread_options; +static inline void *td_var(struct thread_options *to, struct fio_option *o, + unsigned int offset) +{ + if (o->prof_opts) + return __td_var(o->prof_opts, offset); + + return __td_var(to, offset); +} static inline int parse_is_percent(unsigned long long val) { diff --git a/profile.c b/profile.c index 5d0b866..90c9ea8 100644 --- a/profile.c +++ b/profile.c @@ -52,6 +52,7 @@ static int add_profile_options(struct profile_ops *ops) o = ops->options; while (o->name) { o->prof_name = ops->name; + o->prof_opts = ops->opt_data; if (add_option(o)) return 1; o++; diff --git a/profile.h b/profile.h index de35e9b..8d1f757 100644 --- a/profile.h +++ b/profile.h @@ -27,6 +27,7 @@ struct profile_ops { * Profile specific options */ struct fio_option *options; + void *opt_data; /* * Called after parsing options, to prepare 'cmdline' diff --git a/profiles/act.c b/profiles/act.c index 7e2f8af..4d2ec5c 100644 --- a/profiles/act.c +++ b/profiles/act.c @@ -74,12 +74,25 @@ static unsigned int org_idx; static int act_add_opt(const char *format, ...) __attribute__ ((__format__ (__printf__, 1, 2))); +struct act_options { + unsigned int pad; + char *device_names; + unsigned int load; + unsigned int prep; + unsigned int threads_per_queue; + unsigned int num_read_blocks; + unsigned int write_size; + unsigned long long test_duration; +}; + +static struct act_options act_options; + static struct fio_option options[] = { { .name = "device-names", .lname = "device-names", .type = FIO_OPT_STR_STORE, - .roff1 = &device_names, + .off1 = offsetof(struct act_options, device_names), .help = "Devices to use", .category = FIO_OPT_C_PROFILE, .group = FIO_OPT_G_ACT, @@ -88,7 +101,7 @@ static struct fio_option options[] = { .name = "load", .lname = "Load multiplier", .type = FIO_OPT_INT, - .roff1 = &load, + .off1 = offsetof(struct act_options, load), .help = "ACT load multipler (default 1x)", .def = "1", .category = FIO_OPT_C_PROFILE, @@ -98,7 +111,7 @@ static struct fio_option options[] = { .name = "test-duration", .lname = "Test duration", .type = FIO_OPT_STR_VAL_TIME, - .roff1 = &test_duration, + .off1 = offsetof(struct act_options, test_duration), .help = "How long the entire test takes to run", .def = "24h", .category = FIO_OPT_C_PROFILE, @@ -108,7 +121,7 @@ static struct fio_option options[] = { .name = "threads-per-queue", .lname = "Number of read IO threads per device", .type = FIO_OPT_INT, - .roff1 = &threads_per_queue, + .off1 = offsetof(struct act_options, threads_per_queue), .help = "Number of read IO threads per device", .def = "8", .category = FIO_OPT_C_PROFILE, @@ -118,7 +131,7 @@ static struct fio_option options[] = { .name = "read-req-num-512-blocks", .lname = "Number of 512b blocks to read", .type = FIO_OPT_INT, - .roff1 = &num_read_blocks, + .off1 = offsetof(struct act_options, num_read_blocks), .help = "Number of 512b blocks to read at the time", .def = "3", .category = FIO_OPT_C_PROFILE, @@ -128,7 +141,7 @@ static struct fio_option options[] = { .name = "large-block-op-kbytes", .lname = "Size of large block ops (writes)", .type = FIO_OPT_INT, - .roff1 = &write_size, + .off1 = offsetof(struct act_options, write_size), .help = "Size of large block ops (writes)", .def = "128k", .category = FIO_OPT_C_PROFILE, @@ -138,7 +151,7 @@ static struct fio_option options[] = { .name = "prep", .lname = "Run ACT prep phase", .type = FIO_OPT_STR_SET, - .roff1 = &prep, + .off1 = offsetof(struct act_options, prep), .help = "Set to run ACT prep phase", .category = FIO_OPT_C_PROFILE, .group = FIO_OPT_G_ACT, @@ -445,6 +458,7 @@ static struct profile_ops act_profile = { .name = "act", .desc = "ACT Aerospike like benchmark", .options = options, + .opt_data = &act_options, .prep_cmd = act_prep_cmdline, .cmdline = act_opts, .io_ops = &act_io_ops, diff --git a/profiles/tiobench.c b/profiles/tiobench.c index bdb5985..99c88c4 100644 --- a/profiles/tiobench.c +++ b/profiles/tiobench.c @@ -21,12 +21,23 @@ static const char *tb_opts[] = { "name=randread", "stonewall", "rw=randread", NULL, }; +struct tiobench_options { + unsigned int pad; + unsigned long long size; + unsigned int loops; + unsigned int bs; + unsigned int nthreads; + char *dir; +}; + +static struct tiobench_options tiobench_options; + static struct fio_option options[] = { { .name = "size", .lname = "Tiobench size", .type = FIO_OPT_STR_VAL, - .roff1 = &size, + .off1 = offsetof(struct tiobench_options, size), .help = "Size in MB", .category = FIO_OPT_C_PROFILE, .group = FIO_OPT_G_TIOBENCH, @@ -35,7 +46,7 @@ static struct fio_option options[] = { .name = "block", .lname = "Tiobench block", .type = FIO_OPT_INT, - .roff1 = &bs, + .off1 = offsetof(struct tiobench_options, bs), .help = "Block size in bytes", .def = "4k", .category = FIO_OPT_C_PROFILE, @@ -45,7 +56,7 @@ static struct fio_option options[] = { .name = "numruns", .lname = "Tiobench numruns", .type = FIO_OPT_INT, - .roff1 = &loops, + .off1 = offsetof(struct tiobench_options, loops), .help = "Number of runs", .category = FIO_OPT_C_PROFILE, .group = FIO_OPT_G_TIOBENCH, @@ -54,7 +65,7 @@ static struct fio_option options[] = { .name = "dir", .lname = "Tiobench directory", .type = FIO_OPT_STR_STORE, - .roff1 = &dir, + .off1 = offsetof(struct tiobench_options, dir), .help = "Test directory", .category = FIO_OPT_C_PROFILE, .group = FIO_OPT_G_TIOBENCH, @@ -63,7 +74,7 @@ static struct fio_option options[] = { .name = "threads", .lname = "Tiobench threads", .type = FIO_OPT_INT, - .roff1 = &nthreads, + .off1 = offsetof(struct tiobench_options, nthreads), .help = "Number of Threads", .category = FIO_OPT_C_PROFILE, .group = FIO_OPT_G_TIOBENCH, @@ -105,6 +116,8 @@ static struct profile_ops tiobench_profile = { .options = options, .prep_cmd = tb_prep_cmdline, .cmdline = tb_opts, + .options = options, + .opt_data = &tiobench_options, }; static void fio_init tiobench_register(void) -- To unsubscribe from this list: send the line "unsubscribe fio" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html