On 2026/09/11 7:43, Gurchetan Singh wrote:




On Mon, Sep 7, 2026 at 11:13 PM Akihiko Odaki <[email protected] tokyo.ac.jp <mailto:[email protected]>> wrote:

    Compatibility note: This series makes virtio-gpu-rutabaga-device
    incompatible with virtio-mmio-bus, as there is no straightforward way to
    fix reset for this combination. I believe nobody uses it, but please let
    me know if anyone relies on it.

    Gurchetan, please confirm if this impacts the use case behind your
    original virtio-gpu-rutabaga contribution.


Yes, deleting the MMIO is fine, but I curious what aspect of the API makes it difficult say in comparison to virglrenderer/gfxstream?  They all use guest memory blobs occasionally.  Or is the thread model?

Thanks for confirmation.

It's true that virglrenderer also uses guest memory blobs, and we apply the same thread model for virglrenderer and Rutabaga.

The difference is that Rutabaga has a feature that clearly requires waiting for proper reset completion: cross-domain. QEMU invokes both APIs from the main-loop thread, but cross-domain also has a worker that writes responses directly into guest backing. Stopping QEMU's command processing does not stop that worker. We therefore need to tear down the old Rutabaga instance and join its worker before reporting reset completion. Rutabaga requires that teardown to run on the thread that initialized it.

The reset timing implemented for virglrenderer looks like as follows:
1. The driver requests reset.
2. The device synchronously notifies reset completion, though actual
   reset is still pending. It makes the device compatible with
   virtio-mmio-bus, which requires synchronous reset completion.
3. The device asynchronously completes actual reset.

The assumption here is that the device may read blobs after notifying reset completion to the driver but may not write. Perhaps reading blobs after notifying reset completion may cause displaying garbage, but it's much better than deadlocks and potential use-after-free we currently have.

cross-domain breaks this assumption. With cross-domain, the following may happen:
1. The driver requests reset.
2. The device synchronously notifies reset completion.
3. The driver reuses the blob memory for something else.
4. The device writes to the blob memory, corrupting its content.
5. The device asynchronously completes actual reset.

So we cannot let the device synchronously notify reset completion with Rutabaga to make it compatible with virtio-mmio-bus.

Regards,
Akihiko Odaki



    =======================================================================

    This series fixes a deadlock I previously observed with the test in [1].
    It also fixes a command-ordering race exposed by the same BQL handoff,
    along with command and fence lifetime and accounting issues found while
    auditing device and virtqueue reset. Reset now drains command and fence
    queues without dropping the BQL, while resource destruction and surface
    replacement are deferred to the next control or cursor BH. Scanout state
    needed for migration is cleared synchronously before that deferred
    cleanup. The remaining patches detach popped queue elements before
    freeing commands, track suspension independently of fencing, balance
    inflight accounting, handle control-queue reset for the non-renderer
    backend, and stop advertising queue reset for virtio-gpu-gl,
    virtio-gpu-rutabaga, and vhost-user-gpu, whose current backend
    interfaces cannot quiesce a single queue.

    Finally, the virtio core changes split reset initiation from completion
    so device reset handlers can choose when reset is complete. An error
    during reset leaves the device broken and prevents its status from being
    cleared. Rutabaga's same-thread API requires whole-device reset to
    finish in the main-loop GPU BH, where the old backend is torn down and
    reinitialized before completion is reported.


    Note on the deadlock: I can no longer reproduce the issue reliably with
    the test in [1], so I used Codex, a coding agent, to write a more
    reliable local test case, shown below. I applied to Codex for Open
    Source to get access. The test case is not intended for merge: current
    policy prohibits that, and it is probably not worth carrying anyway
    because race-condition tests are inherently fragile. The remaining
    patches were written by me.

    [1] https://lore.kernel.org/qemu-devel/20251014111234.3190346-9-
    [email protected]/ <https://lore.kernel.org/qemu-
    devel/[email protected]/>

    Below is the Codex-written test case:

    diff --git a/tests/functional/aarch64/test_gpu_blob.py b/tests/
    functional/aarch64/test_gpu_blob.py
    index a913d3b29c84..52627b4541f9 100755
    --- a/tests/functional/aarch64/test_gpu_blob.py
    +++ b/tests/functional/aarch64/test_gpu_blob.py
    @@ -13,7 +13,9 @@
      #
      # SPDX-License-Identifier: GPL-2.0-or-later

    -from qemu.machine.machine import VMLaunchFailure
    +import subprocess
    +
    +from qemu.machine.machine import AbnormalShutdown, VMLaunchFailure

      from qemu_test import Asset
      from qemu_test import wait_for_console_pattern
    @@ -25,8 +27,7 @@ class Aarch64VirtBlobTest(LinuxKernelTest):
                             'download?path=%2Fblob-
    test&files=qemu-880.bin',
'2f6ab85d0b156c94fcedd2c4c821c5cbd52925a2de107f8e2d569ea2e34e42eb')

    -    def test_virtio_gpu_blob(self):
    -
    +    def launch_blob_test(self):
              self.set_machine('virt')
              self.require_accelerator("tcg")

    @@ -65,9 +66,27 @@ def test_virtio_gpu_blob(self):
    self.log.info <http://self.log.info>("unhandled launch failure: %s",
    excp.output)
                      raise excp

    +    def test_virtio_gpu_blob(self):
    +        self.launch_blob_test()
    +
              self.wait_for_console_pattern('[INFO] virtio-gpu test
    finished')
              # the test should cleanly exit

    +    def test_virtio_gpu_blob_shutdown_race(self):
    +        self.launch_blob_test()
    +
    +        self.wait_for_console_pattern('[INFO] unmapping blob object
    resource')
    +
    +        try:
    +            self.vm.shutdown(timeout=10)
    +        except AbnormalShutdown as excp:
    +            if isinstance(excp.__cause__, subprocess.TimeoutExpired):
    +                raise AssertionError(
    +                    "QEMU failed to exit while virtio-gpu reset was
    racing "
    +                    "with shutdown") from excp
    + self.log.info <http://self.log.info>("QEMU exited before the
    shutdown request completed: %s",
    +                          excp)
    +

      if __name__ == '__main__':
          LinuxKernelTest.main()

    Signed-off-by: Akihiko Odaki <[email protected]
    <mailto:[email protected]>>
    ---
    Changes in v3:
    - Rebased.
    - Dropped the patch "virtio-gpu: Run reset cleanup in the same BH" and
       reworked reset cleanup to preserve control and cursor queue ordering
       and migration-visible state without dropping the BQL.
    - Detached popped virtqueue elements before freeing reset commands.
    - Added fixes for fenced blob unmapping and inflight counter accounting.
    - Added control-queue reset handling for the non-renderer backend.
    - Disabled queue reset for virtio-gpu-gl, virtio-gpu-rutabaga, and
       vhost-user-gpu, whose current backend interfaces cannot quiesce a
       single queue.
    - Split virtio reset initiation from completion, moved completion into
       device reset handlers, and preserved errors raised during reset.
    - Added Rutabaga teardown and reinitialization in the main-loop GPU BH
       before reporting whole-device reset completion.
    - Link to v2: https://lore.kernel.org/qemu-devel/20260424-gpu-
    [email protected] <https://lore.kernel.org/
    qemu-devel/[email protected]>

    Changes in v2:
    - Added the patch "virtio-gpu: Run reset cleanup in the same BH".
    - My assumption about the ordering was incorrect, so I changed the patch
       to follow the approach used by virtio-gpu-gl.
    - Link to v1: https://lore.kernel.org/qemu-devel/20251029-gpu-v1-1-
    [email protected] <https://lore.kernel.org/qemu-
    devel/[email protected]>

    ---
    Akihiko Odaki (9):
           virtio: Introduce virtio_complete_reset()
           virtio: Move the virtio_complete_reset() call
           virtio: Preserve an error during reset
           hw/display/virtio-gpu-rutabaga: Reset Rutabaga
           virtio-gpu: Do not wait for the main thread during reset
           hw/display/virtio-gpu: Fix fenced blob unmapping
           hw/display/virtio-gpu: Balance inflight counter changes
           hw/display/virtio-gpu: Reject queue_reset when unsupported
           hw/display/virtio-gpu: Handle virtqueue reset

      include/hw/virtio/virtio-gpu.h   |   7 +-
      include/hw/virtio/virtio.h       |   1 +
      hw/9pfs/virtio-9p-device.c       |   1 +
      hw/audio/virtio-snd.c            |   2 +
      hw/block/vhost-user-blk.c        |   1 +
      hw/block/virtio-blk.c            |   1 +
      hw/char/virtio-serial-bus.c      |   1 +
      hw/display/vhost-user-gpu.c      |  10 ++-
      hw/display/virtio-gpu-base.c     |   2 +
      hw/display/virtio-gpu-gl.c       |  12 +++
      hw/display/virtio-gpu-rutabaga.c |  29 +++++++
      hw/display/virtio-gpu-virgl.c    |  25 +++---
      hw/display/virtio-gpu.c          | 174 ++++++++++++++++++++++++
    +--------------
      hw/input/virtio-input.c          |   2 +
      hw/net/virtio-net.c              |   1 +
      hw/scsi/vhost-user-scsi.c        |   1 +
      hw/scsi/virtio-scsi.c            |   2 +
      hw/virtio/virtio-balloon.c       |   1 +
      hw/virtio/virtio-crypto.c        |   2 +
      hw/virtio/virtio.c               |  25 ++++--
      system/qdev-monitor.c            |   2 -
      21 files changed, 210 insertions(+), 92 deletions(-)
    ---
    base-commit: d2e570cc0f97b936902a5b1b86b73c0f5998b475
    change-id: 20251029-gpu-c3f45747f7ba

    Best regards,
-- Akihiko Odaki <[email protected]
    <mailto:[email protected]>>



Reply via email to