AIO callbacks must be called in the originally calling AioContext, regardless of the BDS’s “main” AioContext.
Note: I tried to test this (under wine), but failed. Whenever I tried to use multiqueue or even just an I/O thread for a virtio-blk (or virtio-scsi) device, I/O stalled, both with and without this patch. For what it’s worth, when not using an I/O thread, I/O continued to work with this patch. Signed-off-by: Hanna Czenczek <[email protected]> --- block/win32-aio.c | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/block/win32-aio.c b/block/win32-aio.c index 6327861e1d..f0689f3ee9 100644 --- a/block/win32-aio.c +++ b/block/win32-aio.c @@ -48,48 +48,62 @@ struct QEMUWin32AIOState { typedef struct QEMUWin32AIOCB { BlockAIOCB common; struct QEMUWin32AIOState *ctx; + AioContext *req_ctx; int nbytes; OVERLAPPED ov; QEMUIOVector *qiov; void *buf; bool is_read; bool is_linear; + int ret; } QEMUWin32AIOCB; +static void win32_aio_completion_cb_bh(void *opaque) +{ + QEMUWin32AIOCB *waiocb = opaque; + + waiocb->common.cb(waiocb->common.opaque, waiocb->ret); + aio_context_unref(waiocb->req_ctx); + qemu_aio_unref(waiocb); +} + /* * Completes an AIO request (calls the callback and frees the ACB). */ static void win32_aio_process_completion(QEMUWin32AIOState *s, QEMUWin32AIOCB *waiocb, DWORD count) { - int ret; s->count--; if (waiocb->ov.Internal != 0) { - ret = -EIO; + waiocb->ret = -EIO; } else { - ret = 0; + waiocb->ret = 0; if (count < waiocb->nbytes) { /* Short reads mean EOF, pad with zeros. */ if (waiocb->is_read) { qemu_iovec_memset(waiocb->qiov, count, 0, waiocb->qiov->size - count); } else { - ret = -EINVAL; + waiocb->ret = -EINVAL; } } } if (!waiocb->is_linear) { - if (ret == 0 && waiocb->is_read) { + if (waiocb->ret == 0 && waiocb->is_read) { QEMUIOVector *qiov = waiocb->qiov; iov_from_buf(qiov->iov, qiov->niov, 0, waiocb->buf, qiov->size); } qemu_vfree(waiocb->buf); } - waiocb->common.cb(waiocb->common.opaque, ret); - qemu_aio_unref(waiocb); + if (waiocb->req_ctx == s->aio_ctx) { + win32_aio_completion_cb_bh(waiocb); + } else { + aio_bh_schedule_oneshot(waiocb->req_ctx, win32_aio_completion_cb_bh, + waiocb); + } } static void win32_aio_completion_cb(EventNotifier *e) @@ -120,10 +134,13 @@ BlockAIOCB *win32_aio_submit(BlockDriverState *bs, DWORD rc; waiocb = qemu_aio_get(&win32_aiocb_info, bs, cb, opaque); + waiocb->req_ctx = qemu_get_current_aio_context(); waiocb->nbytes = bytes; waiocb->qiov = qiov; waiocb->is_read = (type == QEMU_AIO_READ); + aio_context_ref(waiocb->req_ctx); + if (qiov->niov > 1) { waiocb->buf = qemu_try_blockalign(bs, qiov->size); if (waiocb->buf == NULL) { -- 2.51.0
