Skip to content

Backport: system/memory: Backport direct access support for RAM device regions - #34

Closed
nvmochs wants to merge 3 commits into
NVIDIA:nvidia_stable-11.0from
nvmochs:nvb5407564_virtio_bounce_110
Closed

Backport: system/memory: Backport direct access support for RAM device regions#34
nvmochs wants to merge 3 commits into
NVIDIA:nvidia_stable-11.0from
nvmochs:nvb5407564_virtio_bounce_110

Conversation

@nvmochs

@nvmochs nvmochs commented Aug 11, 2026

Copy link
Copy Markdown
Collaborator

Summary

Backport the three-patch upstream QEMU series that makes RAM device regions directly accessible while preserving exact-width access semantics:

QEMU memory: Make RAM device regions directly accessible (https://lore.kernel.org/all/20260728031731.286666-1-gshan@redhat.com/)

This resolves a virtio-blk failure observed when guest I/O buffers are allocated from passed-through GPU coherent memory.

Problem

When NVIDIA GPU coherent memory is onlined in a guest, the corresponding VFIO BAR memory is represented by QEMU as a RAM device region. Current versions of QEMU treat RAM device regions as indirectly accessible.

When virtio-blk processes an I/O request whose buffer resides in GPU coherent memory, address_space_map() therefore allocates a bounce buffer instead of returning a direct mapping.

The bounce-buffer budget defaults to only 4096 bytes per PCI device. Once that budget is exhausted, address_space_map() returns NULL, and virtqueue_map_desc() reports:

virtio: bogus descriptor or out of resources

The virtio device is then marked broken and enters VIRTIO_CONFIG_S_NEEDS_RESET. Outstanding block completions may be lost, leaving guest processes blocked in uninterruptible I/O and potentially locking up the VM.

The issue was initially observed during DCGM diagnostics and highly parallel CUDA sample builds. It was later reduced to a deterministic direct-I/O reproducer.

Reproducer

On a VM with a passed-through GPU and a memory-bearing GPU NUMA node:

numactl --membind=<gpu-numa-node> dd if=/dev/zero of=/root/test bs=1M count=512 oflag=direct

The unpatched QEMU baseline reports virtio: bogus descriptor or out of resources immediately and marks the virtio-blk device broken.

Increasing the bounce-buffer limit only mitigates the issue. It does not address the underlying unnecessary bounce operation.

Backported series

  1. system/memory: Use memmove() for directly accessible regions

    Uses memmove() in direct-access paths where source and destination ranges may overlap.

  2. system/memory: Use qemu_ram_move() for directly accessible regions

    Introduces qemu_ram_move(). Naturally aligned 1-, 2-, 4-, and 8-byte accesses use exact-width atomic operations; other accesses fall back to memmove(). This preserves the access semantics required when RAM-device backing may represent PCI BAR memory.

  3. system/memory: Make ram device region directly accessible

    Removes the indirect RAM-device MemoryRegionOps implementation and initializes RAM device regions using the normal RAM-pointer path. memory_access_is_direct() can consequently return true for these regions, allowing address_space_map() to return the underlying RAM pointer instead of allocating a bounce buffer.

Verification

Validation was performed on the QEMU baseline and fixed builds using the same VM configuration.

Baseline

  • The direct-I/O loop failed immediately with:

    virtio: bogus descriptor or out of resources

Fixed build

  • Confirmed the I/O buffer was allocated on the memory-bearing GPU NUMA node using numastat and /proc//numa_maps.

  • Confirmed x-max-bounce-buffer-size remained at its default 4096-byte value; no bounce-buffer increase was used.

  • Completed 8 GiB direct writes and reads using GPU-node-bound buffers.

  • Completed repeated 32-cycle bidirectional direct-I/O tests across independent QEMU boots.

  • Switched back to the baseline and reproduced the failure immediately, then restored the fixed build and passed another 32-cycle test.

  • Completed an 8 GiB multijob fio CRC verification workload with:

    • err=0
    • No short operations
    • No dropped operations
  • Completed a five-minute, eight-job mixed random read/write fio workload at queue depth 64 with:

    • err=0
    • No short operations
    • No dropped operations
  • Confirmed guest dmesg contained no virtio errors, I/O errors, hung tasks, soft lockups, or GPU Xids.

  • Confirmed through the QEMU monitor:

    • broken: false
    • disabled: false
    • No VIRTIO_CONFIG_S_NEEDS_RESET
    • All four virtio queues had inuse: 0
    • used_idx, last_avail_idx, shadow_avail_idx, and signalled_used matched after I/O quiesced

The baseline/fixed/baseline comparison demonstrates that the failure follows the QEMU code version, while the fixed build remains healthy under sustained multiqueue direct I/O from GPU coherent memory.

Gavin Shan added 3 commits August 10, 2026 16:00
…egions

Similar to what's done in commit 4a73aee ("softmmu: Use memmove in
flatview_write_continue"), there are more sites where the overlapping
source and destination buffer are allowed for the directly accessible
regions. Use memmove() in those sites, listed as below.

  hw/remote/vfio-user-obj.c::vfu_object_mr_rw
  include/system/memory.h::address_space_read
  system/physmem.c::flatview_read_continue_step

Signed-off-by: Gavin Shan <gshan@redhat.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Peter Xu <peterx@redhat.com>
Link: https://lore.kernel.org/r/20260728031731.286666-2-gshan@redhat.com
Signed-off-by: Peter Xu <peterx@redhat.com>
(cherry picked from commit 1efb05224dc2544f27687ad2970082e2a8c0a37d https://gitlab.com/peterx/qemu)
Signed-off-by: Matthew R. Ochs <mochs@nvidia.com>
…ible regions

All ram device regions were turned to be indirectly accessible by commit
4a2e242 ("memory: Don't use memcpy for ram_device regions"). This leads
to guest hang on attempt to build 'cuda-samples' as reported by Julia. The
guest is started by the following command lines, with GH100 GPU card passed
from the host.

   host$ lspci | grep GH100
   0009:01:00.0 3D controller: NVIDIA Corporation GH100 [GH200 120GB / 480GB] (rev a1)
   host$ /home/sandbox/gavin/qemu.main/build/qemu-system-aarch64            \
         -machine virt,gic-version=host,ras=on,highmem-mmio-size=4T         \
         -accel kvm -cpu host -smp cpus=48 -m size=8G                       \
         -drive file=/home/gavin/sandbox/images/disk.qcow2,if=none,id=d0    \
         -device virtio-blk-pci,id=vb0,bus=pcie.0,drive=d0,num-queues=4     \
         -device vfio-pci-nohotplug,host=0009:01:00.0,bus=pcie.1.0
           :
   guest$ cd cuda-samples/build
   guest$ make -j 20 clean
   guest$ make -j 20
           :
   [ 54%] Linking CUDA executable graphMemoryNodes
   [ 54%] Built target graphMemoryNodes
   <no more output afterwards, guest becomes frozen here>

   guest$ qemu-system-aarch64: virtio: bogus descriptor or out of resources
   [  555.814025] virtio_blk virtio0: [vda] new size: 268435456 512-byte logical blocks (137 GB/128 GiB)

When the GPU's driver (NVidia open driver) is loaded on guest bootup,
the memory blocks residing in the PCI BAR#4 of the GH100 GPU card can
be presented to the guest through memory hot-add. The page cache can
then be allocated from the hot added memory blocks when cuda-samples
is being built. Afterwards, the page cache is sent to QEMU's virtio-blk
device as part of the DMA request, the bounce buffer has to be used to
accomodate the request as the corresponding memory region (MemoryRegion)
is an indirectly accessible ram device region in qemu. However, the max
bounce bufer size is only 4096 bytes by default and that is exhausted
quickly, leading to a reset on the virtio-blk device and frozen guest
eventually.

  QEMU
  ====
  virtio_blk_handle_output
    virtio_blk_handle_vq
      virtio_blk_get_request
        virtqueue_pop
          virtqueue_split_pop
            virtqueue_map_desc
              address_space_map
                memory_access_is_direct         # Return false
                  memory_region_supports_direct_access

  (qemu) info mtree
  memory-region: pci_bridge_pci
    0000000000000000-ffffffffffffffff (prio 0, container): pci_bridge_pci
      0000042000000000-0000043fffffffff (prio 1, i/o): 0009:01:00.0 base BAR 4
        0000042000000000-0000043fffffffff (prio 0, i/o): 0009:01:00.0 BAR 4
          0000042000000000-000004379fffffff (prio 0, ramd): 0009:01:00.0 BAR 4 mmaps[0]

This adds qemu_ram_move() where the aligned and small-sized accesses are
handled by qatomics, and fall back to memmove() otherwise. The memove()
for the directly accessible regions is replaced by qemu_ram_move() so that
the issue covered by commit 4a2e242 (MMIO access instructions were
optimized to SSE instructions) is fixed. This makes 'ram_device_mem_ops'
redundant, paving the way to revert that commit to make the ram device
region directly accessible again in the next patch.

Besides, this also fixes the issue of the unexpected frozen reception on
e1000 NIC in the scenario of DPDK due to the wrong Rx queue full indication
caused by the following memcpy(), which is turned to 3 consective 'strb'
instructions to the same location by glibc-2.24+ for aarch64. With this
applied, the syntax of one-byte store is strictly ensured by a one-byte
qatomic set.

  QEMU
  ====
  e1000_receive_iov
    pci_dma_write
      pci_dma_rw
        dma_memory_rw
          dma_memory_rw_relaxed
            address_space_rw
              address_space_write
                flatview_write
                  flatview_write_continue
                    flatview_write_continue_step
                      memcpy    # 3 consective 'strb' instructions

Reported-by: Julia Graham <jugraham@redhat.com>
Reported-by: Liu Gang <liugang24219@sangfor.com.cn>
Reported-by: Ding Hui <dinghui@sangfor.com.cn>
Suggested-by: Michael S. Tsirkin <mst@redhat.com>
Suggested-by: Peter Xu <peterx@redhat.com>
Suggested-by: Richard Henderson <richard.henderson@linaro.org>
Suggested-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Gavin Shan <gshan@redhat.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Link: https://lore.kernel.org/r/20260728031731.286666-3-gshan@redhat.com
[peterx: remove src==dst check, fix doc, enhance comments, per PeterM, add R-b]
Signed-off-by: Peter Xu <peterx@redhat.com>
(backported from commit 9f32b8e9624459856f9b93c04dd56d4f5c66f58a https://gitlab.com/peterx/qemu)
[mochs: Minor context adjustment]
Signed-off-by: Matthew R. Ochs <mochs@nvidia.com>
This basically reverts 4a2e242 ("memory: Don't use memcpy for
ram_device regions") to make ram device region directly accessible
again. With this, the bounce buffer is bypassed in address_space_map()
when a ram device region is involved, potentially avoid to overrun
the (small) bounce buffer.

Reported-by: Julia Graham <jugraham@redhat.com>
Suggested-by: Michael S. Tsirkin <mst@redhat.com>
Suggested-by: Peter Xu <peterx@redhat.com>
Suggested-by: Richard Henderson <richard.henderson@linaro.org>
Suggested-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Gavin Shan <gshan@redhat.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Link: https://lore.kernel.org/r/20260728031731.286666-4-gshan@redhat.com
Signed-off-by: Peter Xu <peterx@redhat.com>
(cherry picked from commit 4fa94987b760f8a137e8911decf72d363ae1306e https://gitlab.com/peterx/qemu)
Signed-off-by: Matthew R. Ochs <mochs@nvidia.com>
@nirmoy

nirmoy commented Aug 11, 2026

Copy link
Copy Markdown

BaseOS Kernel Review

Summary

Only commit-message clarity issues were found: awkward grammar in two messages and several spelling errors in another. No runtime behavior issues were identified.

Findings: Critical: 0, High: 0, Medium: 0, Low: 3

Latest watcher review: open review

Head: b37bf99d9458

This comment is maintained by nv-pr-bot. It is updated when the GitHub watcher publishes a newer review.

@shamiali2008

Copy link
Copy Markdown

Backport LGTM:

Acked-by: Shameer Kolothum skolothumtho@nvidia.com

@NathanChenNVIDIA

Copy link
Copy Markdown
Collaborator

LGTM
Acked-by: Nathan Chen <nathanc@nvidia.com>

@mxc42

mxc42 commented Aug 12, 2026

Copy link
Copy Markdown

LGTM, and ran a successful test build.

Acked-by: Morgan Hunter <morgan.hunter@canonical.com>

@MitchellAugustin MitchellAugustin left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All of the changes here look correct to me, and everything looks consistent with the latest version of the patch series that was approved and queued into the upstream tree here.

Please let me know when you're ready for a build of this version in the staging PPA @nvmochs .

Acked-by: Mitchell Augustin <mitchell.augustin@canonical.com>

@nvmochs

nvmochs commented Aug 13, 2026

Copy link
Copy Markdown
Collaborator Author

Thanks all for the reviews!

Merged, closing PR.

d3b9383469e7 (HEAD -> nvidia_stable-11.0) 1:11.0.0+nvidia6-1
ac146ef2f62f NVIDIA: SAUCE: system/memory: Make ram device region directly accessible
d51cd18fe1c0 NVIDIA: SAUCE: system/memory: Use qemu_ram_move() for directly accessible regions
3a880a826ebf NVIDIA: SAUCE: system/memory: Use memmove() for directly accessible regions

@nvmochs nvmochs closed this Aug 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants