|
|
9ae3a8 |
From 9291ea1d33e70d9c01558da25ac6744ff2ef77ec Mon Sep 17 00:00:00 2001
|
|
|
9ae3a8 |
From: Alex Williamson <alex.williamson@redhat.com>
|
|
|
9ae3a8 |
Date: Fri, 29 Sep 2017 21:46:24 +0200
|
|
|
9ae3a8 |
Subject: [PATCH 16/27] vfio: Handle zero-length sparse mmap ranges
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
RH-Author: Alex Williamson <alex.williamson@redhat.com>
|
|
|
9ae3a8 |
Message-id: <20170929214624.16765.84023.stgit@gimli.home>
|
|
|
9ae3a8 |
Patchwork-id: 76774
|
|
|
9ae3a8 |
O-Subject: [RHEL-7.5 qemu-kvm PATCH 16/16] vfio: Handle zero-length sparse mmap ranges
|
|
|
9ae3a8 |
Bugzilla: 1494181
|
|
|
9ae3a8 |
RH-Acked-by: Paolo Bonzini <pbonzini@redhat.com>
|
|
|
9ae3a8 |
RH-Acked-by: Auger Eric <eric.auger@redhat.com>
|
|
|
9ae3a8 |
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
Upstream: 24acf72b9a291cebfd05f2ecdf3a982ac01e6291
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
As reported in the link below, user has a PCI device with a 4KB BAR
|
|
|
9ae3a8 |
which contains the MSI-X table. This seems to hit a corner case in
|
|
|
9ae3a8 |
the kernel where the region reports being mmap capable, but the sparse
|
|
|
9ae3a8 |
mmap information reports a zero sized range. It's not entirely clear
|
|
|
9ae3a8 |
that the kernel is incorrect in doing this, but regardless, we need
|
|
|
9ae3a8 |
to handle it. To do this, fill our mmap array only with non-zero
|
|
|
9ae3a8 |
sized sparse mmap entries and add an error return from the function
|
|
|
9ae3a8 |
so we can tell the difference between nr_mmaps being zero based on
|
|
|
9ae3a8 |
sparse mmap info vs lack of sparse mmap info.
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
NB, this doesn't actually change the behavior of the device, it only
|
|
|
9ae3a8 |
removes the scary "Failed to mmap ... Performance may be slow" error
|
|
|
9ae3a8 |
message. We cannot currently create an mmap over the MSI-X table.
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
Link: http://lists.nongnu.org/archive/html/qemu-discuss/2016-10/msg00009.html
|
|
|
9ae3a8 |
Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
|
|
|
9ae3a8 |
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
|
|
|
9ae3a8 |
---
|
|
|
9ae3a8 |
hw/misc/vfio.c | 36 ++++++++++++++++++++++--------------
|
|
|
9ae3a8 |
1 file changed, 22 insertions(+), 14 deletions(-)
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
diff --git a/hw/misc/vfio.c b/hw/misc/vfio.c
|
|
|
9ae3a8 |
index a27698b..68ff949 100644
|
|
|
9ae3a8 |
--- a/hw/misc/vfio.c
|
|
|
9ae3a8 |
+++ b/hw/misc/vfio.c
|
|
|
9ae3a8 |
@@ -2621,16 +2621,16 @@ vfio_get_region_info_cap(struct vfio_region_info *info, uint16_t id)
|
|
|
9ae3a8 |
return NULL;
|
|
|
9ae3a8 |
}
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
-static void vfio_setup_region_sparse_mmaps(VFIORegion *region,
|
|
|
9ae3a8 |
- struct vfio_region_info *info)
|
|
|
9ae3a8 |
+static int vfio_setup_region_sparse_mmaps(VFIORegion *region,
|
|
|
9ae3a8 |
+ struct vfio_region_info *info)
|
|
|
9ae3a8 |
{
|
|
|
9ae3a8 |
struct vfio_info_cap_header *hdr;
|
|
|
9ae3a8 |
struct vfio_region_info_cap_sparse_mmap *sparse;
|
|
|
9ae3a8 |
- int i;
|
|
|
9ae3a8 |
+ int i, j;
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
hdr = vfio_get_region_info_cap(info, VFIO_REGION_INFO_CAP_SPARSE_MMAP);
|
|
|
9ae3a8 |
if (!hdr) {
|
|
|
9ae3a8 |
- return;
|
|
|
9ae3a8 |
+ return -ENODEV;
|
|
|
9ae3a8 |
}
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
sparse = container_of(hdr, struct vfio_region_info_cap_sparse_mmap, header);
|
|
|
9ae3a8 |
@@ -2638,16 +2638,24 @@ static void vfio_setup_region_sparse_mmaps(VFIORegion *region,
|
|
|
9ae3a8 |
trace_vfio_region_sparse_mmap_header(region->vbasedev->name,
|
|
|
9ae3a8 |
region->nr, sparse->nr_areas);
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
- region->nr_mmaps = sparse->nr_areas;
|
|
|
9ae3a8 |
- region->mmaps = g_new0(VFIOMmap, region->nr_mmaps);
|
|
|
9ae3a8 |
+ region->mmaps = g_new0(VFIOMmap, sparse->nr_areas);
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
- for (i = 0; i < region->nr_mmaps; i++) {
|
|
|
9ae3a8 |
- region->mmaps[i].offset = sparse->areas[i].offset;
|
|
|
9ae3a8 |
- region->mmaps[i].size = sparse->areas[i].size;
|
|
|
9ae3a8 |
- trace_vfio_region_sparse_mmap_entry(i, region->mmaps[i].offset,
|
|
|
9ae3a8 |
- region->mmaps[i].offset +
|
|
|
9ae3a8 |
- region->mmaps[i].size);
|
|
|
9ae3a8 |
+ for (i = 0, j = 0; i < sparse->nr_areas; i++) {
|
|
|
9ae3a8 |
+ trace_vfio_region_sparse_mmap_entry(i, sparse->areas[i].offset,
|
|
|
9ae3a8 |
+ sparse->areas[i].offset +
|
|
|
9ae3a8 |
+ sparse->areas[i].size);
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+ if (sparse->areas[i].size) {
|
|
|
9ae3a8 |
+ region->mmaps[j].offset = sparse->areas[i].offset;
|
|
|
9ae3a8 |
+ region->mmaps[j].size = sparse->areas[i].size;
|
|
|
9ae3a8 |
+ j++;
|
|
|
9ae3a8 |
+ }
|
|
|
9ae3a8 |
}
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+ region->nr_mmaps = j;
|
|
|
9ae3a8 |
+ region->mmaps = g_realloc(region->mmaps, j * sizeof(VFIOMmap));
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+ return 0;
|
|
|
9ae3a8 |
}
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
static int vfio_region_setup(Object *obj, VFIODevice *vbasedev,
|
|
|
9ae3a8 |
@@ -2676,9 +2684,9 @@ static int vfio_region_setup(Object *obj, VFIODevice *vbasedev,
|
|
|
9ae3a8 |
region->flags & VFIO_REGION_INFO_FLAG_MMAP &&
|
|
|
9ae3a8 |
!(region->size & ~TARGET_PAGE_MASK)) {
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
- vfio_setup_region_sparse_mmaps(region, info);
|
|
|
9ae3a8 |
+ ret = vfio_setup_region_sparse_mmaps(region, info);
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
- if (!region->nr_mmaps) {
|
|
|
9ae3a8 |
+ if (ret) {
|
|
|
9ae3a8 |
region->nr_mmaps = 1;
|
|
|
9ae3a8 |
region->mmaps = g_new0(VFIOMmap, region->nr_mmaps);
|
|
|
9ae3a8 |
region->mmaps[0].offset = 0;
|
|
|
9ae3a8 |
--
|
|
|
9ae3a8 |
1.8.3.1
|
|
|
9ae3a8 |
|