Add Solaris native aio engine
authorJens Axboe <jens.axboe@oracle.com>
Mon, 2 Jun 2008 09:59:30 +0000 (11:59 +0200)
committerJens Axboe <jens.axboe@oracle.com>
Mon, 2 Jun 2008 09:59:30 +0000 (11:59 +0200)
Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
HOWTO
Makefile.solaris
engines/solarisaio.c [new file with mode: 0644]
fio.h
options.c
os/os-solaris.h

diff --git a/HOWTO b/HOWTO
index 15ee367..12974f3 100644 (file)
--- a/HOWTO
+++ b/HOWTO
@@ -375,6 +375,8 @@ ioengine=str        Defines how the job issues io to the file. The following
 
                        posixaio glibc posix asynchronous io.
 
+                       solarisaio Solaris native asynchronous io.
+
                        mmap    File is memory mapped and data copied
                                to/from using memcpy(3).
 
index f92a92e..f7235db 100644 (file)
@@ -20,6 +20,7 @@ OBJS += engines/posixaio.o
 OBJS += engines/sync.o
 OBJS += engines/null.o
 OBJS += engines/net.o
+OBJS += engines/solarisaio.o
 
 INSTALL = install
 prefix = /usr/local
diff --git a/engines/solarisaio.c b/engines/solarisaio.c
new file mode 100644 (file)
index 0000000..ab27b55
--- /dev/null
@@ -0,0 +1,184 @@
+/*
+ * Native Solaris async IO engine
+ *
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include "../fio.h"
+
+#ifdef FIO_HAVE_SOLARISAIO
+
+#include <sys/asynch.h>
+
+struct solarisaio_data {
+       struct io_u **aio_events;
+       unsigned int nr;
+};
+
+static int fio_solarisaio_cancel(struct thread_data fio_unused *td,
+                              struct io_u *io_u)
+{
+       return aiocancel(&io_u->resultp);
+}
+
+static int fio_solarisaio_prep(struct thread_data fio_unused *td,
+                           struct io_u *io_u)
+{
+       io_u->resultp.aio_return = AIO_INPROGRESS;
+       return 0;
+}
+
+static int fio_solarisaio_getevents(struct thread_data *td, unsigned int min,
+                                   unsigned int max, struct timespec *t)
+{
+       struct solarisaio_data *sd = td->io_ops->data;
+       struct timeval tv;
+       unsigned int r;
+
+       r = 0;
+       do {
+               struct io_u *io_u;
+               aio_result_t *p;
+
+               if (!min || !t) {
+                       tv.tv_sec = 0;
+                       tv.tv_usec = 0;
+               } else {
+                       tv.tv_sec = t->tv_sec;
+                       tv.tv_usec = t->tv_nsec / 1000;
+               }
+
+               p = aiowait(&tv);
+               if (p) {
+                       io_u = container_of(p, struct io_u, resultp);
+
+                       sd->aio_events[r++] = io_u;
+                       sd->nr--;
+
+                       if (io_u->resultp.aio_return >= 0) {
+                               io_u->resid = io_u->xfer_buflen
+                                               - io_u->resultp.aio_return;
+                               io_u->error = 0;
+                       } else
+                               io_u->error = io_u->resultp.aio_return;
+               }
+       } while (r < min);
+
+       return r;
+}
+
+static struct io_u *fio_solarisaio_event(struct thread_data *td, int event)
+{
+       struct solarisaio_data *sd = td->io_ops->data;
+
+       return sd->aio_events[event];
+}
+
+static int fio_solarisaio_queue(struct thread_data fio_unused *td,
+                             struct io_u *io_u)
+{
+       struct solarisaio_data *sd = td->io_ops->data;
+       struct fio_file *f = io_u->file;
+       off_t off;
+       int ret;
+
+       fio_ro_check(td, io_u);
+
+       if (io_u->ddir == DDIR_SYNC) {
+               if (sd->nr)
+                       return FIO_Q_BUSY;
+               if (fsync(f->fd) < 0)
+                       io_u->error = errno;
+
+               return FIO_Q_COMPLETED;
+       }
+
+       if (sd->nr == td->o.iodepth)
+               return FIO_Q_BUSY;
+
+       off = io_u->offset;
+       if (io_u->ddir == DDIR_READ)
+               ret = aioread(f->fd, io_u->xfer_buf, io_u->xfer_buflen, off,
+                                       SEEK_SET, &io_u->resultp);
+       else
+               ret = aiowrite(f->fd, io_u->xfer_buf, io_u->xfer_buflen, off,
+                                       SEEK_SET, &io_u->resultp);
+       if (ret) {
+               io_u->error = errno;
+               td_verror(td, io_u->error, "xfer");
+               return FIO_Q_COMPLETED;
+       }
+
+       sd->nr++;
+       return FIO_Q_QUEUED;
+}
+
+static void fio_solarisaio_cleanup(struct thread_data *td)
+{
+       struct solarisaio_data *sd = td->io_ops->data;
+
+       if (sd) {
+               free(sd->aio_events);
+               free(sd);
+       }
+}
+
+static int fio_solarisaio_init(struct thread_data *td)
+{
+       struct solarisaio_data *sd = malloc(sizeof(*sd));
+
+       memset(sd, 0, sizeof(*sd));
+       sd->aio_events = malloc(td->o.iodepth * sizeof(struct io_u *));
+       memset(sd->aio_events, 0, td->o.iodepth * sizeof(struct io_u *));
+
+       td->io_ops->data = sd;
+       return 0;
+}
+
+static struct ioengine_ops ioengine = {
+       .name           = "solarisaio",
+       .version        = FIO_IOOPS_VERSION,
+       .init           = fio_solarisaio_init,
+       .prep           = fio_solarisaio_prep,
+       .queue          = fio_solarisaio_queue,
+       .cancel         = fio_solarisaio_cancel,
+       .getevents      = fio_solarisaio_getevents,
+       .event          = fio_solarisaio_event,
+       .cleanup        = fio_solarisaio_cleanup,
+       .open_file      = generic_open_file,
+       .close_file     = generic_close_file,
+};
+
+#else /* FIO_HAVE_SOLARISAIO */
+
+/*
+ * When we have a proper configure system in place, we simply wont build
+ * and install this io engine. For now install a crippled version that
+ * just complains and fails to load.
+ */
+static int fio_solarisaio_init(struct thread_data fio_unused *td)
+{
+       fprintf(stderr, "fio: solarisaio not available\n");
+       return 1;
+}
+
+static struct ioengine_ops ioengine = {
+       .name           = "solarisaio",
+       .version        = FIO_IOOPS_VERSION,
+       .init           = fio_solarisaio_init,
+};
+
+#endif
+
+static void fio_init fio_solarisaio_register(void)
+{
+       register_ioengine(&ioengine);
+}
+
+static void fio_exit fio_solarisaio_unregister(void)
+{
+       unregister_ioengine(&ioengine);
+}
diff --git a/fio.h b/fio.h
index a155518..b1792ab 100644 (file)
--- a/fio.h
+++ b/fio.h
 #include <guasi.h>
 #endif
 
+#ifdef FIO_HAVE_SOLARISAIO
+#include <sys/asynch.h>
+#endif
+
 enum fio_ddir {
        DDIR_READ = 0,
        DDIR_WRITE,
@@ -126,6 +130,9 @@ struct io_u {
 #endif
 #ifdef FIO_HAVE_GUASI
                guasi_req_t greq;
+#endif
+#ifdef FIO_HAVE_SOLARISAIO
+               aio_result_t resultp;
 #endif
        };
        struct timeval start_time;
index 5aad005..cc131a2 100644 (file)
--- a/options.c
+++ b/options.c
@@ -556,6 +556,11 @@ static struct fio_option options[] = {
                          { .ival = "posixaio",
                            .help = "POSIX asynchronous IO",
                          },
+#endif
+#ifdef FIO_HAVE_SOLARISAIO
+                         { .ival = "solarisaio",
+                           .help = "Solaris native asynchronous IO",
+                         },
 #endif
                          { .ival = "mmap",
                            .help = "Memory mapped IO",
index 21d28e9..7fa0bb5 100644 (file)
@@ -3,6 +3,7 @@
 
 #undef FIO_HAVE_LIBAIO
 #define FIO_HAVE_POSIXAIO
+#define FIO_HAVE_SOLARISAIO
 #undef FIO_HAVE_FADVISE
 #undef FIO_HAVE_CPU_AFFINITY
 #undef FIO_HAVE_DISK_UTIL