|
|
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 |
|