[PATCH 16/16] win32-aio: Run CB in original context

Hanna Czenczek posted 16 patches 2 weeks, 3 days ago
Maintainers: Paolo Bonzini <pbonzini@redhat.com>, "Alex Bennée" <alex.bennee@linaro.org>, Kevin Wolf <kwolf@redhat.com>, Hanna Reitz <hreitz@redhat.com>, Stefan Hajnoczi <stefanha@redhat.com>, Fam Zheng <fam@euphon.net>, Ronnie Sahlberg <ronniesahlberg@gmail.com>, Peter Lieven <pl@dlhnet.de>, "Philippe Mathieu-Daudé" <philmd@linaro.org>, Ilya Dryomov <idryomov@gmail.com>, "Richard W.M. Jones" <rjones@redhat.com>, Stefan Weil <sw@weilnetz.de>
There is a newer version of this series
[PATCH 16/16] win32-aio: Run CB in original context
Posted by Hanna Czenczek 2 weeks, 3 days ago
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 <hreitz@redhat.com>
---
 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


Re: [PATCH 16/16] win32-aio: Run CB in original context
Posted by Kevin Wolf 2 weeks, 1 day ago
Am 28.10.2025 um 17:33 hat Hanna Czenczek geschrieben:
> 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 <hreitz@redhat.com>

Should we then do the opposite thing and just move every request into
the main thread and only move back before returning to the caller?

But I'm also not against making the theoretical fix so that maybe
someone can fix the other problem later. It just seems to be of somewhat
limited use on its own.

Kevin


Re: [PATCH 16/16] win32-aio: Run CB in original context
Posted by Hanna Czenczek 2 weeks ago
On 30.10.25 15:12, Kevin Wolf wrote:
> Am 28.10.2025 um 17:33 hat Hanna Czenczek geschrieben:
>> 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 <hreitz@redhat.com>
> Should we then do the opposite thing and just move every request into
> the main thread and only move back before returning to the caller?

Maybe it would be fairer to fail requests when they’re not in BDS context?

> But I'm also not against making the theoretical fix so that maybe
> someone can fix the other problem later. It just seems to be of somewhat
> limited use on its own.

True.  But as explained in patch 13, these last few patches are not 
really that useful in practice anyway…

Hanna