There are some situations during migration when we want to change the runstate of the VM, but don't actually want the new runstate to be put on the wire to be restored on the destination VM. In those cases, the pattern is to use global_state_store() to save the state for migration before changing it.
One scenario where this happens is when switching the source VM into the FINISH_MIGRATE state. This state only makes sense on the source VM. Another situation is when pausing the source VM prior to migration completion. We are about to introduce a third scenario when the whole migration should be performed with a paused VM. In this case we will want to save the VM runstate at the very start of the migration and that state will be the one restored on the destination regardless of all the runstate changes that happen in between. To achieve that we need to make sure that the other two calls to global_state_store() do not overwrite the state that is to be migrated. Introduce a version of global_state_store() that only saves the state if no other state has already been saved. Signed-off-by: Fabiano Rosas <faro...@suse.de> --- include/migration/global_state.h | 1 + migration/global_state.c | 13 +++++++++++++ migration/migration.c | 6 +++--- 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/include/migration/global_state.h b/include/migration/global_state.h index e268dc1f18..9d3624100e 100644 --- a/include/migration/global_state.h +++ b/include/migration/global_state.h @@ -17,6 +17,7 @@ void register_global_state(void); RunState global_state_store(void); +RunState global_state_store_once(void); void global_state_store_running(void); bool global_state_received(void); RunState global_state_get_runstate(void); diff --git a/migration/global_state.c b/migration/global_state.c index d094af6198..beb00039d9 100644 --- a/migration/global_state.c +++ b/migration/global_state.c @@ -45,6 +45,19 @@ RunState global_state_store(void) return r; } +RunState global_state_store_once(void) +{ + int r; + char *runstate = (char *)global_state.runstate; + + r = qapi_enum_parse(&RunState_lookup, runstate, -1, NULL); + if (r < 0) { + return global_state_store(); + } + + return r; +} + void global_state_store_running(void) { global_state_do_store(RUN_STATE_RUNNING); diff --git a/migration/migration.c b/migration/migration.c index 0c23117369..a6efbd837a 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -2144,7 +2144,7 @@ static int postcopy_start(MigrationState *ms, Error **errp) trace_postcopy_start_set_run(); qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER, NULL); - global_state_store(); + global_state_store_once(); ret = vm_stop_force_state(RUN_STATE_FINISH_MIGRATE); if (ret < 0) { goto fail; @@ -2344,7 +2344,7 @@ static int migration_completion_precopy(MigrationState *s, s->downtime_start = qemu_clock_get_ms(QEMU_CLOCK_REALTIME); qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER, NULL); - s->vm_old_state = global_state_store(); + s->vm_old_state = global_state_store_once(); ret = vm_stop_force_state(RUN_STATE_FINISH_MIGRATE); trace_migration_completion_vm_stop(ret); @@ -3200,7 +3200,7 @@ static void *bg_migration_thread(void *opaque) * transition in vm_stop_force_state() we need to wakeup it up. */ qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER, NULL); - s->vm_old_state = global_state_store(); + s->vm_old_state = global_state_store_once(); /* Forcibly stop VM before saving state of vCPUs and devices */ if (vm_stop_force_state(RUN_STATE_PAUSED)) { -- 2.35.3