Initial support for explicit write barriers

Signed-off-by: Jens Axboe <jaxboe@fusionio.com>
diff --git a/engines/binject.c b/engines/binject.c
index 65894c2..44a3796 100644
--- a/engines/binject.c
+++ b/engines/binject.c
@@ -191,7 +191,10 @@
 		buc->type = B_TYPE_READ;
 	} else if (io_u->ddir == DDIR_WRITE) {
 		binject_buc_init(bd, io_u);
-		buc->type = B_TYPE_WRITE;
+		if (io_u->flags & IO_U_F_BARRIER)
+			buc->type = B_TYPE_WRITEBARRIER;
+		else
+			buc->type = B_TYPE_WRITE;
 	} else if (io_u->ddir == DDIR_TRIM) {
 		binject_buc_init(bd, io_u);
 		buc->type = B_TYPE_DISCARD;
@@ -407,7 +410,7 @@
 	.open_file	= fio_binject_open_file,
 	.close_file	= fio_binject_close_file,
 	.get_file_size	= generic_get_file_size,
-	.flags		= FIO_RAWIO,
+	.flags		= FIO_RAWIO | FIO_BARRIER,
 };
 
 #else /* FIO_HAVE_BINJECT */
diff --git a/fio.h b/fio.h
index c2a0d4d..4ed8cb1 100644
--- a/fio.h
+++ b/fio.h
@@ -217,6 +217,7 @@
 	unsigned int thinktime_blocks;
 	unsigned int fsync_blocks;
 	unsigned int fdatasync_blocks;
+	unsigned int barrier_blocks;
 	unsigned long start_delay;
 	unsigned long long timeout;
 	unsigned long long ramp_time;
diff --git a/io_u.c b/io_u.c
index baa961b..6d539a0 100644
--- a/io_u.c
+++ b/io_u.c
@@ -501,6 +501,17 @@
 	return td->rwmix_ddir;
 }
 
+static void set_rw_ddir(struct thread_data *td, struct io_u *io_u)
+{
+	io_u->ddir = get_rw_ddir(td);
+
+	if (io_u->ddir == DDIR_WRITE && (td->io_ops->flags & FIO_BARRIER) &&
+	    td->o.barrier_blocks &&
+	   !(td->io_issues[DDIR_WRITE] % td->o.barrier_blocks) &&
+	     td->io_issues[DDIR_WRITE])
+		io_u->flags |= IO_U_F_BARRIER;
+}
+
 void put_file_log(struct thread_data *td, struct fio_file *f)
 {
 	int ret = put_file(td, f);
@@ -560,7 +571,7 @@
 	if (td->io_ops->flags & FIO_NOIO)
 		goto out;
 
-	io_u->ddir = get_rw_ddir(td);
+	set_rw_ddir(td, io_u);
 
 	/*
 	 * fsync() or fdatasync() or trim etc, we are done
@@ -963,7 +974,7 @@
 	if (io_u) {
 		assert(io_u->flags & IO_U_F_FREE);
 		io_u->flags &= ~(IO_U_F_FREE | IO_U_F_FREE_DEF);
-		io_u->flags &= ~IO_U_F_TRIMMED;
+		io_u->flags &= ~(IO_U_F_TRIMMED | IO_U_F_BARRIER);
 
 		io_u->error = 0;
 		flist_del(&io_u->list);
diff --git a/ioengine.h b/ioengine.h
index 344cdbf..7a3c08f 100644
--- a/ioengine.h
+++ b/ioengine.h
@@ -10,6 +10,7 @@
 	IO_U_F_IN_CUR_DEPTH	= 1 << 3,
 	IO_U_F_BUSY_OK		= 1 << 4,
 	IO_U_F_TRIMMED		= 1 << 5,
+	IO_U_F_BARRIER		= 1 << 6,
 };
 
 /*
@@ -126,6 +127,7 @@
 	FIO_NOIO	= 1 << 6,	/* thread does only pseudo IO */
 	FIO_SIGQUIT	= 1 << 7,	/* needs SIGQUIT to exit */
 	FIO_PIPEIO	= 1 << 8,	/* input/output no seekable */
+	FIO_BARRIER	= 1 << 9,	/* engine supports barriers */
 };
 
 /*
diff --git a/options.c b/options.c
index bdf3582..d111018 100644
--- a/options.c
+++ b/options.c
@@ -1185,6 +1185,13 @@
 		.help	= "Issue fdatasync for writes every given number of blocks",
 		.def	= "0",
 	},
+	{
+		.name	= "write_barrier",
+		.type	= FIO_OPT_INT,
+		.off1	= td_var_offset(barrier_blocks),
+		.help	= "Make every Nth write a barrier write",
+		.def	= "0",
+	},
 #ifdef FIO_HAVE_SYNC_FILE_RANGE
 	{
 		.name	= "sync_file_range",