[PATCH] 'null' ioengine

Add a null io engine, which can be used to exercise and test/debug fio
itself. It doesn't transfer any data, just pretends to.

Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
diff --git a/HOWTO b/HOWTO
index 1176d22..a5caea3 100644
--- a/HOWTO
+++ b/HOWTO
@@ -264,6 +264,10 @@
 				we use read(2) and write(2) for asynchronous
 				io.
 
+			null	Doesn't transfer any data, just pretends
+				to. This is mainly used to exercise fio
+				itself and for debugging/testing purposes.
+
 iodepth=int	This defines how many io units to keep in flight against
 		the file. The default is 1 for each file defined in this
 		job, can be overridden with a larger value for higher
diff --git a/Makefile b/Makefile
index 4a4434d..71b33c8 100644
--- a/Makefile
+++ b/Makefile
@@ -12,6 +12,7 @@
 OBJS += engines/fio-engine-sg.o
 OBJS += engines/fio-engine-splice.o
 OBJS += engines/fio-engine-sync.o
+OBJS += engines/fio-engine-null.o
 
 INSTALL = install
 prefix = /usr/local
diff --git a/Makefile.FreeBSD b/Makefile.FreeBSD
index 8947117..ed75473 100644
--- a/Makefile.FreeBSD
+++ b/Makefile.FreeBSD
@@ -9,6 +9,7 @@
 OBJS += engines/fio-engine-mmap.o
 OBJS += engines/fio-engine-posixaio.o
 OBJS += engines/fio-engine-sync.o
+OBJS += engines/fio-engine-null.o
 
 all: depend $(PROGS) $(SCRIPTS)
 
diff --git a/Makefile.solaris b/Makefile.solaris
index b487a05..9eb2ebc 100644
--- a/Makefile.solaris
+++ b/Makefile.solaris
@@ -9,6 +9,7 @@
 OBJS += engines/fio-engine-mmap.o
 OBJS += engines/fio-engine-posixaio.o
 OBJS += engines/fio-engine-sync.o
+OBJS += engines/fio-engine-null.o
 
 all: depend $(PROGS) $(SCRIPTS)
 
diff --git a/README b/README
index 04ff1ee..01cc19e 100644
--- a/README
+++ b/README
@@ -90,7 +90,9 @@
 			mmap for mmap'ed io, splice for using splice/vmsplice,
 			or sgio for direct SG_IO io. The latter only works on
 			Linux on SCSI (or SCSI-like devices, such as
-			usb-storage or sata/libata driven) devices.
+			usb-storage or sata/libata driven) devices. Fio also
+			has a null io engine, which is mainly used for testing
+			fio itself.
 	iodepth=x	For async io, allow 'x' ios in flight
 	overwrite=x	If 'x', layout a write file first.
 	nrfiles=x	Spread io load over 'x' number of files per job,
diff --git a/engines/fio-engine-null.c b/engines/fio-engine-null.c
new file mode 100644
index 0000000..fc82947
--- /dev/null
+++ b/engines/fio-engine-null.c
@@ -0,0 +1,84 @@
+/*
+ * null engine - doesn't do any transfers. Used to test fio.
+ *
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <assert.h>
+
+#include "../fio.h"
+#include "../os.h"
+
+struct null_data {
+	struct io_u *last_io_u;
+};
+
+static int fio_null_getevents(struct thread_data *td, int fio_unused min,
+			      int max, struct timespec fio_unused *t)
+{
+	assert(max <= 1);
+
+	if (list_empty(&td->io_u_busylist))
+		return 0;
+
+	return 1;
+}
+
+static struct io_u *fio_null_event(struct thread_data *td, int event)
+{
+	struct null_data *nd = td->io_ops->data;
+
+	assert(event == 0);
+
+	return nd->last_io_u;
+}
+
+static int fio_null_queue(struct thread_data *td, struct io_u *io_u)
+{
+	struct null_data *nd = td->io_ops->data;
+
+	io_u->resid = 0;
+	io_u->error = 0;
+	nd->last_io_u = io_u;
+	return 0;
+}
+
+static void fio_null_cleanup(struct thread_data *td)
+{
+	if (td->io_ops->data) {
+		free(td->io_ops->data);
+		td->io_ops->data = NULL;
+	}
+}
+
+static int fio_null_init(struct thread_data *td)
+{
+	struct null_data *nd = malloc(sizeof(*nd));
+
+	nd->last_io_u = NULL;
+	td->io_ops->data = nd;
+	return 0;
+}
+
+static struct ioengine_ops ioengine = {
+	.name		= "null",
+	.version	= FIO_IOOPS_VERSION,
+	.init		= fio_null_init,
+	.queue		= fio_null_queue,
+	.getevents	= fio_null_getevents,
+	.event		= fio_null_event,
+	.cleanup	= fio_null_cleanup,
+	.flags		= FIO_SYNCIO,
+};
+
+static void fio_init fio_null_register(void)
+{
+	register_ioengine(&ioengine);
+}
+
+static void fio_exit fio_null_unregister(void)
+{
+	unregister_ioengine(&ioengine);
+}