mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-05 08:43:55 -06:00
vhost-user: Support transferring inflight buffer between qemu and backend
This patch introduces two new messages VHOST_USER_GET_INFLIGHT_FD and VHOST_USER_SET_INFLIGHT_FD to support transferring a shared buffer between qemu and backend. Firstly, qemu uses VHOST_USER_GET_INFLIGHT_FD to get the shared buffer from backend. Then qemu should send it back through VHOST_USER_SET_INFLIGHT_FD each time we start vhost-user. This shared buffer is used to track inflight I/O by backend. Qemu should retrieve a new one when vm reset. Signed-off-by: Xie Yongji <xieyongji@baidu.com> Signed-off-by: Chai Wen <chaiwen@baidu.com> Signed-off-by: Zhang Yu <zhangyu31@baidu.com> Message-Id: <20190228085355.9614-2-xieyongji@baidu.com> Reviewed-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: Michael S. Tsirkin <mst@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
1b8fff5758
commit
5ad204bf2a
5 changed files with 516 additions and 0 deletions
|
@ -56,6 +56,7 @@ enum VhostUserProtocolFeature {
|
|||
VHOST_USER_PROTOCOL_F_CONFIG = 9,
|
||||
VHOST_USER_PROTOCOL_F_SLAVE_SEND_FD = 10,
|
||||
VHOST_USER_PROTOCOL_F_HOST_NOTIFIER = 11,
|
||||
VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD = 12,
|
||||
VHOST_USER_PROTOCOL_F_MAX
|
||||
};
|
||||
|
||||
|
@ -93,6 +94,8 @@ typedef enum VhostUserRequest {
|
|||
VHOST_USER_POSTCOPY_ADVISE = 28,
|
||||
VHOST_USER_POSTCOPY_LISTEN = 29,
|
||||
VHOST_USER_POSTCOPY_END = 30,
|
||||
VHOST_USER_GET_INFLIGHT_FD = 31,
|
||||
VHOST_USER_SET_INFLIGHT_FD = 32,
|
||||
VHOST_USER_MAX
|
||||
} VhostUserRequest;
|
||||
|
||||
|
@ -151,6 +154,13 @@ typedef struct VhostUserVringArea {
|
|||
uint64_t offset;
|
||||
} VhostUserVringArea;
|
||||
|
||||
typedef struct VhostUserInflight {
|
||||
uint64_t mmap_size;
|
||||
uint64_t mmap_offset;
|
||||
uint16_t num_queues;
|
||||
uint16_t queue_size;
|
||||
} VhostUserInflight;
|
||||
|
||||
typedef struct {
|
||||
VhostUserRequest request;
|
||||
|
||||
|
@ -173,6 +183,7 @@ typedef union {
|
|||
VhostUserConfig config;
|
||||
VhostUserCryptoSession session;
|
||||
VhostUserVringArea area;
|
||||
VhostUserInflight inflight;
|
||||
} VhostUserPayload;
|
||||
|
||||
typedef struct VhostUserMsg {
|
||||
|
@ -1770,6 +1781,100 @@ static bool vhost_user_mem_section_filter(struct vhost_dev *dev,
|
|||
return result;
|
||||
}
|
||||
|
||||
static int vhost_user_get_inflight_fd(struct vhost_dev *dev,
|
||||
uint16_t queue_size,
|
||||
struct vhost_inflight *inflight)
|
||||
{
|
||||
void *addr;
|
||||
int fd;
|
||||
struct vhost_user *u = dev->opaque;
|
||||
CharBackend *chr = u->user->chr;
|
||||
VhostUserMsg msg = {
|
||||
.hdr.request = VHOST_USER_GET_INFLIGHT_FD,
|
||||
.hdr.flags = VHOST_USER_VERSION,
|
||||
.payload.inflight.num_queues = dev->nvqs,
|
||||
.payload.inflight.queue_size = queue_size,
|
||||
.hdr.size = sizeof(msg.payload.inflight),
|
||||
};
|
||||
|
||||
if (!virtio_has_feature(dev->protocol_features,
|
||||
VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (vhost_user_write(dev, &msg, NULL, 0) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (vhost_user_read(dev, &msg) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (msg.hdr.request != VHOST_USER_GET_INFLIGHT_FD) {
|
||||
error_report("Received unexpected msg type. "
|
||||
"Expected %d received %d",
|
||||
VHOST_USER_GET_INFLIGHT_FD, msg.hdr.request);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (msg.hdr.size != sizeof(msg.payload.inflight)) {
|
||||
error_report("Received bad msg size.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!msg.payload.inflight.mmap_size) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
fd = qemu_chr_fe_get_msgfd(chr);
|
||||
if (fd < 0) {
|
||||
error_report("Failed to get mem fd");
|
||||
return -1;
|
||||
}
|
||||
|
||||
addr = mmap(0, msg.payload.inflight.mmap_size, PROT_READ | PROT_WRITE,
|
||||
MAP_SHARED, fd, msg.payload.inflight.mmap_offset);
|
||||
|
||||
if (addr == MAP_FAILED) {
|
||||
error_report("Failed to mmap mem fd");
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
inflight->addr = addr;
|
||||
inflight->fd = fd;
|
||||
inflight->size = msg.payload.inflight.mmap_size;
|
||||
inflight->offset = msg.payload.inflight.mmap_offset;
|
||||
inflight->queue_size = queue_size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vhost_user_set_inflight_fd(struct vhost_dev *dev,
|
||||
struct vhost_inflight *inflight)
|
||||
{
|
||||
VhostUserMsg msg = {
|
||||
.hdr.request = VHOST_USER_SET_INFLIGHT_FD,
|
||||
.hdr.flags = VHOST_USER_VERSION,
|
||||
.payload.inflight.mmap_size = inflight->size,
|
||||
.payload.inflight.mmap_offset = inflight->offset,
|
||||
.payload.inflight.num_queues = dev->nvqs,
|
||||
.payload.inflight.queue_size = inflight->queue_size,
|
||||
.hdr.size = sizeof(msg.payload.inflight),
|
||||
};
|
||||
|
||||
if (!virtio_has_feature(dev->protocol_features,
|
||||
VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (vhost_user_write(dev, &msg, &inflight->fd, 1) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool vhost_user_init(VhostUserState *user, CharBackend *chr, Error **errp)
|
||||
{
|
||||
if (user->chr) {
|
||||
|
@ -1829,4 +1934,6 @@ const VhostOps user_ops = {
|
|||
.vhost_crypto_create_session = vhost_user_crypto_create_session,
|
||||
.vhost_crypto_close_session = vhost_user_crypto_close_session,
|
||||
.vhost_backend_mem_section_filter = vhost_user_mem_section_filter,
|
||||
.vhost_get_inflight_fd = vhost_user_get_inflight_fd,
|
||||
.vhost_set_inflight_fd = vhost_user_set_inflight_fd,
|
||||
};
|
||||
|
|
|
@ -1481,6 +1481,102 @@ void vhost_dev_set_config_notifier(struct vhost_dev *hdev,
|
|||
hdev->config_ops = ops;
|
||||
}
|
||||
|
||||
void vhost_dev_free_inflight(struct vhost_inflight *inflight)
|
||||
{
|
||||
if (inflight->addr) {
|
||||
qemu_memfd_free(inflight->addr, inflight->size, inflight->fd);
|
||||
inflight->addr = NULL;
|
||||
inflight->fd = -1;
|
||||
}
|
||||
}
|
||||
|
||||
static int vhost_dev_resize_inflight(struct vhost_inflight *inflight,
|
||||
uint64_t new_size)
|
||||
{
|
||||
Error *err = NULL;
|
||||
int fd = -1;
|
||||
void *addr = qemu_memfd_alloc("vhost-inflight", new_size,
|
||||
F_SEAL_GROW | F_SEAL_SHRINK | F_SEAL_SEAL,
|
||||
&fd, &err);
|
||||
|
||||
if (err) {
|
||||
error_report_err(err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
vhost_dev_free_inflight(inflight);
|
||||
inflight->offset = 0;
|
||||
inflight->addr = addr;
|
||||
inflight->fd = fd;
|
||||
inflight->size = new_size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void vhost_dev_save_inflight(struct vhost_inflight *inflight, QEMUFile *f)
|
||||
{
|
||||
if (inflight->addr) {
|
||||
qemu_put_be64(f, inflight->size);
|
||||
qemu_put_be16(f, inflight->queue_size);
|
||||
qemu_put_buffer(f, inflight->addr, inflight->size);
|
||||
} else {
|
||||
qemu_put_be64(f, 0);
|
||||
}
|
||||
}
|
||||
|
||||
int vhost_dev_load_inflight(struct vhost_inflight *inflight, QEMUFile *f)
|
||||
{
|
||||
uint64_t size;
|
||||
|
||||
size = qemu_get_be64(f);
|
||||
if (!size) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (inflight->size != size) {
|
||||
if (vhost_dev_resize_inflight(inflight, size)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
inflight->queue_size = qemu_get_be16(f);
|
||||
|
||||
qemu_get_buffer(f, inflight->addr, size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vhost_dev_set_inflight(struct vhost_dev *dev,
|
||||
struct vhost_inflight *inflight)
|
||||
{
|
||||
int r;
|
||||
|
||||
if (dev->vhost_ops->vhost_set_inflight_fd && inflight->addr) {
|
||||
r = dev->vhost_ops->vhost_set_inflight_fd(dev, inflight);
|
||||
if (r) {
|
||||
VHOST_OPS_DEBUG("vhost_set_inflight_fd failed");
|
||||
return -errno;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vhost_dev_get_inflight(struct vhost_dev *dev, uint16_t queue_size,
|
||||
struct vhost_inflight *inflight)
|
||||
{
|
||||
int r;
|
||||
|
||||
if (dev->vhost_ops->vhost_get_inflight_fd) {
|
||||
r = dev->vhost_ops->vhost_get_inflight_fd(dev, queue_size, inflight);
|
||||
if (r) {
|
||||
VHOST_OPS_DEBUG("vhost_get_inflight_fd failed");
|
||||
return -errno;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Host notifiers must be enabled at this point. */
|
||||
int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev)
|
||||
{
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue