Recent changes (master)

Jens Axboe
2014-02-12T13:00:06Z

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)