From: Steve Sistare <steven.sistare@oracle.com>
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.
Signed-off-by: Mark Kanda <mark.kanda@oracle.com>
Signed-off-by: Steve Sistare <steven.sistare@oracle.com>
Signed-off-by: Ben Chaney <bchaney@akamai.com>
---
hw/virtio/vhost-backend.c | 6 ++++++
hw/virtio/vhost.c | 32 ++++++++++++++++++++++++++++++++
include/hw/virtio/vhost-backend.h | 1 +
include/hw/virtio/vhost.h | 1 +
4 files changed, 40 insertions(+)
diff --git a/hw/virtio/vhost-backend.c b/hw/virtio/vhost-backend.c
index 4367db0d95..1447d12963 100644
--- a/hw/virtio/vhost-backend.c
+++ b/hw/virtio/vhost-backend.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 266a11514a..011d73dae2 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"
@@ -1540,6 +1541,32 @@ static int vhost_dev_get_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_transfer_notifier);
+
+ if (dev->vhost_ops->backend_type != VHOST_BACKEND_TYPE_KERNEL) {
+ return 0;
+ }
+
+ if (e->type == MIG_EVENT_PRECOPY_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_PRECOPY_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)
@@ -1550,6 +1577,7 @@ int vhost_dev_init(struct vhost_dev *hdev, void *opaque,
hdev->vdev = NULL;
hdev->migration_blocker = NULL;
+ hdev->cpr_transfer_notifier.notify = NULL;
r = vhost_set_backend_type(hdev, backend_type);
assert(r >= 0);
@@ -1650,6 +1678,9 @@ 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_mode(&hdev->cpr_transfer_notifier,
+ vhost_cpr_notifier,
+ MIG_MODE_CPR_TRANSFER);
QLIST_INSERT_HEAD(&vhost_devices, hdev, entry);
/*
@@ -1702,6 +1733,7 @@ void vhost_dev_cleanup(struct vhost_dev *hdev)
QLIST_REMOVE(hdev, entry);
}
migrate_del_blocker(&hdev->migration_blocker);
+ migration_remove_notifier(&hdev->cpr_transfer_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 ff94fa1734..18ce5ea9a0 100644
--- a/include/hw/virtio/vhost-backend.h
+++ b/include/hw/virtio/vhost-backend.h
@@ -196,6 +196,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 08bbb4dfe9..5d11a97e43 100644
--- a/include/hw/virtio/vhost.h
+++ b/include/hw/virtio/vhost.h
@@ -133,6 +133,7 @@ struct vhost_dev {
QLIST_ENTRY(vhost_dev) logdev_entry;
QLIST_HEAD(, vhost_iommu) iommu_list;
IOMMUNotifier n;
+ NotifierWithReturn cpr_transfer_notifier;
const VhostDevConfigOps *config_ops;
};
--
2.34.1