libvhost-user: support host notifier

This patch introduces the host notifier support in
libvhost-user. A new API is added to support setting
host notifier for each queue.

Signed-off-by: Tiwei Bie <tiwei.bie@intel.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
This commit is contained in:
Tiwei Bie 2018-05-24 18:33:35 +08:00 committed by Michael S. Tsirkin
parent 44866521bd
commit d84599f56c
2 changed files with 105 additions and 8 deletions

View File

@ -314,11 +314,6 @@ vu_message_write(VuDev *dev, int conn_fd, VhostUserMsg *vmsg)
msg.msg_controllen = 0; msg.msg_controllen = 0;
} }
/* Set the version in the flags when sending the reply */
vmsg->flags &= ~VHOST_USER_VERSION_MASK;
vmsg->flags |= VHOST_USER_VERSION;
vmsg->flags |= VHOST_USER_REPLY_MASK;
do { do {
rc = sendmsg(conn_fd, &msg, 0); rc = sendmsg(conn_fd, &msg, 0);
} while (rc < 0 && (errno == EINTR || errno == EAGAIN)); } while (rc < 0 && (errno == EINTR || errno == EAGAIN));
@ -341,6 +336,39 @@ vu_message_write(VuDev *dev, int conn_fd, VhostUserMsg *vmsg)
return true; return true;
} }
static bool
vu_send_reply(VuDev *dev, int conn_fd, VhostUserMsg *vmsg)
{
/* Set the version in the flags when sending the reply */
vmsg->flags &= ~VHOST_USER_VERSION_MASK;
vmsg->flags |= VHOST_USER_VERSION;
vmsg->flags |= VHOST_USER_REPLY_MASK;
return vu_message_write(dev, conn_fd, vmsg);
}
static bool
vu_process_message_reply(VuDev *dev, const VhostUserMsg *vmsg)
{
VhostUserMsg msg_reply;
if ((vmsg->flags & VHOST_USER_NEED_REPLY_MASK) == 0) {
return true;
}
if (!vu_message_read(dev, dev->slave_fd, &msg_reply)) {
return false;
}
if (msg_reply.request != vmsg->request) {
DPRINT("Received unexpected msg type. Expected %d received %d",
vmsg->request, msg_reply.request);
return false;
}
return msg_reply.payload.u64 == 0;
}
/* Kick the log_call_fd if required. */ /* Kick the log_call_fd if required. */
static void static void
vu_log_kick(VuDev *dev) vu_log_kick(VuDev *dev)
@ -536,7 +564,7 @@ vu_set_mem_table_exec_postcopy(VuDev *dev, VhostUserMsg *vmsg)
/* Send the message back to qemu with the addresses filled in */ /* Send the message back to qemu with the addresses filled in */
vmsg->fd_num = 0; vmsg->fd_num = 0;
if (!vu_message_write(dev, dev->sock, vmsg)) { if (!vu_send_reply(dev, dev->sock, vmsg)) {
vu_panic(dev, "failed to respond to set-mem-table for postcopy"); vu_panic(dev, "failed to respond to set-mem-table for postcopy");
return false; return false;
} }
@ -916,6 +944,41 @@ 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)
{
int qidx = vq - dev->vq;
int fd_num = 0;
VhostUserMsg vmsg = {
.request = VHOST_USER_SLAVE_VRING_HOST_NOTIFIER_MSG,
.flags = VHOST_USER_VERSION | VHOST_USER_NEED_REPLY_MASK,
.size = sizeof(vmsg.payload.area),
.payload.area = {
.u64 = qidx & VHOST_USER_VRING_IDX_MASK,
.size = size,
.offset = offset,
},
};
if (fd == -1) {
vmsg.payload.area.u64 |= VHOST_USER_VRING_NOFD_MASK;
} else {
vmsg.fds[fd_num++] = fd;
}
vmsg.fd_num = fd_num;
if ((dev->protocol_features & VHOST_USER_PROTOCOL_F_SLAVE_SEND_FD) == 0) {
return false;
}
if (!vu_message_write(dev, dev->slave_fd, &vmsg)) {
return false;
}
return vu_process_message_reply(dev, &vmsg);
}
static bool static bool
vu_set_vring_call_exec(VuDev *dev, VhostUserMsg *vmsg) vu_set_vring_call_exec(VuDev *dev, VhostUserMsg *vmsg)
{ {
@ -968,7 +1031,9 @@ static bool
vu_get_protocol_features_exec(VuDev *dev, VhostUserMsg *vmsg) vu_get_protocol_features_exec(VuDev *dev, VhostUserMsg *vmsg)
{ {
uint64_t features = 1ULL << VHOST_USER_PROTOCOL_F_LOG_SHMFD | uint64_t features = 1ULL << VHOST_USER_PROTOCOL_F_LOG_SHMFD |
1ULL << VHOST_USER_PROTOCOL_F_SLAVE_REQ; 1ULL << VHOST_USER_PROTOCOL_F_SLAVE_REQ |
1ULL << VHOST_USER_PROTOCOL_F_HOST_NOTIFIER |
1ULL << VHOST_USER_PROTOCOL_F_SLAVE_SEND_FD;
if (have_userfault()) { if (have_userfault()) {
features |= 1ULL << VHOST_USER_PROTOCOL_F_PAGEFAULT; features |= 1ULL << VHOST_USER_PROTOCOL_F_PAGEFAULT;
@ -1252,7 +1317,7 @@ vu_dispatch(VuDev *dev)
goto end; goto end;
} }
if (!vu_message_write(dev, dev->sock, &vmsg)) { if (!vu_send_reply(dev, dev->sock, &vmsg)) {
goto end; goto end;
} }

View File

@ -51,6 +51,8 @@ enum VhostUserProtocolFeature {
VHOST_USER_PROTOCOL_F_CRYPTO_SESSION = 7, VHOST_USER_PROTOCOL_F_CRYPTO_SESSION = 7,
VHOST_USER_PROTOCOL_F_PAGEFAULT = 8, VHOST_USER_PROTOCOL_F_PAGEFAULT = 8,
VHOST_USER_PROTOCOL_F_CONFIG = 9, 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_MAX VHOST_USER_PROTOCOL_F_MAX
}; };
@ -92,6 +94,14 @@ typedef enum VhostUserRequest {
VHOST_USER_MAX VHOST_USER_MAX
} VhostUserRequest; } VhostUserRequest;
typedef enum VhostUserSlaveRequest {
VHOST_USER_SLAVE_NONE = 0,
VHOST_USER_SLAVE_IOTLB_MSG = 1,
VHOST_USER_SLAVE_CONFIG_CHANGE_MSG = 2,
VHOST_USER_SLAVE_VRING_HOST_NOTIFIER_MSG = 3,
VHOST_USER_SLAVE_MAX
} VhostUserSlaveRequest;
typedef struct VhostUserMemoryRegion { typedef struct VhostUserMemoryRegion {
uint64_t guest_phys_addr; uint64_t guest_phys_addr;
uint64_t memory_size; uint64_t memory_size;
@ -122,6 +132,12 @@ static VhostUserConfig c __attribute__ ((unused));
+ sizeof(c.size) \ + sizeof(c.size) \
+ sizeof(c.flags)) + sizeof(c.flags))
typedef struct VhostUserVringArea {
uint64_t u64;
uint64_t size;
uint64_t offset;
} VhostUserVringArea;
#if defined(_WIN32) #if defined(_WIN32)
# define VU_PACKED __attribute__((gcc_struct, packed)) # define VU_PACKED __attribute__((gcc_struct, packed))
#else #else
@ -133,6 +149,7 @@ typedef struct VhostUserMsg {
#define VHOST_USER_VERSION_MASK (0x3) #define VHOST_USER_VERSION_MASK (0x3)
#define VHOST_USER_REPLY_MASK (0x1 << 2) #define VHOST_USER_REPLY_MASK (0x1 << 2)
#define VHOST_USER_NEED_REPLY_MASK (0x1 << 3)
uint32_t flags; uint32_t flags;
uint32_t size; /* the following payload size */ uint32_t size; /* the following payload size */
@ -145,6 +162,7 @@ typedef struct VhostUserMsg {
VhostUserMemory memory; VhostUserMemory memory;
VhostUserLog log; VhostUserLog log;
VhostUserConfig config; VhostUserConfig config;
VhostUserVringArea area;
} payload; } payload;
int fds[VHOST_MEMORY_MAX_NREGIONS]; int fds[VHOST_MEMORY_MAX_NREGIONS];
@ -368,6 +386,20 @@ VuVirtq *vu_get_queue(VuDev *dev, int qidx);
void vu_set_queue_handler(VuDev *dev, VuVirtq *vq, void vu_set_queue_handler(VuDev *dev, VuVirtq *vq,
vu_queue_handler_cb handler); vu_queue_handler_cb handler);
/**
* vu_set_queue_host_notifier:
* @dev: a VuDev context
* @vq: a VuVirtq queue
* @fd: a file descriptor
* @size: host page size
* @offset: notifier offset in @fd file
*
* Set queue's host notifier. This function may be called several
* times for the same queue. If called with -1 @fd, the notifier
* is removed.
*/
bool vu_set_queue_host_notifier(VuDev *dev, VuVirtq *vq, int fd,
int size, int offset);
/** /**
* vu_queue_set_notification: * vu_queue_set_notification: