Re: [PATCH v4 3/3] hw/vfio/region: Create dmabuf for PCI BAR per region
Gavin Shan <[email protected]> Wed, 5 Aug 2026 19:43:45 +1000
| Newsgroups | org.nongnu.qemu-arm,org.nongnu.qemu-devel |
|---|---|
| Message-ID | <[email protected]> |
Hi Shameer, On 8/5/26 6:33 PM, Shameer Kolothum Thodi wrote: > Hi Gavin, > >> -----Original Message----- >> From: Gavin Shan <[email protected]> >> Sent: 05 August 2026 02:10 >> To: Shameer Kolothum Thodi <[email protected]>; qemu- >> [email protected]; [email protected] >> Cc: [email protected]; [email protected]; [email protected]; >> [email protected]; [email protected]; Nicolin Chen <[email protected]>; >> Nathan Chen <[email protected]>; Matt Ochs <[email protected]>; >> Jason Gunthorpe <[email protected]>; [email protected]; >> [email protected]; [email protected]; Krishnakant Jaju >> <[email protected]>; [email protected] >> Subject: Re: [PATCH v4 3/3] hw/vfio/region: Create dmabuf for PCI BAR per >> region >> >> External email: Use caution opening links or attachments >> >> >> Hi Nicolin and Shameer, >> >> On 1/21/26 9:41 PM, Shameer Kolothum wrote: >>> From: Nicolin Chen <[email protected]> >>> >>> Linux now provides a VFIO dmabuf exporter to expose PCI BAR memory for >> P2P >>> use cases. Create a dmabuf for each mapped BAR region after the mmap is >> set >>> up, and store the returned fd in the region’s RAMBlock. This allows QEMU to >>> pass the fd to dma_map_file(), enabling iommufd to import the dmabuf and >> map >>> the BAR correctly in the host IOMMU page table. >>> >>> If the kernel lacks support or dmabuf setup fails, QEMU skips the setup >>> and continues with normal mmap handling. >>> >>> Tested-by: Nicolin Chen <[email protected]> >>> Reviewed-by: Zhenzhong Duan <[email protected]> >>> Reviewed-by: Cédric Le Goater <[email protected]> >>> Signed-off-by: Nicolin Chen <[email protected]> >>> Signed-off-by: Shameer Kolothum <[email protected]> >>> --- >>> hw/vfio/region.c | 65 >> +++++++++++++++++++++++++++++++++++++++++++- >>> hw/vfio/trace-events | 1 + >>> 2 files changed, 65 insertions(+), 1 deletion(-) >>> >>> diff --git a/hw/vfio/region.c b/hw/vfio/region.c >>> index ca75ab1be4..ab39d77574 100644 >>> --- a/hw/vfio/region.c >>> +++ b/hw/vfio/region.c >>> @@ -29,6 +29,7 @@ >>> #include "qemu/error-report.h" >>> #include "qemu/units.h" >>> #include "monitor/monitor.h" >>> +#include "system/ramblock.h" >>> #include "vfio-helpers.h" >>> >>> /* >>> @@ -238,13 +239,71 @@ static void vfio_subregion_unmap(VFIORegion >> *region, int index) >>> region->mmaps[index].mmap = NULL; >>> } >>> >>> +static bool vfio_region_create_dma_buf(VFIORegion *region, Error **errp) >>> +{ >>> + g_autofree struct vfio_device_feature *feature = NULL; >>> + VFIODevice *vbasedev = region->vbasedev; >>> + struct vfio_device_feature_dma_buf *dma_buf; >>> + size_t total_size; >>> + int i, ret; >>> + >>> + total_size = sizeof(*feature) + sizeof(*dma_buf) + >>> + sizeof(struct vfio_region_dma_range) * region->nr_mmaps; >>> + feature = g_malloc0(total_size); >>> + *feature = (struct vfio_device_feature) { >>> + .argsz = total_size, >>> + .flags = VFIO_DEVICE_FEATURE_GET | >> VFIO_DEVICE_FEATURE_DMA_BUF, >>> + }; >>> + >>> + dma_buf = (void *)feature->data; >>> + *dma_buf = (struct vfio_device_feature_dma_buf) { >>> + .region_index = region->nr, >>> + .open_flags = O_RDWR, >>> + .nr_ranges = region->nr_mmaps, >>> + }; >>> + >>> + for (i = 0; i < region->nr_mmaps; i++) { >>> + dma_buf->dma_ranges[i].offset = region->mmaps[i].offset; >>> + dma_buf->dma_ranges[i].length = region->mmaps[i].size; >>> + } >>> + >> >> Shall we check if @offset and @size is aligned to PAGE_SIZE? If they're not, >> I guess we need to skip populating DMA buffer instead of preventing the >> device from being passed through to the guest. > > Hmm..does it prevent passthrough in this case? The intention was not to do that. > vfio_region_mmap() returns 0 irrespective of dma-buf outcome. > > If the concern was the usage of error_report_err() as does in patch, > > + if (!vfio_region_create_dma_buf(region, &local_err)) { > + error_report_err(local_err); > + } > > this is now updated to warn_report_err_once() by commit: > > 4b2e6505d59b: vfio/region: Clarify dma-buf failure messages > > Or may be I am missing your actual concern here. Please let me know. > > Thanks, > Shameer > You're correct. I overlooked that @err returned from vfio_region_create_dma_buf() isn't propagated and stopping the NVMe card from being passed to the guest. Question: Since @err returned from vfio_region_create_dma_buf() is just used as the warning message storage, it's more reasonable to use warn_report_once(), replacing error_setg_errno() in vfio_region_create_dma_buf(). With this, the argument @errp and the boolean return value of the function can be dropped. I didn't check the history why we need the argument @errp for vfio_region_create_dma_buf(). > >> >> Meghana <[email protected]> runs into issue when passing through an >> NVMe >> card. The only memory BAR on the NVMe card is 16K, which is not aligned to >> 64KB (host page size). >> >> -device vfio-pci,id=nvme,host=0004:01:00.0,addr=0x2.0x1,bus=pcie.0 >> >> host$ sh vfio.sh >> QEMU 10.1.0 monitor - type 'help' for more information >> (qemu) qemu-kvm: -device vfio- >> pci,id=nvme,host=0004:01:00.0,addr=0x2.0x1,bus=pcie.0: \ >> 0004:01:00.0 BAR 0: failed to create dma-buf: PCI BAR IOMMU >> mappings may fail: Invalid argument >> >> host$ lspci -vvvs 0004:01:00.0 | grep Region.*Memory >> Region 0: Memory at 620040010000 (64-bit, non-prefetchable) [size=16K] >> >> host kernel >> =========== >> vfio_device_fops_unl_ioctl >> vfio_ioctl_device_feature >> vfio_pci_core_ioctl_feature >> vfio_pci_core_feature_dma_buf >> validate_dmabuf_input // Return -EINVAL for !PAGE_ALIGNED(len) >> >> >>> + ret = vfio_device_get_feature(vbasedev, feature); >>> + if (ret < 0) { >>> + if (ret == -ENOTTY) { >>> + warn_report_once("VFIO dma-buf not supported in kernel: " >>> + "PCI BAR IOMMU mappings may fail"); >>> + return true; >>> + } >>> + /* P2P DMA or exposing device memory use cases are not supported. >> */ >>> + error_setg_errno(errp, -ret, "%s: failed to create dma-buf: " >>> + "PCI BAR IOMMU mappings may fail", >>> + memory_region_name(region->mem)); >>> + return false; >>> + } >>> + >>> + /* Assign the dmabuf fd to associated RAMBlock */ >>> + for (i = 0; i < region->nr_mmaps; i++) { >>> + MemoryRegion *mr = ®ion->mmaps[i].mem; >>> + RAMBlock *ram_block = mr->ram_block; >>> + >>> + ram_block->fd = ret; >>> + ram_block->fd_offset = region->mmaps[i].offset; >>> + trace_vfio_region_dmabuf(region->vbasedev->name, ret, region->nr, >>> + memory_region_name(region->mem), >>> + region->mmaps[i].offset, >>> + region->mmaps[i].size); >>> + } >>> + return true; >>> +} >>> + >>> int vfio_region_mmap(VFIORegion *region) >>> { >>> int i, ret, prot = 0; >>> + Error *local_err = NULL; >>> char *name; >>> int fd; >>> >>> - if (!region->mem) { >>> + if (!region->mem || !region->nr_mmaps) { >>> return 0; >>> } >>> >>> @@ -305,6 +364,10 @@ int vfio_region_mmap(VFIORegion *region) >>> region->mmaps[i].size - 1); >>> } >>> >>> + if (!vfio_region_create_dma_buf(region, &local_err)) { >>> + error_report_err(local_err); >>> + } >>> + >>> return 0; >>> >>> no_mmap: >>> diff --git a/hw/vfio/trace-events b/hw/vfio/trace-events >>> index 180e3d526b..466695507b 100644 >>> --- a/hw/vfio/trace-events >>> +++ b/hw/vfio/trace-events >>> @@ -118,6 +118,7 @@ vfio_device_put(int fd) "close vdev->fd=%d" >>> vfio_region_write(const char *name, int index, uint64_t addr, uint64_t >> data, unsigned size) " (%s:region%d+0x%"PRIx64", 0x%"PRIx64 ", %d)" >>> vfio_region_read(char *name, int index, uint64_t addr, unsigned size, >> uint64_t data) " (%s:region%d+0x%"PRIx64", %d) = 0x%"PRIx64 >>> vfio_region_setup(const char *dev, int index, const char *name, unsigned >> long flags, unsigned long offset, unsigned long size) "Device %s, region %d >> \"%s\", flags: 0x%lx, offset: 0x%lx, size: 0x%lx" >>> +vfio_region_dmabuf(const char *dev, int fd, int index, const char *name, >> unsigned long offset, unsigned long size) "Device %s, dmabuf fd %d region %d >> \"%s\", offset: 0x%lx, size: 0x%lx" >>> vfio_region_mmap_fault(const char *name, int index, unsigned long offset, >> unsigned long size, int fault) "Region %s mmaps[%d], [0x%lx - 0x%lx], fault: >> %d" >>> vfio_region_mmap(const char *name, unsigned long offset, unsigned long >> end) "Region %s [0x%lx - 0x%lx]" >>> vfio_region_exit(const char *name, int index) "Device %s, region %d" >> Thanks, Gavin