From 00636d4945615f869926ec05df55680dfb452a01 Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Wed, 22 Jan 2014 20:52:52 -0500 Subject: [PATCH 1/6] vfio-pci: Fail initfn on DMA mapping errors Message-id: <20140122205231.4223.40719.stgit@bling.home> Patchwork-id: 56900 O-Subject: [RHEL-7 qemu-kvm PATCH 1/1] vfio-pci: Fail initfn on DMA mapping errors Bugzilla: 1044815 RH-Acked-by: Bandan Das RH-Acked-by: Laszlo Ersek RH-Acked-by: Markus Armbruster Bugzilla: 1044815 Upstream: 87ca1f77b1c406137fe36ab73b2dc91fb75f8d0a (tag from pull request) The vfio-pci initfn will currently succeed even if DMA mappings fail. A typical reason for failure is if the user does not have sufficient privilege to lock all the memory for the guest. In this case, the device gets attached, but can only access a portion of guest memory and is extremely unlikely to work. DMA mappings are done via a MemoryListener, which provides no direct error return path. We therefore stuff the errno into our container structure and check for error after registration completes. We can also test for mapping errors during runtime, but our only option for resolution at that point is to kill the guest with a hw_error. Signed-off-by: Alex Williamson (cherry picked from commit 87ca1f77b1c406137fe36ab73b2dc91fb75f8d0a) --- hw/misc/vfio.c | 44 ++++++++++++++++++++++++++++++++++++++------ 1 file changed, 38 insertions(+), 6 deletions(-) Signed-off-by: Miroslav Rezanina --- hw/misc/vfio.c | 44 ++++++++++++++++++++++++++++++++++++++------ 1 file changed, 38 insertions(+), 6 deletions(-) diff --git a/hw/misc/vfio.c b/hw/misc/vfio.c index bd30130..83f2b6a 100644 --- a/hw/misc/vfio.c +++ b/hw/misc/vfio.c @@ -133,12 +133,18 @@ enum { struct VFIOGroup; +typedef struct VFIOType1 { + MemoryListener listener; + int error; + bool initialized; +} VFIOType1; + typedef struct VFIOContainer { int fd; /* /dev/vfio/vfio, empowered by the attached groups */ struct { /* enable abstraction to support various iommu backends */ union { - MemoryListener listener; /* Used by type1 iommu */ + VFIOType1 type1; }; void (*release)(struct VFIOContainer *); } iommu_data; @@ -2102,7 +2108,7 @@ static void vfio_listener_region_add(MemoryListener *listener, MemoryRegionSection *section) { VFIOContainer *container = container_of(listener, VFIOContainer, - iommu_data.listener); + iommu_data.type1.listener); hwaddr iova, end; void *vaddr; int ret; @@ -2140,6 +2146,19 @@ static void vfio_listener_region_add(MemoryListener *listener, error_report("vfio_dma_map(%p, 0x%"HWADDR_PRIx", " "0x%"HWADDR_PRIx", %p) = %d (%m)", container, iova, end - iova, vaddr, ret); + + /* + * On the initfn path, store the first error in the container so we + * can gracefully fail. Runtime, there's not much we can do other + * than throw a hardware error. + */ + if (!container->iommu_data.type1.initialized) { + if (!container->iommu_data.type1.error) { + container->iommu_data.type1.error = ret; + } + } else { + hw_error("vfio: DMA mapping failed, unable to continue\n"); + } } } @@ -2147,7 +2166,7 @@ static void vfio_listener_region_del(MemoryListener *listener, MemoryRegionSection *section) { VFIOContainer *container = container_of(listener, VFIOContainer, - iommu_data.listener); + iommu_data.type1.listener); hwaddr iova, end; int ret; @@ -2190,7 +2209,7 @@ static MemoryListener vfio_memory_listener = { static void vfio_listener_release(VFIOContainer *container) { - memory_listener_unregister(&container->iommu_data.listener); + memory_listener_unregister(&container->iommu_data.type1.listener); } /* @@ -3159,10 +3178,23 @@ static int vfio_connect_container(VFIOGroup *group) return -errno; } - container->iommu_data.listener = vfio_memory_listener; + container->iommu_data.type1.listener = vfio_memory_listener; container->iommu_data.release = vfio_listener_release; - memory_listener_register(&container->iommu_data.listener, &address_space_memory); + memory_listener_register(&container->iommu_data.type1.listener, + &address_space_memory); + + if (container->iommu_data.type1.error) { + ret = container->iommu_data.type1.error; + vfio_listener_release(container); + g_free(container); + close(fd); + error_report("vfio: memory listener initialization failed for container\n"); + return ret; + } + + container->iommu_data.type1.initialized = true; + } else { error_report("vfio: No available IOMMU models"); g_free(container); -- 1.8.3.1