vhost: use a function for each call

Replace the generic vhost_call() by specific functions for each
function call to help with type safety and changing arguments.

While doing this, I found that "unsigned long long" and "uint64_t" were
used interchangeably and causing compilation warnings, using uint64_t
instead, as the vhost & protocol specifies.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
[Fix enum usage and MQ - Thibaut Collet]
Signed-off-by: Thibaut Collet <thibaut.collet@6wind.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Tested-by: Thibaut Collet <thibaut.collet@6wind.com>
This commit is contained in:
Marc-André Lureau 2015-10-09 17:17:28 +02:00 committed by Michael S. Tsirkin
parent d2fc4402cb
commit 21e704256d
7 changed files with 511 additions and 281 deletions

View File

@ -252,8 +252,7 @@ static int vhost_net_start_one(struct vhost_net *net,
file.fd = net->backend; file.fd = net->backend;
for (file.index = 0; file.index < net->dev.nvqs; ++file.index) { for (file.index = 0; file.index < net->dev.nvqs; ++file.index) {
const VhostOps *vhost_ops = net->dev.vhost_ops; const VhostOps *vhost_ops = net->dev.vhost_ops;
r = vhost_ops->vhost_call(&net->dev, VHOST_NET_SET_BACKEND, r = vhost_ops->vhost_net_set_backend(&net->dev, &file);
&file);
if (r < 0) { if (r < 0) {
r = -errno; r = -errno;
goto fail; goto fail;
@ -266,8 +265,7 @@ fail:
if (net->nc->info->type == NET_CLIENT_OPTIONS_KIND_TAP) { if (net->nc->info->type == NET_CLIENT_OPTIONS_KIND_TAP) {
while (file.index-- > 0) { while (file.index-- > 0) {
const VhostOps *vhost_ops = net->dev.vhost_ops; const VhostOps *vhost_ops = net->dev.vhost_ops;
int r = vhost_ops->vhost_call(&net->dev, VHOST_NET_SET_BACKEND, int r = vhost_ops->vhost_net_set_backend(&net->dev, &file);
&file);
assert(r >= 0); assert(r >= 0);
} }
} }
@ -289,15 +287,13 @@ static void vhost_net_stop_one(struct vhost_net *net,
if (net->nc->info->type == NET_CLIENT_OPTIONS_KIND_TAP) { if (net->nc->info->type == NET_CLIENT_OPTIONS_KIND_TAP) {
for (file.index = 0; file.index < net->dev.nvqs; ++file.index) { for (file.index = 0; file.index < net->dev.nvqs; ++file.index) {
const VhostOps *vhost_ops = net->dev.vhost_ops; const VhostOps *vhost_ops = net->dev.vhost_ops;
int r = vhost_ops->vhost_call(&net->dev, VHOST_NET_SET_BACKEND, int r = vhost_ops->vhost_net_set_backend(&net->dev, &file);
&file);
assert(r >= 0); assert(r >= 0);
} }
} else if (net->nc->info->type == NET_CLIENT_OPTIONS_KIND_VHOST_USER) { } else if (net->nc->info->type == NET_CLIENT_OPTIONS_KIND_VHOST_USER) {
for (file.index = 0; file.index < net->dev.nvqs; ++file.index) { for (file.index = 0; file.index < net->dev.nvqs; ++file.index) {
const VhostOps *vhost_ops = net->dev.vhost_ops; const VhostOps *vhost_ops = net->dev.vhost_ops;
int r = vhost_ops->vhost_call(&net->dev, VHOST_RESET_DEVICE, int r = vhost_ops->vhost_reset_device(&net->dev);
NULL);
assert(r >= 0); assert(r >= 0);
} }
} }
@ -428,8 +424,8 @@ int vhost_set_vring_enable(NetClientState *nc, int enable)
VHostNetState *net = get_vhost_net(nc); VHostNetState *net = get_vhost_net(nc);
const VhostOps *vhost_ops = net->dev.vhost_ops; const VhostOps *vhost_ops = net->dev.vhost_ops;
if (vhost_ops->vhost_backend_set_vring_enable) { if (vhost_ops->vhost_set_vring_enable) {
return vhost_ops->vhost_backend_set_vring_enable(&net->dev, enable); return vhost_ops->vhost_set_vring_enable(&net->dev, enable);
} }
return 0; return 0;

View File

@ -46,7 +46,7 @@ static int vhost_scsi_set_endpoint(VHostSCSI *s)
memset(&backend, 0, sizeof(backend)); memset(&backend, 0, sizeof(backend));
pstrcpy(backend.vhost_wwpn, sizeof(backend.vhost_wwpn), vs->conf.wwpn); pstrcpy(backend.vhost_wwpn, sizeof(backend.vhost_wwpn), vs->conf.wwpn);
ret = vhost_ops->vhost_call(&s->dev, VHOST_SCSI_SET_ENDPOINT, &backend); ret = vhost_ops->vhost_scsi_set_endpoint(&s->dev, &backend);
if (ret < 0) { if (ret < 0) {
return -errno; return -errno;
} }
@ -61,7 +61,7 @@ static void vhost_scsi_clear_endpoint(VHostSCSI *s)
memset(&backend, 0, sizeof(backend)); memset(&backend, 0, sizeof(backend));
pstrcpy(backend.vhost_wwpn, sizeof(backend.vhost_wwpn), vs->conf.wwpn); pstrcpy(backend.vhost_wwpn, sizeof(backend.vhost_wwpn), vs->conf.wwpn);
vhost_ops->vhost_call(&s->dev, VHOST_SCSI_CLEAR_ENDPOINT, &backend); vhost_ops->vhost_scsi_clear_endpoint(&s->dev, &backend);
} }
static int vhost_scsi_start(VHostSCSI *s) static int vhost_scsi_start(VHostSCSI *s)
@ -77,8 +77,7 @@ static int vhost_scsi_start(VHostSCSI *s)
return -ENOSYS; return -ENOSYS;
} }
ret = vhost_ops->vhost_call(&s->dev, ret = vhost_ops->vhost_scsi_get_abi_version(&s->dev, &abi_version);
VHOST_SCSI_GET_ABI_VERSION, &abi_version);
if (ret < 0) { if (ret < 0) {
return -errno; return -errno;
} }

View File

@ -43,13 +43,6 @@ static int vhost_kernel_cleanup(struct vhost_dev *dev)
return close(fd); return close(fd);
} }
static int vhost_kernel_get_vq_index(struct vhost_dev *dev, int idx)
{
assert(idx >= dev->vq_index && idx < dev->vq_index + dev->nvqs);
return idx - dev->vq_index;
}
static int vhost_kernel_memslots_limit(struct vhost_dev *dev) static int vhost_kernel_memslots_limit(struct vhost_dev *dev)
{ {
int limit = 64; int limit = 64;
@ -67,20 +60,135 @@ static int vhost_kernel_memslots_limit(struct vhost_dev *dev)
return limit; return limit;
} }
static int vhost_set_log_base(struct vhost_dev *dev, uint64_t base, static int vhost_kernel_net_set_backend(struct vhost_dev *dev,
struct vhost_log *log) struct vhost_vring_file *file)
{
return vhost_kernel_call(dev, VHOST_NET_SET_BACKEND, file);
}
static int vhost_kernel_scsi_set_endpoint(struct vhost_dev *dev,
struct vhost_scsi_target *target)
{
return vhost_kernel_call(dev, VHOST_SCSI_SET_ENDPOINT, target);
}
static int vhost_kernel_scsi_clear_endpoint(struct vhost_dev *dev,
struct vhost_scsi_target *target)
{
return vhost_kernel_call(dev, VHOST_SCSI_CLEAR_ENDPOINT, target);
}
static int vhost_kernel_scsi_get_abi_version(struct vhost_dev *dev, int *version)
{
return vhost_kernel_call(dev, VHOST_SCSI_GET_ABI_VERSION, version);
}
static int vhost_kernel_set_log_base(struct vhost_dev *dev, uint64_t base,
struct vhost_log *log)
{ {
return vhost_kernel_call(dev, VHOST_SET_LOG_BASE, &base); return vhost_kernel_call(dev, VHOST_SET_LOG_BASE, &base);
} }
static int vhost_kernel_set_mem_table(struct vhost_dev *dev,
struct vhost_memory *mem)
{
return vhost_kernel_call(dev, VHOST_SET_MEM_TABLE, mem);
}
static int vhost_kernel_set_vring_addr(struct vhost_dev *dev,
struct vhost_vring_addr *addr)
{
return vhost_kernel_call(dev, VHOST_SET_VRING_ADDR, addr);
}
static int vhost_kernel_set_vring_endian(struct vhost_dev *dev,
struct vhost_vring_state *ring)
{
return vhost_kernel_call(dev, VHOST_SET_VRING_ENDIAN, ring);
}
static int vhost_kernel_set_vring_num(struct vhost_dev *dev,
struct vhost_vring_state *ring)
{
return vhost_kernel_call(dev, VHOST_SET_VRING_NUM, ring);
}
static int vhost_kernel_set_vring_base(struct vhost_dev *dev,
struct vhost_vring_state *ring)
{
return vhost_kernel_call(dev, VHOST_SET_VRING_BASE, ring);
}
static int vhost_kernel_get_vring_base(struct vhost_dev *dev,
struct vhost_vring_state *ring)
{
return vhost_kernel_call(dev, VHOST_GET_VRING_BASE, ring);
}
static int vhost_kernel_set_vring_kick(struct vhost_dev *dev,
struct vhost_vring_file *file)
{
return vhost_kernel_call(dev, VHOST_SET_VRING_KICK, file);
}
static int vhost_kernel_set_vring_call(struct vhost_dev *dev,
struct vhost_vring_file *file)
{
return vhost_kernel_call(dev, VHOST_SET_VRING_CALL, file);
}
static int vhost_kernel_set_features(struct vhost_dev *dev,
uint64_t features)
{
return vhost_kernel_call(dev, VHOST_SET_FEATURES, &features);
}
static int vhost_kernel_get_features(struct vhost_dev *dev,
uint64_t *features)
{
return vhost_kernel_call(dev, VHOST_GET_FEATURES, features);
}
static int vhost_kernel_set_owner(struct vhost_dev *dev)
{
return vhost_kernel_call(dev, VHOST_SET_OWNER, NULL);
}
static int vhost_kernel_reset_device(struct vhost_dev *dev)
{
return vhost_kernel_call(dev, VHOST_RESET_DEVICE, NULL);
}
static int vhost_kernel_get_vq_index(struct vhost_dev *dev, int idx)
{
assert(idx >= dev->vq_index && idx < dev->vq_index + dev->nvqs);
return idx - dev->vq_index;
}
static const VhostOps kernel_ops = { static const VhostOps kernel_ops = {
.backend_type = VHOST_BACKEND_TYPE_KERNEL, .backend_type = VHOST_BACKEND_TYPE_KERNEL,
.vhost_call = vhost_kernel_call,
.vhost_backend_init = vhost_kernel_init, .vhost_backend_init = vhost_kernel_init,
.vhost_backend_cleanup = vhost_kernel_cleanup, .vhost_backend_cleanup = vhost_kernel_cleanup,
.vhost_backend_get_vq_index = vhost_kernel_get_vq_index,
.vhost_backend_memslots_limit = vhost_kernel_memslots_limit, .vhost_backend_memslots_limit = vhost_kernel_memslots_limit,
.vhost_set_log_base = vhost_set_log_base, .vhost_net_set_backend = vhost_kernel_net_set_backend,
.vhost_scsi_set_endpoint = vhost_kernel_scsi_set_endpoint,
.vhost_scsi_clear_endpoint = vhost_kernel_scsi_clear_endpoint,
.vhost_scsi_get_abi_version = vhost_kernel_scsi_get_abi_version,
.vhost_set_log_base = vhost_kernel_set_log_base,
.vhost_set_mem_table = vhost_kernel_set_mem_table,
.vhost_set_vring_addr = vhost_kernel_set_vring_addr,
.vhost_set_vring_endian = vhost_kernel_set_vring_endian,
.vhost_set_vring_num = vhost_kernel_set_vring_num,
.vhost_set_vring_base = vhost_kernel_set_vring_base,
.vhost_get_vring_base = vhost_kernel_get_vring_base,
.vhost_set_vring_kick = vhost_kernel_set_vring_kick,
.vhost_set_vring_call = vhost_kernel_set_vring_call,
.vhost_set_features = vhost_kernel_set_features,
.vhost_get_features = vhost_kernel_get_features,
.vhost_set_owner = vhost_kernel_set_owner,
.vhost_reset_device = vhost_kernel_reset_device,
.vhost_get_vq_index = vhost_kernel_get_vq_index,
}; };
int vhost_set_backend_type(struct vhost_dev *dev, VhostBackendType backend_type) int vhost_set_backend_type(struct vhost_dev *dev, VhostBackendType backend_type)

View File

@ -99,37 +99,6 @@ static bool ioeventfd_enabled(void)
return kvm_enabled() && kvm_eventfds_enabled(); return kvm_enabled() && kvm_eventfds_enabled();
} }
static unsigned long int ioctl_to_vhost_user_request[VHOST_USER_MAX] = {
-1, /* VHOST_USER_NONE */
VHOST_GET_FEATURES, /* VHOST_USER_GET_FEATURES */
VHOST_SET_FEATURES, /* VHOST_USER_SET_FEATURES */
VHOST_SET_OWNER, /* VHOST_USER_SET_OWNER */
VHOST_RESET_DEVICE, /* VHOST_USER_RESET_DEVICE */
VHOST_SET_MEM_TABLE, /* VHOST_USER_SET_MEM_TABLE */
VHOST_SET_LOG_BASE, /* VHOST_USER_SET_LOG_BASE */
VHOST_SET_LOG_FD, /* VHOST_USER_SET_LOG_FD */
VHOST_SET_VRING_NUM, /* VHOST_USER_SET_VRING_NUM */
VHOST_SET_VRING_ADDR, /* VHOST_USER_SET_VRING_ADDR */
VHOST_SET_VRING_BASE, /* VHOST_USER_SET_VRING_BASE */
VHOST_GET_VRING_BASE, /* VHOST_USER_GET_VRING_BASE */
VHOST_SET_VRING_KICK, /* VHOST_USER_SET_VRING_KICK */
VHOST_SET_VRING_CALL, /* VHOST_USER_SET_VRING_CALL */
VHOST_SET_VRING_ERR /* VHOST_USER_SET_VRING_ERR */
};
static VhostUserRequest vhost_user_request_translate(unsigned long int request)
{
VhostUserRequest idx;
for (idx = 0; idx < VHOST_USER_MAX; idx++) {
if (ioctl_to_vhost_user_request[idx] == request) {
break;
}
}
return (idx == VHOST_USER_MAX) ? VHOST_USER_NONE : idx;
}
static int vhost_user_read(struct vhost_dev *dev, VhostUserMsg *msg) static int vhost_user_read(struct vhost_dev *dev, VhostUserMsg *msg)
{ {
CharDriverState *chr = dev->opaque; CharDriverState *chr = dev->opaque;
@ -176,20 +145,6 @@ fail:
return -1; return -1;
} }
static int vhost_user_write(struct vhost_dev *dev, VhostUserMsg *msg,
int *fds, int fd_num)
{
CharDriverState *chr = dev->opaque;
int size = VHOST_USER_HDR_SIZE + msg->size;
if (fd_num) {
qemu_chr_fe_set_msgfds(chr, fds, fd_num);
}
return qemu_chr_fe_write_all(chr, (const uint8_t *) msg, size) == size ?
0 : -1;
}
static bool vhost_user_one_time_request(VhostUserRequest request) static bool vhost_user_one_time_request(VhostUserRequest request)
{ {
switch (request) { switch (request) {
@ -203,173 +158,32 @@ static bool vhost_user_one_time_request(VhostUserRequest request)
} }
} }
static int vhost_user_call(struct vhost_dev *dev, unsigned long int request, /* most non-init callers ignore the error */
void *arg) static int vhost_user_write(struct vhost_dev *dev, VhostUserMsg *msg,
int *fds, int fd_num)
{ {
VhostUserMsg msg; CharDriverState *chr = dev->opaque;
VhostUserRequest msg_request; int size = VHOST_USER_HDR_SIZE + msg->size;
struct vhost_vring_file *file = 0;
int need_reply = 0;
int fds[VHOST_MEMORY_MAX_NREGIONS];
int i, fd;
size_t fd_num = 0;
assert(dev->vhost_ops->backend_type == VHOST_BACKEND_TYPE_USER);
/* only translate vhost ioctl requests */
if (request > VHOST_USER_MAX) {
msg_request = vhost_user_request_translate(request);
} else {
msg_request = request;
}
/* /*
* For non-vring specific requests, like VHOST_USER_SET_MEM_TABLE, * For non-vring specific requests, like VHOST_USER_SET_MEM_TABLE,
* we just need send it once in the first time. For later such * we just need send it once in the first time. For later such
* request, we just ignore it. * request, we just ignore it.
*/ */
if (vhost_user_one_time_request(msg_request) && dev->vq_index != 0) { if (vhost_user_one_time_request(msg->request) && dev->vq_index != 0) {
return 0; return 0;
} }
msg.request = msg_request; if (fd_num) {
msg.flags = VHOST_USER_VERSION; qemu_chr_fe_set_msgfds(chr, fds, fd_num);
msg.size = 0;
switch (msg_request) {
case VHOST_USER_GET_FEATURES:
case VHOST_USER_GET_PROTOCOL_FEATURES:
case VHOST_USER_GET_QUEUE_NUM:
need_reply = 1;
break;
case VHOST_USER_SET_FEATURES:
case VHOST_USER_SET_PROTOCOL_FEATURES:
msg.u64 = *((__u64 *) arg);
msg.size = sizeof(m.u64);
break;
case VHOST_USER_SET_OWNER:
case VHOST_USER_RESET_DEVICE:
break;
case VHOST_USER_SET_MEM_TABLE:
for (i = 0; i < dev->mem->nregions; ++i) {
struct vhost_memory_region *reg = dev->mem->regions + i;
ram_addr_t ram_addr;
assert((uintptr_t)reg->userspace_addr == reg->userspace_addr);
qemu_ram_addr_from_host((void *)(uintptr_t)reg->userspace_addr, &ram_addr);
fd = qemu_get_ram_fd(ram_addr);
if (fd > 0) {
msg.memory.regions[fd_num].userspace_addr = reg->userspace_addr;
msg.memory.regions[fd_num].memory_size = reg->memory_size;
msg.memory.regions[fd_num].guest_phys_addr = reg->guest_phys_addr;
msg.memory.regions[fd_num].mmap_offset = reg->userspace_addr -
(uintptr_t) qemu_get_ram_block_host_ptr(ram_addr);
assert(fd_num < VHOST_MEMORY_MAX_NREGIONS);
fds[fd_num++] = fd;
}
}
msg.memory.nregions = fd_num;
if (!fd_num) {
error_report("Failed initializing vhost-user memory map, "
"consider using -object memory-backend-file share=on");
return -1;
}
msg.size = sizeof(m.memory.nregions);
msg.size += sizeof(m.memory.padding);
msg.size += fd_num * sizeof(VhostUserMemoryRegion);
break;
case VHOST_USER_SET_LOG_FD:
fds[fd_num++] = *((int *) arg);
break;
case VHOST_USER_SET_VRING_NUM:
case VHOST_USER_SET_VRING_BASE:
case VHOST_USER_SET_VRING_ENABLE:
memcpy(&msg.state, arg, sizeof(struct vhost_vring_state));
msg.size = sizeof(m.state);
break;
case VHOST_USER_GET_VRING_BASE:
memcpy(&msg.state, arg, sizeof(struct vhost_vring_state));
msg.size = sizeof(m.state);
need_reply = 1;
break;
case VHOST_USER_SET_VRING_ADDR:
memcpy(&msg.addr, arg, sizeof(struct vhost_vring_addr));
msg.size = sizeof(m.addr);
break;
case VHOST_USER_SET_VRING_KICK:
case VHOST_USER_SET_VRING_CALL:
case VHOST_USER_SET_VRING_ERR:
file = arg;
msg.u64 = file->index & VHOST_USER_VRING_IDX_MASK;
msg.size = sizeof(m.u64);
if (ioeventfd_enabled() && file->fd > 0) {
fds[fd_num++] = file->fd;
} else {
msg.u64 |= VHOST_USER_VRING_NOFD_MASK;
}
break;
default:
error_report("vhost-user trying to send unhandled ioctl");
return -1;
break;
} }
if (vhost_user_write(dev, &msg, fds, fd_num) < 0) { return qemu_chr_fe_write_all(chr, (const uint8_t *) msg, size) == size ?
return 0; 0 : -1;
}
if (need_reply) {
if (vhost_user_read(dev, &msg) < 0) {
return 0;
}
if (msg_request != msg.request) {
error_report("Received unexpected msg type."
" Expected %d received %d", msg_request, msg.request);
return -1;
}
switch (msg_request) {
case VHOST_USER_GET_FEATURES:
case VHOST_USER_GET_PROTOCOL_FEATURES:
case VHOST_USER_GET_QUEUE_NUM:
if (msg.size != sizeof(m.u64)) {
error_report("Received bad msg size.");
return -1;
}
*((__u64 *) arg) = msg.u64;
break;
case VHOST_USER_GET_VRING_BASE:
if (msg.size != sizeof(m.state)) {
error_report("Received bad msg size.");
return -1;
}
memcpy(arg, &msg.state, sizeof(struct vhost_vring_state));
break;
default:
error_report("Received unexpected msg type.");
return -1;
break;
}
}
return 0;
} }
static int vhost_set_log_base(struct vhost_dev *dev, uint64_t base, static int vhost_user_set_log_base(struct vhost_dev *dev, uint64_t base,
struct vhost_log *log) struct vhost_log *log)
{ {
int fds[VHOST_MEMORY_MAX_NREGIONS]; int fds[VHOST_MEMORY_MAX_NREGIONS];
size_t fd_num = 0; size_t fd_num = 0;
@ -405,16 +219,284 @@ static int vhost_set_log_base(struct vhost_dev *dev, uint64_t base,
return 0; return 0;
} }
static int vhost_user_set_mem_table(struct vhost_dev *dev,
struct vhost_memory *mem)
{
int fds[VHOST_MEMORY_MAX_NREGIONS];
int i, fd;
size_t fd_num = 0;
VhostUserMsg msg = {
.request = VHOST_USER_SET_MEM_TABLE,
.flags = VHOST_USER_VERSION,
};
for (i = 0; i < dev->mem->nregions; ++i) {
struct vhost_memory_region *reg = dev->mem->regions + i;
ram_addr_t ram_addr;
assert((uintptr_t)reg->userspace_addr == reg->userspace_addr);
qemu_ram_addr_from_host((void *)(uintptr_t)reg->userspace_addr,
&ram_addr);
fd = qemu_get_ram_fd(ram_addr);
if (fd > 0) {
msg.memory.regions[fd_num].userspace_addr = reg->userspace_addr;
msg.memory.regions[fd_num].memory_size = reg->memory_size;
msg.memory.regions[fd_num].guest_phys_addr = reg->guest_phys_addr;
msg.memory.regions[fd_num].mmap_offset = reg->userspace_addr -
(uintptr_t) qemu_get_ram_block_host_ptr(ram_addr);
assert(fd_num < VHOST_MEMORY_MAX_NREGIONS);
fds[fd_num++] = fd;
}
}
msg.memory.nregions = fd_num;
if (!fd_num) {
error_report("Failed initializing vhost-user memory map, "
"consider using -object memory-backend-file share=on");
return -1;
}
msg.size = sizeof(m.memory.nregions);
msg.size += sizeof(m.memory.padding);
msg.size += fd_num * sizeof(VhostUserMemoryRegion);
vhost_user_write(dev, &msg, fds, fd_num);
return 0;
}
static int vhost_user_set_vring_addr(struct vhost_dev *dev,
struct vhost_vring_addr *addr)
{
VhostUserMsg msg = {
.request = VHOST_USER_SET_VRING_ADDR,
.flags = VHOST_USER_VERSION,
.addr = *addr,
.size = sizeof(*addr),
};
vhost_user_write(dev, &msg, NULL, 0);
return 0;
}
static int vhost_user_set_vring_endian(struct vhost_dev *dev,
struct vhost_vring_state *ring)
{
error_report("vhost-user trying to send unhandled ioctl");
return -1;
}
static int vhost_set_vring(struct vhost_dev *dev,
unsigned long int request,
struct vhost_vring_state *ring)
{
VhostUserMsg msg = {
.request = request,
.flags = VHOST_USER_VERSION,
.state = *ring,
.size = sizeof(*ring),
};
vhost_user_write(dev, &msg, NULL, 0);
return 0;
}
static int vhost_user_set_vring_num(struct vhost_dev *dev,
struct vhost_vring_state *ring)
{
return vhost_set_vring(dev, VHOST_USER_SET_VRING_NUM, ring);
}
static int vhost_user_set_vring_base(struct vhost_dev *dev,
struct vhost_vring_state *ring)
{
return vhost_set_vring(dev, VHOST_USER_SET_VRING_BASE, ring);
}
static int vhost_user_set_vring_enable(struct vhost_dev *dev, int enable)
{
struct vhost_vring_state state = {
.index = dev->vq_index,
.num = enable,
};
if (!(dev->protocol_features & (1ULL << VHOST_USER_PROTOCOL_F_MQ))) {
return -1;
}
return vhost_set_vring(dev, VHOST_USER_SET_VRING_ENABLE, &state);
}
static int vhost_user_get_vring_base(struct vhost_dev *dev,
struct vhost_vring_state *ring)
{
VhostUserMsg msg = {
.request = VHOST_USER_GET_VRING_BASE,
.flags = VHOST_USER_VERSION,
.state = *ring,
.size = sizeof(*ring),
};
vhost_user_write(dev, &msg, NULL, 0);
if (vhost_user_read(dev, &msg) < 0) {
return 0;
}
if (msg.request != VHOST_USER_GET_VRING_BASE) {
error_report("Received unexpected msg type. Expected %d received %d",
VHOST_USER_GET_VRING_BASE, msg.request);
return -1;
}
if (msg.size != sizeof(m.state)) {
error_report("Received bad msg size.");
return -1;
}
*ring = msg.state;
return 0;
}
static int vhost_set_vring_file(struct vhost_dev *dev,
VhostUserRequest request,
struct vhost_vring_file *file)
{
int fds[VHOST_MEMORY_MAX_NREGIONS];
size_t fd_num = 0;
VhostUserMsg msg = {
.request = request,
.flags = VHOST_USER_VERSION,
.u64 = file->index & VHOST_USER_VRING_IDX_MASK,
.size = sizeof(m.u64),
};
if (ioeventfd_enabled() && file->fd > 0) {
fds[fd_num++] = file->fd;
} else {
msg.u64 |= VHOST_USER_VRING_NOFD_MASK;
}
vhost_user_write(dev, &msg, fds, fd_num);
return 0;
}
static int vhost_user_set_vring_kick(struct vhost_dev *dev,
struct vhost_vring_file *file)
{
return vhost_set_vring_file(dev, VHOST_USER_SET_VRING_KICK, file);
}
static int vhost_user_set_vring_call(struct vhost_dev *dev,
struct vhost_vring_file *file)
{
return vhost_set_vring_file(dev, VHOST_USER_SET_VRING_CALL, file);
}
static int vhost_user_set_u64(struct vhost_dev *dev, int request, uint64_t u64)
{
VhostUserMsg msg = {
.request = request,
.flags = VHOST_USER_VERSION,
.u64 = u64,
.size = sizeof(m.u64),
};
vhost_user_write(dev, &msg, NULL, 0);
return 0;
}
static int vhost_user_set_features(struct vhost_dev *dev,
uint64_t features)
{
return vhost_user_set_u64(dev, VHOST_USER_SET_FEATURES, features);
}
static int vhost_user_set_protocol_features(struct vhost_dev *dev,
uint64_t features)
{
return vhost_user_set_u64(dev, VHOST_USER_SET_PROTOCOL_FEATURES, features);
}
static int vhost_user_get_u64(struct vhost_dev *dev, int request, uint64_t *u64)
{
VhostUserMsg msg = {
.request = request,
.flags = VHOST_USER_VERSION,
};
if (vhost_user_one_time_request(request) && dev->vq_index != 0) {
return 0;
}
vhost_user_write(dev, &msg, NULL, 0);
if (vhost_user_read(dev, &msg) < 0) {
return 0;
}
if (msg.request != request) {
error_report("Received unexpected msg type. Expected %d received %d",
request, msg.request);
return -1;
}
if (msg.size != sizeof(m.u64)) {
error_report("Received bad msg size.");
return -1;
}
*u64 = msg.u64;
return 0;
}
static int vhost_user_get_features(struct vhost_dev *dev, uint64_t *features)
{
return vhost_user_get_u64(dev, VHOST_USER_GET_FEATURES, features);
}
static int vhost_user_set_owner(struct vhost_dev *dev)
{
VhostUserMsg msg = {
.request = VHOST_USER_SET_OWNER,
.flags = VHOST_USER_VERSION,
};
vhost_user_write(dev, &msg, NULL, 0);
return 0;
}
static int vhost_user_reset_device(struct vhost_dev *dev)
{
VhostUserMsg msg = {
.request = VHOST_USER_RESET_DEVICE,
.flags = VHOST_USER_VERSION,
};
vhost_user_write(dev, &msg, NULL, 0);
return 0;
}
static int vhost_user_init(struct vhost_dev *dev, void *opaque) static int vhost_user_init(struct vhost_dev *dev, void *opaque)
{ {
unsigned long long features; uint64_t features;
int err; int err;
assert(dev->vhost_ops->backend_type == VHOST_BACKEND_TYPE_USER); assert(dev->vhost_ops->backend_type == VHOST_BACKEND_TYPE_USER);
dev->opaque = opaque; dev->opaque = opaque;
err = vhost_user_call(dev, VHOST_USER_GET_FEATURES, &features); err = vhost_user_get_features(dev, &features);
if (err < 0) { if (err < 0) {
return err; return err;
} }
@ -422,21 +504,22 @@ static int vhost_user_init(struct vhost_dev *dev, void *opaque)
if (virtio_has_feature(features, VHOST_USER_F_PROTOCOL_FEATURES)) { if (virtio_has_feature(features, VHOST_USER_F_PROTOCOL_FEATURES)) {
dev->backend_features |= 1ULL << VHOST_USER_F_PROTOCOL_FEATURES; dev->backend_features |= 1ULL << VHOST_USER_F_PROTOCOL_FEATURES;
err = vhost_user_call(dev, VHOST_USER_GET_PROTOCOL_FEATURES, &features); err = vhost_user_get_u64(dev, VHOST_USER_GET_PROTOCOL_FEATURES,
&features);
if (err < 0) { if (err < 0) {
return err; return err;
} }
dev->protocol_features = features & VHOST_USER_PROTOCOL_FEATURE_MASK; dev->protocol_features = features & VHOST_USER_PROTOCOL_FEATURE_MASK;
err = vhost_user_call(dev, VHOST_USER_SET_PROTOCOL_FEATURES, err = vhost_user_set_protocol_features(dev, dev->protocol_features);
&dev->protocol_features);
if (err < 0) { if (err < 0) {
return err; return err;
} }
/* query the max queues we support if backend supports Multiple Queue */ /* query the max queues we support if backend supports Multiple Queue */
if (dev->protocol_features & (1ULL << VHOST_USER_PROTOCOL_F_MQ)) { if (dev->protocol_features & (1ULL << VHOST_USER_PROTOCOL_F_MQ)) {
err = vhost_user_call(dev, VHOST_USER_GET_QUEUE_NUM, &dev->max_queues); err = vhost_user_get_u64(dev, VHOST_USER_GET_QUEUE_NUM,
&dev->max_queues);
if (err < 0) { if (err < 0) {
return err; return err;
} }
@ -454,22 +537,6 @@ static int vhost_user_init(struct vhost_dev *dev, void *opaque)
return 0; return 0;
} }
static int vhost_user_set_vring_enable(struct vhost_dev *dev, int enable)
{
struct vhost_vring_state state = {
.index = dev->vq_index,
.num = enable,
};
assert(dev->vhost_ops->backend_type == VHOST_BACKEND_TYPE_USER);
if (!(dev->protocol_features & (1ULL << VHOST_USER_PROTOCOL_F_MQ))) {
return -1;
}
return vhost_user_call(dev, VHOST_USER_SET_VRING_ENABLE, &state);
}
static int vhost_user_cleanup(struct vhost_dev *dev) static int vhost_user_cleanup(struct vhost_dev *dev)
{ {
assert(dev->vhost_ops->backend_type == VHOST_BACKEND_TYPE_USER); assert(dev->vhost_ops->backend_type == VHOST_BACKEND_TYPE_USER);
@ -501,12 +568,23 @@ static bool vhost_user_requires_shm_log(struct vhost_dev *dev)
const VhostOps user_ops = { const VhostOps user_ops = {
.backend_type = VHOST_BACKEND_TYPE_USER, .backend_type = VHOST_BACKEND_TYPE_USER,
.vhost_call = vhost_user_call,
.vhost_backend_init = vhost_user_init, .vhost_backend_init = vhost_user_init,
.vhost_backend_cleanup = vhost_user_cleanup, .vhost_backend_cleanup = vhost_user_cleanup,
.vhost_backend_get_vq_index = vhost_user_get_vq_index,
.vhost_backend_set_vring_enable = vhost_user_set_vring_enable,
.vhost_backend_memslots_limit = vhost_user_memslots_limit, .vhost_backend_memslots_limit = vhost_user_memslots_limit,
.vhost_set_log_base = vhost_set_log_base, .vhost_set_log_base = vhost_user_set_log_base,
.vhost_set_mem_table = vhost_user_set_mem_table,
.vhost_set_vring_addr = vhost_user_set_vring_addr,
.vhost_set_vring_endian = vhost_user_set_vring_endian,
.vhost_set_vring_num = vhost_user_set_vring_num,
.vhost_set_vring_base = vhost_user_set_vring_base,
.vhost_get_vring_base = vhost_user_get_vring_base,
.vhost_set_vring_kick = vhost_user_set_vring_kick,
.vhost_set_vring_call = vhost_user_set_vring_call,
.vhost_set_features = vhost_user_set_features,
.vhost_get_features = vhost_user_get_features,
.vhost_set_owner = vhost_user_set_owner,
.vhost_reset_device = vhost_user_reset_device,
.vhost_get_vq_index = vhost_user_get_vq_index,
.vhost_set_vring_enable = vhost_user_set_vring_enable,
.vhost_requires_shm_log = vhost_user_requires_shm_log, .vhost_requires_shm_log = vhost_user_requires_shm_log,
}; };

View File

@ -555,7 +555,7 @@ static void vhost_commit(MemoryListener *listener)
} }
if (!dev->log_enabled) { if (!dev->log_enabled) {
r = dev->vhost_ops->vhost_call(dev, VHOST_SET_MEM_TABLE, dev->mem); r = dev->vhost_ops->vhost_set_mem_table(dev, dev->mem);
assert(r >= 0); assert(r >= 0);
dev->memory_changed = false; dev->memory_changed = false;
return; return;
@ -568,7 +568,7 @@ static void vhost_commit(MemoryListener *listener)
if (dev->log_size < log_size) { if (dev->log_size < log_size) {
vhost_dev_log_resize(dev, log_size + VHOST_LOG_BUFFER); vhost_dev_log_resize(dev, log_size + VHOST_LOG_BUFFER);
} }
r = dev->vhost_ops->vhost_call(dev, VHOST_SET_MEM_TABLE, dev->mem); r = dev->vhost_ops->vhost_set_mem_table(dev, dev->mem);
assert(r >= 0); assert(r >= 0);
/* To log less, can only decrease log size after table update. */ /* To log less, can only decrease log size after table update. */
if (dev->log_size > log_size + VHOST_LOG_BUFFER) { if (dev->log_size > log_size + VHOST_LOG_BUFFER) {
@ -636,7 +636,7 @@ static int vhost_virtqueue_set_addr(struct vhost_dev *dev,
.log_guest_addr = vq->used_phys, .log_guest_addr = vq->used_phys,
.flags = enable_log ? (1 << VHOST_VRING_F_LOG) : 0, .flags = enable_log ? (1 << VHOST_VRING_F_LOG) : 0,
}; };
int r = dev->vhost_ops->vhost_call(dev, VHOST_SET_VRING_ADDR, &addr); int r = dev->vhost_ops->vhost_set_vring_addr(dev, &addr);
if (r < 0) { if (r < 0) {
return -errno; return -errno;
} }
@ -650,7 +650,7 @@ static int vhost_dev_set_features(struct vhost_dev *dev, bool enable_log)
if (enable_log) { if (enable_log) {
features |= 0x1ULL << VHOST_F_LOG_ALL; features |= 0x1ULL << VHOST_F_LOG_ALL;
} }
r = dev->vhost_ops->vhost_call(dev, VHOST_SET_FEATURES, &features); r = dev->vhost_ops->vhost_set_features(dev, features);
return r < 0 ? -errno : 0; return r < 0 ? -errno : 0;
} }
@ -755,7 +755,7 @@ static int vhost_virtqueue_set_vring_endian_legacy(struct vhost_dev *dev,
.num = is_big_endian .num = is_big_endian
}; };
if (!dev->vhost_ops->vhost_call(dev, VHOST_SET_VRING_ENDIAN, &s)) { if (!dev->vhost_ops->vhost_set_vring_endian(dev, &s)) {
return 0; return 0;
} }
@ -774,7 +774,7 @@ static int vhost_virtqueue_start(struct vhost_dev *dev,
{ {
hwaddr s, l, a; hwaddr s, l, a;
int r; int r;
int vhost_vq_index = dev->vhost_ops->vhost_backend_get_vq_index(dev, idx); int vhost_vq_index = dev->vhost_ops->vhost_get_vq_index(dev, idx);
struct vhost_vring_file file = { struct vhost_vring_file file = {
.index = vhost_vq_index .index = vhost_vq_index
}; };
@ -785,13 +785,13 @@ static int vhost_virtqueue_start(struct vhost_dev *dev,
vq->num = state.num = virtio_queue_get_num(vdev, idx); vq->num = state.num = virtio_queue_get_num(vdev, idx);
r = dev->vhost_ops->vhost_call(dev, VHOST_SET_VRING_NUM, &state); r = dev->vhost_ops->vhost_set_vring_num(dev, &state);
if (r) { if (r) {
return -errno; return -errno;
} }
state.num = virtio_queue_get_last_avail_idx(vdev, idx); state.num = virtio_queue_get_last_avail_idx(vdev, idx);
r = dev->vhost_ops->vhost_call(dev, VHOST_SET_VRING_BASE, &state); r = dev->vhost_ops->vhost_set_vring_base(dev, &state);
if (r) { if (r) {
return -errno; return -errno;
} }
@ -843,7 +843,7 @@ static int vhost_virtqueue_start(struct vhost_dev *dev,
} }
file.fd = event_notifier_get_fd(virtio_queue_get_host_notifier(vvq)); file.fd = event_notifier_get_fd(virtio_queue_get_host_notifier(vvq));
r = dev->vhost_ops->vhost_call(dev, VHOST_SET_VRING_KICK, &file); r = dev->vhost_ops->vhost_set_vring_kick(dev, &file);
if (r) { if (r) {
r = -errno; r = -errno;
goto fail_kick; goto fail_kick;
@ -876,13 +876,13 @@ static void vhost_virtqueue_stop(struct vhost_dev *dev,
struct vhost_virtqueue *vq, struct vhost_virtqueue *vq,
unsigned idx) unsigned idx)
{ {
int vhost_vq_index = dev->vhost_ops->vhost_backend_get_vq_index(dev, idx); int vhost_vq_index = dev->vhost_ops->vhost_get_vq_index(dev, idx);
struct vhost_vring_state state = { struct vhost_vring_state state = {
.index = vhost_vq_index, .index = vhost_vq_index,
}; };
int r; int r;
r = dev->vhost_ops->vhost_call(dev, VHOST_GET_VRING_BASE, &state); r = dev->vhost_ops->vhost_get_vring_base(dev, &state);
if (r < 0) { if (r < 0) {
fprintf(stderr, "vhost VQ %d ring restore failed: %d\n", idx, r); fprintf(stderr, "vhost VQ %d ring restore failed: %d\n", idx, r);
fflush(stderr); fflush(stderr);
@ -929,7 +929,7 @@ static void vhost_eventfd_del(MemoryListener *listener,
static int vhost_virtqueue_init(struct vhost_dev *dev, static int vhost_virtqueue_init(struct vhost_dev *dev,
struct vhost_virtqueue *vq, int n) struct vhost_virtqueue *vq, int n)
{ {
int vhost_vq_index = dev->vhost_ops->vhost_backend_get_vq_index(dev, n); int vhost_vq_index = dev->vhost_ops->vhost_get_vq_index(dev, n);
struct vhost_vring_file file = { struct vhost_vring_file file = {
.index = vhost_vq_index, .index = vhost_vq_index,
}; };
@ -939,7 +939,7 @@ static int vhost_virtqueue_init(struct vhost_dev *dev,
} }
file.fd = event_notifier_get_fd(&vq->masked_notifier); file.fd = event_notifier_get_fd(&vq->masked_notifier);
r = dev->vhost_ops->vhost_call(dev, VHOST_SET_VRING_CALL, &file); r = dev->vhost_ops->vhost_set_vring_call(dev, &file);
if (r) { if (r) {
r = -errno; r = -errno;
goto fail_call; goto fail_call;
@ -981,12 +981,12 @@ int vhost_dev_init(struct vhost_dev *hdev, void *opaque,
} }
QLIST_INSERT_HEAD(&vhost_devices, hdev, entry); QLIST_INSERT_HEAD(&vhost_devices, hdev, entry);
r = hdev->vhost_ops->vhost_call(hdev, VHOST_SET_OWNER, NULL); r = hdev->vhost_ops->vhost_set_owner(hdev);
if (r < 0) { if (r < 0) {
goto fail; goto fail;
} }
r = hdev->vhost_ops->vhost_call(hdev, VHOST_GET_FEATURES, &features); r = hdev->vhost_ops->vhost_get_features(hdev, &features);
if (r < 0) { if (r < 0) {
goto fail; goto fail;
} }
@ -1147,8 +1147,8 @@ void vhost_virtqueue_mask(struct vhost_dev *hdev, VirtIODevice *vdev, int n,
file.fd = event_notifier_get_fd(virtio_queue_get_guest_notifier(vvq)); file.fd = event_notifier_get_fd(virtio_queue_get_guest_notifier(vvq));
} }
file.index = hdev->vhost_ops->vhost_backend_get_vq_index(hdev, n); file.index = hdev->vhost_ops->vhost_get_vq_index(hdev, n);
r = hdev->vhost_ops->vhost_call(hdev, VHOST_SET_VRING_CALL, &file); r = hdev->vhost_ops->vhost_set_vring_call(hdev, &file);
assert(r >= 0); assert(r >= 0);
} }
@ -1190,7 +1190,7 @@ int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev)
if (r < 0) { if (r < 0) {
goto fail_features; goto fail_features;
} }
r = hdev->vhost_ops->vhost_call(hdev, VHOST_SET_MEM_TABLE, hdev->mem); r = hdev->vhost_ops->vhost_set_mem_table(hdev, hdev->mem);
if (r < 0) { if (r < 0) {
r = -errno; r = -errno;
goto fail_mem; goto fail_mem;

View File

@ -22,28 +22,77 @@ typedef enum VhostBackendType {
struct vhost_dev; struct vhost_dev;
struct vhost_log; struct vhost_log;
struct vhost_memory;
struct vhost_vring_file;
struct vhost_vring_state;
struct vhost_vring_addr;
struct vhost_scsi_target;
typedef int (*vhost_call)(struct vhost_dev *dev, unsigned long int request,
void *arg);
typedef int (*vhost_backend_init)(struct vhost_dev *dev, void *opaque); typedef int (*vhost_backend_init)(struct vhost_dev *dev, void *opaque);
typedef int (*vhost_backend_cleanup)(struct vhost_dev *dev); typedef int (*vhost_backend_cleanup)(struct vhost_dev *dev);
typedef int (*vhost_backend_get_vq_index)(struct vhost_dev *dev, int idx);
typedef int (*vhost_backend_set_vring_enable)(struct vhost_dev *dev, int enable);
typedef int (*vhost_backend_memslots_limit)(struct vhost_dev *dev); typedef int (*vhost_backend_memslots_limit)(struct vhost_dev *dev);
typedef int (*vhost_net_set_backend_op)(struct vhost_dev *dev,
struct vhost_vring_file *file);
typedef int (*vhost_scsi_set_endpoint_op)(struct vhost_dev *dev,
struct vhost_scsi_target *target);
typedef int (*vhost_scsi_clear_endpoint_op)(struct vhost_dev *dev,
struct vhost_scsi_target *target);
typedef int (*vhost_scsi_get_abi_version_op)(struct vhost_dev *dev,
int *version);
typedef int (*vhost_set_log_base_op)(struct vhost_dev *dev, uint64_t base, typedef int (*vhost_set_log_base_op)(struct vhost_dev *dev, uint64_t base,
struct vhost_log *log); struct vhost_log *log);
typedef int (*vhost_set_mem_table_op)(struct vhost_dev *dev,
struct vhost_memory *mem);
typedef int (*vhost_set_vring_addr_op)(struct vhost_dev *dev,
struct vhost_vring_addr *addr);
typedef int (*vhost_set_vring_endian_op)(struct vhost_dev *dev,
struct vhost_vring_state *ring);
typedef int (*vhost_set_vring_num_op)(struct vhost_dev *dev,
struct vhost_vring_state *ring);
typedef int (*vhost_set_vring_base_op)(struct vhost_dev *dev,
struct vhost_vring_state *ring);
typedef int (*vhost_get_vring_base_op)(struct vhost_dev *dev,
struct vhost_vring_state *ring);
typedef int (*vhost_set_vring_kick_op)(struct vhost_dev *dev,
struct vhost_vring_file *file);
typedef int (*vhost_set_vring_call_op)(struct vhost_dev *dev,
struct vhost_vring_file *file);
typedef int (*vhost_set_features_op)(struct vhost_dev *dev,
uint64_t features);
typedef int (*vhost_get_features_op)(struct vhost_dev *dev,
uint64_t *features);
typedef int (*vhost_set_owner_op)(struct vhost_dev *dev);
typedef int (*vhost_reset_device_op)(struct vhost_dev *dev);
typedef int (*vhost_get_vq_index_op)(struct vhost_dev *dev, int idx);
typedef int (*vhost_set_vring_enable_op)(struct vhost_dev *dev,
int enable);
typedef bool (*vhost_requires_shm_log_op)(struct vhost_dev *dev); typedef bool (*vhost_requires_shm_log_op)(struct vhost_dev *dev);
typedef struct VhostOps { typedef struct VhostOps {
VhostBackendType backend_type; VhostBackendType backend_type;
vhost_call vhost_call;
vhost_backend_init vhost_backend_init; vhost_backend_init vhost_backend_init;
vhost_backend_cleanup vhost_backend_cleanup; vhost_backend_cleanup vhost_backend_cleanup;
vhost_backend_get_vq_index vhost_backend_get_vq_index;
vhost_backend_set_vring_enable vhost_backend_set_vring_enable;
vhost_backend_memslots_limit vhost_backend_memslots_limit; vhost_backend_memslots_limit vhost_backend_memslots_limit;
vhost_net_set_backend_op vhost_net_set_backend;
vhost_scsi_set_endpoint_op vhost_scsi_set_endpoint;
vhost_scsi_clear_endpoint_op vhost_scsi_clear_endpoint;
vhost_scsi_get_abi_version_op vhost_scsi_get_abi_version;
vhost_set_log_base_op vhost_set_log_base; vhost_set_log_base_op vhost_set_log_base;
vhost_set_mem_table_op vhost_set_mem_table;
vhost_set_vring_addr_op vhost_set_vring_addr;
vhost_set_vring_endian_op vhost_set_vring_endian;
vhost_set_vring_num_op vhost_set_vring_num;
vhost_set_vring_base_op vhost_set_vring_base;
vhost_get_vring_base_op vhost_get_vring_base;
vhost_set_vring_kick_op vhost_set_vring_kick;
vhost_set_vring_call_op vhost_set_vring_call;
vhost_set_features_op vhost_set_features;
vhost_get_features_op vhost_get_features;
vhost_set_owner_op vhost_set_owner;
vhost_reset_device_op vhost_reset_device;
vhost_get_vq_index_op vhost_get_vq_index;
vhost_set_vring_enable_op vhost_set_vring_enable;
vhost_requires_shm_log_op vhost_requires_shm_log; vhost_requires_shm_log_op vhost_requires_shm_log;
} VhostOps; } VhostOps;

View File

@ -45,14 +45,14 @@ struct vhost_dev {
int nvqs; int nvqs;
/* the first virtqueue which would be used by this vhost dev */ /* the first virtqueue which would be used by this vhost dev */
int vq_index; int vq_index;
unsigned long long features; uint64_t features;
unsigned long long acked_features; uint64_t acked_features;
unsigned long long backend_features; uint64_t backend_features;
unsigned long long protocol_features; uint64_t protocol_features;
unsigned long long max_queues; uint64_t max_queues;
bool started; bool started;
bool log_enabled; bool log_enabled;
unsigned long long log_size; uint64_t log_size;
Error *migration_blocker; Error *migration_blocker;
bool memory_changed; bool memory_changed;
hwaddr mem_changed_start_addr; hwaddr mem_changed_start_addr;