summaryrefslogtreecommitdiff
path: root/posix-aio-compat.c
diff options
context:
space:
mode:
authorKevin Wolf <kwolf@redhat.com>2011-07-25 19:42:37 +0200
committerKevin Wolf <kwolf@redhat.com>2011-08-02 15:53:41 +0200
commitba1d1afdfeeb5ec6cbfd0052ab298d9b7cb7e5ba (patch)
treeef588f40db43bf62d0ba098b6a99b4b69888d68e /posix-aio-compat.c
parente680cfa7e20f5049c475ac94f998a79c9997b48d (diff)
posix-aio-compat: Allow read after EOF
In order to be able to transparently replace bdrv_read calls by bdrv_co_read, reading beyond EOF must produce zeros instead of short reads for AIO, too. Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Diffstat (limited to 'posix-aio-compat.c')
-rw-r--r--posix-aio-compat.c19
1 files changed, 19 insertions, 0 deletions
diff --git a/posix-aio-compat.c b/posix-aio-compat.c
index 788d11386..8dc00cbb0 100644
--- a/posix-aio-compat.c
+++ b/posix-aio-compat.c
@@ -198,6 +198,12 @@ static ssize_t handle_aiocb_rw_vector(struct qemu_paiocb *aiocb)
return len;
}
+/*
+ * Read/writes the data to/from a given linear buffer.
+ *
+ * Returns the number of bytes handles or -errno in case of an error. Short
+ * reads are only returned if the end of the file is reached.
+ */
static ssize_t handle_aiocb_rw_linear(struct qemu_paiocb *aiocb, char *buf)
{
ssize_t offset = 0;
@@ -334,6 +340,19 @@ static void *aio_thread(void *unused)
switch (aiocb->aio_type & QEMU_AIO_TYPE_MASK) {
case QEMU_AIO_READ:
+ ret = handle_aiocb_rw(aiocb);
+ if (ret >= 0 && ret < aiocb->aio_nbytes && aiocb->common.bs->growable) {
+ /* A short read means that we have reached EOF. Pad the buffer
+ * with zeros for bytes after EOF. */
+ QEMUIOVector qiov;
+
+ qemu_iovec_init_external(&qiov, aiocb->aio_iov,
+ aiocb->aio_niov);
+ qemu_iovec_memset_skip(&qiov, 0, aiocb->aio_nbytes - ret, ret);
+
+ ret = aiocb->aio_nbytes;
+ }
+ break;
case QEMU_AIO_WRITE:
ret = handle_aiocb_rw(aiocb);
break;