On Thu, Jun 22, 2023 at 10:19 PM Marc-André Lureau < marcandre.lur...@gmail.com> wrote:
> Hi > > On Wed, May 24, 2023 at 11:13 AM Albert Esteve <aest...@redhat.com> wrote: > >> Add new vhost-user protocol message >> `VHOST_USER_BACKEND_SHARED_OBJECT`. This new >> message is sent from vhost-user back-ends >> to interact with the virtio-dmabuf table >> in order to add, remove, or lookup for >> virtio dma-buf shared objects. >> >> The action taken in the front-end depends >> on the type stored in the payload struct. >> >> In the libvhost-user library add helper >> functions to allow sending messages to >> interact with the virtio shared objects >> hash table. >> >> Signed-off-by: Albert Esteve <aest...@redhat.com> >> --- >> docs/interop/vhost-user.rst | 15 ++++ >> hw/virtio/vhost-user.c | 68 ++++++++++++++++++ >> subprojects/libvhost-user/libvhost-user.c | 88 +++++++++++++++++++++++ >> subprojects/libvhost-user/libvhost-user.h | 56 +++++++++++++++ >> 4 files changed, 227 insertions(+) >> >> diff --git a/docs/interop/vhost-user.rst b/docs/interop/vhost-user.rst >> index 5a070adbc1..d3d8db41e5 100644 >> --- a/docs/interop/vhost-user.rst >> +++ b/docs/interop/vhost-user.rst >> @@ -1528,6 +1528,21 @@ is sent by the front-end. >> >> The state.num field is currently reserved and must be set to 0. >> >> +``VHOST_USER_BACKEND_SHARED_OBJECT`` >> + :id: 6 >> + :equivalent ioctl: N/A >> + :request payload: ``struct VhostUserShared`` >> + :reply payload: ``struct VhostUserShared`` (only for ``LOOKUP`` >> requests) >> > > only for LOOKUP, ahah... > I wasn't sure how to highlight that the reply was not required in all cases... > > >> + >> + Backends that need to interact with the virtio-dmabuf shared table API >> + can send this message. The operation is determined by the ``type`` >> member >> + of the payload struct. The valid values for the operation type are >> + ``VHOST_SHARED_OBJECT_*`` members, i.e., ``ADD``, ``LOOKUP``, and >> ``REMOVE``. >> > > ...why not use specific messages instead of this extra "type"? > I wouldn't mind having specific messages for each type. I initially opted for having it one message to avoid having the code that handles the message scattered. The logic of each operation is simple and this way we have a single handler method for all of them. Also, there are currently only a few slave requests available, so adding 3 new requests felt like a higher "overhead". But as I said, I don't have a strong opinion. Should I change it? > > > >> + ``LOOKUP`` operations require the ``VHOST_USER_NEED_REPLY_MASK`` flag >> to be >> + set by the back-end, and the front-end will then send the dma-buf fd as >> + a response if the UUID matches an object in the table, or a negative >> value >> + otherwise. >> > > This new message(s) should be initially negotiated with a protocol feature > flag. > Ok. Similar to `VHOST_USER_PROTOCOL_F_INBAND_NOTIFICATIONS` and `VHOST_USER_BACKEND_VRING_CALL`, where it checks the feature with `vu_has_protocol_feature`? The name could be `VHOST_USER_PROTOCOL_F_SHARED_OBJECT` (?). > > >> + >> .. _reply_ack: >> >> VHOST_USER_PROTOCOL_F_REPLY_ACK >> diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c >> index 74a2a28663..5ac5f0eafd 100644 >> --- a/hw/virtio/vhost-user.c >> +++ b/hw/virtio/vhost-user.c >> @@ -10,6 +10,7 @@ >> >> #include "qemu/osdep.h" >> #include "qapi/error.h" >> +#include "hw/virtio/virtio-dmabuf.h" >> #include "hw/virtio/vhost.h" >> #include "hw/virtio/vhost-user.h" >> #include "hw/virtio/vhost-backend.h" >> @@ -20,6 +21,7 @@ >> #include "sysemu/kvm.h" >> #include "qemu/error-report.h" >> #include "qemu/main-loop.h" >> +#include "qemu/uuid.h" >> #include "qemu/sockets.h" >> #include "sysemu/runstate.h" >> #include "sysemu/cryptodev.h" >> @@ -128,6 +130,7 @@ typedef enum VhostUserSlaveRequest { >> VHOST_USER_BACKEND_IOTLB_MSG = 1, >> VHOST_USER_BACKEND_CONFIG_CHANGE_MSG = 2, >> VHOST_USER_BACKEND_VRING_HOST_NOTIFIER_MSG = 3, >> + VHOST_USER_BACKEND_SHARED_OBJECT = 6, >> VHOST_USER_BACKEND_MAX >> } VhostUserSlaveRequest; >> >> @@ -190,6 +193,18 @@ typedef struct VhostUserInflight { >> uint16_t queue_size; >> } VhostUserInflight; >> >> +typedef enum VhostUserSharedType { >> + VHOST_SHARED_OBJECT_ADD = 0, >> + VHOST_SHARED_OBJECT_LOOKUP, >> + VHOST_SHARED_OBJECT_REMOVE, >> +} VhostUserSharedType; >> + >> +typedef struct VhostUserShared { >> + unsigned char uuid[16]; >> + VhostUserSharedType type; >> + int dmabuf_fd; >> +} VhostUserShared; >> + >> typedef struct { >> VhostUserRequest request; >> >> @@ -214,6 +229,7 @@ typedef union { >> VhostUserCryptoSession session; >> VhostUserVringArea area; >> VhostUserInflight inflight; >> + VhostUserShared object; >> } VhostUserPayload; >> >> typedef struct VhostUserMsg { >> @@ -1582,6 +1598,52 @@ static int >> vhost_user_slave_handle_vring_host_notifier(struct vhost_dev *dev, >> return 0; >> } >> >> +static int vhost_user_backend_handle_shared_object(VhostUserShared >> *object) >> +{ >> + QemuUUID uuid; >> + memcpy(uuid.data, object->uuid, sizeof(object->uuid)); >> + >> + switch (object->type) { >> + case VHOST_SHARED_OBJECT_ADD: >> + return virtio_add_dmabuf(&uuid, object->dmabuf_fd); >> + case VHOST_SHARED_OBJECT_LOOKUP: >> + object->dmabuf_fd = virtio_lookup_dmabuf(&uuid); >> + if (object->dmabuf_fd < 0) { >> + return object->dmabuf_fd; >> + } >> + break; >> + case VHOST_SHARED_OBJECT_REMOVE: >> + return virtio_remove_resource(&uuid); >> + } >> + >> + return 0; >> +} >> + >> +static bool >> +vhost_user_backend_send_dmabuf_fd(QIOChannel *ioc, VhostUserHeader *hdr, >> + VhostUserPayload *payload) >> +{ >> + Error *local_err = NULL; >> + struct iovec iov[2]; >> + if (hdr->flags & VHOST_USER_NEED_REPLY_MASK) { >> + hdr->flags &= ~VHOST_USER_NEED_REPLY_MASK; >> + hdr->flags |= VHOST_USER_REPLY_MASK; >> + >> + hdr->size = sizeof(payload->object); >> + >> + iov[0].iov_base = hdr; >> + iov[0].iov_len = VHOST_USER_HDR_SIZE; >> + iov[1].iov_base = payload; >> + iov[1].iov_len = hdr->size; >> + >> + if (qio_channel_writev_all(ioc, iov, ARRAY_SIZE(iov), >> &local_err)) { >> + error_report_err(local_err); >> + return false; >> + } >> + } >> + return true; >> +} >> + >> static void close_slave_channel(struct vhost_user *u) >> { >> g_source_destroy(u->slave_src); >> @@ -1639,6 +1701,12 @@ static gboolean slave_read(QIOChannel *ioc, >> GIOCondition condition, >> ret = vhost_user_slave_handle_vring_host_notifier(dev, >> &payload.area, >> fd ? fd[0] : >> -1); >> break; >> + case VHOST_USER_BACKEND_SHARED_OBJECT: >> + ret = vhost_user_backend_handle_shared_object(&payload.object); >> + if (!vhost_user_backend_send_dmabuf_fd(ioc, &hdr, &payload)) { >> + goto err; >> + } >> + break; >> default: >> error_report("Received unexpected msg type: %d.", hdr.request); >> ret = -EINVAL; >> diff --git a/subprojects/libvhost-user/libvhost-user.c >> b/subprojects/libvhost-user/libvhost-user.c >> index 8fb61e2df2..27f16d292a 100644 >> --- a/subprojects/libvhost-user/libvhost-user.c >> +++ b/subprojects/libvhost-user/libvhost-user.c >> @@ -1403,6 +1403,94 @@ bool vu_set_queue_host_notifier(VuDev *dev, >> VuVirtq *vq, int fd, >> return vu_process_message_reply(dev, &vmsg); >> } >> >> +bool >> +vu_get_shared_object(VuDev *dev, unsigned char uuid[UUID_LEN], int >> *dmabuf_fd) >> +{ >> + bool result = false; >> + VhostUserMsg msg_reply; >> + VhostUserMsg msg = { >> + .request = VHOST_USER_BACKEND_SHARED_OBJECT, >> + .size = sizeof(msg.payload.object), >> + .flags = VHOST_USER_VERSION | VHOST_USER_NEED_REPLY_MASK, >> + .payload.object = { >> + .type = VHOST_SHARED_OBJECT_LOOKUP, >> + }, >> + }; >> + >> + memcpy(msg.payload.object.uuid, uuid, sizeof(uuid[0]) * UUID_LEN); >> + >> + pthread_mutex_lock(&dev->slave_mutex); >> + if (!vu_message_write(dev, dev->slave_fd, &msg)) { >> + goto out; >> + } >> + >> + if (!vu_message_read_default(dev, dev->slave_fd, &msg_reply)) { >> + goto out; >> + } >> + >> + if (msg_reply.request != msg.request) { >> + DPRINT("Received unexpected msg type. Expected %d, received %d", >> + msg.request, msg_reply.request); >> + goto out; >> + } >> + >> + *dmabuf_fd = msg_reply.payload.object.dmabuf_fd; >> + result = *dmabuf_fd > 0; >> +out: >> + pthread_mutex_unlock(&dev->slave_mutex); >> + >> + return result; >> +} >> + >> +static bool >> +vu_send_message(VuDev *dev, VhostUserMsg *vmsg) >> +{ >> + bool result = false; >> + pthread_mutex_lock(&dev->slave_mutex); >> + if (!vu_message_write(dev, dev->slave_fd, vmsg)) { >> + goto out; >> + } >> + >> + result = true; >> +out: >> + pthread_mutex_unlock(&dev->slave_mutex); >> + >> + return result; >> +} >> + >> +bool >> +vu_add_shared_object(VuDev *dev, unsigned char uuid[UUID_LEN], int >> dmabuf_fd) >> +{ >> + VhostUserMsg msg = { >> + .request = VHOST_USER_BACKEND_SHARED_OBJECT, >> + .size = sizeof(msg.payload.object), >> + .flags = VHOST_USER_VERSION, >> + .payload.object = { >> + .dmabuf_fd = dmabuf_fd, >> + .type = VHOST_SHARED_OBJECT_ADD, >> + }, >> + }; >> + memcpy(msg.payload.object.uuid, uuid, sizeof(uuid[0]) * UUID_LEN); >> + >> + return vu_send_message(dev, &msg); >> +} >> + >> +bool >> +vu_rm_shared_object(VuDev *dev, unsigned char uuid[UUID_LEN]) >> +{ >> + VhostUserMsg msg = { >> + .request = VHOST_USER_BACKEND_SHARED_OBJECT, >> + .size = sizeof(msg.payload.object), >> + .flags = VHOST_USER_VERSION, >> + .payload.object = { >> + .type = VHOST_SHARED_OBJECT_REMOVE, >> + }, >> + }; >> + memcpy(msg.payload.object.uuid, uuid, sizeof(uuid[0]) * UUID_LEN); >> + >> + return vu_send_message(dev, &msg); >> +} >> + >> static bool >> vu_set_vring_call_exec(VuDev *dev, VhostUserMsg *vmsg) >> { >> diff --git a/subprojects/libvhost-user/libvhost-user.h >> b/subprojects/libvhost-user/libvhost-user.h >> index 49208cceaa..a43d115bd7 100644 >> --- a/subprojects/libvhost-user/libvhost-user.h >> +++ b/subprojects/libvhost-user/libvhost-user.h >> @@ -119,6 +119,7 @@ typedef enum VhostUserSlaveRequest { >> VHOST_USER_BACKEND_VRING_HOST_NOTIFIER_MSG = 3, >> VHOST_USER_BACKEND_VRING_CALL = 4, >> VHOST_USER_BACKEND_VRING_ERR = 5, >> + VHOST_USER_BACKEND_SHARED_OBJECT = 6, >> VHOST_USER_BACKEND_MAX >> } VhostUserSlaveRequest; >> >> @@ -172,6 +173,20 @@ typedef struct VhostUserInflight { >> uint16_t queue_size; >> } VhostUserInflight; >> >> +typedef enum VhostUserSharedType { >> + VHOST_SHARED_OBJECT_ADD = 0, >> + VHOST_SHARED_OBJECT_LOOKUP, >> + VHOST_SHARED_OBJECT_REMOVE, >> +} VhostUserSharedType; >> + >> +#define UUID_LEN 16 >> + >> +typedef struct VhostUserShared { >> + unsigned char uuid[UUID_LEN]; >> + VhostUserSharedType type; >> + int dmabuf_fd; >> +} VhostUserShared; >> + >> #if defined(_WIN32) && (defined(__x86_64__) || defined(__i386__)) >> # define VU_PACKED __attribute__((gcc_struct, packed)) >> #else >> @@ -199,6 +214,7 @@ typedef struct VhostUserMsg { >> VhostUserConfig config; >> VhostUserVringArea area; >> VhostUserInflight inflight; >> + VhostUserShared object; >> } payload; >> >> int fds[VHOST_MEMORY_BASELINE_NREGIONS]; >> @@ -539,6 +555,46 @@ void vu_set_queue_handler(VuDev *dev, VuVirtq *vq, >> bool vu_set_queue_host_notifier(VuDev *dev, VuVirtq *vq, int fd, >> int size, int offset); >> >> +/** >> + * vu_get_shared_object: >> + * @dev: a VuDev context >> + * @uuid: UUID of the shared object >> + * @dmabuf_fd: output dma-buf file descriptor >> + * >> + * Lookup for a virtio shared object (i.e., dma-buf fd) associated with >> the >> + * received UUID. Result, if found, is stored in the dmabuf_fd argument. >> + * >> + * Returns: whether the virtio object was found. >> + */ >> +bool vu_get_shared_object(VuDev *dev, unsigned char uuid[UUID_LEN], >> + int *dmabuf_fd); >> + >> +/** >> + * vu_add_shared_object: >> + * @dev: a VuDev context >> + * @uuid: UUID of the shared object >> + * @dmabuf_fd: output dma-buf file descriptor >> + * >> + * Stores a new shared object (i.e., dma-buf fd) in the hash table, and >> + * associates it with the received UUID. >> + * >> + * Returns: TRUE on success, FALSE on failure. >> + */ >> +bool vu_add_shared_object(VuDev *dev, unsigned char uuid[UUID_LEN], >> + int dmabuf_fd); >> + >> +/** >> + * vu_rm_shared_object: >> + * @dev: a VuDev context >> + * @uuid: UUID of the shared object >> + * >> + * Removes a shared object (i.e., dma-buf fd) associated with the >> + * received UUID from the hash table. >> + * >> + * Returns: TRUE on success, FALSE on failure. >> + */ >> +bool vu_rm_shared_object(VuDev *dev, unsigned char uuid[UUID_LEN]); >> + >> /** >> * vu_queue_set_notification: >> * @dev: a VuDev context >> -- >> 2.40.0 >> >> > > -- > Marc-André Lureau > Thanks! Albert Esteve