Add the 'zbd' debug level
[fio.git] / engines / solarisaio.c
index f7f832b8b9ae66842011274f6053ac82ab0f9dde..21e95935b20bdc387a41f5c176fd806ff3c8f504 100644 (file)
@@ -5,16 +5,16 @@
 #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;
 };
@@ -28,67 +28,87 @@ 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)
+                                   unsigned int max, const struct timespec *t)
 {
-       struct solarisaio_data *sd = td->io_ops->data;
+       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 == (aio_result_t *) -1) {
-                       int err = errno;
-
-                       if (err == EINVAL)
-                               break;
-                       td_verror(td, err, "aiowait");
-                       break;
-               } else if (p != NULL) {
-                       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);
+       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;
+       }
 
-       return r;
+       while (sd->aio_pending < min)
+               wait_for_event(&tv);
+
+       /*
+        * 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)
 {
-       struct solarisaio_data *sd = td->io_ops->data;
+       struct solarisaio_data *sd = td->io_ops_data;
 
        return sd->aio_events[event];
 }
 
-static int fio_solarisaio_queue(struct thread_data fio_unused *td,
+static enum fio_q_status fio_solarisaio_queue(struct thread_data fio_unused *td,
                              struct io_u *io_u)
 {
-       struct solarisaio_data *sd = td->io_ops->data;
+       struct solarisaio_data *sd = td->io_ops_data;
        struct fio_file *f = io_u->file;
        off_t off;
        int ret;
@@ -104,6 +124,15 @@ static int fio_solarisaio_queue(struct thread_data fio_unused *td,
                return FIO_Q_COMPLETED;
        }
 
+       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;
 
@@ -126,7 +155,7 @@ static int fio_solarisaio_queue(struct thread_data fio_unused *td,
 
 static void fio_solarisaio_cleanup(struct thread_data *td)
 {
-       struct solarisaio_data *sd = td->io_ops->data;
+       struct solarisaio_data *sd = td->io_ops_data;
 
        if (sd) {
                free(sd->aio_events);
@@ -134,6 +163,26 @@ 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));
@@ -151,7 +200,11 @@ static int fio_solarisaio_init(struct thread_data *td)
        memset(sd->aio_events, 0, max_depth * sizeof(struct io_u *));
        sd->max_depth = max_depth;
 
-       td->io_ops->data = sd;
+#ifdef USE_SIGNAL_COMPLETIONS
+       fio_solarisaio_init_sigio();
+#endif
+
+       td->io_ops_data = sd;
        return 0;
 }
 
@@ -167,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);