]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
vfio: selftests: update DMA map/unmap helpers to support more test kinds
authorAlex Mastro <amastro@fb.com>
Tue, 28 Oct 2025 16:15:03 +0000 (09:15 -0700)
committerAlex Williamson <alex@shazbot.org>
Tue, 28 Oct 2025 21:54:41 +0000 (15:54 -0600)
Add __vfio_pci_dma_*() helpers which return -errno from the underlying
ioctls.

Add __vfio_pci_dma_unmap_all() to test more unmapping code paths. Add an
out unmapped arg to report the unmapped byte size.

The existing vfio_pci_dma_*() functions, which are intended for
happy-path usage (assert on failure) are now thin wrappers on top of the
double-underscore helpers.

Reviewed-by: David Matlack <dmatlack@google.com>
Signed-off-by: Alex Mastro <amastro@fb.com>
Link: https://lore.kernel.org/r/20251028-fix-unmap-v6-4-2542b96bcc8e@fb.com
Signed-off-by: Alex Williamson <alex@shazbot.org>
tools/testing/selftests/vfio/lib/include/vfio_util.h
tools/testing/selftests/vfio/lib/vfio_pci_device.c
tools/testing/selftests/vfio/vfio_dma_mapping_test.c

index ed31606e01b78584583f5d6631974255362edd6e..240409bf5f8ad6201cd0505059bdaf701cf5813a 100644 (file)
@@ -206,10 +206,29 @@ struct vfio_pci_device *vfio_pci_device_init(const char *bdf, const char *iommu_
 void vfio_pci_device_cleanup(struct vfio_pci_device *device);
 void vfio_pci_device_reset(struct vfio_pci_device *device);
 
-void vfio_pci_dma_map(struct vfio_pci_device *device,
-                     struct vfio_dma_region *region);
-void vfio_pci_dma_unmap(struct vfio_pci_device *device,
-                       struct vfio_dma_region *region);
+int __vfio_pci_dma_map(struct vfio_pci_device *device,
+                      struct vfio_dma_region *region);
+int __vfio_pci_dma_unmap(struct vfio_pci_device *device,
+                        struct vfio_dma_region *region,
+                        u64 *unmapped);
+int __vfio_pci_dma_unmap_all(struct vfio_pci_device *device, u64 *unmapped);
+
+static inline void vfio_pci_dma_map(struct vfio_pci_device *device,
+                                   struct vfio_dma_region *region)
+{
+       VFIO_ASSERT_EQ(__vfio_pci_dma_map(device, region), 0);
+}
+
+static inline void vfio_pci_dma_unmap(struct vfio_pci_device *device,
+                                     struct vfio_dma_region *region)
+{
+       VFIO_ASSERT_EQ(__vfio_pci_dma_unmap(device, region, NULL), 0);
+}
+
+static inline void vfio_pci_dma_unmap_all(struct vfio_pci_device *device)
+{
+       VFIO_ASSERT_EQ(__vfio_pci_dma_unmap_all(device, NULL), 0);
+}
 
 void vfio_pci_config_access(struct vfio_pci_device *device, bool write,
                            size_t config, size_t size, void *data);
index 0921b2451ba5c5490d5395e24578d4064956406e..a381fd253aa7ece000aeda1a26afd3caadb2ddf7 100644 (file)
@@ -2,6 +2,7 @@
 #include <dirent.h>
 #include <fcntl.h>
 #include <libgen.h>
+#include <stdint.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
@@ -141,7 +142,7 @@ static void vfio_pci_irq_get(struct vfio_pci_device *device, u32 index,
        ioctl_assert(device->fd, VFIO_DEVICE_GET_IRQ_INFO, irq_info);
 }
 
-static void vfio_iommu_dma_map(struct vfio_pci_device *device,
+static int vfio_iommu_dma_map(struct vfio_pci_device *device,
                               struct vfio_dma_region *region)
 {
        struct vfio_iommu_type1_dma_map args = {
@@ -152,10 +153,13 @@ static void vfio_iommu_dma_map(struct vfio_pci_device *device,
                .size = region->size,
        };
 
-       ioctl_assert(device->container_fd, VFIO_IOMMU_MAP_DMA, &args);
+       if (ioctl(device->container_fd, VFIO_IOMMU_MAP_DMA, &args))
+               return -errno;
+
+       return 0;
 }
 
-static void iommufd_dma_map(struct vfio_pci_device *device,
+static int iommufd_dma_map(struct vfio_pci_device *device,
                            struct vfio_dma_region *region)
 {
        struct iommu_ioas_map args = {
@@ -169,54 +173,108 @@ static void iommufd_dma_map(struct vfio_pci_device *device,
                .ioas_id = device->ioas_id,
        };
 
-       ioctl_assert(device->iommufd, IOMMU_IOAS_MAP, &args);
+       if (ioctl(device->iommufd, IOMMU_IOAS_MAP, &args))
+               return -errno;
+
+       return 0;
 }
 
-void vfio_pci_dma_map(struct vfio_pci_device *device,
+int __vfio_pci_dma_map(struct vfio_pci_device *device,
                      struct vfio_dma_region *region)
 {
+       int ret;
+
        if (device->iommufd)
-               iommufd_dma_map(device, region);
+               ret = iommufd_dma_map(device, region);
        else
-               vfio_iommu_dma_map(device, region);
+               ret = vfio_iommu_dma_map(device, region);
+
+       if (ret)
+               return ret;
 
        list_add(&region->link, &device->dma_regions);
+
+       return 0;
 }
 
-static void vfio_iommu_dma_unmap(struct vfio_pci_device *device,
-                                struct vfio_dma_region *region)
+static int vfio_iommu_dma_unmap(int fd, u64 iova, u64 size, u32 flags,
+                               u64 *unmapped)
 {
        struct vfio_iommu_type1_dma_unmap args = {
                .argsz = sizeof(args),
-               .iova = region->iova,
-               .size = region->size,
+               .iova = iova,
+               .size = size,
+               .flags = flags,
        };
 
-       ioctl_assert(device->container_fd, VFIO_IOMMU_UNMAP_DMA, &args);
+       if (ioctl(fd, VFIO_IOMMU_UNMAP_DMA, &args))
+               return -errno;
+
+       if (unmapped)
+               *unmapped = args.size;
+
+       return 0;
 }
 
-static void iommufd_dma_unmap(struct vfio_pci_device *device,
-                             struct vfio_dma_region *region)
+static int iommufd_dma_unmap(int fd, u64 iova, u64 length, u32 ioas_id,
+                            u64 *unmapped)
 {
        struct iommu_ioas_unmap args = {
                .size = sizeof(args),
-               .iova = region->iova,
-               .length = region->size,
-               .ioas_id = device->ioas_id,
+               .iova = iova,
+               .length = length,
+               .ioas_id = ioas_id,
        };
 
-       ioctl_assert(device->iommufd, IOMMU_IOAS_UNMAP, &args);
+       if (ioctl(fd, IOMMU_IOAS_UNMAP, &args))
+               return -errno;
+
+       if (unmapped)
+               *unmapped = args.length;
+
+       return 0;
 }
 
-void vfio_pci_dma_unmap(struct vfio_pci_device *device,
-                       struct vfio_dma_region *region)
+int __vfio_pci_dma_unmap(struct vfio_pci_device *device,
+                        struct vfio_dma_region *region, u64 *unmapped)
 {
+       int ret;
+
+       if (device->iommufd)
+               ret = iommufd_dma_unmap(device->iommufd, region->iova,
+                                       region->size, device->ioas_id,
+                                       unmapped);
+       else
+               ret = vfio_iommu_dma_unmap(device->container_fd, region->iova,
+                                          region->size, 0, unmapped);
+
+       if (ret)
+               return ret;
+
+       list_del_init(&region->link);
+
+       return 0;
+}
+
+int __vfio_pci_dma_unmap_all(struct vfio_pci_device *device, u64 *unmapped)
+{
+       int ret;
+       struct vfio_dma_region *curr, *next;
+
        if (device->iommufd)
-               iommufd_dma_unmap(device, region);
+               ret = iommufd_dma_unmap(device->iommufd, 0, UINT64_MAX,
+                                       device->ioas_id, unmapped);
        else
-               vfio_iommu_dma_unmap(device, region);
+               ret = vfio_iommu_dma_unmap(device->container_fd, 0, 0,
+                                          VFIO_DMA_UNMAP_FLAG_ALL, unmapped);
+
+       if (ret)
+               return ret;
+
+       list_for_each_entry_safe(curr, next, &device->dma_regions, link)
+               list_del_init(&curr->link);
 
-       list_del(&region->link);
+       return 0;
 }
 
 static void vfio_pci_region_get(struct vfio_pci_device *device, int index,
index ab19c54a774dafdf49fd20867c95bfda9b984d9e..a38966e8e5a609158984b0f2f899a1d0d77b40b5 100644 (file)
@@ -129,6 +129,7 @@ TEST_F(vfio_dma_mapping_test, dma_map_unmap)
        struct vfio_dma_region region;
        struct iommu_mapping mapping;
        u64 mapping_size = size;
+       u64 unmapped;
        int rc;
 
        region.vaddr = mmap(NULL, size, PROT_READ | PROT_WRITE, flags, -1, 0);
@@ -184,7 +185,9 @@ TEST_F(vfio_dma_mapping_test, dma_map_unmap)
        }
 
 unmap:
-       vfio_pci_dma_unmap(self->device, &region);
+       rc = __vfio_pci_dma_unmap(self->device, &region, &unmapped);
+       ASSERT_EQ(rc, 0);
+       ASSERT_EQ(unmapped, region.size);
        printf("Unmapped IOVA 0x%lx\n", region.iova);
        ASSERT_EQ(INVALID_IOVA, __to_iova(self->device, region.vaddr));
        ASSERT_NE(0, iommu_mapping_get(device_bdf, region.iova, &mapping));