diff options
author | Thanos Makatos <thanos.makatos@nutanix.com> | 2020-12-14 15:50:37 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-12-14 15:50:37 +0000 |
commit | f240c889171ab22e7b8b0b460792b0df94c335c1 (patch) | |
tree | c0a60b0dbd7f32ffac3b8caf8d1bbcfa8bfed491 /lib | |
parent | d7157efb22c9fc06f85e40f0e6b6c5e16dc5e8e2 (diff) | |
download | libvfio-user-f240c889171ab22e7b8b0b460792b0df94c335c1.zip libvfio-user-f240c889171ab22e7b8b0b460792b0df94c335c1.tar.gz libvfio-user-f240c889171ab22e7b8b0b460792b0df94c335c1.tar.bz2 |
return region capabilities a la VFIO (#187)
This patch returns region capabilities the same way VFIO does: if argsz
is not large enough then it returns only region info and sets argsz to
what it should be in order to fit the capabilities, the client then
retries with a large enough argsz. The protocol specification has been
updated as well.
Plus unit tests.
Signed-off-by: Thanos Makatos <thanos.makatos@nutanix.com>
Diffstat (limited to 'lib')
-rw-r--r-- | lib/libvfio-user.c | 44 | ||||
-rw-r--r-- | lib/private.h | 3 |
2 files changed, 28 insertions, 19 deletions
diff --git a/lib/libvfio-user.c b/lib/libvfio-user.c index c3cd1e2..042a473 100644 --- a/lib/libvfio-user.c +++ b/lib/libvfio-user.c @@ -154,12 +154,6 @@ dev_get_caps(vfu_ctx_t *vfu_ctx, vfu_reg_info_t *vfu_reg, bool is_migr_reg, sparse->areas[i].offset + sparse->areas[i].size); } } - - /* - * FIXME VFIO_REGION_INFO_FLAG_MMAP is valid if the region is - * memory-mappable in general, not only if it supports sparse mmap. - */ - vfio_reg->flags |= VFIO_REGION_INFO_FLAG_MMAP | VFIO_REGION_INFO_FLAG_CAPS; } #define VFU_REGION_SHIFT 40 @@ -211,13 +205,12 @@ is_migr_reg(vfu_ctx_t *vfu_ctx, int index) return &vfu_ctx->reg_info[index] == vfu_ctx->migr_reg; } -static long -dev_get_reginfo(vfu_ctx_t *vfu_ctx, uint32_t index, +long +dev_get_reginfo(vfu_ctx_t *vfu_ctx, uint32_t index, uint32_t argsz, struct vfio_region_info **vfio_reg) { vfu_reg_info_t *vfu_reg; size_t caps_size; - uint32_t argsz; assert(vfu_ctx != NULL); assert(vfio_reg != NULL); @@ -225,26 +218,38 @@ dev_get_reginfo(vfu_ctx_t *vfu_ctx, uint32_t index, vfu_reg = &vfu_ctx->reg_info[index]; if (index >= vfu_ctx->nr_regions) { - vfu_log(vfu_ctx, LOG_DEBUG, "bad region index %d", index); + vfu_log(vfu_ctx, LOG_DEBUG, "bad region index %d in get region info", + index); return -EINVAL; } - caps_size = get_vfio_caps_size(is_migr_reg(vfu_ctx, index), - vfu_reg->mmap_areas); - argsz = caps_size + sizeof(struct vfio_region_info); + if (argsz < sizeof(struct vfio_region_info)) { + vfu_log(vfu_ctx, LOG_DEBUG, "bad argsz %d", argsz); + return -EINVAL; + } + + /* + * TODO We assume that the client expects to receive argsz bytes. + */ *vfio_reg = calloc(1, argsz); if (!*vfio_reg) { return -ENOMEM; } - /* FIXME document in the protocol that vfio_req->argsz is ignored */ - (*vfio_reg)->argsz = argsz; + caps_size = get_vfio_caps_size(is_migr_reg(vfu_ctx, index), + vfu_reg->mmap_areas); + (*vfio_reg)->argsz = caps_size + sizeof(struct vfio_region_info); (*vfio_reg)->flags = vfu_reg->flags; (*vfio_reg)->index = index; (*vfio_reg)->offset = region_to_offset((*vfio_reg)->index); (*vfio_reg)->size = vfu_reg->size; if (caps_size > 0) { - dev_get_caps(vfu_ctx, vfu_reg, is_migr_reg(vfu_ctx, index), *vfio_reg); + if (vfu_reg->mmap_areas != NULL) { + (*vfio_reg)->flags |= VFIO_REGION_INFO_FLAG_CAPS; + } + if (argsz >= (*vfio_reg)->argsz) { + dev_get_caps(vfu_ctx, vfu_reg, is_migr_reg(vfu_ctx, index), *vfio_reg); + } } vfu_log(vfu_ctx, LOG_DEBUG, "region_info[%d] offset %#llx flags %#x size %llu " @@ -479,11 +484,12 @@ handle_device_get_region_info(vfu_ctx_t *vfu_ctx, uint32_t size, struct vfio_region_info *reg_info_in, struct vfio_region_info **reg_info_out) { - if (size != sizeof(*reg_info_in) || size != reg_info_in->argsz) { + if (size < sizeof(*reg_info_in)) { return -EINVAL; } - return dev_get_reginfo(vfu_ctx, reg_info_in->index, reg_info_out); + return dev_get_reginfo(vfu_ctx, reg_info_in->index, reg_info_in->argsz, + reg_info_out); } int @@ -955,7 +961,7 @@ exec_command(vfu_ctx_t *vfu_ctx, struct vfio_user_header *hdr, size_t size, &dev_reg_info); if (ret == 0) { _iovecs[1].iov_base = dev_reg_info; - _iovecs[1].iov_len = dev_reg_info->argsz; + _iovecs[1].iov_len = hdr->msg_size; *iovecs = _iovecs; *nr_iovecs = 2; } diff --git a/lib/private.h b/lib/private.h index 5321734..7860ec2 100644 --- a/lib/private.h +++ b/lib/private.h @@ -171,6 +171,9 @@ consume_fd(int *fds, size_t nr_fds, size_t index); int handle_device_get_info(vfu_ctx_t *vfu_ctx, uint32_t size, struct vfio_device_info *dev_info); +long +dev_get_reginfo(vfu_ctx_t *vfu_ctx, uint32_t index, uint32_t argsz, + struct vfio_region_info **vfio_reg); #endif /* LIB_VFIO_USER_PRIVATE_H */ |