When preserving a vhost fd using CPR, call VHOST_RESET_OWNER prior to CPR in old QEMU. Otherwise, new QEMU will fail when it calls VHOST_SET_OWNER during vhost_dev_init.
This patch is a rework of the change originally proposed by Steve, Ben and Mark at [0]. [0] https://lore.kernel.org/qemu-devel/[email protected] Originally-by: Mark Kanda <[email protected]> Originally-by: Steve Sistare <[email protected]> Originally-by: Ben Chaney <[email protected]> Signed-off-by: Andrey Drobyshev <[email protected]> --- hw/virtio/vhost-kernel.c | 6 ++++++ hw/virtio/vhost.c | 33 +++++++++++++++++++++++++++++++ include/hw/virtio/vhost-backend.h | 1 + include/hw/virtio/vhost.h | 1 + 4 files changed, 41 insertions(+) diff --git a/hw/virtio/vhost-kernel.c b/hw/virtio/vhost-kernel.c index 3390b48c6f1..55d316b88e9 100644 --- a/hw/virtio/vhost-kernel.c +++ b/hw/virtio/vhost-kernel.c @@ -261,6 +261,11 @@ static int vhost_kernel_set_owner(struct vhost_dev *dev) return vhost_kernel_call(dev, VHOST_SET_OWNER, NULL); } +static int vhost_kernel_reset_owner(struct vhost_dev *dev) +{ + return vhost_kernel_call(dev, VHOST_RESET_OWNER, 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); @@ -385,6 +390,7 @@ const VhostOps kernel_ops = { .vhost_get_features_ex = vhost_kernel_get_features, .vhost_set_backend_cap = vhost_kernel_set_backend_cap, .vhost_set_owner = vhost_kernel_set_owner, + .vhost_reset_owner = vhost_kernel_reset_owner, .vhost_get_vq_index = vhost_kernel_get_vq_index, .vhost_vsock_set_guest_cid = vhost_kernel_vsock_set_guest_cid, .vhost_vsock_set_running = vhost_kernel_vsock_set_running, diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c index af41841b529..1521b50cbff 100644 --- a/hw/virtio/vhost.c +++ b/hw/virtio/vhost.c @@ -24,6 +24,7 @@ #include "standard-headers/linux/vhost_types.h" #include "hw/virtio/virtio-bus.h" #include "hw/mem/memory-device.h" +#include "migration/misc.h" #include "migration/blocker.h" #include "migration/qemu-file-types.h" #include "system/dma.h" @@ -1667,6 +1668,32 @@ static int vhost_dev_init_features(struct vhost_dev *hdev) return r; } +static int vhost_cpr_notifier(NotifierWithReturn *notifier, + MigrationEvent *e, Error **errp) +{ + struct vhost_dev *dev; + int r; + + dev = container_of(notifier, struct vhost_dev, cpr_notifier); + + if (dev->vhost_ops->backend_type != VHOST_BACKEND_TYPE_KERNEL) { + return 0; + } + + if (e->type == MIG_EVENT_SETUP) { + r = dev->vhost_ops->vhost_reset_owner(dev); + if (r < 0) { + VHOST_OPS_DEBUG(r, "vhost_reset_owner failed"); + } + } else if (e->type == MIG_EVENT_FAILED) { + r = dev->vhost_ops->vhost_set_owner(dev); + if (r < 0) { + VHOST_OPS_DEBUG(r, "vhost_set_owner failed"); + } + } + return 0; +} + int vhost_dev_init(struct vhost_dev *hdev, void *opaque, VhostBackendType backend_type, uint32_t busyloop_timeout, Error **errp) @@ -1678,6 +1705,7 @@ int vhost_dev_init(struct vhost_dev *hdev, void *opaque, hdev->vdev = NULL; hdev->migration_blocker = NULL; + hdev->cpr_notifier.notify = NULL; r = vhost_set_backend_type(hdev, backend_type); assert(r >= 0); @@ -1766,6 +1794,10 @@ int vhost_dev_init(struct vhost_dev *hdev, void *opaque, hdev->log_enabled = false; hdev->started = false; memory_listener_register(&hdev->memory_listener, &address_space_memory); + migration_add_notifier_modes(&hdev->cpr_notifier, + vhost_cpr_notifier, + BIT(MIG_MODE_CPR_TRANSFER) | + BIT(MIG_MODE_CPR_EXEC)); QLIST_INSERT_HEAD(&vhost_devices, hdev, entry); /* @@ -1814,6 +1846,7 @@ void vhost_dev_cleanup(struct vhost_dev *hdev) QLIST_REMOVE(hdev, entry); } migrate_del_blocker(&hdev->migration_blocker); + migration_remove_notifier(&hdev->cpr_notifier); g_free(hdev->mem); g_free(hdev->mem_sections); if (hdev->vhost_ops) { diff --git a/include/hw/virtio/vhost-backend.h b/include/hw/virtio/vhost-backend.h index d878d7b733a..6c949e6a38d 100644 --- a/include/hw/virtio/vhost-backend.h +++ b/include/hw/virtio/vhost-backend.h @@ -204,6 +204,7 @@ typedef struct VhostOps { vhost_get_features_op vhost_get_features; vhost_set_backend_cap_op vhost_set_backend_cap; vhost_set_owner_op vhost_set_owner; + vhost_set_owner_op vhost_reset_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; diff --git a/include/hw/virtio/vhost.h b/include/hw/virtio/vhost.h index 684bafcaadd..1a722ddf16e 100644 --- a/include/hw/virtio/vhost.h +++ b/include/hw/virtio/vhost.h @@ -119,6 +119,7 @@ struct vhost_dev { QLIST_ENTRY(vhost_dev) logdev_entry; QLIST_HEAD(, vhost_iommu) iommu_list; IOMMUNotifier n; + NotifierWithReturn cpr_notifier; const VhostDevConfigOps *config_ops; }; -- 2.47.1
