vfio: selftests: update DMA map/unmap helpers to support more test kinds

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>
This commit is contained in:
Alex Mastro 2025-10-28 09:15:03 -07:00 committed by Alex Williamson
parent ef270ec446
commit 16950b60c1
3 changed files with 110 additions and 30 deletions

View 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,
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);

View 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)
{
if (device->iommufd)
iommufd_dma_unmap(device, region);
else
vfio_iommu_dma_unmap(device, region);
int ret;
list_del(&region->link);
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)
ret = iommufd_dma_unmap(device->iommufd, 0, UINT64_MAX,
device->ioas_id, unmapped);
else
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);
return 0;
}
static void vfio_pci_region_get(struct vfio_pci_device *device, int index,

View 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));