| From 00636d4945615f869926ec05df55680dfb452a01 Mon Sep 17 00:00:00 2001 |
| From: Alex Williamson <alex.williamson@redhat.com> |
| 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 <bsd@redhat.com> |
| RH-Acked-by: Laszlo Ersek <lersek@redhat.com> |
| RH-Acked-by: Markus Armbruster <armbru@redhat.com> |
| |
| 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 <alex.williamson@redhat.com> |
| (cherry picked from commit 87ca1f77b1c406137fe36ab73b2dc91fb75f8d0a) |
| |
| hw/misc/vfio.c | 44 ++++++++++++++++++++++++++++++++++++++------ |
| 1 file changed, 38 insertions(+), 6 deletions(-) |
| |
| Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com> |
| |
| 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 |
| |
| |
| @@ -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 |
| |