From: Denis V. Lunev <[email protected]>

Commit 7b842fe354c ("migration: Introduce POSTCOPY_DEVICE state") keeps
the source in POSTCOPY_DEVICE until the destination answers the
QEMU_VM_PING_PACKAGED_LOADED ping packaged right before
CMD_POSTCOPY_RUN. The destination answers it from the generic
MIG_CMD_PING handler as soon as it reads it, so the source's
postcopy-active means the device state is loaded, not that the
destination has left RUN_STATE_INMIGRATE. Management acting on the
destination once the source reports postcopy-active can still race
with loadvm_postcopy_handle_run_bh().

Record the ping in the MIG_CMD_PING handler instead of answering it,
and send the pong at the end of the run BH, after the run state change.

The wire format is unchanged: the pong only arrives later, and an
older destination keeps answering at once, so mixed versions
interoperate. The cost is that the source stays in POSTCOPY_DEVICE for
the duration of the run BH, including block layer activation when the
destination autostarts.

Suggested-by: Peter Xu <[email protected]>
Signed-off-by: Denis V. Lunev <[email protected]>
Cc: Peter Xu <[email protected]>
Cc: Fabiano Rosas <[email protected]>
Cc: Juraj Marcin <[email protected]>
---
 migration/migration.c | 1 +
 migration/migration.h | 2 ++
 migration/savevm.c    | 8 ++++++++
 3 files changed, 11 insertions(+)

diff --git a/migration/migration.c b/migration/migration.c
index 8944acf3cd..f93f99f30e 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -495,6 +495,7 @@ void migration_incoming_state_destroy(void)
     migration_incoming_transport_cleanup(mis);
     qemu_event_reset(&mis->main_thread_load_event);
     qemu_event_reset(&mis->postcopy_run_event);
+    mis->postcopy_package_loaded_ping = false;
 
     if (mis->page_requested) {
         g_tree_destroy(mis->page_requested);
diff --git a/migration/migration.h b/migration/migration.h
index c65212ff63..80401391f8 100644
--- a/migration/migration.h
+++ b/migration/migration.h
@@ -110,6 +110,8 @@ struct MigrationIncomingState {
     QemuEvent main_thread_load_event;
     /* Set once the postcopy run BH has changed the run state */
     QemuEvent postcopy_run_event;
+    /* QEMU_VM_PING_PACKAGED_LOADED received, answered by the run BH */
+    bool postcopy_package_loaded_ping;
 
     /* For network announces */
     AnnounceTimer  announce_timer;
diff --git a/migration/savevm.c b/migration/savevm.c
index bc1bc98a0e..e20471892f 100644
--- a/migration/savevm.c
+++ b/migration/savevm.c
@@ -2267,6 +2267,10 @@ static void loadvm_postcopy_handle_run_bh(void *opaque)
     /* Already POSTCOPY_ACTIVE without a return path or in fast snapshot load 
*/
     migrate_set_state(&mis->state, MIGRATION_STATUS_POSTCOPY_DEVICE,
                       MIGRATION_STATUS_POSTCOPY_ACTIVE);
+    if (mis->postcopy_package_loaded_ping) {
+        mis->postcopy_package_loaded_ping = false;
+        migrate_send_rp_pong(mis, QEMU_VM_PING_PACKAGED_LOADED);
+    }
     qemu_event_set(&mis->postcopy_run_event);
 }
 
@@ -2618,6 +2622,10 @@ static int loadvm_process_command(QEMUFile *f, Error 
**errp)
                        tmp32);
             return -1;
         }
+        if (tmp32 == QEMU_VM_PING_PACKAGED_LOADED) {
+            mis->postcopy_package_loaded_ping = true;
+            return 0;
+        }
         migrate_send_rp_pong(mis, tmp32);
         return 0;
 
-- 
2.53.0


Reply via email to