diff --git a/include/libvfio-user.h b/include/libvfio-user.h index 84eb2d88..1cfd5e50 100644 --- a/include/libvfio-user.h +++ b/include/libvfio-user.h @@ -1073,7 +1073,7 @@ vfu_sg_is_mappable(vfu_ctx_t *vfu_ctx, dma_sg_t *sg); 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); + uint64_t datamatch, int data_fd); #ifdef __cplusplus } diff --git a/include/vfio-user.h b/include/vfio-user.h index 7439484b..dc6fafaa 100644 --- a/include/vfio-user.h +++ b/include/vfio-user.h @@ -168,6 +168,7 @@ typedef struct vfio_user_region_io_fds_request { #define VFIO_USER_IO_FD_TYPE_IOEVENTFD 0 #define VFIO_USER_IO_FD_TYPE_IOREGIONFD 1 +#define VFIO_USER_IO_FD_TYPE_IOEVENTFD_SHADOW 2 typedef struct vfio_user_sub_region_ioeventfd { uint64_t offset; diff --git a/lib/libvfio-user.c b/lib/libvfio-user.c index ac04d3ba..9a9a6a15 100644 --- a/lib/libvfio-user.c +++ b/lib/libvfio-user.c @@ -467,7 +467,7 @@ 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) + uint64_t datamatch, int data_fd) { vfu_reg_info_t *vfu_reg; @@ -494,6 +494,7 @@ vfu_create_ioeventfd(vfu_ctx_t *vfu_ctx, uint32_t region_idx, int fd, elem->size = size; elem->flags = flags; elem->datamatch = datamatch; + elem->data_fd = data_fd; LIST_INSERT_HEAD(&vfu_reg->subregions, elem, entry); return 0; @@ -580,6 +581,7 @@ handle_device_get_region_io_fds(vfu_ctx_t *vfu_ctx, vfu_msg_t *msg) // At least one flag must be set for a valid region. if (!(vfu_reg->flags & VFU_REGION_FLAG_MASK)) { + vfu_log(vfu_ctx, LOG_DEBUG, "no flag for region index %d", req->index); return ERROR_INT(EINVAL); } @@ -627,7 +629,13 @@ handle_device_get_region_io_fds(vfu_ctx_t *vfu_ctx, vfu_msg_t *msg) ioefd->size = sub_reg->size; ioefd->fd_index = add_fd_index(msg->out.fds, &msg->out.nr_fds, sub_reg->fd); - ioefd->type = VFIO_USER_IO_FD_TYPE_IOEVENTFD; + if (sub_reg->data_fd == -1) { + 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->nr_out_fds, sub_reg->data_fd); + assert(ret == 1); + } ioefd->flags = sub_reg->flags; ioefd->datamatch = sub_reg->datamatch; @@ -1832,6 +1840,10 @@ vfu_setup_region(vfu_ctx_t *vfu_ctx, int region_idx, size_t size, assert(vfu_ctx != NULL); + /* + * FIXME should we set a flag in the region to indicate that it has I/O + * region FDs? This way the client won't have to blindly look for them. + */ if ((flags & ~(VFU_REGION_FLAG_MASK)) || (!(flags & VFU_REGION_FLAG_RW))) { vfu_log(vfu_ctx, LOG_ERR, "invalid region flags"); diff --git a/lib/private.h b/lib/private.h index 7ffd6bec..29bc8b85 100644 --- a/lib/private.h +++ b/lib/private.h @@ -186,6 +186,7 @@ typedef struct ioeventfd { int32_t fd; uint32_t flags; uint64_t datamatch; + int32_t data_fd; LIST_ENTRY(ioeventfd) entry; } ioeventfd_t;