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
