On Mon, Nov 03, 2025 at 12:07:12PM -0800, Alex Mastro wrote:
On Sun, Nov 02, 2025 at 10:00:48AM +0200, Leon Romanovsky wrote:
Changelog: v6:
- Fixed wrong error check from pcim_p2pdma_init().
- Documented pcim_p2pdma_provider() function.
- Improved commit messages.
- Added VFIO DMA-BUF selftest.
- Added __counted_by(nr_ranges) annotation to struct vfio_device_feature_dma_buf.
- Fixed error unwind when dma_buf_fd() fails.
- Document latest changes to p2pmem.
- Removed EXPORT_SYMBOL_GPL from pci_p2pdma_map_type.
- Moved DMA mapping logic to DMA-BUF.
- Removed types patch to avoid dependencies between subsystems.
- Moved vfio_pci_dma_buf_move() in err_undo block.
- Added nvgrace patch.
Thanks Leon. Attaching a toy program which sanity tests the dma-buf export UAPI by feeding the allocated dma-buf into an dma-buf importer (libibverbs + CX-7).
Oh! Here is my toy program to do the same with iommufd as the importer:
#define _GNU_SOURCE #define __user #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <sys/ioctl.h> #include <unistd.h> #include "include/uapi/linux/vfio.h" #include "include/uapi/linux/iommufd.h" #include <string.h> #include <sys/mman.h> #include <errno.h>
int main(int argc, const char *argv[]) { int vfio_dev_fd, iommufd_fd, ret;
// Open the per-device VFIO file (e.g., /dev/vfio/devices/vfio3) vfio_dev_fd = open("/dev/vfio/devices/vfio0", O_RDWR); if (vfio_dev_fd < 0) { perror("Failed to open VFIO per-device file"); return 1; }
// Open /dev/iommu for iommufd iommufd_fd = open("/dev/iommu", O_RDWR); if (iommufd_fd < 0) { perror("Failed to open /dev/iommu"); close(vfio_dev_fd); return 1; }
// Bind device FD to iommufd struct vfio_device_bind_iommufd bind = { .argsz = sizeof(bind), .flags = 0, .iommufd = iommufd_fd, }; ret = ioctl(vfio_dev_fd, VFIO_DEVICE_BIND_IOMMUFD, &bind); if (ret < 0) { perror("VFIO_DEVICE_BIND_IOMMUFD failed"); close(vfio_dev_fd); close(iommufd_fd); return 1; }
// Allocate an IOAS (I/O address space) struct iommu_ioas_alloc alloc_data = { .size = sizeof(alloc_data), .flags = 0, }; ret = ioctl(iommufd_fd, IOMMU_IOAS_ALLOC, &alloc_data); if (ret < 0) { perror("IOMMU_IOAS_ALLOC failed"); close(vfio_dev_fd); close(iommufd_fd); return 1; }
// Attach the device to the IOAS struct vfio_device_attach_iommufd_pt attach_data = { .argsz = sizeof(attach_data), .flags = 0, .pt_id = alloc_data.out_ioas_id, }; ret = ioctl(vfio_dev_fd, VFIO_DEVICE_ATTACH_IOMMUFD_PT, &attach_data); if (ret < 0) { perror("VFIO_DEVICE_ATTACH_IOMMUFD_PT failed"); close(vfio_dev_fd); close(iommufd_fd); return 1; }
#if 0 int mapfd = memfd_create("test", MFD_CLOEXEC); if (mapfd == -1) { perror("memfd_create failed"); return 1; } ftruncate(mapfd, 4096); #else struct dmabuf_arg { struct vfio_device_feature hdr; struct vfio_device_feature_dma_buf dma_buf; struct vfio_region_dma_range range; } dma_buf_feature = { .hdr = { .argsz = sizeof(dma_buf_feature), .flags = VFIO_DEVICE_FEATURE_GET | VFIO_DEVICE_FEATURE_DMA_BUF }, .dma_buf = { .region_index = VFIO_PCI_BAR0_REGION_INDEX, .open_flags = O_CLOEXEC, .nr_ranges = 1 }, .range = { .length = 4096 }, }; ret = ioctl(vfio_dev_fd, VFIO_DEVICE_FEATURE, &dma_buf_feature); if (ret < 0) { perror("VFIO_DEVICE_FEATURE_GET failed"); return 1; } int mapfd = ret; #endif
struct iommu_ioas_map_file map_file = { .size = sizeof(map_file), .flags = IOMMU_IOAS_MAP_WRITEABLE | IOMMU_IOAS_MAP_READABLE, .ioas_id = alloc_data.out_ioas_id, .fd = mapfd, .start = 0, .length = 4096, }; ret = ioctl(iommufd_fd, IOMMU_IOAS_MAP_FILE, &map_file); if (ret < 0) { perror("IOMMU_IOAS_MAP_FILE failed"); return 1; }
printf("Successfully attached device to IOAS ID: %u\n", alloc_data.out_ioas_id);
close(vfio_dev_fd); close(iommufd_fd);
return 0; }