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