xref: /kvmtool/disk/aio.c (revision 200cb82311bb79b18994b2bfbad6b090eee7f0d0)
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 
69*200cb823SJean-Philippe Brucker static int disk_aio_get_events(struct disk_image *disk)
7030a9aa69SJean-Philippe Brucker {
7130a9aa69SJean-Philippe Brucker 	struct io_event event[AIO_MAX];
7230a9aa69SJean-Philippe Brucker 	struct timespec notime = {0};
7330a9aa69SJean-Philippe Brucker 	int nr, i;
74*200cb823SJean-Philippe Brucker 
75*200cb823SJean-Philippe Brucker 	do {
76*200cb823SJean-Philippe Brucker 		nr = io_getevents(disk->ctx, 1, ARRAY_SIZE(event), event, &notime);
77*200cb823SJean-Philippe Brucker 		for (i = 0; i < nr; i++)
78*200cb823SJean-Philippe Brucker 			disk->disk_req_cb(event[i].data, event[i].res);
79*200cb823SJean-Philippe Brucker 	} while (nr > 0);
80*200cb823SJean-Philippe Brucker 
81*200cb823SJean-Philippe Brucker 	return 0;
82*200cb823SJean-Philippe Brucker }
83*200cb823SJean-Philippe Brucker 
84*200cb823SJean-Philippe Brucker static void *disk_aio_thread(void *param)
85*200cb823SJean-Philippe Brucker {
86*200cb823SJean-Philippe Brucker 	struct disk_image *disk = param;
8730a9aa69SJean-Philippe Brucker 	u64 dummy;
8830a9aa69SJean-Philippe Brucker 
8930a9aa69SJean-Philippe Brucker 	kvm__set_thread_name("disk-image-io");
9030a9aa69SJean-Philippe Brucker 
9130a9aa69SJean-Philippe Brucker 	while (read(disk->evt, &dummy, sizeof(dummy)) > 0) {
92*200cb823SJean-Philippe Brucker 		if (disk_aio_get_events(disk))
93*200cb823SJean-Philippe Brucker 			break;
9430a9aa69SJean-Philippe Brucker 	}
9530a9aa69SJean-Philippe Brucker 
9630a9aa69SJean-Philippe Brucker 	return NULL;
9730a9aa69SJean-Philippe Brucker }
9830a9aa69SJean-Philippe Brucker 
9930a9aa69SJean-Philippe Brucker int disk_aio_setup(struct disk_image *disk)
10030a9aa69SJean-Philippe Brucker {
10130a9aa69SJean-Philippe Brucker 	int r;
10230a9aa69SJean-Philippe Brucker 	pthread_t thread;
10330a9aa69SJean-Philippe Brucker 
104d62e8ee0SJean-Philippe Brucker 	/* No need to setup AIO if the disk ops won't make use of it */
105d62e8ee0SJean-Philippe Brucker 	if (!disk->ops->async)
106d62e8ee0SJean-Philippe Brucker 		return 0;
107d62e8ee0SJean-Philippe Brucker 
10830a9aa69SJean-Philippe Brucker 	disk->evt = eventfd(0, 0);
10930a9aa69SJean-Philippe Brucker 	if (disk->evt < 0)
11030a9aa69SJean-Philippe Brucker 		return -errno;
11130a9aa69SJean-Philippe Brucker 
11230a9aa69SJean-Philippe Brucker 	io_setup(AIO_MAX, &disk->ctx);
11330a9aa69SJean-Philippe Brucker 	r = pthread_create(&thread, NULL, disk_aio_thread, disk);
11430a9aa69SJean-Philippe Brucker 	if (r) {
11530a9aa69SJean-Philippe Brucker 		r = -errno;
11630a9aa69SJean-Philippe Brucker 		close(disk->evt);
11730a9aa69SJean-Philippe Brucker 		return r;
11830a9aa69SJean-Philippe Brucker 	}
119d62e8ee0SJean-Philippe Brucker 
120d62e8ee0SJean-Philippe Brucker 	disk->async = true;
12130a9aa69SJean-Philippe Brucker 	return 0;
12230a9aa69SJean-Philippe Brucker }
12330a9aa69SJean-Philippe Brucker 
12430a9aa69SJean-Philippe Brucker void disk_aio_destroy(struct disk_image *disk)
12530a9aa69SJean-Philippe Brucker {
126d62e8ee0SJean-Philippe Brucker 	if (!disk->async)
127d62e8ee0SJean-Philippe Brucker 		return;
128d62e8ee0SJean-Philippe Brucker 
12930a9aa69SJean-Philippe Brucker 	close(disk->evt);
13030a9aa69SJean-Philippe Brucker 	io_destroy(disk->ctx);
13130a9aa69SJean-Philippe Brucker }
132