In case of local backend migration, skip backend-related
initialization, but instead get the state from migration
channel (including secondary channel file descriptor).

Signed-off-by: Vladimir Sementsov-Ogievskiy <vsement...@yandex-team.ru>
---
 hw/virtio/vhost-user.c | 62 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 62 insertions(+)

diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c
index 3979582975..f220af270e 100644
--- a/hw/virtio/vhost-user.c
+++ b/hw/virtio/vhost-user.c
@@ -28,6 +28,8 @@
 #include "system/runstate.h"
 #include "system/cryptodev.h"
 #include "migration/postcopy-ram.h"
+#include "migration/qemu-file-types.h"
+#include "migration/qemu-file.h"
 #include "trace.h"
 #include "system/ramblock.h"
 
@@ -2273,6 +2275,10 @@ static int vhost_user_backend_init(struct vhost_dev 
*dev, void *opaque,
     u->dev = dev;
     dev->opaque = u;
 
+    if (dev->migrating_backend) {
+        goto out;
+    }
+
     err = vhost_user_get_features(dev, &features);
     if (err < 0) {
         error_setg_errno(errp, -err, "vhost_backend_init failed");
@@ -2387,6 +2393,7 @@ static int vhost_user_backend_init(struct vhost_dev *dev, 
void *opaque,
         }
     }
 
+out:
     u->postcopy_notifier.notify = vhost_user_postcopy_notifier;
     postcopy_add_notifier(&u->postcopy_notifier);
 
@@ -2936,6 +2943,10 @@ void vhost_user_async_close(DeviceState *d,
 
 static int vhost_user_dev_start(struct vhost_dev *dev, bool started)
 {
+    if (dev->migrating_backend) {
+        return 0;
+    }
+
     if (!vhost_user_has_prot(dev, VHOST_USER_PROTOCOL_F_STATUS)) {
         return 0;
     }
@@ -3105,6 +3116,55 @@ static void vhost_user_qmp_status(struct vhost_dev *dev, 
VhostStatus *status)
     status->protocol_features = qmp_decode_protocols(u->protocol_features);
 }
 
+static void vhost_user_save(struct vhost_dev *dev, QEMUFile *f)
+{
+    struct vhost_user *u = dev->opaque;
+    bool has_backend_channel = !!u->backend_sioc;
+    qemu_put_be64(f, u->protocol_features);
+    qemu_put_be32(f, u->user->memory_slots);
+
+    qemu_put_byte(f, has_backend_channel);
+    if (u->backend_sioc) {
+        qemu_file_put_fd(f, u->backend_sioc->fd);
+    }
+}
+
+static int vhost_user_load(struct vhost_dev *dev, QEMUFile *f)
+{
+    struct vhost_user *u = dev->opaque;
+    uint8_t has_backend_channel;
+    uint32_t memory_slots;
+
+    qemu_get_be64s(f, &u->protocol_features);
+    qemu_get_be32s(f, &memory_slots);
+    qemu_get_8s(f, &has_backend_channel);
+
+    u->user->memory_slots = memory_slots;
+
+    if (has_backend_channel) {
+        int fd = qemu_file_get_fd(f);
+        Error *local_err = NULL;
+
+        u->backend_sioc = qio_channel_socket_new_fd(fd, &local_err);
+        if (!u->backend_sioc) {
+            error_report_err(local_err);
+            return -ECONNREFUSED;
+        }
+        u->backend_src = qio_channel_add_watch_source(
+            QIO_CHANNEL(u->backend_sioc), G_IO_IN | G_IO_HUP,
+            backend_read, dev, NULL, NULL);
+    }
+
+    if (dev->migration_blocker == NULL &&
+        !vhost_user_has_prot(dev, 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;
+}
+
 const VhostOps user_ops = {
         .backend_type = VHOST_BACKEND_TYPE_USER,
         .vhost_backend_init = vhost_user_backend_init,
@@ -3146,4 +3206,6 @@ const VhostOps user_ops = {
         .vhost_set_device_state_fd = vhost_user_set_device_state_fd,
         .vhost_check_device_state = vhost_user_check_device_state,
         .vhost_qmp_status = vhost_user_qmp_status,
+        .vhost_save_backend = vhost_user_save,
+        .vhost_load_backend = vhost_user_load,
 };
-- 
2.48.1


Reply via email to