[PATCH] Support residual io counts from io engines
authorJens Axboe <jens.axboe@oracle.com>
Tue, 6 Feb 2007 19:15:38 +0000 (20:15 +0100)
committerJens Axboe <jens.axboe@oracle.com>
Tue, 6 Feb 2007 19:15:38 +0000 (20:15 +0100)
We need this for requeuing support, the network engine makes this
pretty apparent (it's not unusual to see short tranfers there).

Basically we add an xfer_buf and xfer_buflen member to the io_u,
and these are the fields that the io engine MUST use. That allows
fio to increment and reset these appropriately, and simply requeue
the io_u for service of the next part of it.

Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
engines/libaio.c
engines/mmap.c
engines/net.c
engines/posixaio.c
engines/sg.c
engines/splice.c
engines/sync.c
fio.c
fio.h
io_u.c

index da43f18ce1571b7c729ceb35fce02ec1aae00e12..9a644f6fe4d07d17be9997a7cc94c882c275cd3e 100644 (file)
@@ -25,9 +25,9 @@ static int fio_libaio_prep(struct thread_data fio_unused *td, struct io_u *io_u)
        struct fio_file *f = io_u->file;
 
        if (io_u->ddir == DDIR_READ)
-               io_prep_pread(&io_u->iocb, f->fd, io_u->buf, io_u->buflen, io_u->offset);
+               io_prep_pread(&io_u->iocb, f->fd, io_u->xfer_buf, io_u->xfer_buflen, io_u->offset);
        else if (io_u->ddir == DDIR_WRITE)
-               io_prep_pwrite(&io_u->iocb, f->fd, io_u->buf, io_u->buflen, io_u->offset);
+               io_prep_pwrite(&io_u->iocb, f->fd, io_u->xfer_buf, io_u->xfer_buflen, io_u->offset);
        else if (io_u->ddir == DDIR_SYNC)
                io_prep_fsync(&io_u->iocb, f->fd);
        else
@@ -87,7 +87,7 @@ static int fio_libaio_queue(struct thread_data *td, struct io_u *io_u)
        } while (1);
 
        if (ret <= 0) {
-               io_u->resid = io_u->buflen;
+               io_u->resid = io_u->xfer_buflen;
                io_u->error = -ret;
                return 1;
        }
index 20dcfd2264cb3afc981e371c9c89aa2c28c1a447..dc1fd33a2927fc8163140875ee12dbd0e6f22684 100644 (file)
@@ -48,9 +48,9 @@ static int fio_mmapio_queue(struct thread_data *td, struct io_u *io_u)
        struct mmapio_data *sd = td->io_ops->data;
 
        if (io_u->ddir == DDIR_READ)
-               memcpy(io_u->buf, f->mmap + real_off, io_u->buflen);
+               memcpy(io_u->xfer_buf, f->mmap + real_off, io_u->xfer_buflen);
        else if (io_u->ddir == DDIR_WRITE)
-               memcpy(f->mmap + real_off, io_u->buf, io_u->buflen);
+               memcpy(f->mmap + real_off, io_u->xfer_buf, io_u->xfer_buflen);
        else if (io_u->ddir == DDIR_SYNC) {
                if (msync(f->mmap, f->file_size, MS_SYNC))
                        io_u->error = errno;
@@ -60,9 +60,9 @@ static int fio_mmapio_queue(struct thread_data *td, struct io_u *io_u)
         * not really direct, but should drop the pages from the cache
         */
        if (td->odirect && io_u->ddir != DDIR_SYNC) {
-               if (msync(f->mmap + real_off, io_u->buflen, MS_SYNC) < 0)
+               if (msync(f->mmap + real_off, io_u->xfer_buflen, MS_SYNC) < 0)
                        io_u->error = errno;
-               if (madvise(f->mmap + real_off, io_u->buflen,  MADV_DONTNEED) < 0)
+               if (madvise(f->mmap + real_off, io_u->xfer_buflen,  MADV_DONTNEED) < 0)
                        io_u->error = errno;
        }
 
index b1a4cdc21e4092d39b907526a25078cb184de4e1..43026e5f747469c50093587d234732f874e801fe 100644 (file)
@@ -77,17 +77,18 @@ static int fio_netio_queue(struct thread_data *td, struct io_u *io_u)
 {
        struct net_data *nd = td->io_ops->data;
        struct fio_file *f = io_u->file;
-       unsigned int ret = 0;
+       int ret = 0;
 
        if (io_u->ddir == DDIR_WRITE)
-               ret = write(f->fd, io_u->buf, io_u->buflen);
+               ret = write(f->fd, io_u->xfer_buf, io_u->xfer_buflen);
        else if (io_u->ddir == DDIR_READ)
-               ret = read(f->fd, io_u->buf, io_u->buflen);
+               ret = read(f->fd, io_u->xfer_buf, io_u->xfer_buflen);
 
-       if (ret != io_u->buflen) {
+       if (ret != (int) io_u->xfer_buflen) {
                if (ret > 0) {
-                       io_u->resid = io_u->buflen - ret;
-                       io_u->error = EIO;
+                       io_u->resid = io_u->xfer_buflen - ret;
+                       io_u->error = 0;
+                       return ret;
                } else
                        io_u->error = errno;
        }
index ef4d78ebe8a58c03465eb33cdc58aa7f90b52d7c..71601fdd31c8df937cc08498c04d308875135d5e 100644 (file)
@@ -67,8 +67,8 @@ static int fio_posixaio_prep(struct thread_data fio_unused *td,
        struct fio_file *f = io_u->file;
 
        aiocb->aio_fildes = f->fd;
-       aiocb->aio_buf = io_u->buf;
-       aiocb->aio_nbytes = io_u->buflen;
+       aiocb->aio_buf = io_u->xfer_buf;
+       aiocb->aio_nbytes = io_u->xfer_buflen;
        aiocb->aio_offset = io_u->offset;
 
        io_u->seen = 0;
index 3ea1e289604ba6159bf9e3c3f92b3b8d0000ee92..862cd609b45f5870ed2d53e2ef9901feff75ae76 100644 (file)
@@ -40,8 +40,8 @@ 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;
        }
 }
 
@@ -160,7 +160,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 +183,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);
index fa4a6ee1db21ff192d811f1a95dfacc05de35483..026a82bb053b538ac61f83ed721f8ca4448fb8a1 100644 (file)
@@ -57,8 +57,8 @@ static int fio_splice_read(struct thread_data *td, struct io_u *io_u)
        void *p;
 
        offset = io_u->offset;
-       buflen = io_u->buflen;
-       p = io_u->buf;
+       buflen = io_u->xfer_buflen;
+       p = io_u->xfer_buf;
        while (buflen) {
                int this_len = buflen;
 
@@ -85,7 +85,7 @@ static int fio_splice_read(struct thread_data *td, struct io_u *io_u)
                }
        }
 
-       return io_u->buflen;
+       return io_u->xfer_buflen;
 }
 
 /*
@@ -97,8 +97,8 @@ static int fio_splice_write(struct thread_data *td, struct io_u *io_u)
        struct spliceio_data *sd = td->io_ops->data;
        struct iovec iov[1] = {
                {
-                       .iov_base = io_u->buf,
-                       .iov_len = io_u->buflen,
+                       .iov_base = io_u->xfer_buf,
+                       .iov_len = io_u->xfer_buflen,
                }
        };
        struct pollfd pfd = { .fd = sd->pipe[1], .events = POLLOUT, };
@@ -126,13 +126,13 @@ static int fio_splice_write(struct thread_data *td, struct io_u *io_u)
                }
        }
 
-       return io_u->buflen;
+       return io_u->xfer_buflen;
 }
 
 static int fio_spliceio_queue(struct thread_data *td, struct io_u *io_u)
 {
        struct spliceio_data *sd = td->io_ops->data;
-       unsigned int ret;
+       int ret;
 
        if (io_u->ddir == DDIR_READ)
                ret = fio_splice_read(td, io_u);
@@ -141,10 +141,11 @@ static int fio_spliceio_queue(struct thread_data *td, struct io_u *io_u)
        else
                ret = fsync(io_u->file->fd);
 
-       if (ret != io_u->buflen) {
+       if (ret != (int) io_u->xfer_buflen) {
                if (ret > 0) {
-                       io_u->resid = io_u->buflen - ret;
-                       io_u->error = ENODATA;
+                       io_u->resid = io_u->xfer_buflen - ret;
+                       io_u->error = 0;
+                       return ret;
                } else
                        io_u->error = errno;
        }
index c7ddd4c52956125bd408e4c6f2a0d86f95908041..94dd71049f0cb1cf85f355ba210754150b1eec64 100644 (file)
@@ -60,19 +60,20 @@ static int fio_syncio_queue(struct thread_data *td, struct io_u *io_u)
 {
        struct syncio_data *sd = td->io_ops->data;
        struct fio_file *f = io_u->file;
-       unsigned int ret;
+       int ret;
 
        if (io_u->ddir == DDIR_READ)
-               ret = read(f->fd, io_u->buf, io_u->buflen);
+               ret = read(f->fd, io_u->xfer_buf, io_u->xfer_buflen);
        else if (io_u->ddir == DDIR_WRITE)
-               ret = write(f->fd, io_u->buf, io_u->buflen);
+               ret = write(f->fd, io_u->xfer_buf, io_u->xfer_buflen);
        else
                ret = fsync(f->fd);
 
-       if (ret != io_u->buflen) {
+       if (ret != (int) io_u->xfer_buflen) {
                if (ret > 0) {
-                       io_u->resid = io_u->buflen - ret;
-                       io_u->error = EIO;
+                       io_u->resid = io_u->xfer_buflen - ret;
+                       io_u->error = 0;
+                       return ret;
                } else
                        io_u->error = errno;
        }
diff --git a/fio.c b/fio.c
index bce13a72306fccc62d84020ee4d57a3a2d8d8722..127314e3590bd1efd79908eeb5363c5580afef86 100644 (file)
--- a/fio.c
+++ b/fio.c
@@ -406,11 +406,22 @@ static void do_io(struct thread_data *td)
 
                memcpy(&s, &io_u->start_time, sizeof(s));
 
+requeue:
                ret = td_io_queue(td, io_u);
                if (ret) {
-                       td_verror(td, io_u->error);
-                       put_io_u(td, io_u);
-                       break;
+                       if (ret > 0 && (io_u->xfer_buflen != io_u->resid) &&
+                           io_u->resid) {
+                               /*
+                                * short read/write. requeue.
+                                */
+                               io_u->xfer_buflen = io_u->resid;
+                               io_u->xfer_buf += ret;
+                               goto requeue;
+                       } else {
+                               td_verror(td, io_u->error);
+                               put_io_u(td, io_u);
+                               break;
+                       }
                }
 
                add_slat_sample(td, io_u->ddir, mtime_since(&io_u->start_time, &io_u->issue_time));
diff --git a/fio.h b/fio.h
index d635e99d0454f47241e199df671be79ddc7758d6..56ed248551a5f6158dedf99eb0e4033f2bf0bf2d 100644 (file)
--- a/fio.h
+++ b/fio.h
@@ -75,6 +75,9 @@ struct io_u {
        unsigned int buflen;
        unsigned long long offset;
 
+       void *xfer_buf;
+       unsigned int xfer_buflen;
+
        unsigned int resid;
        unsigned int error;
 
diff --git a/io_u.c b/io_u.c
index 5e53b81443cda688bdb42163dc2a5af4cc28fe04..da6fe8f3af0a55f2f0a26680f257b78f6996d0de 100644 (file)
--- a/io_u.c
+++ b/io_u.c
@@ -322,6 +322,8 @@ struct io_u *get_io_u(struct thread_data *td, struct fio_file *f)
                return NULL;
        }
 
+       io_u->xfer_buf = io_u->buf;
+       io_u->xfer_buflen = io_u->buflen;
        fio_gettime(&io_u->start_time, NULL);
        return io_u;
 }