From 2ce68e4cf5be9b5176a3c3c372948d6340724d2d Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Tue, 6 Oct 2015 10:37:27 +0200 Subject: vhost: add vhost_has_free_slot() interface it will allow for other parts of QEMU check if it's safe to map memory region during hotplug/runtime. That way hotplug path will have a chance to cancel hotplug operation instead of crashing in vhost_commit(). Signed-off-by: Igor Mammedov Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/vhost.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'hw/virtio/vhost.c') diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c index c0ed5b263f..a3b4f9e8ea 100644 --- a/hw/virtio/vhost.c +++ b/hw/virtio/vhost.c @@ -26,6 +26,22 @@ static struct vhost_log *vhost_log; +static unsigned int used_memslots; +static QLIST_HEAD(, vhost_dev) vhost_devices = + QLIST_HEAD_INITIALIZER(vhost_devices); + +bool vhost_has_free_slot(void) +{ + unsigned int slots_limit = ~0U; + struct vhost_dev *hdev; + + QLIST_FOREACH(hdev, &vhost_devices, entry) { + unsigned int r = hdev->vhost_ops->vhost_backend_memslots_limit(hdev); + slots_limit = MIN(slots_limit, r); + } + return slots_limit > used_memslots; +} + static void vhost_dev_sync_region(struct vhost_dev *dev, MemoryRegionSection *section, uint64_t mfirst, uint64_t mlast, @@ -457,6 +473,7 @@ static void vhost_set_memory(MemoryListener *listener, dev->mem_changed_start_addr = MIN(dev->mem_changed_start_addr, start_addr); dev->mem_changed_end_addr = MAX(dev->mem_changed_end_addr, start_addr + size - 1); dev->memory_changed = true; + used_memslots = dev->mem->nregions; } static bool vhost_section(MemoryRegionSection *section) @@ -916,6 +933,8 @@ int vhost_dev_init(struct vhost_dev *hdev, void *opaque, return -errno; } + QLIST_INSERT_HEAD(&vhost_devices, hdev, entry); + r = hdev->vhost_ops->vhost_call(hdev, VHOST_SET_OWNER, NULL); if (r < 0) { goto fail; @@ -972,6 +991,7 @@ fail_vq: fail: r = -errno; hdev->vhost_ops->vhost_backend_cleanup(hdev); + QLIST_REMOVE(hdev, entry); return r; } @@ -989,6 +1009,7 @@ void vhost_dev_cleanup(struct vhost_dev *hdev) g_free(hdev->mem); g_free(hdev->mem_sections); hdev->vhost_ops->vhost_backend_cleanup(hdev); + QLIST_REMOVE(hdev, entry); } /* Stop processing guest IO notifications in qemu. -- cgit 1.4.1 From aebf81680bf49c5953d7ae9ebb7b98c0f4dad8f3 Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Tue, 6 Oct 2015 10:37:29 +0200 Subject: vhost: fail backend intialization early Don't initialize vhost backend if memslots number exceeds the supported limit. This prevents failures down the road when backend is actually started. [MST: rewrite commit log] Signed-off-by: Igor Mammedov Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/vhost.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'hw/virtio/vhost.c') diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c index a3b4f9e8ea..f14a5c5133 100644 --- a/hw/virtio/vhost.c +++ b/hw/virtio/vhost.c @@ -933,6 +933,12 @@ int vhost_dev_init(struct vhost_dev *hdev, void *opaque, return -errno; } + if (used_memslots > hdev->vhost_ops->vhost_backend_memslots_limit(hdev)) { + fprintf(stderr, "vhost backend memory slots limit is less" + " than current number of present memory slots\n"); + close((uintptr_t)opaque); + return -1; + } QLIST_INSERT_HEAD(&vhost_devices, hdev, entry); r = hdev->vhost_ops->vhost_call(hdev, VHOST_SET_OWNER, NULL); -- cgit 1.4.1 From 636f4dddfe48ccabaf5198bba440354d6a268d62 Mon Sep 17 00:00:00 2001 From: Marc-André Lureau Date: Fri, 9 Oct 2015 17:17:22 +0200 Subject: vhost: document log resizing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marc-André Lureau Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Tested-by: Thibaut Collet --- hw/virtio/vhost.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'hw/virtio/vhost.c') diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c index f14a5c5133..f5ecaf0d02 100644 --- a/hw/virtio/vhost.c +++ b/hw/virtio/vhost.c @@ -350,6 +350,8 @@ static inline void vhost_dev_log_resize(struct vhost_dev* dev, uint64_t size) uint64_t log_base = (uintptr_t)log->log; int r; + /* inform backend of log switching, this must be done before + releasing the current log, to ensure no logging is lost */ r = dev->vhost_ops->vhost_call(dev, VHOST_SET_LOG_BASE, &log_base); assert(r >= 0); vhost_log_put(dev, true); -- cgit 1.4.1 From c2bea314f6a2870b847c79e2e11263c5f9334db7 Mon Sep 17 00:00:00 2001 From: Marc-André Lureau Date: Fri, 9 Oct 2015 17:17:23 +0200 Subject: vhost: add vhost_set_log_base op MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Split VHOST_SET_LOG_BASE call in a seperate function callback, so that type safety works and more arguments can be added in the next patches. Signed-off-by: Marc-André Lureau Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Tested-by: Thibaut Collet --- hw/virtio/vhost-backend.c | 6 ++++++ hw/virtio/vhost-user.c | 16 +++++++++++++++- hw/virtio/vhost.c | 6 +++--- include/hw/virtio/vhost-backend.h | 3 +++ 4 files changed, 27 insertions(+), 4 deletions(-) (limited to 'hw/virtio/vhost.c') diff --git a/hw/virtio/vhost-backend.c b/hw/virtio/vhost-backend.c index 910d8e00e3..5846c37f6d 100644 --- a/hw/virtio/vhost-backend.c +++ b/hw/virtio/vhost-backend.c @@ -67,6 +67,11 @@ static int vhost_kernel_memslots_limit(struct vhost_dev *dev) return limit; } +static int vhost_set_log_base(struct vhost_dev *dev, uint64_t base) +{ + return vhost_kernel_call(dev, VHOST_SET_LOG_BASE, &base); +} + static const VhostOps kernel_ops = { .backend_type = VHOST_BACKEND_TYPE_KERNEL, .vhost_call = vhost_kernel_call, @@ -74,6 +79,7 @@ static const VhostOps kernel_ops = { .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_set_log_base = vhost_set_log_base, }; int vhost_set_backend_type(struct vhost_dev *dev, VhostBackendType backend_type) diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c index 9585637d07..5d512898cf 100644 --- a/hw/virtio/vhost-user.c +++ b/hw/virtio/vhost-user.c @@ -242,7 +242,6 @@ static int vhost_user_call(struct vhost_dev *dev, unsigned long int request, break; case VHOST_USER_SET_FEATURES: - case VHOST_USER_SET_LOG_BASE: case VHOST_USER_SET_PROTOCOL_FEATURES: msg.u64 = *((__u64 *) arg); msg.size = sizeof(m.u64); @@ -367,6 +366,20 @@ static int vhost_user_call(struct vhost_dev *dev, unsigned long int request, return 0; } +static int vhost_set_log_base(struct vhost_dev *dev, uint64_t base) +{ + VhostUserMsg msg = { + .request = VHOST_USER_SET_LOG_BASE, + .flags = VHOST_USER_VERSION, + .u64 = base, + .size = sizeof(m.u64), + }; + + vhost_user_write(dev, &msg, NULL, 0); + + return 0; +} + static int vhost_user_init(struct vhost_dev *dev, void *opaque) { unsigned long long features; @@ -453,4 +466,5 @@ const VhostOps user_ops = { .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_set_log_base = vhost_set_log_base, }; diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c index f5ecaf0d02..f2b31b7d12 100644 --- a/hw/virtio/vhost.c +++ b/hw/virtio/vhost.c @@ -352,7 +352,7 @@ static inline void vhost_dev_log_resize(struct vhost_dev* dev, uint64_t size) /* inform backend of log switching, this must be done before releasing the current log, to ensure no logging is lost */ - r = dev->vhost_ops->vhost_call(dev, VHOST_SET_LOG_BASE, &log_base); + r = dev->vhost_ops->vhost_set_log_base(dev, log_base); assert(r >= 0); vhost_log_put(dev, true); dev->log = log; @@ -1167,8 +1167,8 @@ int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev) hdev->log_size = vhost_get_log_size(hdev); hdev->log = vhost_log_get(hdev->log_size); log_base = (uintptr_t)hdev->log->log; - r = hdev->vhost_ops->vhost_call(hdev, VHOST_SET_LOG_BASE, - hdev->log_size ? &log_base : NULL); + r = hdev->vhost_ops->vhost_set_log_base(hdev, + hdev->log_size ? log_base : 0); if (r < 0) { r = -errno; goto fail_log; diff --git a/include/hw/virtio/vhost-backend.h b/include/hw/virtio/vhost-backend.h index 7d4a8ad968..c9035736db 100644 --- a/include/hw/virtio/vhost-backend.h +++ b/include/hw/virtio/vhost-backend.h @@ -28,6 +28,8 @@ 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_set_log_base_op)(struct vhost_dev *dev, uint64_t base); + typedef struct VhostOps { VhostBackendType backend_type; vhost_call vhost_call; @@ -36,6 +38,7 @@ typedef struct VhostOps { 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_set_log_base_op vhost_set_log_base; } VhostOps; extern const VhostOps user_ops; -- cgit 1.4.1 From 15324404f68cde561d0eeee3d18a7b203f57f095 Mon Sep 17 00:00:00 2001 From: Marc-André Lureau Date: Fri, 9 Oct 2015 17:17:25 +0200 Subject: vhost: alloc shareable log MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If the backend is requires it, allocate shareable memory. vhost_log_get() now uses 2 globals "vhost_log" and "vhost_log_shm", that way there is a common non-shareable log and a common shareable one. Signed-off-by: Marc-André Lureau Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Tested-by: Thibaut Collet --- hw/virtio/vhost.c | 57 ++++++++++++++++++++++++++++++++++++++--------- include/hw/virtio/vhost.h | 3 ++- 2 files changed, 49 insertions(+), 11 deletions(-) (limited to 'hw/virtio/vhost.c') diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c index f2b31b7d12..aec92d4691 100644 --- a/hw/virtio/vhost.c +++ b/hw/virtio/vhost.c @@ -18,6 +18,7 @@ #include "qemu/atomic.h" #include "qemu/range.h" #include "qemu/error-report.h" +#include "qemu/memfd.h" #include #include "exec/address-spaces.h" #include "hw/virtio/virtio-bus.h" @@ -25,6 +26,7 @@ #include "migration/migration.h" static struct vhost_log *vhost_log; +static struct vhost_log *vhost_log_shm; static unsigned int used_memslots; static QLIST_HEAD(, vhost_dev) vhost_devices = @@ -302,25 +304,46 @@ static uint64_t vhost_get_log_size(struct vhost_dev *dev) } return log_size; } -static struct vhost_log *vhost_log_alloc(uint64_t size) + +static struct vhost_log *vhost_log_alloc(uint64_t size, bool share) { - struct vhost_log *log = g_malloc0(sizeof *log + size * sizeof(*(log->log))); + struct vhost_log *log; + uint64_t logsize = size * sizeof(*(log->log)); + int fd = -1; + + log = g_new0(struct vhost_log, 1); + if (share) { + log->log = qemu_memfd_alloc("vhost-log", logsize, + F_SEAL_GROW | F_SEAL_SHRINK | F_SEAL_SEAL, + &fd); + memset(log->log, 0, logsize); + } else { + log->log = g_malloc0(logsize); + } log->size = size; log->refcnt = 1; + log->fd = fd; return log; } -static struct vhost_log *vhost_log_get(uint64_t size) +static struct vhost_log *vhost_log_get(uint64_t size, bool share) { - if (!vhost_log || vhost_log->size != size) { - vhost_log = vhost_log_alloc(size); + struct vhost_log *log = share ? vhost_log_shm : vhost_log; + + if (!log || log->size != size) { + log = vhost_log_alloc(size, share); + if (share) { + vhost_log_shm = log; + } else { + vhost_log = log; + } } else { - ++vhost_log->refcnt; + ++log->refcnt; } - return vhost_log; + return log; } static void vhost_log_put(struct vhost_dev *dev, bool sync) @@ -337,16 +360,29 @@ static void vhost_log_put(struct vhost_dev *dev, bool sync) if (dev->log_size && sync) { vhost_log_sync_range(dev, 0, dev->log_size * VHOST_LOG_CHUNK - 1); } + if (vhost_log == log) { + g_free(log->log); vhost_log = NULL; + } else if (vhost_log_shm == log) { + qemu_memfd_free(log->log, log->size * sizeof(*(log->log)), + log->fd); + vhost_log_shm = NULL; } + g_free(log); } } -static inline void vhost_dev_log_resize(struct vhost_dev* dev, uint64_t size) +static bool vhost_dev_log_is_shared(struct vhost_dev *dev) +{ + return dev->vhost_ops->vhost_requires_shm_log && + dev->vhost_ops->vhost_requires_shm_log(dev); +} + +static inline void vhost_dev_log_resize(struct vhost_dev *dev, uint64_t size) { - struct vhost_log *log = vhost_log_get(size); + struct vhost_log *log = vhost_log_get(size, vhost_dev_log_is_shared(dev)); uint64_t log_base = (uintptr_t)log->log; int r; @@ -1165,7 +1201,8 @@ int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev) uint64_t log_base; hdev->log_size = vhost_get_log_size(hdev); - hdev->log = vhost_log_get(hdev->log_size); + hdev->log = vhost_log_get(hdev->log_size, + vhost_dev_log_is_shared(hdev)); log_base = (uintptr_t)hdev->log->log; r = hdev->vhost_ops->vhost_set_log_base(hdev, hdev->log_size ? log_base : 0); diff --git a/include/hw/virtio/vhost.h b/include/hw/virtio/vhost.h index 080831ed67..6bf759f5c7 100644 --- a/include/hw/virtio/vhost.h +++ b/include/hw/virtio/vhost.h @@ -31,7 +31,8 @@ typedef unsigned long vhost_log_chunk_t; struct vhost_log { unsigned long long size; int refcnt; - vhost_log_chunk_t log[0]; + int fd; + vhost_log_chunk_t *log; }; struct vhost_memory; -- cgit 1.4.1 From 9a78a5dd272a190d262b5ba5d4721ab93d48c564 Mon Sep 17 00:00:00 2001 From: Marc-André Lureau Date: Fri, 9 Oct 2015 17:17:26 +0200 Subject: vhost-user: send log shm fd along with log_base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Send the shm for the dirty pages logging if the backend supports VHOST_USER_PROTOCOL_F_LOG_SHMFD. Wait for a reply to make sure the old log is no longer used. Signed-off-by: Marc-André Lureau Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Tested-by: Thibaut Collet --- hw/virtio/vhost-backend.c | 3 ++- hw/virtio/vhost-user.c | 27 +++++++++++++++++++++++++-- hw/virtio/vhost.c | 5 +++-- include/hw/virtio/vhost-backend.h | 4 +++- 4 files changed, 33 insertions(+), 6 deletions(-) (limited to 'hw/virtio/vhost.c') diff --git a/hw/virtio/vhost-backend.c b/hw/virtio/vhost-backend.c index 5846c37f6d..5a2f1af137 100644 --- a/hw/virtio/vhost-backend.c +++ b/hw/virtio/vhost-backend.c @@ -67,7 +67,8 @@ static int vhost_kernel_memslots_limit(struct vhost_dev *dev) return limit; } -static int vhost_set_log_base(struct vhost_dev *dev, uint64_t base) +static int vhost_set_log_base(struct vhost_dev *dev, uint64_t base, + struct vhost_log *log) { return vhost_kernel_call(dev, VHOST_SET_LOG_BASE, &base); } diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c index e10ce87299..2709c4ee39 100644 --- a/hw/virtio/vhost-user.c +++ b/hw/virtio/vhost-user.c @@ -367,8 +367,13 @@ static int vhost_user_call(struct vhost_dev *dev, unsigned long int request, return 0; } -static int vhost_set_log_base(struct vhost_dev *dev, uint64_t base) +static int vhost_set_log_base(struct vhost_dev *dev, uint64_t base, + struct vhost_log *log) { + int fds[VHOST_MEMORY_MAX_NREGIONS]; + size_t fd_num = 0; + bool shmfd = virtio_has_feature(dev->protocol_features, + VHOST_USER_PROTOCOL_F_LOG_SHMFD); VhostUserMsg msg = { .request = VHOST_USER_SET_LOG_BASE, .flags = VHOST_USER_VERSION, @@ -376,7 +381,25 @@ static int vhost_set_log_base(struct vhost_dev *dev, uint64_t base) .size = sizeof(m.u64), }; - vhost_user_write(dev, &msg, NULL, 0); + if (shmfd && log->fd != -1) { + fds[fd_num++] = log->fd; + } + + vhost_user_write(dev, &msg, fds, fd_num); + + if (shmfd) { + msg.size = 0; + if (vhost_user_read(dev, &msg) < 0) { + return 0; + } + + if (msg.request != VHOST_USER_SET_LOG_BASE) { + error_report("Received unexpected msg type. " + "Expected %d received %d", + VHOST_USER_SET_LOG_BASE, msg.request); + return -1; + } + } return 0; } diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c index aec92d4691..65c09bf888 100644 --- a/hw/virtio/vhost.c +++ b/hw/virtio/vhost.c @@ -388,7 +388,7 @@ static inline void vhost_dev_log_resize(struct vhost_dev *dev, uint64_t size) /* inform backend of log switching, this must be done before releasing the current log, to ensure no logging is lost */ - r = dev->vhost_ops->vhost_set_log_base(dev, log_base); + r = dev->vhost_ops->vhost_set_log_base(dev, log_base, log); assert(r >= 0); vhost_log_put(dev, true); dev->log = log; @@ -1205,7 +1205,8 @@ int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev) vhost_dev_log_is_shared(hdev)); log_base = (uintptr_t)hdev->log->log; r = hdev->vhost_ops->vhost_set_log_base(hdev, - hdev->log_size ? log_base : 0); + hdev->log_size ? log_base : 0, + hdev->log); if (r < 0) { r = -errno; goto fail_log; diff --git a/include/hw/virtio/vhost-backend.h b/include/hw/virtio/vhost-backend.h index c33570aeea..375625f5fb 100644 --- a/include/hw/virtio/vhost-backend.h +++ b/include/hw/virtio/vhost-backend.h @@ -21,6 +21,7 @@ typedef enum VhostBackendType { } VhostBackendType; struct vhost_dev; +struct vhost_log; typedef int (*vhost_call)(struct vhost_dev *dev, unsigned long int request, void *arg); @@ -30,7 +31,8 @@ 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_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); typedef bool (*vhost_requires_shm_log_op)(struct vhost_dev *dev); typedef struct VhostOps { -- cgit 1.4.1 From d2fc4402cb152d3e526f736d7d53dbd050ef8794 Mon Sep 17 00:00:00 2001 From: Marc-André Lureau Date: Fri, 9 Oct 2015 17:17:27 +0200 Subject: vhost-user: add a migration blocker MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If VHOST_USER_PROTOCOL_F_LOG_SHMFD is not announced, block vhost-user migration. The blocker is removed in vhost_dev_cleanup(). Signed-off-by: Marc-André Lureau Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Tested-by: Thibaut Collet --- hw/virtio/vhost-user.c | 9 +++++++++ hw/virtio/vhost.c | 16 ++++++++++++---- 2 files changed, 21 insertions(+), 4 deletions(-) (limited to 'hw/virtio/vhost.c') diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c index 2709c4ee39..fb3aa40d59 100644 --- a/hw/virtio/vhost-user.c +++ b/hw/virtio/vhost-user.c @@ -15,6 +15,7 @@ #include "qemu/error-report.h" #include "qemu/sockets.h" #include "exec/ram_addr.h" +#include "migration/migration.h" #include #include @@ -442,6 +443,14 @@ static int vhost_user_init(struct vhost_dev *dev, void *opaque) } } + if (dev->migration_blocker == NULL && + !virtio_has_feature(dev->protocol_features, + VHOST_USER_PROTOCOL_F_LOG_SHMFD)) { + error_setg(&dev->migration_blocker, + "Migration disabled: vhost-user backend lacks " + "VHOST_USER_PROTOCOL_F_LOG_SHMFD feature."); + } + return 0; } diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c index 65c09bf888..a553256081 100644 --- a/hw/virtio/vhost.c +++ b/hw/virtio/vhost.c @@ -961,6 +961,8 @@ int vhost_dev_init(struct vhost_dev *hdev, void *opaque, uint64_t features; int i, r; + hdev->migration_blocker = NULL; + if (vhost_set_backend_type(hdev, backend_type) < 0) { close((uintptr_t)opaque); return -1; @@ -1012,12 +1014,18 @@ int vhost_dev_init(struct vhost_dev *hdev, void *opaque, .eventfd_del = vhost_eventfd_del, .priority = 10 }; - hdev->migration_blocker = NULL; - if (!(hdev->features & (0x1ULL << VHOST_F_LOG_ALL))) { - error_setg(&hdev->migration_blocker, - "Migration disabled: vhost lacks VHOST_F_LOG_ALL feature."); + + if (hdev->migration_blocker == NULL) { + if (!(hdev->features & (0x1ULL << VHOST_F_LOG_ALL))) { + error_setg(&hdev->migration_blocker, + "Migration disabled: vhost lacks VHOST_F_LOG_ALL feature."); + } + } + + if (hdev->migration_blocker != NULL) { migrate_add_blocker(hdev->migration_blocker); } + hdev->mem = g_malloc0(offsetof(struct vhost_memory, regions)); hdev->n_mem_sections = 0; hdev->mem_sections = NULL; -- cgit 1.4.1 From 21e704256dea24baf93b169f5d7b0e7fe684bd15 Mon Sep 17 00:00:00 2001 From: Marc-André Lureau Date: Fri, 9 Oct 2015 17:17:28 +0200 Subject: vhost: use a function for each call MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 [Fix enum usage and MQ - Thibaut Collet] Signed-off-by: Thibaut Collet Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Tested-by: Thibaut Collet --- hw/net/vhost_net.c | 16 +- hw/scsi/vhost-scsi.c | 7 +- hw/virtio/vhost-backend.c | 132 +++++++++- hw/virtio/vhost-user.c | 522 ++++++++++++++++++++++---------------- hw/virtio/vhost.c | 36 +-- include/hw/virtio/vhost-backend.h | 63 ++++- include/hw/virtio/vhost.h | 12 +- 7 files changed, 509 insertions(+), 279 deletions(-) (limited to 'hw/virtio/vhost.c') diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c index 2bce89129d..1ab4133769 100644 --- a/hw/net/vhost_net.c +++ b/hw/net/vhost_net.c @@ -252,8 +252,7 @@ static int vhost_net_start_one(struct vhost_net *net, file.fd = net->backend; for (file.index = 0; file.index < net->dev.nvqs; ++file.index) { const VhostOps *vhost_ops = net->dev.vhost_ops; - r = vhost_ops->vhost_call(&net->dev, VHOST_NET_SET_BACKEND, - &file); + r = vhost_ops->vhost_net_set_backend(&net->dev, &file); if (r < 0) { r = -errno; goto fail; @@ -266,8 +265,7 @@ fail: if (net->nc->info->type == NET_CLIENT_OPTIONS_KIND_TAP) { while (file.index-- > 0) { const VhostOps *vhost_ops = net->dev.vhost_ops; - int r = vhost_ops->vhost_call(&net->dev, VHOST_NET_SET_BACKEND, - &file); + int r = vhost_ops->vhost_net_set_backend(&net->dev, &file); 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) { for (file.index = 0; file.index < net->dev.nvqs; ++file.index) { const VhostOps *vhost_ops = net->dev.vhost_ops; - int r = vhost_ops->vhost_call(&net->dev, VHOST_NET_SET_BACKEND, - &file); + int r = vhost_ops->vhost_net_set_backend(&net->dev, &file); assert(r >= 0); } } else if (net->nc->info->type == NET_CLIENT_OPTIONS_KIND_VHOST_USER) { for (file.index = 0; file.index < net->dev.nvqs; ++file.index) { const VhostOps *vhost_ops = net->dev.vhost_ops; - int r = vhost_ops->vhost_call(&net->dev, VHOST_RESET_DEVICE, - NULL); + int r = vhost_ops->vhost_reset_device(&net->dev); assert(r >= 0); } } @@ -428,8 +424,8 @@ int vhost_set_vring_enable(NetClientState *nc, int enable) VHostNetState *net = get_vhost_net(nc); const VhostOps *vhost_ops = net->dev.vhost_ops; - if (vhost_ops->vhost_backend_set_vring_enable) { - return vhost_ops->vhost_backend_set_vring_enable(&net->dev, enable); + if (vhost_ops->vhost_set_vring_enable) { + return vhost_ops->vhost_set_vring_enable(&net->dev, enable); } return 0; diff --git a/hw/scsi/vhost-scsi.c b/hw/scsi/vhost-scsi.c index fb7983d9dc..00cdac62f9 100644 --- a/hw/scsi/vhost-scsi.c +++ b/hw/scsi/vhost-scsi.c @@ -46,7 +46,7 @@ static int vhost_scsi_set_endpoint(VHostSCSI *s) memset(&backend, 0, sizeof(backend)); 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) { return -errno; } @@ -61,7 +61,7 @@ static void vhost_scsi_clear_endpoint(VHostSCSI *s) memset(&backend, 0, sizeof(backend)); 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) @@ -77,8 +77,7 @@ static int vhost_scsi_start(VHostSCSI *s) return -ENOSYS; } - ret = vhost_ops->vhost_call(&s->dev, - VHOST_SCSI_GET_ABI_VERSION, &abi_version); + ret = vhost_ops->vhost_scsi_get_abi_version(&s->dev, &abi_version); if (ret < 0) { return -errno; } diff --git a/hw/virtio/vhost-backend.c b/hw/virtio/vhost-backend.c index 5a2f1af137..1d5f684eb0 100644 --- a/hw/virtio/vhost-backend.c +++ b/hw/virtio/vhost-backend.c @@ -43,13 +43,6 @@ static int vhost_kernel_cleanup(struct vhost_dev *dev) 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) { int limit = 64; @@ -67,20 +60,135 @@ static int vhost_kernel_memslots_limit(struct vhost_dev *dev) return limit; } -static int vhost_set_log_base(struct vhost_dev *dev, uint64_t base, - struct vhost_log *log) +static int vhost_kernel_net_set_backend(struct vhost_dev *dev, + 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); } +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 = { .backend_type = VHOST_BACKEND_TYPE_KERNEL, - .vhost_call = vhost_kernel_call, .vhost_backend_init = vhost_kernel_init, .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_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) diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c index fb3aa40d59..16d8e80a2a 100644 --- a/hw/virtio/vhost-user.c +++ b/hw/virtio/vhost-user.c @@ -99,37 +99,6 @@ static bool ioeventfd_enabled(void) 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) { CharDriverState *chr = dev->opaque; @@ -176,12 +145,35 @@ fail: return -1; } +static bool vhost_user_one_time_request(VhostUserRequest request) +{ + switch (request) { + case VHOST_USER_SET_OWNER: + case VHOST_USER_RESET_DEVICE: + case VHOST_USER_SET_MEM_TABLE: + case VHOST_USER_GET_QUEUE_NUM: + return true; + default: + return false; + } +} + +/* most non-init callers ignore the error */ 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; + /* + * For non-vring specific requests, like VHOST_USER_SET_MEM_TABLE, + * we just need send it once in the first time. For later such + * request, we just ignore it. + */ + if (vhost_user_one_time_request(msg->request) && dev->vq_index != 0) { + return 0; + } + if (fd_num) { qemu_chr_fe_set_msgfds(chr, fds, fd_num); } @@ -190,231 +182,321 @@ static int vhost_user_write(struct vhost_dev *dev, VhostUserMsg *msg, 0 : -1; } -static bool vhost_user_one_time_request(VhostUserRequest request) +static int vhost_user_set_log_base(struct vhost_dev *dev, uint64_t base, + struct vhost_log *log) { - switch (request) { - case VHOST_USER_SET_OWNER: - case VHOST_USER_RESET_DEVICE: - case VHOST_USER_SET_MEM_TABLE: - case VHOST_USER_GET_QUEUE_NUM: - return true; - default: - return false; + int fds[VHOST_MEMORY_MAX_NREGIONS]; + size_t fd_num = 0; + bool shmfd = virtio_has_feature(dev->protocol_features, + VHOST_USER_PROTOCOL_F_LOG_SHMFD); + VhostUserMsg msg = { + .request = VHOST_USER_SET_LOG_BASE, + .flags = VHOST_USER_VERSION, + .u64 = base, + .size = sizeof(m.u64), + }; + + if (shmfd && log->fd != -1) { + fds[fd_num++] = log->fd; + } + + vhost_user_write(dev, &msg, fds, fd_num); + + if (shmfd) { + msg.size = 0; + if (vhost_user_read(dev, &msg) < 0) { + return 0; + } + + if (msg.request != VHOST_USER_SET_LOG_BASE) { + error_report("Received unexpected msg type. " + "Expected %d received %d", + VHOST_USER_SET_LOG_BASE, msg.request); + return -1; + } } + + return 0; } -static int vhost_user_call(struct vhost_dev *dev, unsigned long int request, - void *arg) +static int vhost_user_set_mem_table(struct vhost_dev *dev, + struct vhost_memory *mem) { - VhostUserMsg msg; - VhostUserRequest msg_request; - struct vhost_vring_file *file = 0; - int need_reply = 0; 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, + }; - 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 (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; + } } - /* - * For non-vring specific requests, like VHOST_USER_SET_MEM_TABLE, - * we just need send it once in the first time. For later such - * request, we just ignore it. - */ - if (vhost_user_one_time_request(msg_request) && dev->vq_index != 0) { - return 0; + 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.request = msg_request; - msg.flags = VHOST_USER_VERSION; - msg.size = 0; + msg.size = sizeof(m.memory.nregions); + msg.size += sizeof(m.memory.padding); + msg.size += fd_num * sizeof(VhostUserMemoryRegion); - switch (msg_request) { - case VHOST_USER_GET_FEATURES: - case VHOST_USER_GET_PROTOCOL_FEATURES: - case VHOST_USER_GET_QUEUE_NUM: - need_reply = 1; - break; + vhost_user_write(dev, &msg, fds, fd_num); - case VHOST_USER_SET_FEATURES: - case VHOST_USER_SET_PROTOCOL_FEATURES: - msg.u64 = *((__u64 *) arg); - msg.size = sizeof(m.u64); - break; + return 0; +} - case VHOST_USER_SET_OWNER: - case VHOST_USER_RESET_DEVICE: - break; +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), + }; - 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; - } - } + vhost_user_write(dev, &msg, NULL, 0); - msg.memory.nregions = fd_num; + return 0; +} - if (!fd_num) { - error_report("Failed initializing vhost-user memory map, " - "consider using -object memory-backend-file share=on"); - return -1; - } +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; +} - 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"); +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; - break; } - if (vhost_user_write(dev, &msg, fds, fd_num) < 0) { + 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 (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; - } + 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; + } - 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; - } + if (msg.size != sizeof(m.state)) { + error_report("Received bad msg size."); + return -1; } + *ring = msg.state; + return 0; } -static int vhost_set_log_base(struct vhost_dev *dev, uint64_t base, - struct vhost_log *log) +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; - bool shmfd = virtio_has_feature(dev->protocol_features, - VHOST_USER_PROTOCOL_F_LOG_SHMFD); VhostUserMsg msg = { - .request = VHOST_USER_SET_LOG_BASE, + .request = request, .flags = VHOST_USER_VERSION, - .u64 = base, + .u64 = file->index & VHOST_USER_VRING_IDX_MASK, .size = sizeof(m.u64), }; - if (shmfd && log->fd != -1) { - fds[fd_num++] = log->fd; + 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); - if (shmfd) { - msg.size = 0; - if (vhost_user_read(dev, &msg) < 0) { - return 0; - } + return 0; +} - if (msg.request != VHOST_USER_SET_LOG_BASE) { - error_report("Received unexpected msg type. " - "Expected %d received %d", - VHOST_USER_SET_LOG_BASE, msg.request); - return -1; - } +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) { - unsigned long long features; + uint64_t features; int err; assert(dev->vhost_ops->backend_type == VHOST_BACKEND_TYPE_USER); dev->opaque = opaque; - err = vhost_user_call(dev, VHOST_USER_GET_FEATURES, &features); + err = vhost_user_get_features(dev, &features); if (err < 0) { 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)) { 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) { return err; } dev->protocol_features = features & VHOST_USER_PROTOCOL_FEATURE_MASK; - err = vhost_user_call(dev, VHOST_USER_SET_PROTOCOL_FEATURES, - &dev->protocol_features); + err = vhost_user_set_protocol_features(dev, dev->protocol_features); if (err < 0) { return err; } /* query the max queues we support if backend supports Multiple Queue */ 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) { return err; } @@ -454,22 +537,6 @@ static int vhost_user_init(struct vhost_dev *dev, void *opaque) 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) { 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 = { .backend_type = VHOST_BACKEND_TYPE_USER, - .vhost_call = vhost_user_call, .vhost_backend_init = vhost_user_init, .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_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, }; diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c index a553256081..2e78e4b706 100644 --- a/hw/virtio/vhost.c +++ b/hw/virtio/vhost.c @@ -555,7 +555,7 @@ static void vhost_commit(MemoryListener *listener) } 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); dev->memory_changed = false; return; @@ -568,7 +568,7 @@ static void vhost_commit(MemoryListener *listener) if (dev->log_size < log_size) { 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); /* To log less, can only decrease log size after table update. */ 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, .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) { return -errno; } @@ -650,7 +650,7 @@ static int vhost_dev_set_features(struct vhost_dev *dev, bool enable_log) if (enable_log) { 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; } @@ -755,7 +755,7 @@ static int vhost_virtqueue_set_vring_endian_legacy(struct vhost_dev *dev, .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; } @@ -774,7 +774,7 @@ static int vhost_virtqueue_start(struct vhost_dev *dev, { hwaddr s, l, a; 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 = { .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); - r = dev->vhost_ops->vhost_call(dev, VHOST_SET_VRING_NUM, &state); + r = dev->vhost_ops->vhost_set_vring_num(dev, &state); if (r) { return -errno; } 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) { 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)); - r = dev->vhost_ops->vhost_call(dev, VHOST_SET_VRING_KICK, &file); + r = dev->vhost_ops->vhost_set_vring_kick(dev, &file); if (r) { r = -errno; goto fail_kick; @@ -876,13 +876,13 @@ static void vhost_virtqueue_stop(struct vhost_dev *dev, struct vhost_virtqueue *vq, 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 = { .index = vhost_vq_index, }; 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) { fprintf(stderr, "vhost VQ %d ring restore failed: %d\n", idx, r); fflush(stderr); @@ -929,7 +929,7 @@ static void vhost_eventfd_del(MemoryListener *listener, static int vhost_virtqueue_init(struct vhost_dev *dev, 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 = { .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); - r = dev->vhost_ops->vhost_call(dev, VHOST_SET_VRING_CALL, &file); + r = dev->vhost_ops->vhost_set_vring_call(dev, &file); if (r) { r = -errno; goto fail_call; @@ -981,12 +981,12 @@ int vhost_dev_init(struct vhost_dev *hdev, void *opaque, } 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) { 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) { 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.index = hdev->vhost_ops->vhost_backend_get_vq_index(hdev, n); - r = hdev->vhost_ops->vhost_call(hdev, VHOST_SET_VRING_CALL, &file); + file.index = hdev->vhost_ops->vhost_get_vq_index(hdev, n); + r = hdev->vhost_ops->vhost_set_vring_call(hdev, &file); assert(r >= 0); } @@ -1190,7 +1190,7 @@ int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev) if (r < 0) { 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) { r = -errno; goto fail_mem; diff --git a/include/hw/virtio/vhost-backend.h b/include/hw/virtio/vhost-backend.h index 375625f5fb..ad1948101d 100644 --- a/include/hw/virtio/vhost-backend.h +++ b/include/hw/virtio/vhost-backend.h @@ -22,28 +22,77 @@ typedef enum VhostBackendType { struct vhost_dev; 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_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_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, 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 struct VhostOps { VhostBackendType backend_type; - vhost_call vhost_call; vhost_backend_init vhost_backend_init; 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_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_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; } VhostOps; diff --git a/include/hw/virtio/vhost.h b/include/hw/virtio/vhost.h index 6bf759f5c7..7437fd476a 100644 --- a/include/hw/virtio/vhost.h +++ b/include/hw/virtio/vhost.h @@ -45,14 +45,14 @@ struct vhost_dev { int nvqs; /* the first virtqueue which would be used by this vhost dev */ int vq_index; - unsigned long long features; - unsigned long long acked_features; - unsigned long long backend_features; - unsigned long long protocol_features; - unsigned long long max_queues; + uint64_t features; + uint64_t acked_features; + uint64_t backend_features; + uint64_t protocol_features; + uint64_t max_queues; bool started; bool log_enabled; - unsigned long long log_size; + uint64_t log_size; Error *migration_blocker; bool memory_changed; hwaddr mem_changed_start_addr; -- cgit 1.4.1 From 31190ed781a81d2de65cea405e4cb3441ab929fc Mon Sep 17 00:00:00 2001 From: Marc-André Lureau Date: Fri, 9 Oct 2015 17:17:34 +0200 Subject: vhost: add migration block if memfd failed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marc-André Lureau Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Tested-by: Thibaut Collet --- hw/virtio/vhost.c | 3 +++ include/qemu/memfd.h | 2 ++ util/memfd.c | 22 ++++++++++++++++++++++ 3 files changed, 27 insertions(+) (limited to 'hw/virtio/vhost.c') diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c index 2e78e4b706..feeaaa4186 100644 --- a/hw/virtio/vhost.c +++ b/hw/virtio/vhost.c @@ -1019,6 +1019,9 @@ int vhost_dev_init(struct vhost_dev *hdev, void *opaque, if (!(hdev->features & (0x1ULL << VHOST_F_LOG_ALL))) { error_setg(&hdev->migration_blocker, "Migration disabled: vhost lacks VHOST_F_LOG_ALL feature."); + } else if (!qemu_memfd_check()) { + error_setg(&hdev->migration_blocker, + "Migration disabled: failed to allocate shared memory"); } } diff --git a/include/qemu/memfd.h b/include/qemu/memfd.h index 950fb882a6..53858ed43c 100644 --- a/include/qemu/memfd.h +++ b/include/qemu/memfd.h @@ -2,6 +2,7 @@ #define QEMU_MEMFD_H #include "config-host.h" +#include #ifndef F_LINUX_SPECIFIC_BASE #define F_LINUX_SPECIFIC_BASE 1024 @@ -20,5 +21,6 @@ void *qemu_memfd_alloc(const char *name, size_t size, unsigned int seals, int *fd); void qemu_memfd_free(void *ptr, size_t size, int fd); +bool qemu_memfd_check(void); #endif /* QEMU_MEMFD_H */ diff --git a/util/memfd.c b/util/memfd.c index 4b23765b4a..7c406914c5 100644 --- a/util/memfd.c +++ b/util/memfd.c @@ -138,3 +138,25 @@ void qemu_memfd_free(void *ptr, size_t size, int fd) close(fd); } } + +enum { + MEMFD_KO, + MEMFD_OK, + MEMFD_TODO +}; + +bool qemu_memfd_check(void) +{ + static int memfd_check = MEMFD_TODO; + + if (memfd_check == MEMFD_TODO) { + int fd; + void *ptr; + + ptr = qemu_memfd_alloc("test", 4096, 0, &fd); + memfd_check = ptr ? MEMFD_OK : MEMFD_KO; + qemu_memfd_free(ptr, 4096, fd); + } + + return memfd_check == MEMFD_OK; +} -- cgit 1.4.1 From 25a2a920dddcf72896d94b37b6048a8147bc3198 Mon Sep 17 00:00:00 2001 From: Thibaut Collet Date: Mon, 19 Oct 2015 14:59:27 +0200 Subject: vhost: set the correct queue index in case of migration with multiqueue When a live migration is started the log address to mark dirty pages is provided to the vhost backend through the vhost_dev_set_log function. This function is called for each queue pairs but the queue index is wrongly set: always set to the first queue pair. Then vhost backend lost descriptor addresses of the queue pairs greater than 1 and behaviour of the vhost backend is unpredictable. The queue index is computed by taking account of the vq_index (to retrieve the queue pair index) and calling the vhost_get_vq_index method of the backend. Signed-off-by: Thibaut Collet Cc: qemu-stable@nongnu.org Acked-by: Michael S. Tsirkin Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/vhost.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'hw/virtio/vhost.c') diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c index feeaaa4186..de29968a79 100644 --- a/hw/virtio/vhost.c +++ b/hw/virtio/vhost.c @@ -656,13 +656,14 @@ static int vhost_dev_set_features(struct vhost_dev *dev, bool enable_log) static int vhost_dev_set_log(struct vhost_dev *dev, bool enable_log) { - int r, t, i; + int r, t, i, idx; r = vhost_dev_set_features(dev, enable_log); if (r < 0) { goto err_features; } for (i = 0; i < dev->nvqs; ++i) { - r = vhost_virtqueue_set_addr(dev, dev->vqs + i, i, + idx = dev->vhost_ops->vhost_get_vq_index(dev, dev->vq_index + i); + r = vhost_virtqueue_set_addr(dev, dev->vqs + i, idx, enable_log); if (r < 0) { goto err_vq; @@ -671,7 +672,8 @@ static int vhost_dev_set_log(struct vhost_dev *dev, bool enable_log) return 0; err_vq: for (; i >= 0; --i) { - t = vhost_virtqueue_set_addr(dev, dev->vqs + i, i, + idx = dev->vhost_ops->vhost_get_vq_index(dev, dev->vq_index + i); + t = vhost_virtqueue_set_addr(dev, dev->vqs + i, idx, dev->log_enabled); assert(t >= 0); } -- cgit 1.4.1