Backport: system/memory: Backport direct access support for RAM device regions - #34
Backport: system/memory: Backport direct access support for RAM device regions#34nvmochs wants to merge 3 commits into
Conversation
…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>
BaseOS Kernel ReviewSummaryOnly 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: This comment is maintained by nv-pr-bot. It is updated when the GitHub watcher publishes a newer review. |
|
Backport LGTM: Acked-by: Shameer Kolothum skolothumtho@nvidia.com |
|
LGTM |
|
LGTM, and ran a successful test build.
|
MitchellAugustin
left a comment
There was a problem hiding this comment.
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>
|
Thanks all for the reviews! Merged, closing PR. |
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:
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
system/memory: Use memmove() for directly accessible regions
Uses memmove() in direct-access paths where source and destination ranges may overlap.
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.
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:
Completed a five-minute, eight-job mixed random read/write fio workload at queue depth 64 with:
Confirmed guest dmesg contained no virtio errors, I/O errors, hung tasks, soft lockups, or GPU Xids.
Confirmed through the QEMU monitor:
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.