[PATCH] Make the libaio fsync fallback really work
[fio.git] / engines / sg.c
index 3ea1e289604ba6159bf9e3c3f92b3b8d0000ee92..d32007022aeb8388c6e0fcfef0d5f4ee50393acc 100644 (file)
@@ -22,6 +22,9 @@ struct sgio_cmd {
 struct sgio_data {
        struct sgio_cmd *cmds;
        struct io_u **events;
 struct sgio_data {
        struct sgio_cmd *cmds;
        struct io_u **events;
+       struct pollfd *pfds;
+       int *fd_flags;
+       void *sgbuf;
        unsigned int bs;
 };
 
        unsigned int bs;
 };
 
@@ -40,8 +43,8 @@ static void sgio_hdr_init(struct sgio_data *sd, struct sg_io_hdr *hdr,
        hdr->usr_ptr = io_u;
 
        if (fs) {
        hdr->usr_ptr = io_u;
 
        if (fs) {
-               hdr->dxferp = io_u->buf;
-               hdr->dxfer_len = io_u->buflen;
+               hdr->dxferp = io_u->xfer_buf;
+               hdr->dxfer_len = io_u->xfer_buflen;
        }
 }
 
        }
 }
 
@@ -60,44 +63,91 @@ static int fio_sgio_ioctl_getevents(struct thread_data *td, int fio_unused min,
        return 1;
 }
 
        return 1;
 }
 
+static int pollin_events(struct pollfd *pfds, int fds)
+{
+       int i;
+
+       for (i = 0; i < fds; i++)
+               if (pfds[i].revents & POLLIN)
+                       return 1;
+
+       return 0;
+}
 
 static int fio_sgio_getevents(struct thread_data *td, int min, int max,
                              struct timespec fio_unused *t)
 {
 
 static int fio_sgio_getevents(struct thread_data *td, int min, int max,
                              struct timespec fio_unused *t)
 {
+       /*
+        * normally hard coding &td->files[0] is a bug that needs to be fixed,
+        * but it's ok here as all files should point to the same device.
+        */
        struct fio_file *f = &td->files[0];
        struct sgio_data *sd = td->io_ops->data;
        struct fio_file *f = &td->files[0];
        struct sgio_data *sd = td->io_ops->data;
-       struct pollfd pfd = { .fd = f->fd, .events = POLLIN };
-       void *buf = malloc(max * sizeof(struct sg_io_hdr));
-       int left = max, ret, events, i, r = 0, fl = 0;
+       int left = max, ret, events, i, r = 0;
+       void *buf = sd->sgbuf;
 
        /*
 
        /*
-        * don't block for !events
+        * Fill in the file descriptors
         */
         */
-       if (!min) {
-               fl = fcntl(f->fd, F_GETFL);
-               fcntl(f->fd, F_SETFL, fl | O_NONBLOCK);
+       for_each_file(td, f, i) {
+               /*
+                * don't block for min events == 0
+                */
+               if (!min) {
+                       sd->fd_flags[i] = fcntl(f->fd, F_GETFL);
+                       fcntl(f->fd, F_SETFL, sd->fd_flags[i] | O_NONBLOCK);
+               }
+               sd->pfds[i].fd = f->fd;
+               sd->pfds[i].events = POLLIN;
        }
 
        while (left) {
        }
 
        while (left) {
+               void *p;
+
                do {
                        if (!min)
                                break;
                do {
                        if (!min)
                                break;
-                       poll(&pfd, 1, -1);
-                       if (pfd.revents & POLLIN)
+
+                       ret = poll(sd->pfds, td->nr_files, -1);
+                       if (ret < 0) {
+                               td_verror(td, errno);
+                               if (!r)
+                                       r = -1;
                                break;
                                break;
-               } while (1);
+                       } else if (!ret)
+                               continue;
 
 
-               ret = read(f->fd, buf, left * sizeof(struct sg_io_hdr));
-               if (ret < 0) {
-                       if (errno == EAGAIN)
+                       if (pollin_events(sd->pfds, td->nr_files))
                                break;
                                break;
-                       td_verror(td, errno);
-                       r = -1;
+               } while (1);
+
+               if (r < 0)
                        break;
                        break;
-               } else if (!ret)
+
+re_read:
+               p = buf;
+               events = 0;
+               for_each_file(td, f, i) {
+                       ret = read(f->fd, p, left * sizeof(struct sg_io_hdr));
+                       if (ret < 0) {
+                               if (errno == EAGAIN)
+                                       continue;
+                               td_verror(td, errno);
+                               r = -1;
+                               break;
+                       } else if (ret) {
+                               p += ret;
+                               events += ret / sizeof(struct sg_io_hdr);
+                       }
+               }
+
+               if (r < 0)
                        break;
                        break;
+               if (!events) {
+                       usleep(1000);
+                       goto re_read;
+               }
 
 
-               events = ret / sizeof(struct sg_io_hdr);
                left -= events;
                r += events;
 
                left -= events;
                r += events;
 
@@ -108,10 +158,11 @@ static int fio_sgio_getevents(struct thread_data *td, int min, int max,
                }
        }
 
                }
        }
 
-       if (!min)
-               fcntl(f->fd, F_SETFL, fl);
+       if (!min) {
+               for_each_file(td, f, i)
+                       fcntl(f->fd, F_SETFL, sd->fd_flags[i]);
+       }
 
 
-       free(buf);
        return r;
 }
 
        return r;
 }
 
@@ -160,7 +211,7 @@ static int fio_sgio_prep(struct thread_data *td, struct io_u *io_u)
        struct sgio_data *sd = td->io_ops->data;
        int nr_blocks, lba;
 
        struct sgio_data *sd = td->io_ops->data;
        int nr_blocks, lba;
 
-       if (io_u->buflen & (sd->bs - 1)) {
+       if (io_u->xfer_buflen & (sd->bs - 1)) {
                log_err("read/write not sector aligned\n");
                return EINVAL;
        }
                log_err("read/write not sector aligned\n");
                return EINVAL;
        }
@@ -183,7 +234,7 @@ static int fio_sgio_prep(struct thread_data *td, struct io_u *io_u)
        }
 
        if (hdr->dxfer_direction != SG_DXFER_NONE) {
        }
 
        if (hdr->dxfer_direction != SG_DXFER_NONE) {
-               nr_blocks = io_u->buflen / sd->bs;
+               nr_blocks = io_u->xfer_buflen / sd->bs;
                lba = io_u->offset / sd->bs;
                hdr->cmdp[2] = (unsigned char) ((lba >> 24) & 0xff);
                hdr->cmdp[3] = (unsigned char) ((lba >> 16) & 0xff);
                lba = io_u->offset / sd->bs;
                hdr->cmdp[2] = (unsigned char) ((lba >> 24) & 0xff);
                hdr->cmdp[3] = (unsigned char) ((lba >> 16) & 0xff);
@@ -229,6 +280,7 @@ static int fio_sgio_get_bs(struct thread_data *td, unsigned int *bs)
        int ret;
 
        io_u = __get_io_u(td);
        int ret;
 
        io_u = __get_io_u(td);
+       io_u->file = &td->files[0];
        assert(io_u);
 
        hdr = &io_u->hdr;
        assert(io_u);
 
        hdr = &io_u->hdr;
@@ -253,8 +305,16 @@ static int fio_sgio_get_bs(struct thread_data *td, unsigned int *bs)
 
 static void fio_sgio_cleanup(struct thread_data *td)
 {
 
 static void fio_sgio_cleanup(struct thread_data *td)
 {
-       if (td->io_ops->data) {
-               free(td->io_ops->data);
+       struct sgio_data *sd = td->io_ops->data;
+
+       if (sd) {
+               free(sd->events);
+               free(sd->cmds);
+               free(sd->fd_flags);
+               free(sd->pfds);
+               free(sd->sgbuf);
+               free(sd);
+
                td->io_ops->data = NULL;
        }
 }
                td->io_ops->data = NULL;
        }
 }
@@ -272,6 +332,13 @@ static int fio_sgio_init(struct thread_data *td)
        memset(sd->cmds, 0, td->iodepth * sizeof(struct sgio_cmd));
        sd->events = malloc(td->iodepth * sizeof(struct io_u *));
        memset(sd->events, 0, td->iodepth * sizeof(struct io_u *));
        memset(sd->cmds, 0, td->iodepth * sizeof(struct sgio_cmd));
        sd->events = malloc(td->iodepth * sizeof(struct io_u *));
        memset(sd->events, 0, td->iodepth * sizeof(struct io_u *));
+       sd->pfds = malloc(sizeof(struct pollfd) * td->nr_files);
+       memset(sd->pfds, 0, sizeof(struct pollfd) * td->nr_files);
+       sd->fd_flags = malloc(sizeof(int) * td->nr_files);
+       memset(sd->fd_flags, 0, sizeof(int) * td->nr_files);
+       sd->sgbuf = malloc(sizeof(struct sg_io_hdr) * td->iodepth);
+       memset(sd->sgbuf, 0, sizeof(struct sg_io_hdr) * td->iodepth);
+
        td->io_ops->data = sd;
 
        if (td->filetype == FIO_TYPE_BD) {
        td->io_ops->data = sd;
 
        if (td->filetype == FIO_TYPE_BD) {
@@ -310,6 +377,9 @@ static int fio_sgio_init(struct thread_data *td)
 err:
        free(sd->events);
        free(sd->cmds);
 err:
        free(sd->events);
        free(sd->cmds);
+       free(sd->fd_flags);
+       free(sd->pfds);
+       free(sd->sgbuf);
        free(sd);
        td->io_ops->data = NULL;
        return 1;
        free(sd);
        td->io_ops->data = NULL;
        return 1;