vhost-user: add shared_object msg

Add three new vhost-user protocol
`VHOST_USER_BACKEND_SHARED_OBJECT_* messages`.
These new messages are sent from vhost-user
back-ends to interact with the virtio-dmabuf
table in order to add or remove themselves as
virtio exporters, or lookup for virtio dma-buf
shared objects.

The action taken in the front-end depends
on the type stored in the virtio shared
object hash table.

When the table holds a pointer to a vhost
backend for a given UUID, the front-end sends
a VHOST_USER_GET_SHARED_OBJECT to the
backend holding the shared object.

The messages can only be sent after successfully
negotiating a new VHOST_USER_PROTOCOL_F_SHARED_OBJECT
vhost-user protocol feature bit.

Finally, refactor code to send response message so
that all common parts both for the common REPLY_ACK
case, and other data responses, can call it and
avoid code repetition.

Signed-off-by: Albert Esteve <aesteve@redhat.com>
Message-Id: <20231002065706.94707-4-aesteve@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
This commit is contained in:
Albert Esteve 2023-10-02 08:57:05 +02:00 committed by Michael S. Tsirkin
parent faefdba847
commit 1609476662
4 changed files with 216 additions and 12 deletions

View File

@ -1440,6 +1440,18 @@ Front-end message types
query the back-end for its device status as defined in the Virtio
specification.
``VHOST_USER_GET_SHARED_OBJECT``
:id: 41
:equivalent ioctl: N/A
:request payload: ``struct VhostUserShared``
:reply payload: dmabuf fd
When the ``VHOST_USER_PROTOCOL_F_SHARED_OBJECT`` protocol
feature has been successfully negotiated, and the UUID is found
in the exporters cache, this message is submitted by the front-end
to retrieve a given dma-buf fd from a given back-end, determined by
the requested UUID. Back-end will reply passing the fd when the operation
is successful, or no fd otherwise.
Back-end message types
----------------------
@ -1528,6 +1540,51 @@ is sent by the front-end.
The state.num field is currently reserved and must be set to 0.
``VHOST_USER_BACKEND_SHARED_OBJECT_ADD``
:id: 6
:equivalent ioctl: N/A
:request payload: ``struct VhostUserShared``
:reply payload: N/A
When the ``VHOST_USER_PROTOCOL_F_SHARED_OBJECT`` protocol
feature has been successfully negotiated, this message can be submitted
by the backends to add themselves as exporters to the virtio shared lookup
table. The back-end device gets associated with a UUID in the shared table.
The back-end is responsible of keeping its own table with exported dma-buf fds.
When another back-end tries to import the resource associated with the UUID,
it will send a message to the front-end, which will act as a proxy to the
exporter back-end. If ``VHOST_USER_PROTOCOL_F_REPLY_ACK`` is negotiated, and
the back-end sets the ``VHOST_USER_NEED_REPLY`` flag, the front-end must
respond with zero when operation is successfully completed, or non-zero
otherwise.
``VHOST_USER_BACKEND_SHARED_OBJECT_REMOVE``
:id: 7
:equivalent ioctl: N/A
:request payload: ``struct VhostUserShared``
:reply payload: N/A
When the ``VHOST_USER_PROTOCOL_F_SHARED_OBJECT`` protocol
feature has been successfully negotiated, this message can be submitted
by the backend to remove themselves from to the virtio-dmabuf shared
table API. The shared table will remove the back-end device associated with
the UUID. If ``VHOST_USER_PROTOCOL_F_REPLY_ACK`` is negotiated, and the
back-end sets the ``VHOST_USER_NEED_REPLY`` flag, the front-end must respond
with zero when operation is successfully completed, or non-zero otherwise.
``VHOST_USER_BACKEND_SHARED_OBJECT_LOOKUP``
:id: 8
:equivalent ioctl: N/A
:request payload: ``struct VhostUserShared``
:reply payload: dmabuf fd and ``u64``
When the ``VHOST_USER_PROTOCOL_F_SHARED_OBJECT`` protocol
feature has been successfully negotiated, this message can be submitted
by the backends to retrieve a given dma-buf fd from the virtio-dmabuf
shared table given a UUID. Frontend will reply passing the fd and a zero
when the operation is successful, or non-zero otherwise. Note that if the
operation fails, no fd is sent to the backend.
.. _reply_ack:
VHOST_USER_PROTOCOL_F_REPLY_ACK

View File

@ -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/virtio-crypto.h"
#include "hw/virtio/vhost-user.h"
@ -21,6 +22,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"
@ -100,6 +102,7 @@ typedef enum VhostUserRequest {
VHOST_USER_REM_MEM_REG = 38,
VHOST_USER_SET_STATUS = 39,
VHOST_USER_GET_STATUS = 40,
VHOST_USER_GET_SHARED_OBJECT = 41,
VHOST_USER_MAX
} VhostUserRequest;
@ -108,6 +111,9 @@ typedef enum VhostUserBackendRequest {
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_ADD = 6,
VHOST_USER_BACKEND_SHARED_OBJECT_REMOVE = 7,
VHOST_USER_BACKEND_SHARED_OBJECT_LOOKUP = 8,
VHOST_USER_BACKEND_MAX
} VhostUserBackendRequest;
@ -181,6 +187,10 @@ typedef struct VhostUserInflight {
uint16_t queue_size;
} VhostUserInflight;
typedef struct VhostUserShared {
unsigned char uuid[16];
} VhostUserShared;
typedef struct {
VhostUserRequest request;
@ -205,6 +215,7 @@ typedef union {
VhostUserCryptoSession session;
VhostUserVringArea area;
VhostUserInflight inflight;
VhostUserShared object;
} VhostUserPayload;
typedef struct VhostUserMsg {
@ -1580,6 +1591,139 @@ static int vhost_user_backend_handle_vring_host_notifier(struct vhost_dev *dev,
return 0;
}
static int
vhost_user_backend_handle_shared_object_add(struct vhost_dev *dev,
VhostUserShared *object)
{
QemuUUID uuid;
memcpy(uuid.data, object->uuid, sizeof(object->uuid));
return virtio_add_vhost_device(&uuid, dev);
}
static int
vhost_user_backend_handle_shared_object_remove(VhostUserShared *object)
{
QemuUUID uuid;
memcpy(uuid.data, object->uuid, sizeof(object->uuid));
return virtio_remove_resource(&uuid);
}
static bool vhost_user_send_resp(QIOChannel *ioc, VhostUserHeader *hdr,
VhostUserPayload *payload, Error **errp)
{
struct iovec iov[] = {
{ .iov_base = hdr, .iov_len = VHOST_USER_HDR_SIZE },
{ .iov_base = payload, .iov_len = hdr->size },
};
hdr->flags &= ~VHOST_USER_NEED_REPLY_MASK;
hdr->flags |= VHOST_USER_REPLY_MASK;
return !qio_channel_writev_all(ioc, iov, ARRAY_SIZE(iov), errp);
}
static bool
vhost_user_backend_send_dmabuf_fd(QIOChannel *ioc, VhostUserHeader *hdr,
VhostUserPayload *payload, Error **errp)
{
hdr->size = sizeof(payload->u64);
return vhost_user_send_resp(ioc, hdr, payload, errp);
}
int vhost_user_get_shared_object(struct vhost_dev *dev, unsigned char *uuid,
int *dmabuf_fd)
{
struct vhost_user *u = dev->opaque;
CharBackend *chr = u->user->chr;
int ret;
VhostUserMsg msg = {
.hdr.request = VHOST_USER_GET_SHARED_OBJECT,
.hdr.flags = VHOST_USER_VERSION,
};
memcpy(msg.payload.object.uuid, uuid, sizeof(msg.payload.object.uuid));
ret = vhost_user_write(dev, &msg, NULL, 0);
if (ret < 0) {
return ret;
}
ret = vhost_user_read(dev, &msg);
if (ret < 0) {
return ret;
}
if (msg.hdr.request != VHOST_USER_GET_SHARED_OBJECT) {
error_report("Received unexpected msg type. "
"Expected %d received %d",
VHOST_USER_GET_SHARED_OBJECT, msg.hdr.request);
return -EPROTO;
}
*dmabuf_fd = qemu_chr_fe_get_msgfd(chr);
if (*dmabuf_fd < 0) {
error_report("Failed to get dmabuf fd");
return -EIO;
}
return 0;
}
static int
vhost_user_backend_handle_shared_object_lookup(struct vhost_user *u,
QIOChannel *ioc,
VhostUserHeader *hdr,
VhostUserPayload *payload)
{
QemuUUID uuid;
CharBackend *chr = u->user->chr;
Error *local_err = NULL;
int dmabuf_fd = -1;
int fd_num = 0;
memcpy(uuid.data, payload->object.uuid, sizeof(payload->object.uuid));
payload->u64 = 0;
switch (virtio_object_type(&uuid)) {
case TYPE_DMABUF:
dmabuf_fd = virtio_lookup_dmabuf(&uuid);
break;
case TYPE_VHOST_DEV:
{
struct vhost_dev *dev = virtio_lookup_vhost_device(&uuid);
if (dev == NULL) {
payload->u64 = -EINVAL;
break;
}
int ret = vhost_user_get_shared_object(dev, uuid.data, &dmabuf_fd);
if (ret < 0) {
payload->u64 = ret;
}
break;
}
case TYPE_INVALID:
payload->u64 = -EINVAL;
break;
}
if (dmabuf_fd != -1) {
fd_num++;
}
if (qemu_chr_fe_set_msgfds(chr, &dmabuf_fd, fd_num) < 0) {
error_report("Failed to set msg fds.");
payload->u64 = -EINVAL;
}
if (!vhost_user_backend_send_dmabuf_fd(ioc, hdr, payload, &local_err)) {
error_report_err(local_err);
return -EINVAL;
}
return 0;
}
static void close_backend_channel(struct vhost_user *u)
{
g_source_destroy(u->backend_src);
@ -1637,6 +1781,16 @@ static gboolean backend_read(QIOChannel *ioc, GIOCondition condition,
ret = vhost_user_backend_handle_vring_host_notifier(dev, &payload.area,
fd ? fd[0] : -1);
break;
case VHOST_USER_BACKEND_SHARED_OBJECT_ADD:
ret = vhost_user_backend_handle_shared_object_add(dev, &payload.object);
break;
case VHOST_USER_BACKEND_SHARED_OBJECT_REMOVE:
ret = vhost_user_backend_handle_shared_object_remove(&payload.object);
break;
case VHOST_USER_BACKEND_SHARED_OBJECT_LOOKUP:
ret = vhost_user_backend_handle_shared_object_lookup(dev->opaque, ioc,
&hdr, &payload);
break;
default:
error_report("Received unexpected msg type: %d.", hdr.request);
ret = -EINVAL;
@ -1647,21 +1801,10 @@ static gboolean backend_read(QIOChannel *ioc, GIOCondition condition,
* directly in their request handlers.
*/
if (hdr.flags & VHOST_USER_NEED_REPLY_MASK) {
struct iovec iovec[2];
hdr.flags &= ~VHOST_USER_NEED_REPLY_MASK;
hdr.flags |= VHOST_USER_REPLY_MASK;
payload.u64 = !!ret;
hdr.size = sizeof(payload.u64);
iovec[0].iov_base = &hdr;
iovec[0].iov_len = VHOST_USER_HDR_SIZE;
iovec[1].iov_base = &payload;
iovec[1].iov_len = hdr.size;
if (qio_channel_writev_all(ioc, iovec, ARRAY_SIZE(iovec), &local_err)) {
if (!vhost_user_send_resp(ioc, &hdr, &payload, &local_err)) {
error_report_err(local_err);
goto err;
}

View File

@ -196,4 +196,7 @@ int vhost_backend_handle_iotlb_msg(struct vhost_dev *dev,
int vhost_user_gpu_set_socket(struct vhost_dev *dev, int fd);
int vhost_user_get_shared_object(struct vhost_dev *dev, unsigned char *uuid,
int *dmabuf_fd);
#endif /* VHOST_BACKEND_H */

View File

@ -29,6 +29,7 @@ enum VhostUserProtocolFeature {
VHOST_USER_PROTOCOL_F_INBAND_NOTIFICATIONS = 14,
VHOST_USER_PROTOCOL_F_CONFIGURE_MEM_SLOTS = 15,
VHOST_USER_PROTOCOL_F_STATUS = 16,
VHOST_USER_PROTOCOL_F_SHARED_OBJECT = 17,
VHOST_USER_PROTOCOL_F_MAX
};