diff mbox series

[kvmtool,4/9] disk/aio: Refactor AIO code

Message ID 20190218130702.32575-5-jean-philippe.brucker@arm.com (mailing list archive)
State New, archived
Headers show
Series Disk fixes and AIO reset | expand

Commit Message

Jean-Philippe Brucker Feb. 18, 2019, 1:06 p.m. UTC
Move all AIO code to a separate file, disk/aio.c, to remove as much
#ifdefs as possible. Split the raw read/write disk ops into async and
sync, and choose which ones to use depending on CONFIG_HAS_AIO. Note that
we fix raw_image__close() which incorrectly checked CONFIG_HAS_VIRTIO
instead of CONFIG_HAS_AIO, and closed an unitialized disk->evt. A
subsequent commit will complete this refactoring by fixing use of the
'async' disk attribute.

Signed-off-by: Jean-Philippe Brucker <jean-philippe.brucker@arm.com>
---
 Makefile                 |   2 +
 disk/aio.c               | 111 +++++++++++++++++++++++++++++++++++++++
 disk/core.c              |  52 +++++-------------
 disk/raw.c               |  39 +++-----------
 include/kvm/disk-image.h |  41 ++++++++++++---
 include/kvm/read-write.h |  11 ----
 util/read-write.c        |  36 -------------
 7 files changed, 167 insertions(+), 125 deletions(-)
 create mode 100644 disk/aio.c

Comments

Andre Przywara Feb. 22, 2019, 4:37 p.m. UTC | #1
On Mon, 18 Feb 2019 13:06:57 +0000
Jean-Philippe Brucker <jean-philippe.brucker@arm.com> wrote:

> Move all AIO code to a separate file, disk/aio.c, to remove as much
> #ifdefs as possible. Split the raw read/write disk ops into async and
> sync, and choose which ones to use depending on CONFIG_HAS_AIO. Note that
> we fix raw_image__close() which incorrectly checked CONFIG_HAS_VIRTIO
> instead of CONFIG_HAS_AIO, and closed an unitialized disk->evt. A
> subsequent commit will complete this refactoring by fixing use of the
> 'async' disk attribute.

So I chased every function and line down from where it left to where it
went, and it seems like a valid transformation to me.
 
> Signed-off-by: Jean-Philippe Brucker <jean-philippe.brucker@arm.com>

Reviewed-by: Andre Przywara <andre.przywara@arm.com>

Thanks!
Andre.

> ---
>  Makefile                 |   2 +
>  disk/aio.c               | 111 +++++++++++++++++++++++++++++++++++++++
>  disk/core.c              |  52 +++++-------------
>  disk/raw.c               |  39 +++-----------
>  include/kvm/disk-image.h |  41 ++++++++++++---
>  include/kvm/read-write.h |  11 ----
>  util/read-write.c        |  36 -------------
>  7 files changed, 167 insertions(+), 125 deletions(-)
>  create mode 100644 disk/aio.c
> 
> diff --git a/Makefile b/Makefile
> index ec75cd999..89acec2d5 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -275,10 +275,12 @@ endif
>  ifeq ($(call try-build,$(SOURCE_AIO),$(CFLAGS),$(LDFLAGS) -laio),y)
>  	CFLAGS_DYNOPT	+= -DCONFIG_HAS_AIO
>  	LIBS_DYNOPT	+= -laio
> +	OBJS		+= disk/aio.o
>  else
>  	ifeq ($(call try-build,$(SOURCE_AIO),$(CFLAGS),$(LDFLAGS) -laio -static),y)
>  		CFLAGS_STATOPT	+= -DCONFIG_HAS_AIO
>  		LIBS_STATOPT	+= -laio
> +		OBJS		+= disk/aio.o
>  	else
>  		NOTFOUND	+= aio
>  	endif
> diff --git a/disk/aio.c b/disk/aio.c
> new file mode 100644
> index 000000000..6afcffe5a
> --- /dev/null
> +++ b/disk/aio.c
> @@ -0,0 +1,111 @@
> +#include <libaio.h>
> +#include <pthread.h>
> +#include <sys/eventfd.h>
> +
> +#include "kvm/disk-image.h"
> +#include "kvm/kvm.h"
> +#include "linux/list.h"
> +
> +#define AIO_MAX 256
> +
> +static int aio_pwritev(io_context_t ctx, struct iocb *iocb, int fd,
> +		       const struct iovec *iov, int iovcnt, off_t offset,
> +		       int ev, void *param)
> +{
> +	struct iocb *ios[1] = { iocb };
> +	int ret;
> +
> +	io_prep_pwritev(iocb, fd, iov, iovcnt, offset);
> +	io_set_eventfd(iocb, ev);
> +	iocb->data = param;
> +
> +restart:
> +	ret = io_submit(ctx, 1, ios);
> +	if (ret == -EAGAIN)
> +		goto restart;
> +	return ret;
> +}
> +
> +static int aio_preadv(io_context_t ctx, struct iocb *iocb, int fd,
> +		      const struct iovec *iov, int iovcnt, off_t offset,
> +		      int ev, void *param)
> +{
> +	struct iocb *ios[1] = { iocb };
> +	int ret;
> +
> +	io_prep_preadv(iocb, fd, iov, iovcnt, offset);
> +	io_set_eventfd(iocb, ev);
> +	iocb->data = param;
> +
> +restart:
> +	ret = io_submit(ctx, 1, ios);
> +	if (ret == -EAGAIN)
> +		goto restart;
> +	return ret;
> +}
> +
> +ssize_t raw_image__read_async(struct disk_image *disk, u64 sector,
> +			      const struct iovec *iov, int iovcount,
> +			      void *param)
> +{
> +	u64 offset = sector << SECTOR_SHIFT;
> +	struct iocb iocb;
> +
> +	return aio_preadv(disk->ctx, &iocb, disk->fd, iov, iovcount,
> +			  offset, disk->evt, param);
> +}
> +
> +ssize_t raw_image__write_async(struct disk_image *disk, u64 sector,
> +			       const struct iovec *iov, int iovcount,
> +			       void *param)
> +{
> +	u64 offset = sector << SECTOR_SHIFT;
> +	struct iocb iocb;
> +
> +	return aio_pwritev(disk->ctx, &iocb, disk->fd, iov, iovcount,
> +			   offset, disk->evt, param);
> +}
> +
> +static void *disk_aio_thread(void *param)
> +{
> +	struct disk_image *disk = param;
> +	struct io_event event[AIO_MAX];
> +	struct timespec notime = {0};
> +	int nr, i;
> +	u64 dummy;
> +
> +	kvm__set_thread_name("disk-image-io");
> +
> +	while (read(disk->evt, &dummy, sizeof(dummy)) > 0) {
> +		nr = io_getevents(disk->ctx, 1, ARRAY_SIZE(event), event, &notime);
> +		for (i = 0; i < nr; i++)
> +			disk->disk_req_cb(event[i].data, event[i].res);
> +	}
> +
> +	return NULL;
> +}
> +
> +int disk_aio_setup(struct disk_image *disk)
> +{
> +	int r;
> +	pthread_t thread;
> +
> +	disk->evt = eventfd(0, 0);
> +	if (disk->evt < 0)
> +		return -errno;
> +
> +	io_setup(AIO_MAX, &disk->ctx);
> +	r = pthread_create(&thread, NULL, disk_aio_thread, disk);
> +	if (r) {
> +		r = -errno;
> +		close(disk->evt);
> +		return r;
> +	}
> +	return 0;
> +}
> +
> +void disk_aio_destroy(struct disk_image *disk)
> +{
> +	close(disk->evt);
> +	io_destroy(disk->ctx);
> +}
> diff --git a/disk/core.c b/disk/core.c
> index 4c7c4f030..89880703e 100644
> --- a/disk/core.c
> +++ b/disk/core.c
> @@ -4,11 +4,8 @@
>  #include "kvm/kvm.h"
>  
>  #include <linux/err.h>
> -#include <sys/eventfd.h>
>  #include <poll.h>
>  
> -#define AIO_MAX 256
> -
>  int debug_iodelay;
>  
>  static int disk_image__close(struct disk_image *disk);
> @@ -54,27 +51,6 @@ int disk_img_name_parser(const struct option *opt, const char *arg, int unset)
>  	return 0;
>  }
>  
> -#ifdef CONFIG_HAS_AIO
> -static void *disk_image__thread(void *param)
> -{
> -	struct disk_image *disk = param;
> -	struct io_event event[AIO_MAX];
> -	struct timespec notime = {0};
> -	int nr, i;
> -	u64 dummy;
> -
> -	kvm__set_thread_name("disk-image-io");
> -
> -	while (read(disk->evt, &dummy, sizeof(dummy)) > 0) {
> -		nr = io_getevents(disk->ctx, 1, ARRAY_SIZE(event), event, &notime);
> -		for (i = 0; i < nr; i++)
> -			disk->disk_req_cb(event[i].data, event[i].res);
> -	}
> -
> -	return NULL;
> -}
> -#endif
> -
>  struct disk_image *disk_image__new(int fd, u64 size,
>  				   struct disk_image_operations *ops,
>  				   int use_mmap)
> @@ -99,26 +75,22 @@ struct disk_image *disk_image__new(int fd, u64 size,
>  		disk->priv = mmap(NULL, size, PROT_RW, MAP_PRIVATE | MAP_NORESERVE, fd, 0);
>  		if (disk->priv == MAP_FAILED) {
>  			r = -errno;
> -			free(disk);
> -			return ERR_PTR(r);
> +			goto err_free_disk;
>  		}
>  	}
>  
> -#ifdef CONFIG_HAS_AIO
> -	{
> -		pthread_t thread;
> +	r = disk_aio_setup(disk);
> +	if (r)
> +		goto err_unmap_disk;
>  
> -		disk->evt = eventfd(0, 0);
> -		io_setup(AIO_MAX, &disk->ctx);
> -		r = pthread_create(&thread, NULL, disk_image__thread, disk);
> -		if (r) {
> -			r = -errno;
> -			free(disk);
> -			return ERR_PTR(r);
> -		}
> -	}
> -#endif
>  	return disk;
> +
> +err_unmap_disk:
> +	if (disk->priv)
> +		munmap(disk->priv, size);
> +err_free_disk:
> +	free(disk);
> +	return ERR_PTR(r);
>  }
>  
>  static struct disk_image *disk_image__open(const char *filename, bool readonly, bool direct)
> @@ -243,6 +215,8 @@ static int disk_image__close(struct disk_image *disk)
>  	if (!disk)
>  		return 0;
>  
> +	disk_aio_destroy(disk);
> +
>  	if (disk->ops->close)
>  		return disk->ops->close(disk);
>  
> diff --git a/disk/raw.c b/disk/raw.c
> index 93b2b4e8d..09da7e081 100644
> --- a/disk/raw.c
> +++ b/disk/raw.c
> @@ -2,38 +2,17 @@
>  
>  #include <linux/err.h>
>  
> -#ifdef CONFIG_HAS_AIO
> -#include <libaio.h>
> -#endif
> -
> -ssize_t raw_image__read(struct disk_image *disk, u64 sector, const struct iovec *iov,
> +ssize_t raw_image__read_sync(struct disk_image *disk, u64 sector, const struct iovec *iov,
>  				int iovcount, void *param)
>  {
> -	u64 offset = sector << SECTOR_SHIFT;
> -
> -#ifdef CONFIG_HAS_AIO
> -	struct iocb iocb;
> -
> -	return aio_preadv(disk->ctx, &iocb, disk->fd, iov, iovcount, offset,
> -				disk->evt, param);
> -#else
> -	return preadv_in_full(disk->fd, iov, iovcount, offset);
> -#endif
> +	return preadv_in_full(disk->fd, iov, iovcount, sector << SECTOR_SHIFT);
>  }
>  
> -ssize_t raw_image__write(struct disk_image *disk, u64 sector, const struct iovec *iov,
> -				int iovcount, void *param)
> +ssize_t raw_image__write_sync(struct disk_image *disk, u64 sector,
> +			      const struct iovec *iov, int iovcount,
> +			      void *param)
>  {
> -	u64 offset = sector << SECTOR_SHIFT;
> -
> -#ifdef CONFIG_HAS_AIO
> -	struct iocb iocb;
> -
> -	return aio_pwritev(disk->ctx, &iocb, disk->fd, iov, iovcount, offset,
> -				disk->evt, param);
> -#else
> -	return pwritev_in_full(disk->fd, iov, iovcount, offset);
> -#endif
> +	return pwritev_in_full(disk->fd, iov, iovcount, sector << SECTOR_SHIFT);
>  }
>  
>  ssize_t raw_image__read_mmap(struct disk_image *disk, u64 sector, const struct iovec *iov,
> @@ -79,12 +58,6 @@ int raw_image__close(struct disk_image *disk)
>  	if (disk->priv != MAP_FAILED)
>  		ret = munmap(disk->priv, disk->size);
>  
> -	close(disk->evt);
> -
> -#ifdef CONFIG_HAS_VIRTIO
> -	io_destroy(disk->ctx);
> -#endif
> -
>  	return ret;
>  }
>  
> diff --git a/include/kvm/disk-image.h b/include/kvm/disk-image.h
> index 4746e88c9..953beb2d5 100644
> --- a/include/kvm/disk-image.h
> +++ b/include/kvm/disk-image.h
> @@ -19,6 +19,10 @@
>  #include <unistd.h>
>  #include <fcntl.h>
>  
> +#ifdef CONFIG_HAS_AIO
> +#include <libaio.h>
> +#endif
> +
>  #define SECTOR_SHIFT		9
>  #define SECTOR_SIZE		(1UL << SECTOR_SHIFT)
>  
> @@ -61,10 +65,10 @@ struct disk_image {
>  	void				(*disk_req_cb)(void *param, long len);
>  	bool				readonly;
>  	bool				async;
> -	int				evt;
>  #ifdef CONFIG_HAS_AIO
>  	io_context_t			ctx;
> -#endif
> +	int				evt;
> +#endif /* CONFIG_HAS_AIO */
>  	const char			*wwpn;
>  	const char			*tpgt;
>  	int				debug_iodelay;
> @@ -84,14 +88,39 @@ ssize_t disk_image__get_serial(struct disk_image *disk, void *buffer, ssize_t *l
>  struct disk_image *raw_image__probe(int fd, struct stat *st, bool readonly);
>  struct disk_image *blkdev__probe(const char *filename, int flags, struct stat *st);
>  
> -ssize_t raw_image__read(struct disk_image *disk, u64 sector,
> -				const struct iovec *iov, int iovcount, void *param);
> -ssize_t raw_image__write(struct disk_image *disk, u64 sector,
> -				const struct iovec *iov, int iovcount, void *param);
> +ssize_t raw_image__read_sync(struct disk_image *disk, u64 sector,
> +			     const struct iovec *iov, int iovcount, void *param);
> +ssize_t raw_image__write_sync(struct disk_image *disk, u64 sector,
> +			      const struct iovec *iov, int iovcount, void *param);
>  ssize_t raw_image__read_mmap(struct disk_image *disk, u64 sector,
>  				const struct iovec *iov, int iovcount, void *param);
>  ssize_t raw_image__write_mmap(struct disk_image *disk, u64 sector,
>  				const struct iovec *iov, int iovcount, void *param);
>  int raw_image__close(struct disk_image *disk);
>  void disk_image__set_callback(struct disk_image *disk, void (*disk_req_cb)(void *param, long len));
> +
> +#ifdef CONFIG_HAS_AIO
> +int disk_aio_setup(struct disk_image *disk);
> +void disk_aio_destroy(struct disk_image *disk);
> +ssize_t raw_image__read_async(struct disk_image *disk, u64 sector,
> +			      const struct iovec *iov, int iovcount, void *param);
> +ssize_t raw_image__write_async(struct disk_image *disk, u64 sector,
> +			       const struct iovec *iov, int iovcount, void *param);
> +
> +#define raw_image__read		raw_image__read_async
> +#define raw_image__write	raw_image__write_async
> +
> +#else /* !CONFIG_HAS_AIO */
> +static inline int disk_aio_setup(struct disk_image *disk)
> +{
> +	/* No-op */
> +	return 0;
> +}
> +static inline void disk_aio_destroy(struct disk_image *disk)
> +{
> +}
> +#define raw_image__read		raw_image__read_sync
> +#define raw_image__write	raw_image__write_sync
> +#endif /* CONFIG_HAS_AIO */
> +
>  #endif /* KVM__DISK_IMAGE_H */
> diff --git a/include/kvm/read-write.h b/include/kvm/read-write.h
> index acbd6f0b1..8375d7c7d 100644
> --- a/include/kvm/read-write.h
> +++ b/include/kvm/read-write.h
> @@ -5,10 +5,6 @@
>  #include <sys/uio.h>
>  #include <unistd.h>
>  
> -#ifdef CONFIG_HAS_AIO
> -#include <libaio.h>
> -#endif
> -
>  ssize_t xread(int fd, void *buf, size_t count);
>  ssize_t xwrite(int fd, const void *buf, size_t count);
>  
> @@ -35,11 +31,4 @@ ssize_t xpwritev(int fd, const struct iovec *iov, int iovcnt, off_t offset);
>  ssize_t preadv_in_full(int fd, const struct iovec *iov, int iovcnt, off_t offset);
>  ssize_t pwritev_in_full(int fd, const struct iovec *iov, int iovcnt, off_t offset);
>  
> -#ifdef CONFIG_HAS_AIO
> -int aio_preadv(io_context_t ctx, struct iocb *iocb, int fd, const struct iovec *iov, int iovcnt,
> -		off_t offset, int ev, void *param);
> -int aio_pwritev(io_context_t ctx, struct iocb *iocb, int fd, const struct iovec *iov, int iovcnt,
> -		off_t offset, int ev, void *param);
> -#endif
> -
>  #endif /* KVM_READ_WRITE_H */
> diff --git a/util/read-write.c b/util/read-write.c
> index bf6fb2fc2..06fc0dfff 100644
> --- a/util/read-write.c
> +++ b/util/read-write.c
> @@ -337,39 +337,3 @@ ssize_t pwritev_in_full(int fd, const struct iovec *iov, int iovcnt, off_t offse
>  
>  	return total;
>  }
> -
> -#ifdef CONFIG_HAS_AIO
> -int aio_pwritev(io_context_t ctx, struct iocb *iocb, int fd, const struct iovec *iov, int iovcnt,
> -		off_t offset, int ev, void *param)
> -{
> -	struct iocb *ios[1] = { iocb };
> -	int ret;
> -
> -	io_prep_pwritev(iocb, fd, iov, iovcnt, offset);
> -	io_set_eventfd(iocb, ev);
> -	iocb->data = param;
> -
> -restart:
> -	ret = io_submit(ctx, 1, ios);
> -	if (ret == -EAGAIN)
> -		goto restart;
> -	return ret;
> -}
> -
> -int aio_preadv(io_context_t ctx, struct iocb *iocb, int fd, const struct iovec *iov, int iovcnt,
> -		off_t offset, int ev, void *param)
> -{
> -	struct iocb *ios[1] = { iocb };
> -	int ret;
> -
> -	io_prep_preadv(iocb, fd, iov, iovcnt, offset);
> -	io_set_eventfd(iocb, ev);
> -	iocb->data = param;
> -
> -restart:
> -	ret = io_submit(ctx, 1, ios);
> -	if (ret == -EAGAIN)
> -		goto restart;
> -	return ret;
> -}
> -#endif
Jean-Philippe Brucker Feb. 22, 2019, 6:28 p.m. UTC | #2
On 22/02/2019 16:37, Andre Przywara wrote:
> On Mon, 18 Feb 2019 13:06:57 +0000
> Jean-Philippe Brucker <jean-philippe.brucker@arm.com> wrote:
> 
>> Move all AIO code to a separate file, disk/aio.c, to remove as much
>> #ifdefs as possible. Split the raw read/write disk ops into async and
>> sync, and choose which ones to use depending on CONFIG_HAS_AIO. Note that
>> we fix raw_image__close() which incorrectly checked CONFIG_HAS_VIRTIO
>> instead of CONFIG_HAS_AIO, and closed an unitialized disk->evt. A
>> subsequent commit will complete this refactoring by fixing use of the
>> 'async' disk attribute.
> 
> So I chased every function and line down from where it left to where it
> went, and it seems like a valid transformation to me.

Viewing the patch with "git show --color-moved" makes it a bit easier :)

>> Signed-off-by: Jean-Philippe Brucker <jean-philippe.brucker@arm.com>
> 
> Reviewed-by: Andre Przywara <andre.przywara@arm.com>

Thanks!
Jean
Andre Przywara Feb. 22, 2019, 6:35 p.m. UTC | #3
On Fri, 22 Feb 2019 18:28:48 +0000
Jean-Philippe Brucker <jean-philippe.brucker@arm.com> wrote:

> On 22/02/2019 16:37, Andre Przywara wrote:
> > On Mon, 18 Feb 2019 13:06:57 +0000
> > Jean-Philippe Brucker <jean-philippe.brucker@arm.com> wrote:
> >   
> >> Move all AIO code to a separate file, disk/aio.c, to remove as much
> >> #ifdefs as possible. Split the raw read/write disk ops into async and
> >> sync, and choose which ones to use depending on CONFIG_HAS_AIO. Note that
> >> we fix raw_image__close() which incorrectly checked CONFIG_HAS_VIRTIO
> >> instead of CONFIG_HAS_AIO, and closed an unitialized disk->evt. A
> >> subsequent commit will complete this refactoring by fixing use of the
> >> 'async' disk attribute.  
> > 
> > So I chased every function and line down from where it left to where it
> > went, and it seems like a valid transformation to me.  
> 
> Viewing the patch with "git show --color-moved" makes it a bit easier :)

That's a lot of colours! Marc, don't try this! ;-)

But thanks for the hint, didn't know about it.

Cheers,
Andre.

> >> Signed-off-by: Jean-Philippe Brucker <jean-philippe.brucker@arm.com>  
> > 
> > Reviewed-by: Andre Przywara <andre.przywara@arm.com>  
> 
> Thanks!
> Jean
diff mbox series

Patch

diff --git a/Makefile b/Makefile
index ec75cd999..89acec2d5 100644
--- a/Makefile
+++ b/Makefile
@@ -275,10 +275,12 @@  endif
 ifeq ($(call try-build,$(SOURCE_AIO),$(CFLAGS),$(LDFLAGS) -laio),y)
 	CFLAGS_DYNOPT	+= -DCONFIG_HAS_AIO
 	LIBS_DYNOPT	+= -laio
+	OBJS		+= disk/aio.o
 else
 	ifeq ($(call try-build,$(SOURCE_AIO),$(CFLAGS),$(LDFLAGS) -laio -static),y)
 		CFLAGS_STATOPT	+= -DCONFIG_HAS_AIO
 		LIBS_STATOPT	+= -laio
+		OBJS		+= disk/aio.o
 	else
 		NOTFOUND	+= aio
 	endif
diff --git a/disk/aio.c b/disk/aio.c
new file mode 100644
index 000000000..6afcffe5a
--- /dev/null
+++ b/disk/aio.c
@@ -0,0 +1,111 @@ 
+#include <libaio.h>
+#include <pthread.h>
+#include <sys/eventfd.h>
+
+#include "kvm/disk-image.h"
+#include "kvm/kvm.h"
+#include "linux/list.h"
+
+#define AIO_MAX 256
+
+static int aio_pwritev(io_context_t ctx, struct iocb *iocb, int fd,
+		       const struct iovec *iov, int iovcnt, off_t offset,
+		       int ev, void *param)
+{
+	struct iocb *ios[1] = { iocb };
+	int ret;
+
+	io_prep_pwritev(iocb, fd, iov, iovcnt, offset);
+	io_set_eventfd(iocb, ev);
+	iocb->data = param;
+
+restart:
+	ret = io_submit(ctx, 1, ios);
+	if (ret == -EAGAIN)
+		goto restart;
+	return ret;
+}
+
+static int aio_preadv(io_context_t ctx, struct iocb *iocb, int fd,
+		      const struct iovec *iov, int iovcnt, off_t offset,
+		      int ev, void *param)
+{
+	struct iocb *ios[1] = { iocb };
+	int ret;
+
+	io_prep_preadv(iocb, fd, iov, iovcnt, offset);
+	io_set_eventfd(iocb, ev);
+	iocb->data = param;
+
+restart:
+	ret = io_submit(ctx, 1, ios);
+	if (ret == -EAGAIN)
+		goto restart;
+	return ret;
+}
+
+ssize_t raw_image__read_async(struct disk_image *disk, u64 sector,
+			      const struct iovec *iov, int iovcount,
+			      void *param)
+{
+	u64 offset = sector << SECTOR_SHIFT;
+	struct iocb iocb;
+
+	return aio_preadv(disk->ctx, &iocb, disk->fd, iov, iovcount,
+			  offset, disk->evt, param);
+}
+
+ssize_t raw_image__write_async(struct disk_image *disk, u64 sector,
+			       const struct iovec *iov, int iovcount,
+			       void *param)
+{
+	u64 offset = sector << SECTOR_SHIFT;
+	struct iocb iocb;
+
+	return aio_pwritev(disk->ctx, &iocb, disk->fd, iov, iovcount,
+			   offset, disk->evt, param);
+}
+
+static void *disk_aio_thread(void *param)
+{
+	struct disk_image *disk = param;
+	struct io_event event[AIO_MAX];
+	struct timespec notime = {0};
+	int nr, i;
+	u64 dummy;
+
+	kvm__set_thread_name("disk-image-io");
+
+	while (read(disk->evt, &dummy, sizeof(dummy)) > 0) {
+		nr = io_getevents(disk->ctx, 1, ARRAY_SIZE(event), event, &notime);
+		for (i = 0; i < nr; i++)
+			disk->disk_req_cb(event[i].data, event[i].res);
+	}
+
+	return NULL;
+}
+
+int disk_aio_setup(struct disk_image *disk)
+{
+	int r;
+	pthread_t thread;
+
+	disk->evt = eventfd(0, 0);
+	if (disk->evt < 0)
+		return -errno;
+
+	io_setup(AIO_MAX, &disk->ctx);
+	r = pthread_create(&thread, NULL, disk_aio_thread, disk);
+	if (r) {
+		r = -errno;
+		close(disk->evt);
+		return r;
+	}
+	return 0;
+}
+
+void disk_aio_destroy(struct disk_image *disk)
+{
+	close(disk->evt);
+	io_destroy(disk->ctx);
+}
diff --git a/disk/core.c b/disk/core.c
index 4c7c4f030..89880703e 100644
--- a/disk/core.c
+++ b/disk/core.c
@@ -4,11 +4,8 @@ 
 #include "kvm/kvm.h"
 
 #include <linux/err.h>
-#include <sys/eventfd.h>
 #include <poll.h>
 
-#define AIO_MAX 256
-
 int debug_iodelay;
 
 static int disk_image__close(struct disk_image *disk);
@@ -54,27 +51,6 @@  int disk_img_name_parser(const struct option *opt, const char *arg, int unset)
 	return 0;
 }
 
-#ifdef CONFIG_HAS_AIO
-static void *disk_image__thread(void *param)
-{
-	struct disk_image *disk = param;
-	struct io_event event[AIO_MAX];
-	struct timespec notime = {0};
-	int nr, i;
-	u64 dummy;
-
-	kvm__set_thread_name("disk-image-io");
-
-	while (read(disk->evt, &dummy, sizeof(dummy)) > 0) {
-		nr = io_getevents(disk->ctx, 1, ARRAY_SIZE(event), event, &notime);
-		for (i = 0; i < nr; i++)
-			disk->disk_req_cb(event[i].data, event[i].res);
-	}
-
-	return NULL;
-}
-#endif
-
 struct disk_image *disk_image__new(int fd, u64 size,
 				   struct disk_image_operations *ops,
 				   int use_mmap)
@@ -99,26 +75,22 @@  struct disk_image *disk_image__new(int fd, u64 size,
 		disk->priv = mmap(NULL, size, PROT_RW, MAP_PRIVATE | MAP_NORESERVE, fd, 0);
 		if (disk->priv == MAP_FAILED) {
 			r = -errno;
-			free(disk);
-			return ERR_PTR(r);
+			goto err_free_disk;
 		}
 	}
 
-#ifdef CONFIG_HAS_AIO
-	{
-		pthread_t thread;
+	r = disk_aio_setup(disk);
+	if (r)
+		goto err_unmap_disk;
 
-		disk->evt = eventfd(0, 0);
-		io_setup(AIO_MAX, &disk->ctx);
-		r = pthread_create(&thread, NULL, disk_image__thread, disk);
-		if (r) {
-			r = -errno;
-			free(disk);
-			return ERR_PTR(r);
-		}
-	}
-#endif
 	return disk;
+
+err_unmap_disk:
+	if (disk->priv)
+		munmap(disk->priv, size);
+err_free_disk:
+	free(disk);
+	return ERR_PTR(r);
 }
 
 static struct disk_image *disk_image__open(const char *filename, bool readonly, bool direct)
@@ -243,6 +215,8 @@  static int disk_image__close(struct disk_image *disk)
 	if (!disk)
 		return 0;
 
+	disk_aio_destroy(disk);
+
 	if (disk->ops->close)
 		return disk->ops->close(disk);
 
diff --git a/disk/raw.c b/disk/raw.c
index 93b2b4e8d..09da7e081 100644
--- a/disk/raw.c
+++ b/disk/raw.c
@@ -2,38 +2,17 @@ 
 
 #include <linux/err.h>
 
-#ifdef CONFIG_HAS_AIO
-#include <libaio.h>
-#endif
-
-ssize_t raw_image__read(struct disk_image *disk, u64 sector, const struct iovec *iov,
+ssize_t raw_image__read_sync(struct disk_image *disk, u64 sector, const struct iovec *iov,
 				int iovcount, void *param)
 {
-	u64 offset = sector << SECTOR_SHIFT;
-
-#ifdef CONFIG_HAS_AIO
-	struct iocb iocb;
-
-	return aio_preadv(disk->ctx, &iocb, disk->fd, iov, iovcount, offset,
-				disk->evt, param);
-#else
-	return preadv_in_full(disk->fd, iov, iovcount, offset);
-#endif
+	return preadv_in_full(disk->fd, iov, iovcount, sector << SECTOR_SHIFT);
 }
 
-ssize_t raw_image__write(struct disk_image *disk, u64 sector, const struct iovec *iov,
-				int iovcount, void *param)
+ssize_t raw_image__write_sync(struct disk_image *disk, u64 sector,
+			      const struct iovec *iov, int iovcount,
+			      void *param)
 {
-	u64 offset = sector << SECTOR_SHIFT;
-
-#ifdef CONFIG_HAS_AIO
-	struct iocb iocb;
-
-	return aio_pwritev(disk->ctx, &iocb, disk->fd, iov, iovcount, offset,
-				disk->evt, param);
-#else
-	return pwritev_in_full(disk->fd, iov, iovcount, offset);
-#endif
+	return pwritev_in_full(disk->fd, iov, iovcount, sector << SECTOR_SHIFT);
 }
 
 ssize_t raw_image__read_mmap(struct disk_image *disk, u64 sector, const struct iovec *iov,
@@ -79,12 +58,6 @@  int raw_image__close(struct disk_image *disk)
 	if (disk->priv != MAP_FAILED)
 		ret = munmap(disk->priv, disk->size);
 
-	close(disk->evt);
-
-#ifdef CONFIG_HAS_VIRTIO
-	io_destroy(disk->ctx);
-#endif
-
 	return ret;
 }
 
diff --git a/include/kvm/disk-image.h b/include/kvm/disk-image.h
index 4746e88c9..953beb2d5 100644
--- a/include/kvm/disk-image.h
+++ b/include/kvm/disk-image.h
@@ -19,6 +19,10 @@ 
 #include <unistd.h>
 #include <fcntl.h>
 
+#ifdef CONFIG_HAS_AIO
+#include <libaio.h>
+#endif
+
 #define SECTOR_SHIFT		9
 #define SECTOR_SIZE		(1UL << SECTOR_SHIFT)
 
@@ -61,10 +65,10 @@  struct disk_image {
 	void				(*disk_req_cb)(void *param, long len);
 	bool				readonly;
 	bool				async;
-	int				evt;
 #ifdef CONFIG_HAS_AIO
 	io_context_t			ctx;
-#endif
+	int				evt;
+#endif /* CONFIG_HAS_AIO */
 	const char			*wwpn;
 	const char			*tpgt;
 	int				debug_iodelay;
@@ -84,14 +88,39 @@  ssize_t disk_image__get_serial(struct disk_image *disk, void *buffer, ssize_t *l
 struct disk_image *raw_image__probe(int fd, struct stat *st, bool readonly);
 struct disk_image *blkdev__probe(const char *filename, int flags, struct stat *st);
 
-ssize_t raw_image__read(struct disk_image *disk, u64 sector,
-				const struct iovec *iov, int iovcount, void *param);
-ssize_t raw_image__write(struct disk_image *disk, u64 sector,
-				const struct iovec *iov, int iovcount, void *param);
+ssize_t raw_image__read_sync(struct disk_image *disk, u64 sector,
+			     const struct iovec *iov, int iovcount, void *param);
+ssize_t raw_image__write_sync(struct disk_image *disk, u64 sector,
+			      const struct iovec *iov, int iovcount, void *param);
 ssize_t raw_image__read_mmap(struct disk_image *disk, u64 sector,
 				const struct iovec *iov, int iovcount, void *param);
 ssize_t raw_image__write_mmap(struct disk_image *disk, u64 sector,
 				const struct iovec *iov, int iovcount, void *param);
 int raw_image__close(struct disk_image *disk);
 void disk_image__set_callback(struct disk_image *disk, void (*disk_req_cb)(void *param, long len));
+
+#ifdef CONFIG_HAS_AIO
+int disk_aio_setup(struct disk_image *disk);
+void disk_aio_destroy(struct disk_image *disk);
+ssize_t raw_image__read_async(struct disk_image *disk, u64 sector,
+			      const struct iovec *iov, int iovcount, void *param);
+ssize_t raw_image__write_async(struct disk_image *disk, u64 sector,
+			       const struct iovec *iov, int iovcount, void *param);
+
+#define raw_image__read		raw_image__read_async
+#define raw_image__write	raw_image__write_async
+
+#else /* !CONFIG_HAS_AIO */
+static inline int disk_aio_setup(struct disk_image *disk)
+{
+	/* No-op */
+	return 0;
+}
+static inline void disk_aio_destroy(struct disk_image *disk)
+{
+}
+#define raw_image__read		raw_image__read_sync
+#define raw_image__write	raw_image__write_sync
+#endif /* CONFIG_HAS_AIO */
+
 #endif /* KVM__DISK_IMAGE_H */
diff --git a/include/kvm/read-write.h b/include/kvm/read-write.h
index acbd6f0b1..8375d7c7d 100644
--- a/include/kvm/read-write.h
+++ b/include/kvm/read-write.h
@@ -5,10 +5,6 @@ 
 #include <sys/uio.h>
 #include <unistd.h>
 
-#ifdef CONFIG_HAS_AIO
-#include <libaio.h>
-#endif
-
 ssize_t xread(int fd, void *buf, size_t count);
 ssize_t xwrite(int fd, const void *buf, size_t count);
 
@@ -35,11 +31,4 @@  ssize_t xpwritev(int fd, const struct iovec *iov, int iovcnt, off_t offset);
 ssize_t preadv_in_full(int fd, const struct iovec *iov, int iovcnt, off_t offset);
 ssize_t pwritev_in_full(int fd, const struct iovec *iov, int iovcnt, off_t offset);
 
-#ifdef CONFIG_HAS_AIO
-int aio_preadv(io_context_t ctx, struct iocb *iocb, int fd, const struct iovec *iov, int iovcnt,
-		off_t offset, int ev, void *param);
-int aio_pwritev(io_context_t ctx, struct iocb *iocb, int fd, const struct iovec *iov, int iovcnt,
-		off_t offset, int ev, void *param);
-#endif
-
 #endif /* KVM_READ_WRITE_H */
diff --git a/util/read-write.c b/util/read-write.c
index bf6fb2fc2..06fc0dfff 100644
--- a/util/read-write.c
+++ b/util/read-write.c
@@ -337,39 +337,3 @@  ssize_t pwritev_in_full(int fd, const struct iovec *iov, int iovcnt, off_t offse
 
 	return total;
 }
-
-#ifdef CONFIG_HAS_AIO
-int aio_pwritev(io_context_t ctx, struct iocb *iocb, int fd, const struct iovec *iov, int iovcnt,
-		off_t offset, int ev, void *param)
-{
-	struct iocb *ios[1] = { iocb };
-	int ret;
-
-	io_prep_pwritev(iocb, fd, iov, iovcnt, offset);
-	io_set_eventfd(iocb, ev);
-	iocb->data = param;
-
-restart:
-	ret = io_submit(ctx, 1, ios);
-	if (ret == -EAGAIN)
-		goto restart;
-	return ret;
-}
-
-int aio_preadv(io_context_t ctx, struct iocb *iocb, int fd, const struct iovec *iov, int iovcnt,
-		off_t offset, int ev, void *param)
-{
-	struct iocb *ios[1] = { iocb };
-	int ret;
-
-	io_prep_preadv(iocb, fd, iov, iovcnt, offset);
-	io_set_eventfd(iocb, ev);
-	iocb->data = param;
-
-restart:
-	ret = io_submit(ctx, 1, ios);
-	if (ret == -EAGAIN)
-		goto restart;
-	return ret;
-}
-#endif