From 14c0bc58e7278271ba22e6d31480da550db69a0c Mon Sep 17 00:00:00 2001 From: Thanos Makatos Date: Tue, 22 Nov 2022 09:10:27 +0000 Subject: allow shadow memory offset per shadow ioeventfd (#703) Signed-off-by: Thanos Makatos Reviewed-by: John Levon --- include/libvfio-user.h | 7 ++++--- include/vfio-user.h | 5 +++-- lib/libvfio-user.c | 15 ++++++++------- lib/private.h | 3 ++- test/py/libvfio_user.py | 17 +++++++++-------- test/py/test_device_get_region_io_fds.py | 6 +++--- test/py/test_shadow_ioeventfd.py | 9 +++++---- 7 files changed, 34 insertions(+), 28 deletions(-) diff --git a/include/libvfio-user.h b/include/libvfio-user.h index d12d89f..0a8af2b 100644 --- a/include/libvfio-user.h +++ b/include/libvfio-user.h @@ -1065,7 +1065,7 @@ vfu_sg_is_mappable(vfu_ctx_t *vfu_ctx, dma_sg_t *sg); * @vfu_ctx: the libvfio-user context * @region_idx: The index of the memory region to set up the ioeventfd * @fd: the value of the file descriptor - * @offset: The offset into the memory region + * @gpa_offset: The offset into the memory region * @size: size of the ioeventfd * @flags: Any flags to set up the ioeventfd * @datamatch: sets the datamatch value @@ -1076,11 +1076,12 @@ vfu_sg_is_mappable(vfu_ctx_t *vfu_ctx, dma_sg_t *sg); * Requires a kernel with shadow ioeventfd support. * Experimental, must be compiled with SHADOW_IOEVENTFD defined, otherwise * must be -1. + * @shadow_offset: offset in shadow memory where value is written to. */ int vfu_create_ioeventfd(vfu_ctx_t *vfu_ctx, uint32_t region_idx, int fd, - size_t offset, uint32_t size, uint32_t flags, - uint64_t datamatch, int shadow_fd); + size_t gpa_offset, uint32_t size, uint32_t flags, + uint64_t datamatch, int shadow_fd, size_t shadow_offset); #ifdef __cplusplus } #endif diff --git a/include/vfio-user.h b/include/vfio-user.h index dc6fafa..52f0870 100644 --- a/include/vfio-user.h +++ b/include/vfio-user.h @@ -171,12 +171,13 @@ typedef struct vfio_user_region_io_fds_request { #define VFIO_USER_IO_FD_TYPE_IOEVENTFD_SHADOW 2 typedef struct vfio_user_sub_region_ioeventfd { - uint64_t offset; + uint64_t gpa_offset; uint64_t size; uint32_t fd_index; uint32_t type; uint32_t flags; - uint32_t padding; + uint32_t shadow_mem_fd_index; + uint64_t shadow_offset; uint64_t datamatch; } __attribute__((packed)) vfio_user_sub_region_ioeventfd_t; diff --git a/lib/libvfio-user.c b/lib/libvfio-user.c index 93dca6d..219b527 100644 --- a/lib/libvfio-user.c +++ b/lib/libvfio-user.c @@ -477,8 +477,8 @@ handle_device_get_region_info(vfu_ctx_t *vfu_ctx, vfu_msg_t *msg) EXPORT int vfu_create_ioeventfd(vfu_ctx_t *vfu_ctx, uint32_t region_idx, int fd, - size_t offset, uint32_t size, uint32_t flags, - uint64_t datamatch, int shadow_fd) + size_t gpa_offset, uint32_t size, uint32_t flags, + uint64_t datamatch, int shadow_fd, size_t shadow_offset) { vfu_reg_info_t *vfu_reg; @@ -498,7 +498,7 @@ vfu_create_ioeventfd(vfu_ctx_t *vfu_ctx, uint32_t region_idx, int fd, vfu_reg = &vfu_ctx->reg_info[region_idx]; - if (offset + size > vfu_reg->size) { + if (gpa_offset + size > vfu_reg->size) { return ERROR_INT(EINVAL); } @@ -508,11 +508,12 @@ vfu_create_ioeventfd(vfu_ctx_t *vfu_ctx, uint32_t region_idx, int fd, } elem->fd = fd; - elem->offset = offset; + elem->gpa_offset = gpa_offset; elem->size = size; elem->flags = flags; elem->datamatch = datamatch; elem->shadow_fd = shadow_fd; + elem->shadow_offset = shadow_offset; LIST_INSERT_HEAD(&vfu_reg->subregions, elem, entry); return 0; @@ -647,7 +648,7 @@ handle_device_get_region_io_fds(vfu_ctx_t *vfu_ctx, vfu_msg_t *msg) for (i = 0; i < max_sent_sub_regions; i++) { ioefd = &reply->sub_regions[i].ioeventfd; - ioefd->offset = sub_reg->offset; + ioefd->gpa_offset = sub_reg->gpa_offset; ioefd->size = sub_reg->size; ioefd->fd_index = add_fd_index(msg->out.fds, &msg->out.nr_fds, sub_reg->fd); @@ -655,11 +656,11 @@ handle_device_get_region_io_fds(vfu_ctx_t *vfu_ctx, vfu_msg_t *msg) ioefd->type = VFIO_USER_IO_FD_TYPE_IOEVENTFD; } else { ioefd->type = VFIO_USER_IO_FD_TYPE_IOEVENTFD_SHADOW; - int ret = add_fd_index(msg->out.fds, &msg->out.nr_fds, sub_reg->shadow_fd); - assert(ret == 1); + ioefd->shadow_mem_fd_index = add_fd_index(msg->out.fds, &msg->out.nr_fds, sub_reg->shadow_fd); } ioefd->flags = sub_reg->flags; ioefd->datamatch = sub_reg->datamatch; + ioefd->shadow_offset = sub_reg->shadow_offset; sub_reg = LIST_NEXT(sub_reg, entry); } diff --git a/lib/private.h b/lib/private.h index 60adfc9..346cfed 100644 --- a/lib/private.h +++ b/lib/private.h @@ -185,12 +185,13 @@ struct vfu_ctx { }; typedef struct ioeventfd { - uint64_t offset; + uint64_t gpa_offset; uint64_t size; int32_t fd; uint32_t flags; uint64_t datamatch; int32_t shadow_fd; + size_t shadow_offset; LIST_ENTRY(ioeventfd) entry; } ioeventfd_t; diff --git a/test/py/libvfio_user.py b/test/py/libvfio_user.py index 2bcd1bc..fd09fa8 100644 --- a/test/py/libvfio_user.py +++ b/test/py/libvfio_user.py @@ -410,13 +410,14 @@ class vfio_user_region_io_fds_request(Structure): class vfio_user_sub_region_ioeventfd(Structure): _pack_ = 1 _fields_ = [ - ("offset", c.c_uint64), + ("gpa_offset", c.c_uint64), ("size", c.c_uint64), ("fd_index", c.c_uint32), ("type", c.c_uint32), ("flags", c.c_uint32), - ("padding", c.c_uint32), - ("datamatch", c.c_uint64) + ("shadow_mem_fd_index", c.c_uint32), + ("datamatch", c.c_uint64), + ("shadow_offset", c.c_uint64) ] @@ -633,7 +634,7 @@ lib.vfu_sgl_put.argtypes = (c.c_void_p, c.POINTER(dma_sg_t), lib.vfu_create_ioeventfd.argtypes = (c.c_void_p, c.c_uint32, c.c_int, c.c_size_t, c.c_uint32, c.c_uint32, - c.c_uint64, c.c_int32) + c.c_uint64, c.c_int32, c.c_uint64) lib.vfu_device_quiesced.argtypes = (c.c_void_p, c.c_int) @@ -1207,12 +1208,12 @@ def vfu_sgl_put(ctx, sg, iovec, cnt=1): return lib.vfu_sgl_put(ctx, sg, iovec, cnt) -def vfu_create_ioeventfd(ctx, region_idx, fd, offset, size, flags, datamatch, - shadow_fd=-1): +def vfu_create_ioeventfd(ctx, region_idx, fd, gpa_offset, size, flags, + datamatch, shadow_fd=-1, shadow_offset=0): assert ctx is not None - return lib.vfu_create_ioeventfd(ctx, region_idx, fd, offset, size, - flags, datamatch, shadow_fd) + return lib.vfu_create_ioeventfd(ctx, region_idx, fd, gpa_offset, size, + flags, datamatch, shadow_fd, shadow_offset) def vfu_device_quiesced(ctx, err): diff --git a/test/py/test_device_get_region_io_fds.py b/test/py/test_device_get_region_io_fds.py index 924f462..b9c8d93 100644 --- a/test/py/test_device_get_region_io_fds.py +++ b/test/py/test_device_get_region_io_fds.py @@ -225,7 +225,7 @@ def test_device_get_region_io_fds_full(): [out] = struct.unpack("@Q", out) assert out == 1 assert ioevents[i].size == IOEVENT_SIZE - assert ioevents[i].offset == 40 - (IOEVENT_SIZE * i) + assert ioevents[i].gpa_offset == 40 - (IOEVENT_SIZE * i) assert ioevents[i].type == VFIO_USER_IO_FD_TYPE_IOEVENTFD for i in newfds: @@ -284,11 +284,11 @@ def test_device_get_region_io_fds_fds_read_write_dupe_fd(): [out] = struct.unpack("@Q", out) assert out == 1 assert ioevents[i].size == IOEVENT_SIZE - assert ioevents[i].offset == 56 - (IOEVENT_SIZE * i) + assert ioevents[i].gpa_offset == 56 - (IOEVENT_SIZE * i) assert ioevents[i].type == VFIO_USER_IO_FD_TYPE_IOEVENTFD assert ioevents[0].fd_index == ioevents[1].fd_index - assert ioevents[0].offset != ioevents[1].offset + assert ioevents[0].gpa_offset != ioevents[1].gpa_offset os.write(newfds[ioevents[0].fd_index], c.c_ulonglong(1)) diff --git a/test/py/test_shadow_ioeventfd.py b/test/py/test_shadow_ioeventfd.py index 642ad0e..c7cc4e5 100644 --- a/test/py/test_shadow_ioeventfd.py +++ b/test/py/test_shadow_ioeventfd.py @@ -54,7 +54,7 @@ def test_shadow_ioeventfd(): efd = eventfd(flags=EFD_NONBLOCK) ret = vfu_create_ioeventfd(ctx, VFU_PCI_DEV_BAR0_REGION_IDX, efd, 0x8, - 0x16, 0, 0, shadow_fd=fo.fileno()) + 0x16, 0, 0, shadow_fd=fo.fileno(), 0x10) assert ret == 0 ret = vfu_realize_ctx(ctx) assert ret == 0 @@ -70,12 +70,13 @@ def test_shadow_ioeventfd(): reply, ret = vfio_user_region_io_fds_reply.pop_from_buffer(ret) assert reply.count == 1 # 1 eventfd ioevent, _ = vfio_user_sub_region_ioeventfd.pop_from_buffer(ret) - assert ioevent.offset == 0x8 + assert ioevent.gpa_offset == 0x8 assert ioevent.size == 0x16 assert ioevent.fd_index == 0 assert ioevent.type == VFIO_USER_IO_FD_TYPE_IOEVENTFD_SHADOW assert ioevent.flags == 0 assert ioevent.datamatch == 0 + assert ioevent.shadow_offset = 0x10 assert len(newfds) == 2 # 2 FDs: eventfd plus shadow FD cefd = newfds[0] @@ -93,13 +94,13 @@ def test_shadow_ioeventfd(): # Client writes to the I/O region. The write to the eventfd would be done # by KVM and the value would be the same in both cases. - cmem.seek(0x8) + cmem.seek(ioevent.shadow_offset) cmem.write(c.c_ulonglong(0xdeadbeef)) os.write(cefd, c.c_ulonglong(0xcafebabe)) # vfio-user app reads eventfd assert os.read(efd, IOEVENT_SIZE) == to_bytes_le(0xcafebabe, 8) - fo.seek(0x8) + fo.seek(ioevent.shadow_offset) assert fo.read(0x8) == to_bytes_le(0xdeadbeef, 8) vfu_destroy_ctx(ctx) -- cgit v1.1