Fix filling verify pattern for byte sizes of 3, 5, 7, ...
[fio.git] / engines / solarisaio.c
index ab27b55d32f96380e120cc5aff46ba8d4628746e..137dc225d151393959266e0e6e1df51377c67bfc 100644 (file)
@@ -5,17 +5,18 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
+#include <signal.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 aio_pending;
        unsigned int nr;
+       unsigned int max_depth;
 };
 
 static int fio_solarisaio_cancel(struct thread_data fio_unused *td,
@@ -27,47 +28,74 @@ static int fio_solarisaio_cancel(struct thread_data fio_unused *td,
 static int fio_solarisaio_prep(struct thread_data fio_unused *td,
                            struct io_u *io_u)
 {
+       struct solarisaio_data *sd = td->io_ops->data;
+
        io_u->resultp.aio_return = AIO_INPROGRESS;
+       io_u->engine_data = sd;
        return 0;
 }
 
+static void wait_for_event(struct timeval *tv)
+{
+       struct solarisaio_data *sd;
+       struct io_u *io_u;
+       aio_result_t *res;
+
+       res = aiowait(tv);
+       if (res == (aio_result_t *) -1) {
+               int err = errno;
+
+               if (err != EINVAL) {
+                       log_err("fio: solarisaio got %d in aiowait\n", err);
+                       exit(err);
+               }
+               return;
+       } else if (!res)
+               return;
+
+       io_u = container_of(res, struct io_u, resultp);
+       sd = io_u->engine_data;
+
+       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_errno;
+
+       /*
+        * For SIGIO, we need a write barrier between the two, so that
+        * the ->aio_pending store is seen after the ->aio_events store
+        */
+       sd->aio_events[sd->aio_pending] = io_u;
+       write_barrier();
+       sd->aio_pending++;
+       sd->nr--;
+}
+
 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;
-               }
+       int ret;
 
-               p = aiowait(&tv);
-               if (p) {
-                       io_u = container_of(p, struct io_u, resultp);
+       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;
+       }
 
-                       sd->aio_events[r++] = io_u;
-                       sd->nr--;
+       while (sd->aio_pending < min)
+               wait_for_event(&tv);
 
-                       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;
+       /*
+        * should be OK without locking, as int operations should be atomic
+        */
+       ret = sd->aio_pending;
+       sd->aio_pending -= ret;
+       return ret;
 }
 
 static struct io_u *fio_solarisaio_event(struct thread_data *td, int event)
@@ -96,7 +124,16 @@ static int fio_solarisaio_queue(struct thread_data fio_unused *td,
                return FIO_Q_COMPLETED;
        }
 
-       if (sd->nr == td->o.iodepth)
+       if (io_u->ddir == DDIR_DATASYNC) {
+               if (sd->nr)
+                       return FIO_Q_BUSY;
+               if (fdatasync(f->fd) < 0)
+                       io_u->error = errno;
+
+               return FIO_Q_COMPLETED;
+       }
+
+       if (sd->nr == sd->max_depth)
                return FIO_Q_BUSY;
 
        off = io_u->offset;
@@ -126,13 +163,46 @@ static void fio_solarisaio_cleanup(struct thread_data *td)
        }
 }
 
+/*
+ * Set USE_SIGNAL_COMPLETIONS to use SIGIO as completion events.
+ */
+#ifdef USE_SIGNAL_COMPLETIONS
+static void fio_solarisaio_sigio(int sig)
+{
+       wait_for_event(NULL);
+}
+
+static void fio_solarisaio_init_sigio(void)
+{
+       struct sigaction act;
+
+       memset(&act, 0, sizeof(act));
+       act.sa_handler = fio_solarisaio_sigio;
+       act.sa_flags = SA_RESTART;
+       sigaction(SIGIO, &act, NULL);
+}
+#endif
+
 static int fio_solarisaio_init(struct thread_data *td)
 {
        struct solarisaio_data *sd = malloc(sizeof(*sd));
+       unsigned int max_depth;
+
+       max_depth = td->o.iodepth;
+       if (max_depth > MAXASYNCHIO) {
+               max_depth = MAXASYNCHIO;
+               log_info("fio: lower depth to %d due to OS constraints\n",
+                                                       max_depth);
+       }
 
        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 *));
+       sd->aio_events = malloc(max_depth * sizeof(struct io_u *));
+       memset(sd->aio_events, 0, max_depth * sizeof(struct io_u *));
+       sd->max_depth = max_depth;
+
+#ifdef USE_SIGNAL_COMPLETIONS
+       fio_solarisaio_init_sigio();
+#endif
 
        td->io_ops->data = sd;
        return 0;
@@ -150,29 +220,9 @@ static struct ioengine_ops ioengine = {
        .cleanup        = fio_solarisaio_cleanup,
        .open_file      = generic_open_file,
        .close_file     = generic_close_file,
+       .get_file_size  = generic_get_file_size,
 };
 
-#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);