thebeanogamer / rpms / qemu-kvm

Forked from rpms/qemu-kvm 5 months ago
Clone
97168e
From f21a343af4b4d0c6e5181ae0abd0f6280dc8296c Mon Sep 17 00:00:00 2001
97168e
From: "manish.mishra" <manish.mishra@nutanix.com>
97168e
Date: Tue, 20 Dec 2022 18:44:18 +0000
97168e
Subject: [PATCH 2/3] migration: check magic value for deciding the mapping of
97168e
 channels
97168e
MIME-Version: 1.0
97168e
Content-Type: text/plain; charset=UTF-8
97168e
Content-Transfer-Encoding: 8bit
97168e
97168e
RH-Author: Peter Xu <peterx@redhat.com>
97168e
RH-MergeRequest: 258: migration: Fix multifd crash due to channel disorder
97168e
RH-Bugzilla: 2137740
97168e
RH-Acked-by: quintela1 <quintela@redhat.com>
97168e
RH-Acked-by: Leonardo BrĂ¡s <leobras@redhat.com>
97168e
RH-Acked-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
97168e
RH-Commit: [2/2] f97bebef3d3e372cfd660e5ddb6cffba791840d2
97168e
97168e
Conflicts:
97168e
        migration/migration.c
97168e
        migration/multifd.c
97168e
        migration/postcopy-ram.c
97168e
        migration/postcopy-ram.h
97168e
97168e
        There're a bunch of conflicts due to missing upstream patches on
97168e
        e.g. on qemufile reworks, postcopy preempt.  We don't plan to have
97168e
        preempt in rhel8 at all, probably the same as the rest.
97168e
97168e
Current logic assumes that channel connections on the destination side are
97168e
always established in the same order as the source and the first one will
97168e
always be the main channel followed by the multifid or post-copy
97168e
preemption channel. This may not be always true, as even if a channel has a
97168e
connection established on the source side it can be in the pending state on
97168e
the destination side and a newer connection can be established first.
97168e
Basically causing out of order mapping of channels on the destination side.
97168e
Currently, all channels except post-copy preempt send a magic number, this
97168e
patch uses that magic number to decide the type of channel. This logic is
97168e
applicable only for precopy(multifd) live migration, as mentioned, the
97168e
post-copy preempt channel does not send any magic number. Also, tls live
97168e
migrations already does tls handshake before creating other channels, so
97168e
this issue is not possible with tls, hence this logic is avoided for tls
97168e
live migrations. This patch uses read peek to check the magic number of
97168e
channels so that current data/control stream management remains
97168e
un-effected.
97168e
97168e
Reviewed-by: Peter Xu <peterx@redhat.com>
97168e
Reviewed-by: Daniel P. Berrange <berrange@redhat.com>
97168e
Reviewed-by: Juan Quintela <quintela@redhat.com>
97168e
Suggested-by: Daniel P. Berrange <berrange@redhat.com>
97168e
Signed-off-by: manish.mishra <manish.mishra@nutanix.com>
97168e
Signed-off-by: Juan Quintela <quintela@redhat.com>
97168e
(cherry picked from commit 6720c2b32725e6ac404f22851a0ecd0a71d0cbe2)
97168e
Signed-off-by: Peter Xu <peterx@redhat.com>
97168e
---
97168e
 migration/channel.c   | 45 ++++++++++++++++++++++++++++++++++++++
97168e
 migration/channel.h   |  5 +++++
97168e
 migration/migration.c | 51 +++++++++++++++++++++++++++++++------------
97168e
 migration/multifd.c   | 19 ++++++++--------
97168e
 migration/multifd.h   |  2 +-
97168e
 5 files changed, 98 insertions(+), 24 deletions(-)
97168e
97168e
diff --git a/migration/channel.c b/migration/channel.c
97168e
index 086b5c0d8b..ee308fef23 100644
97168e
--- a/migration/channel.c
97168e
+++ b/migration/channel.c
97168e
@@ -98,3 +98,48 @@ void migration_channel_connect(MigrationState *s,
97168e
     g_free(s->hostname);
97168e
     error_free(error);
97168e
 }
97168e
+
97168e
+
97168e
+/**
97168e
+ * @migration_channel_read_peek - Peek at migration channel, without
97168e
+ *     actually removing it from channel buffer.
97168e
+ *
97168e
+ * @ioc: the channel object
97168e
+ * @buf: the memory region to read data into
97168e
+ * @buflen: the number of bytes to read in @buf
97168e
+ * @errp: pointer to a NULL-initialized error object
97168e
+ *
97168e
+ * Returns 0 if successful, returns -1 and sets @errp if fails.
97168e
+ */
97168e
+int migration_channel_read_peek(QIOChannel *ioc,
97168e
+                                const char *buf,
97168e
+                                const size_t buflen,
97168e
+                                Error **errp)
97168e
+{
97168e
+    ssize_t len = 0;
97168e
+    struct iovec iov = { .iov_base = (char *)buf, .iov_len = buflen };
97168e
+
97168e
+    while (true) {
97168e
+        len = qio_channel_readv_full(ioc, &iov, 1, NULL, NULL,
97168e
+                                     QIO_CHANNEL_READ_FLAG_MSG_PEEK, errp);
97168e
+
97168e
+        if (len <= 0 && len != QIO_CHANNEL_ERR_BLOCK) {
97168e
+            error_setg(errp,
97168e
+                       "Failed to peek at channel");
97168e
+            return -1;
97168e
+        }
97168e
+
97168e
+        if (len == buflen) {
97168e
+            break;
97168e
+        }
97168e
+
97168e
+        /* 1ms sleep. */
97168e
+        if (qemu_in_coroutine()) {
97168e
+            qemu_co_sleep_ns(QEMU_CLOCK_REALTIME, 1000000);
97168e
+        } else {
97168e
+            g_usleep(1000);
97168e
+        }
97168e
+    }
97168e
+
97168e
+    return 0;
97168e
+}
97168e
diff --git a/migration/channel.h b/migration/channel.h
97168e
index 67a461c28a..5bdb8208a7 100644
97168e
--- a/migration/channel.h
97168e
+++ b/migration/channel.h
97168e
@@ -24,4 +24,9 @@ void migration_channel_connect(MigrationState *s,
97168e
                                QIOChannel *ioc,
97168e
                                const char *hostname,
97168e
                                Error *error_in);
97168e
+
97168e
+int migration_channel_read_peek(QIOChannel *ioc,
97168e
+                                const char *buf,
97168e
+                                const size_t buflen,
97168e
+                                Error **errp);
97168e
 #endif
97168e
diff --git a/migration/migration.c b/migration/migration.c
97168e
index d8b24a2c91..0885549de0 100644
97168e
--- a/migration/migration.c
97168e
+++ b/migration/migration.c
97168e
@@ -32,6 +32,7 @@
97168e
 #include "savevm.h"
97168e
 #include "qemu-file-channel.h"
97168e
 #include "qemu-file.h"
97168e
+#include "channel.h"
97168e
 #include "migration/vmstate.h"
97168e
 #include "block/block.h"
97168e
 #include "qapi/error.h"
97168e
@@ -637,10 +638,6 @@ static bool migration_incoming_setup(QEMUFile *f, Error **errp)
97168e
 {
97168e
     MigrationIncomingState *mis = migration_incoming_get_current();
97168e
 
97168e
-    if (multifd_load_setup(errp) != 0) {
97168e
-        return false;
97168e
-    }
97168e
-
97168e
     if (!mis->from_src_file) {
97168e
         mis->from_src_file = f;
97168e
     }
97168e
@@ -701,10 +698,42 @@ void migration_fd_process_incoming(QEMUFile *f, Error **errp)
97168e
 void migration_ioc_process_incoming(QIOChannel *ioc, Error **errp)
97168e
 {
97168e
     MigrationIncomingState *mis = migration_incoming_get_current();
97168e
+    bool default_channel = true;
97168e
+    uint32_t channel_magic = 0;
97168e
     Error *local_err = NULL;
97168e
-    bool start_migration;
97168e
+    int ret = 0;
97168e
 
97168e
-    if (!mis->from_src_file) {
97168e
+    if (migrate_use_multifd() && !migrate_postcopy_ram() &&
97168e
+        qio_channel_has_feature(ioc, QIO_CHANNEL_FEATURE_READ_MSG_PEEK)) {
97168e
+        /*
97168e
+         * With multiple channels, it is possible that we receive channels
97168e
+         * out of order on destination side, causing incorrect mapping of
97168e
+         * source channels on destination side. Check channel MAGIC to
97168e
+         * decide type of channel. Please note this is best effort, postcopy
97168e
+         * preempt channel does not send any magic number so avoid it for
97168e
+         * postcopy live migration. Also tls live migration already does
97168e
+         * tls handshake while initializing main channel so with tls this
97168e
+         * issue is not possible.
97168e
+         */
97168e
+        ret = migration_channel_read_peek(ioc, (void *)&channel_magic,
97168e
+                                          sizeof(channel_magic), &local_err);
97168e
+
97168e
+        if (ret != 0) {
97168e
+            error_propagate(errp, local_err);
97168e
+            return;
97168e
+        }
97168e
+
97168e
+        default_channel = (channel_magic == cpu_to_be32(QEMU_VM_FILE_MAGIC));
97168e
+    } else {
97168e
+        default_channel = !mis->from_src_file;
97168e
+    }
97168e
+
97168e
+    if (multifd_load_setup(errp) != 0) {
97168e
+        error_setg(errp, "Failed to setup multifd channels");
97168e
+        return;
97168e
+    }
97168e
+
97168e
+    if (default_channel) {
97168e
         /* The first connection (multifd may have multiple) */
97168e
         QEMUFile *f = qemu_fopen_channel_input(ioc);
97168e
 
97168e
@@ -716,23 +745,17 @@ void migration_ioc_process_incoming(QIOChannel *ioc, Error **errp)
97168e
         if (!migration_incoming_setup(f, errp)) {
97168e
             return;
97168e
         }
97168e
-
97168e
-        /*
97168e
-         * Common migration only needs one channel, so we can start
97168e
-         * right now.  Multifd needs more than one channel, we wait.
97168e
-         */
97168e
-        start_migration = !migrate_use_multifd();
97168e
     } else {
97168e
         /* Multiple connections */
97168e
         assert(migrate_use_multifd());
97168e
-        start_migration = multifd_recv_new_channel(ioc, &local_err);
97168e
+        multifd_recv_new_channel(ioc, &local_err);
97168e
         if (local_err) {
97168e
             error_propagate(errp, local_err);
97168e
             return;
97168e
         }
97168e
     }
97168e
 
97168e
-    if (start_migration) {
97168e
+    if (migration_has_all_channels()) {
97168e
         migration_incoming_process();
97168e
     }
97168e
 }
97168e
diff --git a/migration/multifd.c b/migration/multifd.c
97168e
index 7c16523e6b..75ac052d2f 100644
97168e
--- a/migration/multifd.c
97168e
+++ b/migration/multifd.c
97168e
@@ -1183,9 +1183,14 @@ int multifd_load_setup(Error **errp)
97168e
     uint32_t page_count = MULTIFD_PACKET_SIZE / qemu_target_page_size();
97168e
     uint8_t i;
97168e
 
97168e
-    if (!migrate_use_multifd()) {
97168e
+    /*
97168e
+     * Return successfully if multiFD recv state is already initialised
97168e
+     * or multiFD is not enabled.
97168e
+     */
97168e
+    if (multifd_recv_state || !migrate_use_multifd()) {
97168e
         return 0;
97168e
     }
97168e
+
97168e
     if (!migrate_multifd_is_allowed()) {
97168e
         error_setg(errp, "multifd is not supported by current protocol");
97168e
         return -1;
97168e
@@ -1244,11 +1249,9 @@ bool multifd_recv_all_channels_created(void)
97168e
 
97168e
 /*
97168e
  * Try to receive all multifd channels to get ready for the migration.
97168e
- * - Return true and do not set @errp when correctly receiving all channels;
97168e
- * - Return false and do not set @errp when correctly receiving the current one;
97168e
- * - Return false and set @errp when failing to receive the current channel.
97168e
+ * Sets @errp when failing to receive the current channel.
97168e
  */
97168e
-bool multifd_recv_new_channel(QIOChannel *ioc, Error **errp)
97168e
+void multifd_recv_new_channel(QIOChannel *ioc, Error **errp)
97168e
 {
97168e
     MultiFDRecvParams *p;
97168e
     Error *local_err = NULL;
97168e
@@ -1261,7 +1264,7 @@ bool multifd_recv_new_channel(QIOChannel *ioc, Error **errp)
97168e
                                 "failed to receive packet"
97168e
                                 " via multifd channel %d: ",
97168e
                                 qatomic_read(&multifd_recv_state->count));
97168e
-        return false;
97168e
+        return;
97168e
     }
97168e
     trace_multifd_recv_new_channel(id);
97168e
 
97168e
@@ -1271,7 +1274,7 @@ bool multifd_recv_new_channel(QIOChannel *ioc, Error **errp)
97168e
                    id);
97168e
         multifd_recv_terminate_threads(local_err);
97168e
         error_propagate(errp, local_err);
97168e
-        return false;
97168e
+        return;
97168e
     }
97168e
     p->c = ioc;
97168e
     object_ref(OBJECT(ioc));
97168e
@@ -1282,6 +1285,4 @@ bool multifd_recv_new_channel(QIOChannel *ioc, Error **errp)
97168e
     qemu_thread_create(&p->thread, p->name, multifd_recv_thread, p,
97168e
                        QEMU_THREAD_JOINABLE);
97168e
     qatomic_inc(&multifd_recv_state->count);
97168e
-    return qatomic_read(&multifd_recv_state->count) ==
97168e
-           migrate_multifd_channels();
97168e
 }
97168e
diff --git a/migration/multifd.h b/migration/multifd.h
97168e
index 11d5e273e6..9c0a2a0701 100644
97168e
--- a/migration/multifd.h
97168e
+++ b/migration/multifd.h
97168e
@@ -20,7 +20,7 @@ void multifd_save_cleanup(void);
97168e
 int multifd_load_setup(Error **errp);
97168e
 int multifd_load_cleanup(Error **errp);
97168e
 bool multifd_recv_all_channels_created(void);
97168e
-bool multifd_recv_new_channel(QIOChannel *ioc, Error **errp);
97168e
+void multifd_recv_new_channel(QIOChannel *ioc, Error **errp);
97168e
 void multifd_recv_sync_main(void);
97168e
 int multifd_send_sync_main(QEMUFile *f);
97168e
 int multifd_queue_page(QEMUFile *f, RAMBlock *block, ram_addr_t offset);
97168e
-- 
97168e
2.37.3
97168e