Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Alex Mastro and committed by
Alex Williamson
16950b60 ef270ec4

+110 -30
+23 -4
tools/testing/selftests/vfio/lib/include/vfio_util.h
··· 206 206 void vfio_pci_device_cleanup(struct vfio_pci_device *device); 207 207 void vfio_pci_device_reset(struct vfio_pci_device *device); 208 208 209 - void vfio_pci_dma_map(struct vfio_pci_device *device, 210 - struct vfio_dma_region *region); 211 - void vfio_pci_dma_unmap(struct vfio_pci_device *device, 212 - struct vfio_dma_region *region); 209 + int __vfio_pci_dma_map(struct vfio_pci_device *device, 210 + struct vfio_dma_region *region); 211 + int __vfio_pci_dma_unmap(struct vfio_pci_device *device, 212 + struct vfio_dma_region *region, 213 + u64 *unmapped); 214 + int __vfio_pci_dma_unmap_all(struct vfio_pci_device *device, u64 *unmapped); 215 + 216 + static inline void vfio_pci_dma_map(struct vfio_pci_device *device, 217 + struct vfio_dma_region *region) 218 + { 219 + VFIO_ASSERT_EQ(__vfio_pci_dma_map(device, region), 0); 220 + } 221 + 222 + static inline void vfio_pci_dma_unmap(struct vfio_pci_device *device, 223 + struct vfio_dma_region *region) 224 + { 225 + VFIO_ASSERT_EQ(__vfio_pci_dma_unmap(device, region, NULL), 0); 226 + } 227 + 228 + static inline void vfio_pci_dma_unmap_all(struct vfio_pci_device *device) 229 + { 230 + VFIO_ASSERT_EQ(__vfio_pci_dma_unmap_all(device, NULL), 0); 231 + } 213 232 214 233 void vfio_pci_config_access(struct vfio_pci_device *device, bool write, 215 234 size_t config, size_t size, void *data);
+83 -25
tools/testing/selftests/vfio/lib/vfio_pci_device.c
··· 2 2 #include <dirent.h> 3 3 #include <fcntl.h> 4 4 #include <libgen.h> 5 + #include <stdint.h> 5 6 #include <stdlib.h> 6 7 #include <string.h> 7 8 #include <unistd.h> ··· 142 141 ioctl_assert(device->fd, VFIO_DEVICE_GET_IRQ_INFO, irq_info); 143 142 } 144 143 145 - static void vfio_iommu_dma_map(struct vfio_pci_device *device, 144 + static int vfio_iommu_dma_map(struct vfio_pci_device *device, 146 145 struct vfio_dma_region *region) 147 146 { 148 147 struct vfio_iommu_type1_dma_map args = { ··· 153 152 .size = region->size, 154 153 }; 155 154 156 - ioctl_assert(device->container_fd, VFIO_IOMMU_MAP_DMA, &args); 155 + if (ioctl(device->container_fd, VFIO_IOMMU_MAP_DMA, &args)) 156 + return -errno; 157 + 158 + return 0; 157 159 } 158 160 159 - static void iommufd_dma_map(struct vfio_pci_device *device, 161 + static int iommufd_dma_map(struct vfio_pci_device *device, 160 162 struct vfio_dma_region *region) 161 163 { 162 164 struct iommu_ioas_map args = { ··· 173 169 .ioas_id = device->ioas_id, 174 170 }; 175 171 176 - ioctl_assert(device->iommufd, IOMMU_IOAS_MAP, &args); 172 + if (ioctl(device->iommufd, IOMMU_IOAS_MAP, &args)) 173 + return -errno; 174 + 175 + return 0; 177 176 } 178 177 179 - void vfio_pci_dma_map(struct vfio_pci_device *device, 178 + int __vfio_pci_dma_map(struct vfio_pci_device *device, 180 179 struct vfio_dma_region *region) 181 180 { 181 + int ret; 182 + 182 183 if (device->iommufd) 183 - iommufd_dma_map(device, region); 184 + ret = iommufd_dma_map(device, region); 184 185 else 185 - vfio_iommu_dma_map(device, region); 186 + ret = vfio_iommu_dma_map(device, region); 187 + 188 + if (ret) 189 + return ret; 186 190 187 191 list_add(&region->link, &device->dma_regions); 192 + 193 + return 0; 188 194 } 189 195 190 - static void vfio_iommu_dma_unmap(struct vfio_pci_device *device, 191 - struct vfio_dma_region *region) 196 + static int vfio_iommu_dma_unmap(int fd, u64 iova, u64 size, u32 flags, 197 + u64 *unmapped) 192 198 { 193 199 struct vfio_iommu_type1_dma_unmap args = { 194 200 .argsz = sizeof(args), 195 - .iova = region->iova, 196 - .size = region->size, 201 + .iova = iova, 202 + .size = size, 203 + .flags = flags, 197 204 }; 198 205 199 - ioctl_assert(device->container_fd, VFIO_IOMMU_UNMAP_DMA, &args); 206 + if (ioctl(fd, VFIO_IOMMU_UNMAP_DMA, &args)) 207 + return -errno; 208 + 209 + if (unmapped) 210 + *unmapped = args.size; 211 + 212 + return 0; 200 213 } 201 214 202 - static void iommufd_dma_unmap(struct vfio_pci_device *device, 203 - struct vfio_dma_region *region) 215 + static int iommufd_dma_unmap(int fd, u64 iova, u64 length, u32 ioas_id, 216 + u64 *unmapped) 204 217 { 205 218 struct iommu_ioas_unmap args = { 206 219 .size = sizeof(args), 207 - .iova = region->iova, 208 - .length = region->size, 209 - .ioas_id = device->ioas_id, 220 + .iova = iova, 221 + .length = length, 222 + .ioas_id = ioas_id, 210 223 }; 211 224 212 - ioctl_assert(device->iommufd, IOMMU_IOAS_UNMAP, &args); 225 + if (ioctl(fd, IOMMU_IOAS_UNMAP, &args)) 226 + return -errno; 227 + 228 + if (unmapped) 229 + *unmapped = args.length; 230 + 231 + return 0; 213 232 } 214 233 215 - void vfio_pci_dma_unmap(struct vfio_pci_device *device, 216 - struct vfio_dma_region *region) 234 + int __vfio_pci_dma_unmap(struct vfio_pci_device *device, 235 + struct vfio_dma_region *region, u64 *unmapped) 217 236 { 218 - if (device->iommufd) 219 - iommufd_dma_unmap(device, region); 220 - else 221 - vfio_iommu_dma_unmap(device, region); 237 + int ret; 222 238 223 - list_del(&region->link); 239 + if (device->iommufd) 240 + ret = iommufd_dma_unmap(device->iommufd, region->iova, 241 + region->size, device->ioas_id, 242 + unmapped); 243 + else 244 + ret = vfio_iommu_dma_unmap(device->container_fd, region->iova, 245 + region->size, 0, unmapped); 246 + 247 + if (ret) 248 + return ret; 249 + 250 + list_del_init(&region->link); 251 + 252 + return 0; 253 + } 254 + 255 + int __vfio_pci_dma_unmap_all(struct vfio_pci_device *device, u64 *unmapped) 256 + { 257 + int ret; 258 + struct vfio_dma_region *curr, *next; 259 + 260 + if (device->iommufd) 261 + ret = iommufd_dma_unmap(device->iommufd, 0, UINT64_MAX, 262 + device->ioas_id, unmapped); 263 + else 264 + ret = vfio_iommu_dma_unmap(device->container_fd, 0, 0, 265 + VFIO_DMA_UNMAP_FLAG_ALL, unmapped); 266 + 267 + if (ret) 268 + return ret; 269 + 270 + list_for_each_entry_safe(curr, next, &device->dma_regions, link) 271 + list_del_init(&curr->link); 272 + 273 + return 0; 224 274 } 225 275 226 276 static void vfio_pci_region_get(struct vfio_pci_device *device, int index,
+4 -1
tools/testing/selftests/vfio/vfio_dma_mapping_test.c
··· 129 129 struct vfio_dma_region region; 130 130 struct iommu_mapping mapping; 131 131 u64 mapping_size = size; 132 + u64 unmapped; 132 133 int rc; 133 134 134 135 region.vaddr = mmap(NULL, size, PROT_READ | PROT_WRITE, flags, -1, 0); ··· 185 184 } 186 185 187 186 unmap: 188 - vfio_pci_dma_unmap(self->device, &region); 187 + rc = __vfio_pci_dma_unmap(self->device, &region, &unmapped); 188 + ASSERT_EQ(rc, 0); 189 + ASSERT_EQ(unmapped, region.size); 189 190 printf("Unmapped IOVA 0x%lx\n", region.iova); 190 191 ASSERT_EQ(INVALID_IOVA, __to_iova(self->device, region.vaddr)); 191 192 ASSERT_NE(0, iommu_mapping_get(device_bdf, region.iova, &mapping));