mirror of https://github.com/xemu-project/xemu.git
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:
parent
faefdba847
commit
1609476662
|
@ -1440,6 +1440,18 @@ Front-end message types
|
||||||
query the back-end for its device status as defined in the Virtio
|
query the back-end for its device status as defined in the Virtio
|
||||||
specification.
|
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
|
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.
|
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:
|
.. _reply_ack:
|
||||||
|
|
||||||
VHOST_USER_PROTOCOL_F_REPLY_ACK
|
VHOST_USER_PROTOCOL_F_REPLY_ACK
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
|
|
||||||
#include "qemu/osdep.h"
|
#include "qemu/osdep.h"
|
||||||
#include "qapi/error.h"
|
#include "qapi/error.h"
|
||||||
|
#include "hw/virtio/virtio-dmabuf.h"
|
||||||
#include "hw/virtio/vhost.h"
|
#include "hw/virtio/vhost.h"
|
||||||
#include "hw/virtio/virtio-crypto.h"
|
#include "hw/virtio/virtio-crypto.h"
|
||||||
#include "hw/virtio/vhost-user.h"
|
#include "hw/virtio/vhost-user.h"
|
||||||
|
@ -21,6 +22,7 @@
|
||||||
#include "sysemu/kvm.h"
|
#include "sysemu/kvm.h"
|
||||||
#include "qemu/error-report.h"
|
#include "qemu/error-report.h"
|
||||||
#include "qemu/main-loop.h"
|
#include "qemu/main-loop.h"
|
||||||
|
#include "qemu/uuid.h"
|
||||||
#include "qemu/sockets.h"
|
#include "qemu/sockets.h"
|
||||||
#include "sysemu/runstate.h"
|
#include "sysemu/runstate.h"
|
||||||
#include "sysemu/cryptodev.h"
|
#include "sysemu/cryptodev.h"
|
||||||
|
@ -100,6 +102,7 @@ typedef enum VhostUserRequest {
|
||||||
VHOST_USER_REM_MEM_REG = 38,
|
VHOST_USER_REM_MEM_REG = 38,
|
||||||
VHOST_USER_SET_STATUS = 39,
|
VHOST_USER_SET_STATUS = 39,
|
||||||
VHOST_USER_GET_STATUS = 40,
|
VHOST_USER_GET_STATUS = 40,
|
||||||
|
VHOST_USER_GET_SHARED_OBJECT = 41,
|
||||||
VHOST_USER_MAX
|
VHOST_USER_MAX
|
||||||
} VhostUserRequest;
|
} VhostUserRequest;
|
||||||
|
|
||||||
|
@ -108,6 +111,9 @@ typedef enum VhostUserBackendRequest {
|
||||||
VHOST_USER_BACKEND_IOTLB_MSG = 1,
|
VHOST_USER_BACKEND_IOTLB_MSG = 1,
|
||||||
VHOST_USER_BACKEND_CONFIG_CHANGE_MSG = 2,
|
VHOST_USER_BACKEND_CONFIG_CHANGE_MSG = 2,
|
||||||
VHOST_USER_BACKEND_VRING_HOST_NOTIFIER_MSG = 3,
|
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
|
VHOST_USER_BACKEND_MAX
|
||||||
} VhostUserBackendRequest;
|
} VhostUserBackendRequest;
|
||||||
|
|
||||||
|
@ -181,6 +187,10 @@ typedef struct VhostUserInflight {
|
||||||
uint16_t queue_size;
|
uint16_t queue_size;
|
||||||
} VhostUserInflight;
|
} VhostUserInflight;
|
||||||
|
|
||||||
|
typedef struct VhostUserShared {
|
||||||
|
unsigned char uuid[16];
|
||||||
|
} VhostUserShared;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
VhostUserRequest request;
|
VhostUserRequest request;
|
||||||
|
|
||||||
|
@ -205,6 +215,7 @@ typedef union {
|
||||||
VhostUserCryptoSession session;
|
VhostUserCryptoSession session;
|
||||||
VhostUserVringArea area;
|
VhostUserVringArea area;
|
||||||
VhostUserInflight inflight;
|
VhostUserInflight inflight;
|
||||||
|
VhostUserShared object;
|
||||||
} VhostUserPayload;
|
} VhostUserPayload;
|
||||||
|
|
||||||
typedef struct VhostUserMsg {
|
typedef struct VhostUserMsg {
|
||||||
|
@ -1580,6 +1591,139 @@ static int vhost_user_backend_handle_vring_host_notifier(struct vhost_dev *dev,
|
||||||
return 0;
|
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)
|
static void close_backend_channel(struct vhost_user *u)
|
||||||
{
|
{
|
||||||
g_source_destroy(u->backend_src);
|
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,
|
ret = vhost_user_backend_handle_vring_host_notifier(dev, &payload.area,
|
||||||
fd ? fd[0] : -1);
|
fd ? fd[0] : -1);
|
||||||
break;
|
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:
|
default:
|
||||||
error_report("Received unexpected msg type: %d.", hdr.request);
|
error_report("Received unexpected msg type: %d.", hdr.request);
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
|
@ -1647,21 +1801,10 @@ static gboolean backend_read(QIOChannel *ioc, GIOCondition condition,
|
||||||
* directly in their request handlers.
|
* directly in their request handlers.
|
||||||
*/
|
*/
|
||||||
if (hdr.flags & VHOST_USER_NEED_REPLY_MASK) {
|
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;
|
payload.u64 = !!ret;
|
||||||
hdr.size = sizeof(payload.u64);
|
hdr.size = sizeof(payload.u64);
|
||||||
|
|
||||||
iovec[0].iov_base = &hdr;
|
if (!vhost_user_send_resp(ioc, &hdr, &payload, &local_err)) {
|
||||||
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)) {
|
|
||||||
error_report_err(local_err);
|
error_report_err(local_err);
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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_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 */
|
#endif /* VHOST_BACKEND_H */
|
||||||
|
|
|
@ -29,6 +29,7 @@ enum VhostUserProtocolFeature {
|
||||||
VHOST_USER_PROTOCOL_F_INBAND_NOTIFICATIONS = 14,
|
VHOST_USER_PROTOCOL_F_INBAND_NOTIFICATIONS = 14,
|
||||||
VHOST_USER_PROTOCOL_F_CONFIGURE_MEM_SLOTS = 15,
|
VHOST_USER_PROTOCOL_F_CONFIGURE_MEM_SLOTS = 15,
|
||||||
VHOST_USER_PROTOCOL_F_STATUS = 16,
|
VHOST_USER_PROTOCOL_F_STATUS = 16,
|
||||||
|
VHOST_USER_PROTOCOL_F_SHARED_OBJECT = 17,
|
||||||
VHOST_USER_PROTOCOL_F_MAX
|
VHOST_USER_PROTOCOL_F_MAX
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue