X-Git-Url: https://git.kernel.dk/?p=fio.git;a=blobdiff_plain;f=engines%2Fsg.c;h=b9033b8f7c2a0c8528b35d28f776ef62062028ad;hp=3ea1e289604ba6159bf9e3c3f92b3b8d0000ee92;hb=0be06ea2c87ecf1751a01ed528a2d3170bdca543;hpb=f8fe35e8c9e88dd681ea151251d75f6116a958b4 diff --git a/engines/sg.c b/engines/sg.c index 3ea1e289..b9033b8f 100644 --- a/engines/sg.c +++ b/engines/sg.c @@ -22,6 +22,9 @@ struct sgio_cmd { struct sgio_data { struct sgio_cmd *cmds; struct io_u **events; + struct pollfd *pfds; + int *fd_flags; + void *sgbuf; unsigned int bs; }; @@ -40,64 +43,96 @@ static void sgio_hdr_init(struct sgio_data *sd, struct sg_io_hdr *hdr, 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; } } -static int fio_sgio_ioctl_getevents(struct thread_data *td, int fio_unused min, - int max, struct timespec fio_unused *t) +static int pollin_events(struct pollfd *pfds, int fds) { - assert(max <= 1); + int i; - /* - * we can only have one finished io_u for sync io, since the depth - * is always 1 - */ - if (list_empty(&td->io_u_busylist)) - return 0; + for (i = 0; i < fds; i++) + if (pfds[i].revents & POLLIN) + return 1; - return 1; + return 0; } - 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 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) { + void *p; + do { if (!min) break; - poll(&pfd, 1, -1); - if (pfd.revents & POLLIN) + + ret = poll(sd->pfds, td->nr_files, -1); + if (ret < 0) { + if (!r) + r = -errno; + td_verror(td, errno, "poll"); 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; - td_verror(td, errno); - r = -1; + } while (1); + + if (r < 0) 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; + r = -errno; + td_verror(td, errno, "read"); + break; + } else if (ret) { + p += ret; + events += ret / sizeof(struct sg_io_hdr); + } + } + + if (r < 0) break; + if (!events) { + usleep(1000); + goto re_read; + } - events = ret / sizeof(struct sg_io_hdr); left -= events; r += events; @@ -108,10 +143,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; } @@ -120,10 +156,15 @@ static int fio_sgio_ioctl_doio(struct thread_data *td, { struct sgio_data *sd = td->io_ops->data; struct sg_io_hdr *hdr = &io_u->hdr; + int ret; sd->events[0] = io_u; - return ioctl(f->fd, SG_IO, hdr); + ret = ioctl(f->fd, SG_IO, hdr); + if (ret < 0) + return -errno; + + return FIO_Q_COMPLETED; } static int fio_sgio_rw_doio(struct fio_file *f, struct io_u *io_u, int sync) @@ -138,10 +179,11 @@ static int fio_sgio_rw_doio(struct fio_file *f, struct io_u *io_u, int sync) if (sync) { ret = read(f->fd, hdr, sizeof(*hdr)); if (ret < 0) - return errno; + return -errno; + return FIO_Q_COMPLETED; } - return 0; + return FIO_Q_QUEUED; } static int fio_sgio_doio(struct thread_data *td, struct io_u *io_u, int sync) @@ -160,7 +202,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; - 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; } @@ -183,7 +225,7 @@ static int fio_sgio_prep(struct thread_data *td, struct io_u *io_u) } 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); @@ -210,7 +252,12 @@ static int fio_sgio_queue(struct thread_data *td, struct io_u *io_u) io_u->error = EIO; } - return io_u->error; + if (io_u->error) { + td_verror(td, io_u->error, "xfer"); + return FIO_Q_COMPLETED; + } + + return ret; } static struct io_u *fio_sgio_event(struct thread_data *td, int event) @@ -229,6 +276,7 @@ static int fio_sgio_get_bs(struct thread_data *td, unsigned int *bs) int ret; io_u = __get_io_u(td); + io_u->file = &td->files[0]; assert(io_u); hdr = &io_u->hdr; @@ -253,8 +301,16 @@ static int fio_sgio_get_bs(struct thread_data *td, unsigned int *bs) 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; } } @@ -272,18 +328,25 @@ 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 *)); + 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) { if (ioctl(f->fd, BLKSSZGET, &bs) < 0) { - td_verror(td, errno); + td_verror(td, errno, "ioctl"); goto err; } } else if (td->filetype == FIO_TYPE_CHAR) { int version; if (ioctl(f->fd, SG_GET_VERSION_NUM, &version) < 0) { - td_verror(td, errno); + td_verror(td, errno, "ioctl"); goto err; } @@ -297,10 +360,10 @@ static int fio_sgio_init(struct thread_data *td) sd->bs = bs; - if (td->filetype == FIO_TYPE_BD) - td->io_ops->getevents = fio_sgio_ioctl_getevents; - else - td->io_ops->getevents = fio_sgio_getevents; + if (td->filetype == FIO_TYPE_BD) { + td->io_ops->getevents = NULL; + td->io_ops->event = NULL; + } /* * we want to do it, regardless of whether odirect is set or not @@ -310,6 +373,9 @@ static int fio_sgio_init(struct thread_data *td) 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;