Allow each sparse mmap subregion to specify its own file descriptor and file offset for the mmap call.
Add 'fd' (set to -1 when the region fd should be used) and 'fd_offset' to VFIOMmap, and update vfio_region_mmap() to use them. Signed-off-by: Naman Gulati <[email protected]> --- hw/vfio/vfio-region.h | 4 +++- hw/vfio/pci.c | 2 ++ hw/vfio/region.c | 26 +++++++++++++++++++------- 3 files changed, 24 insertions(+), 8 deletions(-) diff --git a/hw/vfio/vfio-region.h b/hw/vfio/vfio-region.h index 58b236f113..9f6a5cf7d5 100644 --- a/hw/vfio/vfio-region.h +++ b/hw/vfio/vfio-region.h @@ -14,8 +14,10 @@ typedef struct VFIOMmap { MemoryRegion mem; void *mmap; - off_t offset; + off_t offset; /* offset within the region */ size_t size; + int fd; /* per-mmap fd, or -1 to use the region fd */ + uint64_t fd_offset; /* offset within fd for the mmap call */ } VFIOMmap; typedef struct VFIODevice VFIODevice; diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c index c204706e63..0a61a060d9 100644 --- a/hw/vfio/pci.c +++ b/hw/vfio/pci.c @@ -1608,6 +1608,7 @@ static void vfio_pci_fixup_msix_region(VFIOPCIDevice *vdev) vdev->msix->table_bar, 0, 0); } else { region->mmaps[0].offset = end; + region->mmaps[0].fd_offset += end; region->mmaps[0].size = region->size - end; trace_vfio_msix_fixup(vdev->vbasedev.name, vdev->msix->table_bar, region->mmaps[0].offset, @@ -1634,6 +1635,7 @@ static void vfio_pci_fixup_msix_region(VFIOPCIDevice *vdev) region->mmaps[0].offset + region->mmaps[0].size); region->mmaps[1].offset = end; + region->mmaps[1].fd_offset += end; region->mmaps[1].size = region->size - end; trace_vfio_msix_fixup(vdev->vbasedev.name, vdev->msix->table_bar, region->mmaps[1].offset, diff --git a/hw/vfio/region.c b/hw/vfio/region.c index dbde339180..3c746200ca 100644 --- a/hw/vfio/region.c +++ b/hw/vfio/region.c @@ -189,6 +189,9 @@ static int vfio_setup_region_sparse_mmaps(VFIORegion *region, sparse->areas[i].size - 1); region->mmaps[j].offset = sparse->areas[i].offset; region->mmaps[j].size = sparse->areas[i].size; + region->mmaps[j].fd = -1; + region->mmaps[j].fd_offset = region->fd_offset + + sparse->areas[i].offset; j++; } } @@ -262,6 +265,8 @@ int vfio_region_setup(Object *obj, VFIODevice *vbasedev, VFIORegion *region, region->mmaps = g_new0(VFIOMmap, region->nr_mmaps); region->mmaps[0].offset = 0; region->mmaps[0].size = region->size; + region->mmaps[0].fd = -1; + region->mmaps[0].fd_offset = region->fd_offset; } else if (ret) { return ret; } @@ -355,7 +360,6 @@ int vfio_region_mmap(VFIORegion *region) off_t map_offset = 0; size_t align; char *name; - int fd; if (!region->mem || !region->nr_mmaps) { return 0; @@ -392,8 +396,6 @@ int vfio_region_mmap(VFIORegion *region) return ret; } - fd = vfio_device_get_region_fd(region->vbasedev, region->nr); - map_align = (void *)ROUND_UP((uintptr_t)map_base, (uintptr_t)align); munmap(map_base, map_align - map_base); munmap(map_align + region->size, @@ -405,12 +407,22 @@ int vfio_region_mmap(VFIORegion *region) * offsets being in ascending order. */ for (i = 0; i < region->nr_mmaps; i++) { + int fd = region->mmaps[i].fd; + + if (fd < 0) { + fd = vfio_device_get_region_fd(region->vbasedev, region->nr); + } + if (fd < 0) { + ret = -EINVAL; + munmap(map_align + map_offset, region->size - map_offset); + goto no_mmap; + } + munmap(map_align + map_offset, region->mmaps[i].offset - map_offset); region->mmaps[i].mmap = mmap(map_align + region->mmaps[i].offset, region->mmaps[i].size, prot, MAP_SHARED | MAP_FIXED, fd, - region->fd_offset + - region->mmaps[i].offset); + region->mmaps[i].fd_offset); if (region->mmaps[i].mmap == MAP_FAILED) { ret = -errno; /* @@ -455,8 +467,8 @@ int vfio_region_mmap(VFIORegion *region) no_mmap: trace_vfio_region_mmap_fault(memory_region_name(region->mem), i, - region->fd_offset + region->mmaps[i].offset, - region->fd_offset + region->mmaps[i].offset + + region->mmaps[i].fd_offset, + region->mmaps[i].fd_offset + region->mmaps[i].size - 1, ret); region->mmaps[i].mmap = NULL; -- 2.55.0.1082.g2b9226bbc0-goog
