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, ¬ime); 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