Add client support for capability VFIO_REGION_INFO_CAP_SPARSE_MMAP_FDS (capability ID 16) in vfio-user.
Update vfio_user_device_io_get_region_info() to receive multiple file descriptors passed in SCM_RIGHTS ancillary data for a region, and implement setup_sparse_mmaps in vfio_user_device_io_ops_sock to parse per-area file descriptor indices and fd_offset values. Signed-off-by: Naman Gulati <[email protected]> --- hw/vfio-user/device.c | 63 ++++++++++++++++++++++++++++++++++++----- hw/vfio-user/protocol.h | 20 +++++++++++++ 2 files changed, 76 insertions(+), 7 deletions(-) diff --git a/hw/vfio-user/device.c b/hw/vfio-user/device.c index 03a7026778..58a691601c 100644 --- a/hw/vfio-user/device.c +++ b/hw/vfio-user/device.c @@ -14,6 +14,9 @@ #include "hw/vfio-user/device.h" #include "hw/vfio-user/trace.h" +#include "hw/vfio/vfio-region.h" +#include "hw/vfio/vfio-helpers.h" +#include "hw/vfio/trace.h" /* * These are to defend against a malign server trying @@ -172,8 +175,9 @@ static int vfio_user_device_io_get_region_info(VFIODevice *vbasedev, struct vfio_region_info *info, struct VFIORegionFDs *region_fds) { - int fd = -1; - VFIOUserFDs fds = { 0, 1, &fd }; + int fds[VFIO_USER_MAX_MAX_FDS]; + int num_fds = VFIO_USER_MAX_MAX_FDS; + VFIOUserFDs user_fds = { 0, num_fds, fds }; int ret; region_fds->fds = NULL; @@ -183,7 +187,7 @@ static int vfio_user_device_io_get_region_info(VFIODevice *vbasedev, return -EINVAL; } - ret = vfio_user_get_region_info(vbasedev->proxy, info, &fds); + ret = vfio_user_get_region_info(vbasedev->proxy, info, &user_fds); if (ret) { return ret; } @@ -194,10 +198,12 @@ static int vfio_user_device_io_get_region_info(VFIODevice *vbasedev, return -EINVAL; } - if (fds.recv_fds > 0) { - region_fds->fds = g_new0(int, 1); - region_fds->nr_fds = 1; - region_fds->fds[0] = fd; + if (user_fds.recv_fds > 0) { + region_fds->fds = g_new0(int, user_fds.recv_fds); + region_fds->nr_fds = user_fds.recv_fds; + for (int i = 0; i < user_fds.recv_fds; i++) { + region_fds->fds[i] = fds[i]; + } } @@ -483,9 +489,52 @@ static int vfio_user_device_io_region_write(VFIODevice *vbasedev, uint8_t index, /* * Socket-based io_ops */ +static int vfio_user_device_io_setup_sparse_mmaps(VFIORegion *region, + struct vfio_region_info *info, + Error **errp) +{ + struct vfio_info_cap_header *hdr; + int i, j = 0; + + hdr = vfio_get_region_info_cap(info, VFIO_REGION_INFO_CAP_SPARSE_MMAP_FDS); + if (hdr) { + struct vfio_region_info_cap_sparse_mmap_fds *sparse_fds = + container_of(hdr, struct vfio_region_info_cap_sparse_mmap_fds, + header); + + trace_vfio_region_sparse_mmap_header(region->vbasedev->name, + region->nr, sparse_fds->nr_areas); + + region->mmaps = g_new0(VFIOMmap, sparse_fds->nr_areas); + + for (i = 0; i < sparse_fds->nr_areas; i++) { + if (sparse_fds->areas[i].size) { + uint64_t end = sparse_fds->areas[i].offset + + sparse_fds->areas[i].size - 1; + + trace_vfio_region_sparse_mmap_entry(i, + sparse_fds->areas[i].offset, + end); + region->mmaps[j].offset = sparse_fds->areas[i].offset; + region->mmaps[j].fd_offset = sparse_fds->areas[i].fd_offset; + region->mmaps[j].size = sparse_fds->areas[i].size; + region->mmaps[j].fd_index = sparse_fds->areas[i].fd_index; + j++; + } + } + + region->nr_mmaps = j; + region->mmaps = g_realloc(region->mmaps, j * sizeof(VFIOMmap)); + return 0; + } + + return vfio_default_setup_sparse_mmaps(region, info, errp); +} + VFIODeviceIOOps vfio_user_device_io_ops_sock = { .device_feature = vfio_user_device_io_device_feature, .get_region_info = vfio_user_device_io_get_region_info, + .setup_sparse_mmaps = vfio_user_device_io_setup_sparse_mmaps, .get_irq_info = vfio_user_device_io_get_irq_info, .set_irqs = vfio_user_device_io_set_irqs, .region_read = vfio_user_device_io_region_read, diff --git a/hw/vfio-user/protocol.h b/hw/vfio-user/protocol.h index c478d1353f..135b965d99 100644 --- a/hw/vfio-user/protocol.h +++ b/hw/vfio-user/protocol.h @@ -166,6 +166,26 @@ typedef struct { uint64_t offset; } VFIOUserRegionInfo; +/* + * VFIO_REGION_INFO_CAP_SPARSE_MMAP_FDS + */ +#define VFIO_REGION_INFO_CAP_SPARSE_MMAP_FDS 16 + +struct vfio_region_sparse_mmap_fd_area { + uint64_t offset; + uint64_t fd_offset; + uint64_t size; + uint32_t fd_index; + uint32_t pad; +}; + +struct vfio_region_info_cap_sparse_mmap_fds { + struct vfio_info_cap_header header; + uint32_t nr_areas; + uint32_t reserved; + struct vfio_region_sparse_mmap_fd_area areas[]; +}; + /* * VFIO_USER_DEVICE_GET_IRQ_INFO * imported from struct vfio_irq_info -- 2.55.0.860.g4b6b3295ed-goog
