yeahuh / rpms / qemu-kvm

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