X-Git-Url: http://git.maemo.org/git/?p=qemu;a=blobdiff_plain;f=posix-aio-compat.c;h=e9fc9fa60a1d26aabac3f9222ff5940e13a3ade0;hp=0eb77a50d3f79320f98cb4e69c5c6f47ed9001bf;hb=HEAD;hpb=f141eafe286c785f7e2c1e312a73f90d66bdfb90 diff --git a/posix-aio-compat.c b/posix-aio-compat.c index 0eb77a5..e9fc9fa 100644 --- a/posix-aio-compat.c +++ b/posix-aio-compat.c @@ -33,6 +33,12 @@ static int cur_threads = 0; static int idle_threads = 0; static TAILQ_HEAD(, qemu_paiocb) request_list; +#ifdef HAVE_PREADV +static int preadv_present = 1; +#else +static int preadv_present = 0; +#endif + static void die2(int err, const char *what) { fprintf(stderr, "%s failed: %s\n", what, strerror(err)); @@ -84,9 +90,48 @@ static size_t handle_aiocb_ioctl(struct qemu_paiocb *aiocb) ret = ioctl(aiocb->aio_fildes, aiocb->aio_ioctl_cmd, aiocb->aio_ioctl_buf); if (ret == -1) return -errno; - return ret; + + /* + * This looks weird, but the aio code only consideres a request + * successfull if it has written the number full number of bytes. + * + * Now we overload aio_nbytes as aio_ioctl_cmd for the ioctl command, + * so in fact we return the ioctl command here to make posix_aio_read() + * happy.. + */ + return aiocb->aio_nbytes; +} + +#ifdef HAVE_PREADV + +static ssize_t +qemu_preadv(int fd, const struct iovec *iov, int nr_iov, off_t offset) +{ + return preadv(fd, iov, nr_iov, offset); } +static ssize_t +qemu_pwritev(int fd, const struct iovec *iov, int nr_iov, off_t offset) +{ + return pwritev(fd, iov, nr_iov, offset); +} + +#else + +static ssize_t +qemu_preadv(int fd, const struct iovec *iov, int nr_iov, off_t offset) +{ + return -ENOSYS; +} + +static ssize_t +qemu_pwritev(int fd, const struct iovec *iov, int nr_iov, off_t offset) +{ + return -ENOSYS; +} + +#endif + /* * Check if we need to copy the data in the aiocb into a new * properly aligned buffer. @@ -104,6 +149,29 @@ static int aiocb_needs_copy(struct qemu_paiocb *aiocb) return 0; } +static size_t handle_aiocb_rw_vector(struct qemu_paiocb *aiocb) +{ + size_t offset = 0; + ssize_t len; + + do { + if (aiocb->aio_type == QEMU_PAIO_WRITE) + len = qemu_pwritev(aiocb->aio_fildes, + aiocb->aio_iov, + aiocb->aio_niov, + aiocb->aio_offset + offset); + else + len = qemu_preadv(aiocb->aio_fildes, + aiocb->aio_iov, + aiocb->aio_niov, + aiocb->aio_offset + offset); + } while (len == -1 && errno == EINTR); + + if (len == -1) + return -errno; + return len; +} + static size_t handle_aiocb_rw_linear(struct qemu_paiocb *aiocb, char *buf) { size_t offset = 0; @@ -140,12 +208,34 @@ static size_t handle_aiocb_rw(struct qemu_paiocb *aiocb) size_t nbytes; char *buf; - if (!aiocb_needs_copy(aiocb) && aiocb->aio_niov == 1) { + if (!aiocb_needs_copy(aiocb)) { /* * If there is just a single buffer, and it is properly aligned * we can just use plain pread/pwrite without any problems. */ - return handle_aiocb_rw_linear(aiocb, aiocb->aio_iov->iov_base); + if (aiocb->aio_niov == 1) + return handle_aiocb_rw_linear(aiocb, aiocb->aio_iov->iov_base); + + /* + * We have more than one iovec, and all are properly aligned. + * + * Try preadv/pwritev first and fall back to linearizing the + * buffer if it's not supported. + */ + if (preadv_present) { + nbytes = handle_aiocb_rw_vector(aiocb); + if (nbytes == aiocb->aio_nbytes) + return nbytes; + if (nbytes < 0 && nbytes != -ENOSYS) + return nbytes; + preadv_present = 0; + } + + /* + * XXX(hch): short read/write. no easy way to handle the reminder + * using these interfaces. For now retry using plain + * pread/pwrite? + */ } /*