xref: /kvmtool/disk/aio.c (revision d62e8ee002eb1ef50d0ca9dfa4f0c04782e53879)
130a9aa69SJean-Philippe Brucker #include <libaio.h>
230a9aa69SJean-Philippe Brucker #include <pthread.h>
330a9aa69SJean-Philippe Brucker #include <sys/eventfd.h>
430a9aa69SJean-Philippe Brucker 
530a9aa69SJean-Philippe Brucker #include "kvm/disk-image.h"
630a9aa69SJean-Philippe Brucker #include "kvm/kvm.h"
730a9aa69SJean-Philippe Brucker #include "linux/list.h"
830a9aa69SJean-Philippe Brucker 
930a9aa69SJean-Philippe Brucker #define AIO_MAX 256
1030a9aa69SJean-Philippe Brucker 
1130a9aa69SJean-Philippe Brucker static int aio_pwritev(io_context_t ctx, struct iocb *iocb, int fd,
1230a9aa69SJean-Philippe Brucker 		       const struct iovec *iov, int iovcnt, off_t offset,
1330a9aa69SJean-Philippe Brucker 		       int ev, void *param)
1430a9aa69SJean-Philippe Brucker {
1530a9aa69SJean-Philippe Brucker 	struct iocb *ios[1] = { iocb };
1630a9aa69SJean-Philippe Brucker 	int ret;
1730a9aa69SJean-Philippe Brucker 
1830a9aa69SJean-Philippe Brucker 	io_prep_pwritev(iocb, fd, iov, iovcnt, offset);
1930a9aa69SJean-Philippe Brucker 	io_set_eventfd(iocb, ev);
2030a9aa69SJean-Philippe Brucker 	iocb->data = param;
2130a9aa69SJean-Philippe Brucker 
2230a9aa69SJean-Philippe Brucker restart:
2330a9aa69SJean-Philippe Brucker 	ret = io_submit(ctx, 1, ios);
2430a9aa69SJean-Philippe Brucker 	if (ret == -EAGAIN)
2530a9aa69SJean-Philippe Brucker 		goto restart;
2630a9aa69SJean-Philippe Brucker 	return ret;
2730a9aa69SJean-Philippe Brucker }
2830a9aa69SJean-Philippe Brucker 
2930a9aa69SJean-Philippe Brucker static int aio_preadv(io_context_t ctx, struct iocb *iocb, int fd,
3030a9aa69SJean-Philippe Brucker 		      const struct iovec *iov, int iovcnt, off_t offset,
3130a9aa69SJean-Philippe Brucker 		      int ev, void *param)
3230a9aa69SJean-Philippe Brucker {
3330a9aa69SJean-Philippe Brucker 	struct iocb *ios[1] = { iocb };
3430a9aa69SJean-Philippe Brucker 	int ret;
3530a9aa69SJean-Philippe Brucker 
3630a9aa69SJean-Philippe Brucker 	io_prep_preadv(iocb, fd, iov, iovcnt, offset);
3730a9aa69SJean-Philippe Brucker 	io_set_eventfd(iocb, ev);
3830a9aa69SJean-Philippe Brucker 	iocb->data = param;
3930a9aa69SJean-Philippe Brucker 
4030a9aa69SJean-Philippe Brucker restart:
4130a9aa69SJean-Philippe Brucker 	ret = io_submit(ctx, 1, ios);
4230a9aa69SJean-Philippe Brucker 	if (ret == -EAGAIN)
4330a9aa69SJean-Philippe Brucker 		goto restart;
4430a9aa69SJean-Philippe Brucker 	return ret;
4530a9aa69SJean-Philippe Brucker }
4630a9aa69SJean-Philippe Brucker 
4730a9aa69SJean-Philippe Brucker ssize_t raw_image__read_async(struct disk_image *disk, u64 sector,
4830a9aa69SJean-Philippe Brucker 			      const struct iovec *iov, int iovcount,
4930a9aa69SJean-Philippe Brucker 			      void *param)
5030a9aa69SJean-Philippe Brucker {
5130a9aa69SJean-Philippe Brucker 	u64 offset = sector << SECTOR_SHIFT;
5230a9aa69SJean-Philippe Brucker 	struct iocb iocb;
5330a9aa69SJean-Philippe Brucker 
5430a9aa69SJean-Philippe Brucker 	return aio_preadv(disk->ctx, &iocb, disk->fd, iov, iovcount,
5530a9aa69SJean-Philippe Brucker 			  offset, disk->evt, param);
5630a9aa69SJean-Philippe Brucker }
5730a9aa69SJean-Philippe Brucker 
5830a9aa69SJean-Philippe Brucker ssize_t raw_image__write_async(struct disk_image *disk, u64 sector,
5930a9aa69SJean-Philippe Brucker 			       const struct iovec *iov, int iovcount,
6030a9aa69SJean-Philippe Brucker 			       void *param)
6130a9aa69SJean-Philippe Brucker {
6230a9aa69SJean-Philippe Brucker 	u64 offset = sector << SECTOR_SHIFT;
6330a9aa69SJean-Philippe Brucker 	struct iocb iocb;
6430a9aa69SJean-Philippe Brucker 
6530a9aa69SJean-Philippe Brucker 	return aio_pwritev(disk->ctx, &iocb, disk->fd, iov, iovcount,
6630a9aa69SJean-Philippe Brucker 			   offset, disk->evt, param);
6730a9aa69SJean-Philippe Brucker }
6830a9aa69SJean-Philippe Brucker 
6930a9aa69SJean-Philippe Brucker static void *disk_aio_thread(void *param)
7030a9aa69SJean-Philippe Brucker {
7130a9aa69SJean-Philippe Brucker 	struct disk_image *disk = param;
7230a9aa69SJean-Philippe Brucker 	struct io_event event[AIO_MAX];
7330a9aa69SJean-Philippe Brucker 	struct timespec notime = {0};
7430a9aa69SJean-Philippe Brucker 	int nr, i;
7530a9aa69SJean-Philippe Brucker 	u64 dummy;
7630a9aa69SJean-Philippe Brucker 
7730a9aa69SJean-Philippe Brucker 	kvm__set_thread_name("disk-image-io");
7830a9aa69SJean-Philippe Brucker 
7930a9aa69SJean-Philippe Brucker 	while (read(disk->evt, &dummy, sizeof(dummy)) > 0) {
8030a9aa69SJean-Philippe Brucker 		nr = io_getevents(disk->ctx, 1, ARRAY_SIZE(event), event, &notime);
8130a9aa69SJean-Philippe Brucker 		for (i = 0; i < nr; i++)
8230a9aa69SJean-Philippe Brucker 			disk->disk_req_cb(event[i].data, event[i].res);
8330a9aa69SJean-Philippe Brucker 	}
8430a9aa69SJean-Philippe Brucker 
8530a9aa69SJean-Philippe Brucker 	return NULL;
8630a9aa69SJean-Philippe Brucker }
8730a9aa69SJean-Philippe Brucker 
8830a9aa69SJean-Philippe Brucker int disk_aio_setup(struct disk_image *disk)
8930a9aa69SJean-Philippe Brucker {
9030a9aa69SJean-Philippe Brucker 	int r;
9130a9aa69SJean-Philippe Brucker 	pthread_t thread;
9230a9aa69SJean-Philippe Brucker 
93*d62e8ee0SJean-Philippe Brucker 	/* No need to setup AIO if the disk ops won't make use of it */
94*d62e8ee0SJean-Philippe Brucker 	if (!disk->ops->async)
95*d62e8ee0SJean-Philippe Brucker 		return 0;
96*d62e8ee0SJean-Philippe Brucker 
9730a9aa69SJean-Philippe Brucker 	disk->evt = eventfd(0, 0);
9830a9aa69SJean-Philippe Brucker 	if (disk->evt < 0)
9930a9aa69SJean-Philippe Brucker 		return -errno;
10030a9aa69SJean-Philippe Brucker 
10130a9aa69SJean-Philippe Brucker 	io_setup(AIO_MAX, &disk->ctx);
10230a9aa69SJean-Philippe Brucker 	r = pthread_create(&thread, NULL, disk_aio_thread, disk);
10330a9aa69SJean-Philippe Brucker 	if (r) {
10430a9aa69SJean-Philippe Brucker 		r = -errno;
10530a9aa69SJean-Philippe Brucker 		close(disk->evt);
10630a9aa69SJean-Philippe Brucker 		return r;
10730a9aa69SJean-Philippe Brucker 	}
108*d62e8ee0SJean-Philippe Brucker 
109*d62e8ee0SJean-Philippe Brucker 	disk->async = true;
11030a9aa69SJean-Philippe Brucker 	return 0;
11130a9aa69SJean-Philippe Brucker }
11230a9aa69SJean-Philippe Brucker 
11330a9aa69SJean-Philippe Brucker void disk_aio_destroy(struct disk_image *disk)
11430a9aa69SJean-Philippe Brucker {
115*d62e8ee0SJean-Philippe Brucker 	if (!disk->async)
116*d62e8ee0SJean-Philippe Brucker 		return;
117*d62e8ee0SJean-Philippe Brucker 
11830a9aa69SJean-Philippe Brucker 	close(disk->evt);
11930a9aa69SJean-Philippe Brucker 	io_destroy(disk->ctx);
12030a9aa69SJean-Philippe Brucker }
121