Recent changes (master)

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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




[Index of Archives]     [Linux Kernel]     [Linux SCSI]     [Linux IDE]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux SCSI]

  Powered by Linux