struct sgio_data {
struct sgio_cmd *cmds;
struct io_u **events;
+ struct pollfd *pfds;
+ int *fd_flags;
+ void *sgbuf;
unsigned int bs;
};
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;
}
}
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)
{
+ /*
+ * 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) {
+ td_verror(td, errno);
+ if (!r)
+ r = -1;
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;
+ td_verror(td, errno);
+ r = -1;
+ 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;
}
}
- 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;
}
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;
}
}
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);
int ret;
io_u = __get_io_u(td);
+ io_u->file = &td->files[0];
assert(io_u);
hdr = &io_u->hdr;
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;
}
}
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) {
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;