Commit 235f9b3638 for qemu.org

commit 235f9b36383e4cc7a790bca51eddbe38edd5438c
Author: Dmitry Osipenko <dmitry.osipenko@collabora.com>
Date:   Wed Mar 4 16:50:31 2026 +0000

    virtio-gpu: Ensure BHs are invoked only from main-loop thread

    QEMU's display GL core is tied to main-loop thread and virtio-gpu
    interacts with display while processing GPU commands. Virtio-gpu BHs
    work in generic AIO context that can be invoked on vCPU thread, while
    GL and UI toolkits are bound to the main-loop thread.

    Make virtio-gpu BHs use iohandler AIO context that is handled in a
    main-loop thread only.

     0  SDL_GL_MakeCurrent() (libSDL3)
     1  SDL_GL_MakeCurrent_REAL() (libSDL2)
     2  sdl2_gl_make_context_current() (ui/sdl2-gl.c:201)
     3  make_current() (virglrenderer.c:639)
     4  vrend_finish_context_switch() (vrend_renderer.c:11630)
     5  vrend_hw_switch_context() (vrend_renderer.c:11613)
     6  vrend_renderer_force_ctx_0() (vrend_renderer.c:12986)
     7  virgl_renderer_force_ctx_0() (virglrenderer.c:460)
     8  virtio_gpu_virgl_process_cmd() (virtio-gpu-virgl.c:1013)
     9  virtio_gpu_process_cmdq() (virtio-gpu.c:1050)
     10 virtio_gpu_gl_handle_ctrl() (virtio-gpu-gl.c:86)
     11 aio_bh_poll() (util/async.c)
     12 aio_poll() (util/aio-posix.c)
     13 blk_pwrite() (block/block-gen.c:1985)
     14 pflash_update() (pflash_cfi01.c:396)
     15 pflash_write() (pflash_cfi01.c:541)
     16 memory_region_dispatch_write() (system/memory.c:1554)
     17 flatview_write() (system/physmem.c:3333)
     18 address_space_write() (system/physmem.c:3453)
     19 kvm_cpu_exec() (accel/kvm/kall-all.c:3248)
     20 kvm_vcpu_thread_fn() (accel/kvm/kaccel-ops.c:53)

    Cc: qemu-stable@nongnu.org
    Signed-off-by: Dmitry Osipenko <dmitry.osipenko@collabora.com>
    Message-ID: <20260303151422.977399-8-dmitry.osipenko@collabora.com>
    Message-ID: <20260304165043.1437519-10-alex.bennee@linaro.org>
    Signed-off-by: Alex Bennée <alex.bennee@linaro.org>

diff --git a/hw/display/virtio-gpu-virgl.c b/hw/display/virtio-gpu-virgl.c
index 0f754829fb..10c4b5160f 100644
--- a/hw/display/virtio-gpu-virgl.c
+++ b/hw/display/virtio-gpu-virgl.c
@@ -1203,9 +1203,9 @@ int virtio_gpu_virgl_init(VirtIOGPU *g)
     }

 #if VIRGL_VERSION_MAJOR >= 1
-    gl->cmdq_resume_bh = aio_bh_new(qemu_get_aio_context(),
-                                    virtio_gpu_virgl_resume_cmdq_bh,
-                                    g);
+    gl->cmdq_resume_bh = virtio_bh_io_new_guarded(DEVICE(g),
+                                                  virtio_gpu_virgl_resume_cmdq_bh,
+                                                  g);
 #endif

     return 0;
diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c
index b2af861f0d..a89d49aa8c 100644
--- a/hw/display/virtio-gpu.c
+++ b/hw/display/virtio-gpu.c
@@ -1526,9 +1526,9 @@ void virtio_gpu_device_realize(DeviceState *qdev, Error **errp)

     g->ctrl_vq = virtio_get_queue(vdev, 0);
     g->cursor_vq = virtio_get_queue(vdev, 1);
-    g->ctrl_bh = virtio_bh_new_guarded(qdev, virtio_gpu_ctrl_bh, g);
-    g->cursor_bh = virtio_bh_new_guarded(qdev, virtio_gpu_cursor_bh, g);
-    g->reset_bh = qemu_bh_new(virtio_gpu_reset_bh, g);
+    g->ctrl_bh = virtio_bh_io_new_guarded(qdev, virtio_gpu_ctrl_bh, g);
+    g->cursor_bh = virtio_bh_io_new_guarded(qdev, virtio_gpu_cursor_bh, g);
+    g->reset_bh = virtio_bh_io_new_guarded(qdev, virtio_gpu_reset_bh, g);
     qemu_cond_init(&g->reset_cond);
     QTAILQ_INIT(&g->reslist);
     QTAILQ_INIT(&g->cmdq);
diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
index 22d798e6cd..4c5a4479bf 100644
--- a/hw/virtio/virtio.c
+++ b/hw/virtio/virtio.c
@@ -4497,3 +4497,13 @@ QEMUBH *virtio_bh_new_guarded_full(DeviceState *dev,
     return qemu_bh_new_full(cb, opaque, name,
                             &transport->mem_reentrancy_guard);
 }
+
+QEMUBH *virtio_bh_io_new_guarded_full(DeviceState *dev,
+                                      QEMUBHFunc *cb, void *opaque,
+                                      const char *name)
+{
+    DeviceState *transport = qdev_get_parent_bus(dev)->parent;
+
+    return aio_bh_new_full(iohandler_get_aio_context(), cb, opaque, name,
+                           &transport->mem_reentrancy_guard);
+}
diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h
index 42d2089939..6344bd7b68 100644
--- a/include/hw/virtio/virtio.h
+++ b/include/hw/virtio/virtio.h
@@ -552,4 +552,14 @@ QEMUBH *virtio_bh_new_guarded_full(DeviceState *dev,
 #define virtio_bh_new_guarded(dev, cb, opaque) \
     virtio_bh_new_guarded_full((dev), (cb), (opaque), (stringify(cb)))

+/*
+ * The "_io" variant runs BH only on a main-loop thread, while generic BH
+ * may run on a vCPU thread.
+ */
+QEMUBH *virtio_bh_io_new_guarded_full(DeviceState *dev,
+                                      QEMUBHFunc *cb, void *opaque,
+                                      const char *name);
+#define virtio_bh_io_new_guarded(dev, cb, opaque) \
+    virtio_bh_io_new_guarded_full((dev), (cb), (opaque), (stringify(cb)))
+
 #endif