static void qemu_laio_completion_cb(void *opaque) { struct qemu_laio_state *s = opaque; while (1) { struct io_event events[MAX_EVENTS]; uint64_t val; ssize_t ret; struct timespec ts = { 0 }; int nevents, i; do { ret = read(s->efd, &val, sizeof(val)); } while (ret == -1 && errno == EINTR); if (ret == -1 && errno == EAGAIN) break; if (ret != 8) break; do { nevents = io_getevents(s->ctx, val, MAX_EVENTS, events, &ts); } while (nevents == -EINTR); for (i = 0; i < nevents; i++) { struct iocb *iocb = events[i].obj; struct qemu_laiocb *laiocb = container_of(iocb, struct qemu_laiocb, iocb); laiocb->ret = io_event_ret(&events[i]); qemu_laio_process_completion(s, laiocb); } } }
static int ioq_submit(struct qemu_laio_state *s) { int ret, i = 0; int len = s->io_q.idx; do { ret = io_submit(s->ctx, len, s->io_q.iocbs); } while (i++ < 3 && ret == -EAGAIN); /* empty io queue */ s->io_q.idx = 0; if (ret < 0) { i = 0; } else { i = ret; } for (; i < len; i++) { struct qemu_laiocb *laiocb = container_of(s->io_q.iocbs[i], struct qemu_laiocb, iocb); laiocb->ret = (ret < 0) ? ret : -EIO; qemu_laio_process_completion(s, laiocb); } return ret; }
/* The completion BH fetches completed I/O requests and invokes their * callbacks. * * The function is somewhat tricky because it supports nested event loops, for * example when a request callback invokes aio_poll(). In order to do this, * the completion events array and index are kept in qemu_laio_state. The BH * reschedules itself as long as there are completions pending so it will * either be called again in a nested event loop or will be called after all * events have been completed. When there are no events left to complete, the * BH returns without rescheduling. */ static void qemu_laio_completion_bh(void *opaque) { struct qemu_laio_state *s = opaque; /* Fetch more completion events when empty */ if (s->event_idx == s->event_max) { do { struct timespec ts = { 0 }; s->event_max = io_getevents(s->ctx, MAX_EVENTS, MAX_EVENTS, s->events, &ts); } while (s->event_max == -EINTR); s->event_idx = 0; if (s->event_max <= 0) { s->event_max = 0; return; /* no more events */ } } /* Reschedule so nested event loops see currently pending completions */ qemu_bh_schedule(s->completion_bh); /* Process completion events */ while (s->event_idx < s->event_max) { struct iocb *iocb = s->events[s->event_idx].obj; struct qemu_laiocb *laiocb = container_of(iocb, struct qemu_laiocb, iocb); laiocb->ret = io_event_ret(&s->events[s->event_idx]); s->event_idx++; qemu_laio_process_completion(s, laiocb); } }
static void qemu_laio_completion_cb(EventNotifier *e) { struct qemu_laio_state *s = container_of(e, struct qemu_laio_state, e); while (event_notifier_test_and_clear(&s->e)) { struct io_event events[MAX_EVENTS]; struct timespec ts = { 0 }; int nevents, i; do { nevents = io_getevents(s->ctx, MAX_EVENTS, MAX_EVENTS, events, &ts); } while (nevents == -EINTR); for (i = 0; i < nevents; i++) { struct iocb *iocb = events[i].obj; struct qemu_laiocb *laiocb = container_of(iocb, struct qemu_laiocb, iocb); laiocb->ret = io_event_ret(&events[i]); qemu_laio_process_completion(s, laiocb); } } }