* [PATCH V3 01/10] vl: start on wakeup request
2023-08-14 18:54 [PATCH V3 00/10] fix migration of suspended runstate Steve Sistare
@ 2023-08-14 18:54 ` Steve Sistare
2023-08-17 18:27 ` Peter Xu
2023-08-14 18:54 ` [PATCH V3 02/10] migration: preserve suspended runstate Steve Sistare
` (9 subsequent siblings)
10 siblings, 1 reply; 18+ messages in thread
From: Steve Sistare @ 2023-08-14 18:54 UTC (permalink / raw)
To: qemu-devel
Cc: Juan Quintela, Peter Xu, Paolo Bonzini, Thomas Huth,
Daniel P. Berrangé, Steve Sistare
If qemu starts and loads a VM in the suspended state, then a later wakeup
request directly sets the state to running. This skips vm_start() and its
initialization steps, which is fatal for the guest. See
qemu_system_wakeup_request(), and qemu_system_wakeup() in
main_loop_should_exit().
Remember if vm_start has been called. If not, then call vm_start from
qemu_system_wakeup_request.
Signed-off-by: Steve Sistare <steven.sistare@oracle.com>
Reviewed-by: Fabiano Rosas <farosas@suse.de>
---
include/sysemu/runstate.h | 1 +
softmmu/cpus.c | 12 ++++++++++++
softmmu/runstate.c | 2 +-
3 files changed, 14 insertions(+), 1 deletion(-)
diff --git a/include/sysemu/runstate.h b/include/sysemu/runstate.h
index 7beb29c..42ddf83 100644
--- a/include/sysemu/runstate.h
+++ b/include/sysemu/runstate.h
@@ -34,6 +34,7 @@ static inline bool shutdown_caused_by_guest(ShutdownCause cause)
}
void vm_start(void);
+void vm_wakeup(void);
/**
* vm_prepare_start: Prepare for starting/resuming the VM
diff --git a/softmmu/cpus.c b/softmmu/cpus.c
index fed20ff..fa9e5ba 100644
--- a/softmmu/cpus.c
+++ b/softmmu/cpus.c
@@ -66,6 +66,7 @@
#endif /* CONFIG_LINUX */
static QemuMutex qemu_global_mutex;
+static bool vm_started;
/*
* The chosen accelerator is supposed to register this.
@@ -264,6 +265,7 @@ static int do_vm_stop(RunState state, bool send_stop)
if (send_stop) {
qapi_event_send_stop();
}
+ vm_started = false;
}
bdrv_drain_all();
@@ -722,6 +724,16 @@ void vm_start(void)
{
if (!vm_prepare_start(false)) {
resume_all_vcpus();
+ vm_started = true;
+ }
+}
+
+void vm_wakeup(void)
+{
+ if (!vm_started) {
+ vm_start();
+ } else {
+ runstate_set(RUN_STATE_RUNNING);
}
}
diff --git a/softmmu/runstate.c b/softmmu/runstate.c
index f3bd862..95c6ae7 100644
--- a/softmmu/runstate.c
+++ b/softmmu/runstate.c
@@ -580,7 +580,7 @@ void qemu_system_wakeup_request(WakeupReason reason, Error **errp)
if (!(wakeup_reason_mask & (1 << reason))) {
return;
}
- runstate_set(RUN_STATE_RUNNING);
+ vm_wakeup();
wakeup_reason = reason;
qemu_notify_event();
}
--
1.8.3.1
^ permalink raw reply related [flat|nested] 18+ messages in thread
* Re: [PATCH V3 01/10] vl: start on wakeup request
2023-08-14 18:54 ` [PATCH V3 01/10] vl: start on wakeup request Steve Sistare
@ 2023-08-17 18:27 ` Peter Xu
2023-08-24 20:54 ` Steven Sistare
0 siblings, 1 reply; 18+ messages in thread
From: Peter Xu @ 2023-08-17 18:27 UTC (permalink / raw)
To: Steve Sistare
Cc: qemu-devel, Juan Quintela, Paolo Bonzini, Thomas Huth,
Daniel P. Berrangé
On Mon, Aug 14, 2023 at 11:54:27AM -0700, Steve Sistare wrote:
> +void vm_wakeup(void)
> +{
> + if (!vm_started) {
> + vm_start();
(irrelevant of the global var that I wanted to remove..)
Calling vm_start() is wrong here, IMHO.
I think we need to notify everyone on the wakeup before really waking up
the vcpus:
notifier_list_notify(&wakeup_notifiers, &wakeup_reason);
There's resume_all_vcpus() after that. I don't know the side effect of
resuming vcpus without such notifications, at least some acpi fields do not
seem to be updated so the vcpu can see stale values (acpi_notify_wakeup()).
> + } else {
> + runstate_set(RUN_STATE_RUNNING);
> }
> }
--
Peter Xu
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH V3 01/10] vl: start on wakeup request
2023-08-17 18:27 ` Peter Xu
@ 2023-08-24 20:54 ` Steven Sistare
0 siblings, 0 replies; 18+ messages in thread
From: Steven Sistare @ 2023-08-24 20:54 UTC (permalink / raw)
To: Peter Xu
Cc: qemu-devel, Juan Quintela, Paolo Bonzini, Thomas Huth,
Daniel P. Berrangé
On 8/17/2023 2:27 PM, Peter Xu wrote:
> On Mon, Aug 14, 2023 at 11:54:27AM -0700, Steve Sistare wrote:
>> +void vm_wakeup(void)
>> +{
>> + if (!vm_started) {
>> + vm_start();
>
> (irrelevant of the global var that I wanted to remove..)
>
> Calling vm_start() is wrong here, IMHO.
>
> I think we need to notify everyone on the wakeup before really waking up
> the vcpus:
>
> notifier_list_notify(&wakeup_notifiers, &wakeup_reason);
>
> There's resume_all_vcpus() after that. I don't know the side effect of
> resuming vcpus without such notifications, at least some acpi fields do not
> seem to be updated so the vcpu can see stale values (acpi_notify_wakeup()).
Agreed, good catch.
- Steve
>> + } else {
>> + runstate_set(RUN_STATE_RUNNING);
>> }
>> }
>
^ permalink raw reply [flat|nested] 18+ messages in thread
* [PATCH V3 02/10] migration: preserve suspended runstate
2023-08-14 18:54 [PATCH V3 00/10] fix migration of suspended runstate Steve Sistare
2023-08-14 18:54 ` [PATCH V3 01/10] vl: start on wakeup request Steve Sistare
@ 2023-08-14 18:54 ` Steve Sistare
2023-08-14 18:54 ` [PATCH V3 03/10] migration: add runstate function Steve Sistare
` (8 subsequent siblings)
10 siblings, 0 replies; 18+ messages in thread
From: Steve Sistare @ 2023-08-14 18:54 UTC (permalink / raw)
To: qemu-devel
Cc: Juan Quintela, Peter Xu, Paolo Bonzini, Thomas Huth,
Daniel P. Berrangé, Steve Sistare
A guest that is migrated in the suspended state automaticaly wakes and
continues execution. This is wrong; the guest should end migration in
the same state it started. The root causes is that the outgoing migration
code automatically wakes the guest, then saves the RUNNING runstate in
global_state_store(), hence the incoming migration code thinks the guest is
running and continues the guest if autostart is true.
On the outgoing side, do not call qemu_system_wakeup_request(). That
alone fixes precopy migration, as process_incoming_migration_bh correctly
sets runstate from global_state_get_runstate().
On the incoming side for postcopy, do not wake the guest, and apply the
the same logic as found in precopy: if autostart and the runstate is
RUNNING, then vm_start, else merely restore the runstate.
In both cases, if the restored state is SUSPENDED, then a later wakeup
request will resume the guest, courtesy of the previous "start on wakeup"
patch.
Signed-off-by: Steve Sistare <steven.sistare@oracle.com>
Reviewed-by: Fabiano Rosas <farosas@suse.de>
---
migration/migration.c | 2 --
migration/savevm.c | 13 ++++++++-----
2 files changed, 8 insertions(+), 7 deletions(-)
diff --git a/migration/migration.c b/migration/migration.c
index 5528acb..51ace82 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -2109,7 +2109,6 @@ static int postcopy_start(MigrationState *ms, Error **errp)
qemu_mutex_lock_iothread();
trace_postcopy_start_set_run();
- qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER, NULL);
global_state_store();
ret = vm_stop_force_state(RUN_STATE_FINISH_MIGRATE);
if (ret < 0) {
@@ -2315,7 +2314,6 @@ static void migration_completion(MigrationState *s)
if (s->state == MIGRATION_STATUS_ACTIVE) {
qemu_mutex_lock_iothread();
s->downtime_start = qemu_clock_get_ms(QEMU_CLOCK_REALTIME);
- qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER, NULL);
s->vm_old_state = runstate_get();
global_state_store();
diff --git a/migration/savevm.c b/migration/savevm.c
index a2cb885..be42d0a 100644
--- a/migration/savevm.c
+++ b/migration/savevm.c
@@ -2070,12 +2070,15 @@ static void loadvm_postcopy_handle_run_bh(void *opaque)
dirty_bitmap_mig_before_vm_start();
- if (autostart) {
- /* Hold onto your hats, starting the CPU */
- vm_start();
+ if (!global_state_received() ||
+ global_state_get_runstate() == RUN_STATE_RUNNING) {
+ if (autostart) {
+ vm_start();
+ } else {
+ runstate_set(RUN_STATE_PAUSED);
+ }
} else {
- /* leave it paused and let management decide when to start the CPU */
- runstate_set(RUN_STATE_PAUSED);
+ runstate_set(global_state_get_runstate());
}
qemu_bh_delete(mis->bh);
--
1.8.3.1
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH V3 03/10] migration: add runstate function
2023-08-14 18:54 [PATCH V3 00/10] fix migration of suspended runstate Steve Sistare
2023-08-14 18:54 ` [PATCH V3 01/10] vl: start on wakeup request Steve Sistare
2023-08-14 18:54 ` [PATCH V3 02/10] migration: preserve suspended runstate Steve Sistare
@ 2023-08-14 18:54 ` Steve Sistare
2023-08-14 18:54 ` [PATCH V3 04/10] migration: preserve suspended for snapshot Steve Sistare
` (7 subsequent siblings)
10 siblings, 0 replies; 18+ messages in thread
From: Steve Sistare @ 2023-08-14 18:54 UTC (permalink / raw)
To: qemu-devel
Cc: Juan Quintela, Peter Xu, Paolo Bonzini, Thomas Huth,
Daniel P. Berrangé, Steve Sistare
Create a subroutine for preserving the runstate after migration,
to be used in a subsequent patch. No functional change.
Signed-off-by: Steve Sistare <steven.sistare@oracle.com>
Reviewed-by: Fabiano Rosas <farosas@suse.de>
---
migration/migration.c | 14 ++++++++++++++
migration/migration.h | 1 +
migration/savevm.c | 11 +----------
3 files changed, 16 insertions(+), 10 deletions(-)
diff --git a/migration/migration.c b/migration/migration.c
index 51ace82..1a5484a 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -1141,6 +1141,20 @@ void migrate_set_state(int *state, int old_state, int new_state)
}
}
+void migrate_set_runstate(void)
+{
+ if (!global_state_received() ||
+ global_state_get_runstate() == RUN_STATE_RUNNING) {
+ if (autostart) {
+ vm_start();
+ } else {
+ runstate_set(RUN_STATE_PAUSED);
+ }
+ } else {
+ runstate_set(global_state_get_runstate());
+ }
+}
+
static void migrate_fd_cleanup(MigrationState *s)
{
qemu_bh_delete(s->cleanup_bh);
diff --git a/migration/migration.h b/migration/migration.h
index 6eea18d..45e9805 100644
--- a/migration/migration.h
+++ b/migration/migration.h
@@ -456,6 +456,7 @@ struct MigrationState {
};
void migrate_set_state(int *state, int old_state, int new_state);
+void migrate_set_runstate(void);
void migration_fd_process_incoming(QEMUFile *f, Error **errp);
void migration_ioc_process_incoming(QIOChannel *ioc, Error **errp);
diff --git a/migration/savevm.c b/migration/savevm.c
index be42d0a..eba3653 100644
--- a/migration/savevm.c
+++ b/migration/savevm.c
@@ -2070,16 +2070,7 @@ static void loadvm_postcopy_handle_run_bh(void *opaque)
dirty_bitmap_mig_before_vm_start();
- if (!global_state_received() ||
- global_state_get_runstate() == RUN_STATE_RUNNING) {
- if (autostart) {
- vm_start();
- } else {
- runstate_set(RUN_STATE_PAUSED);
- }
- } else {
- runstate_set(global_state_get_runstate());
- }
+ migrate_set_runstate();
qemu_bh_delete(mis->bh);
--
1.8.3.1
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH V3 04/10] migration: preserve suspended for snapshot
2023-08-14 18:54 [PATCH V3 00/10] fix migration of suspended runstate Steve Sistare
` (2 preceding siblings ...)
2023-08-14 18:54 ` [PATCH V3 03/10] migration: add runstate function Steve Sistare
@ 2023-08-14 18:54 ` Steve Sistare
2023-08-14 18:54 ` [PATCH V3 05/10] migration: preserve suspended for bg_migration Steve Sistare
` (6 subsequent siblings)
10 siblings, 0 replies; 18+ messages in thread
From: Steve Sistare @ 2023-08-14 18:54 UTC (permalink / raw)
To: qemu-devel
Cc: Juan Quintela, Peter Xu, Paolo Bonzini, Thomas Huth,
Daniel P. Berrangé, Steve Sistare
Restoring a snapshot can break a suspended guest.
If a guest is suspended and saved to a snapshot using savevm, and qemu
is terminated and restarted with the -S option, then loadvm does not
restore the guest. The runstate is running, but the guest is not, because
vm_start was not called. The root cause is that loadvm does not restore
the runstate (eg suspended) from global_state loaded from the state file.
Restore the runstate, and allow the new state transitions that are possible.
Signed-off-by: Steve Sistare <steven.sistare@oracle.com>
---
migration/savevm.c | 1 +
softmmu/runstate.c | 2 ++
2 files changed, 3 insertions(+)
diff --git a/migration/savevm.c b/migration/savevm.c
index eba3653..7b9c477 100644
--- a/migration/savevm.c
+++ b/migration/savevm.c
@@ -3194,6 +3194,7 @@ bool load_snapshot(const char *name, const char *vmstate,
}
aio_context_acquire(aio_context);
ret = qemu_loadvm_state(f);
+ migrate_set_runstate();
migration_incoming_state_destroy();
aio_context_release(aio_context);
diff --git a/softmmu/runstate.c b/softmmu/runstate.c
index 95c6ae7..2f70c07 100644
--- a/softmmu/runstate.c
+++ b/softmmu/runstate.c
@@ -77,6 +77,8 @@ typedef struct {
static const RunStateTransition runstate_transitions_def[] = {
{ RUN_STATE_PRELAUNCH, RUN_STATE_INMIGRATE },
+ { RUN_STATE_PRELAUNCH, RUN_STATE_PAUSED },
+ { RUN_STATE_PRELAUNCH, RUN_STATE_SUSPENDED },
{ RUN_STATE_DEBUG, RUN_STATE_RUNNING },
{ RUN_STATE_DEBUG, RUN_STATE_FINISH_MIGRATE },
--
1.8.3.1
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH V3 05/10] migration: preserve suspended for bg_migration
2023-08-14 18:54 [PATCH V3 00/10] fix migration of suspended runstate Steve Sistare
` (3 preceding siblings ...)
2023-08-14 18:54 ` [PATCH V3 04/10] migration: preserve suspended for snapshot Steve Sistare
@ 2023-08-14 18:54 ` Steve Sistare
2023-08-14 18:54 ` [PATCH V3 06/10] tests/qtest: migration events Steve Sistare
` (5 subsequent siblings)
10 siblings, 0 replies; 18+ messages in thread
From: Steve Sistare @ 2023-08-14 18:54 UTC (permalink / raw)
To: qemu-devel
Cc: Juan Quintela, Peter Xu, Paolo Bonzini, Thomas Huth,
Daniel P. Berrangé, Steve Sistare
Do not wake a suspended guest during bg_migration.
Signed-off-by: Steve Sistare <steven.sistare@oracle.com>
---
migration/migration.c | 12 +++++-------
softmmu/runstate.c | 1 +
2 files changed, 6 insertions(+), 7 deletions(-)
diff --git a/migration/migration.c b/migration/migration.c
index 1a5484a..e6b8024 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -3069,7 +3069,9 @@ static void bg_migration_vm_start_bh(void *opaque)
qemu_bh_delete(s->vm_start_bh);
s->vm_start_bh = NULL;
- vm_start();
+ if (!runstate_check(RUN_STATE_SUSPENDED)) {
+ vm_start();
+ }
s->downtime = qemu_clock_get_ms(QEMU_CLOCK_REALTIME) - s->downtime_start;
}
@@ -3139,16 +3141,12 @@ static void *bg_migration_thread(void *opaque)
qemu_mutex_lock_iothread();
- /*
- * If VM is currently in suspended state, then, to make a valid runstate
- * 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 = runstate_get();
global_state_store();
/* Forcibly stop VM before saving state of vCPUs and devices */
- if (vm_stop_force_state(RUN_STATE_PAUSED)) {
+ if (!runstate_check(RUN_STATE_SUSPENDED) &&
+ vm_stop_force_state(RUN_STATE_PAUSED)) {
goto fail;
}
/*
diff --git a/softmmu/runstate.c b/softmmu/runstate.c
index 2f70c07..c683dcf 100644
--- a/softmmu/runstate.c
+++ b/softmmu/runstate.c
@@ -163,6 +163,7 @@ static const RunStateTransition runstate_transitions_def[] = {
{ RUN_STATE_SUSPENDED, RUN_STATE_FINISH_MIGRATE },
{ RUN_STATE_SUSPENDED, RUN_STATE_PRELAUNCH },
{ RUN_STATE_SUSPENDED, RUN_STATE_COLO},
+ { RUN_STATE_SUSPENDED, RUN_STATE_PAUSED },
{ RUN_STATE_WATCHDOG, RUN_STATE_RUNNING },
{ RUN_STATE_WATCHDOG, RUN_STATE_FINISH_MIGRATE },
--
1.8.3.1
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH V3 06/10] tests/qtest: migration events
2023-08-14 18:54 [PATCH V3 00/10] fix migration of suspended runstate Steve Sistare
` (4 preceding siblings ...)
2023-08-14 18:54 ` [PATCH V3 05/10] migration: preserve suspended for bg_migration Steve Sistare
@ 2023-08-14 18:54 ` Steve Sistare
2023-08-14 18:54 ` [PATCH V3 07/10] tests/qtest: option to suspend during migration Steve Sistare
` (4 subsequent siblings)
10 siblings, 0 replies; 18+ messages in thread
From: Steve Sistare @ 2023-08-14 18:54 UTC (permalink / raw)
To: qemu-devel
Cc: Juan Quintela, Peter Xu, Paolo Bonzini, Thomas Huth,
Daniel P. Berrangé, Steve Sistare
Define a state object to capture events seen by migration tests, to allow
more events to be captured in a subsequent patch, and simplify event
checking in wait_for_migration_pass. No functional change.
Signed-off-by: Steve Sistare <steven.sistare@oracle.com>
Reviewed-by: Fabiano Rosas <farosas@suse.de>
---
tests/qtest/migration-helpers.c | 24 +++++----------
tests/qtest/migration-helpers.h | 8 +++--
tests/qtest/migration-test.c | 68 +++++++++++++++++++----------------------
3 files changed, 44 insertions(+), 56 deletions(-)
diff --git a/tests/qtest/migration-helpers.c b/tests/qtest/migration-helpers.c
index be00c52..b541108 100644
--- a/tests/qtest/migration-helpers.c
+++ b/tests/qtest/migration-helpers.c
@@ -23,26 +23,16 @@
*/
#define MIGRATION_STATUS_WAIT_TIMEOUT 120
-bool migrate_watch_for_stop(QTestState *who, const char *name,
- QDict *event, void *opaque)
-{
- bool *seen = opaque;
-
- if (g_str_equal(name, "STOP")) {
- *seen = true;
- return true;
- }
-
- return false;
-}
-
-bool migrate_watch_for_resume(QTestState *who, const char *name,
+bool migrate_watch_for_events(QTestState *who, const char *name,
QDict *event, void *opaque)
{
- bool *seen = opaque;
+ QTestMigrationState *state = opaque;
- if (g_str_equal(name, "RESUME")) {
- *seen = true;
+ if (g_str_equal(name, "STOP")) {
+ state->stop_seen = true;
+ return true;
+ } else if (g_str_equal(name, "RESUME")) {
+ state->resume_seen = true;
return true;
}
diff --git a/tests/qtest/migration-helpers.h b/tests/qtest/migration-helpers.h
index 009e250..59fbb83 100644
--- a/tests/qtest/migration-helpers.h
+++ b/tests/qtest/migration-helpers.h
@@ -15,9 +15,11 @@
#include "libqtest.h"
-bool migrate_watch_for_stop(QTestState *who, const char *name,
- QDict *event, void *opaque);
-bool migrate_watch_for_resume(QTestState *who, const char *name,
+typedef struct QTestMigrationState {
+ bool stop_seen, resume_seen;
+} QTestMigrationState;
+
+bool migrate_watch_for_events(QTestState *who, const char *name,
QDict *event, void *opaque);
G_GNUC_PRINTF(3, 4)
diff --git a/tests/qtest/migration-test.c b/tests/qtest/migration-test.c
index 62d3f37..526a1b7 100644
--- a/tests/qtest/migration-test.c
+++ b/tests/qtest/migration-test.c
@@ -43,8 +43,8 @@
unsigned start_address;
unsigned end_address;
static bool uffd_feature_thread_id;
-static bool got_src_stop;
-static bool got_dst_resume;
+static QTestMigrationState src_state;
+static QTestMigrationState dst_state;
/*
* An initial 3 MB offset is used as that corresponds
@@ -188,6 +188,13 @@ static void wait_for_serial(const char *side)
} while (true);
}
+static void wait_for_stop(QTestState *who, QTestMigrationState *state)
+{
+ if (!state->stop_seen) {
+ qtest_qmp_eventwait(who, "STOP");
+ }
+}
+
/*
* It's tricky to use qemu's migration event capability with qtest,
* events suddenly appearing confuse the qmp()/hmp() responses.
@@ -235,21 +242,19 @@ static void read_blocktime(QTestState *who)
qobject_unref(rsp_return);
}
+/*
+ * Wait for two changes in the migration pass count, but bail if we stop.
+ */
static void wait_for_migration_pass(QTestState *who)
{
- uint64_t initial_pass = get_migration_pass(who);
- uint64_t pass;
+ uint64_t pass, prev_pass = 0, changes = 0;
- /* Wait for the 1st sync */
- while (!got_src_stop && !initial_pass) {
- usleep(1000);
- initial_pass = get_migration_pass(who);
- }
-
- do {
+ while (changes < 2 && !src_state.stop_seen) {
usleep(1000);
pass = get_migration_pass(who);
- } while (pass == initial_pass && !got_src_stop);
+ changes += (pass != prev_pass);
+ prev_pass = pass;
+ }
}
static void check_guests_ram(QTestState *who)
@@ -586,10 +591,7 @@ static void migrate_postcopy_start(QTestState *from, QTestState *to)
{
qtest_qmp_assert_success(from, "{ 'execute': 'migrate-start-postcopy' }");
- if (!got_src_stop) {
- qtest_qmp_eventwait(from, "STOP");
- }
-
+ wait_for_stop(from, &src_state);
qtest_qmp_eventwait(to, "RESUME");
}
@@ -720,8 +722,9 @@ static int test_migrate_start(QTestState **from, QTestState **to,
}
}
- got_src_stop = false;
- got_dst_resume = false;
+ dst_state = (QTestMigrationState) { };
+ src_state = (QTestMigrationState) { };
+
bootpath = g_strdup_printf("%s/bootsect", tmpfs);
if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
/* the assembled x86 boot sector should be exactly one sector large */
@@ -801,8 +804,8 @@ static int test_migrate_start(QTestState **from, QTestState **to,
if (!args->only_target) {
*from = qtest_init(cmd_source);
qtest_qmp_set_event_callback(*from,
- migrate_watch_for_stop,
- &got_src_stop);
+ migrate_watch_for_events,
+ &src_state);
}
cmd_target = g_strdup_printf("-accel kvm%s -accel tcg "
@@ -821,8 +824,8 @@ static int test_migrate_start(QTestState **from, QTestState **to,
ignore_stderr);
*to = qtest_init(cmd_target);
qtest_qmp_set_event_callback(*to,
- migrate_watch_for_resume,
- &got_dst_resume);
+ migrate_watch_for_events,
+ &dst_state);
/*
* Remove shmem file immediately to avoid memory leak in test failed case.
@@ -1516,9 +1519,7 @@ static void test_precopy_common(MigrateCommon *args)
*/
if (args->result == MIG_TEST_SUCCEED) {
qtest_qmp_assert_success(from, "{ 'execute' : 'stop'}");
- if (!got_src_stop) {
- qtest_qmp_eventwait(from, "STOP");
- }
+ wait_for_stop(from, &src_state);
migrate_ensure_converge(from);
}
}
@@ -1560,9 +1561,8 @@ static void test_precopy_common(MigrateCommon *args)
*/
wait_for_migration_complete(from);
- if (!got_src_stop) {
- qtest_qmp_eventwait(from, "STOP");
- }
+ wait_for_stop(from, &src_state);
+
} else {
wait_for_migration_complete(from);
/*
@@ -1575,7 +1575,7 @@ static void test_precopy_common(MigrateCommon *args)
qtest_qmp_assert_success(to, "{ 'execute' : 'cont'}");
}
- if (!got_dst_resume) {
+ if (!dst_state.resume_seen) {
qtest_qmp_eventwait(to, "RESUME");
}
@@ -1696,9 +1696,7 @@ static void test_ignore_shared(void)
migrate_wait_for_dirty_mem(from, to);
- if (!got_src_stop) {
- qtest_qmp_eventwait(from, "STOP");
- }
+ wait_for_stop(from, &src_state);
qtest_qmp_eventwait(to, "RESUME");
@@ -2139,7 +2137,7 @@ static void test_migrate_auto_converge(void)
break;
}
usleep(20);
- g_assert_false(got_src_stop);
+ g_assert_false(src_state.stop_seen);
} while (true);
/* The first percentage of throttling should be at least init_pct */
g_assert_cmpint(percentage, >=, init_pct);
@@ -2481,9 +2479,7 @@ static void test_multifd_tcp_cancel(void)
migrate_ensure_converge(from);
- if (!got_src_stop) {
- qtest_qmp_eventwait(from, "STOP");
- }
+ wait_for_stop(from, &src_state);
qtest_qmp_eventwait(to2, "RESUME");
wait_for_serial("dest_serial");
--
1.8.3.1
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH V3 07/10] tests/qtest: option to suspend during migration
2023-08-14 18:54 [PATCH V3 00/10] fix migration of suspended runstate Steve Sistare
` (5 preceding siblings ...)
2023-08-14 18:54 ` [PATCH V3 06/10] tests/qtest: migration events Steve Sistare
@ 2023-08-14 18:54 ` Steve Sistare
2023-08-14 18:54 ` [PATCH V3 08/10] tests/qtest: precopy migration with suspend Steve Sistare
` (3 subsequent siblings)
10 siblings, 0 replies; 18+ messages in thread
From: Steve Sistare @ 2023-08-14 18:54 UTC (permalink / raw)
To: qemu-devel
Cc: Juan Quintela, Peter Xu, Paolo Bonzini, Thomas Huth,
Daniel P. Berrangé, Steve Sistare
Add an option to suspend the src in a-b-bootblock.S, which puts the guest
in S3 state after one round of writing to memory. The option is enabled by
poking a 1 into the suspend_me word in the boot block prior to starting the
src vm. Generate symbol offsets in a-b-bootblock.h so that the suspend_me
offset is known.
Signed-off-by: Steve Sistare <steven.sistare@oracle.com>
---
tests/migration/i386/Makefile | 5 ++--
tests/migration/i386/a-b-bootblock.S | 51 +++++++++++++++++++++++++++++++++---
tests/migration/i386/a-b-bootblock.h | 22 ++++++++++------
tests/qtest/migration-test.c | 4 +++
4 files changed, 68 insertions(+), 14 deletions(-)
diff --git a/tests/migration/i386/Makefile b/tests/migration/i386/Makefile
index 5c03241..37a72ae 100644
--- a/tests/migration/i386/Makefile
+++ b/tests/migration/i386/Makefile
@@ -4,9 +4,10 @@
.PHONY: all clean
all: a-b-bootblock.h
-a-b-bootblock.h: x86.bootsect
+a-b-bootblock.h: x86.bootsect x86.o
echo "$$__note" > header.tmp
xxd -i $< | sed -e 's/.*int.*//' >> header.tmp
+ nm x86.o | awk '{print "#define SYM_"$$3" 0x"$$1}' >> header.tmp
mv header.tmp $@
x86.bootsect: x86.boot
@@ -16,7 +17,7 @@ x86.boot: x86.o
$(CROSS_PREFIX)objcopy -O binary $< $@
x86.o: a-b-bootblock.S
- $(CROSS_PREFIX)gcc -m32 -march=i486 -c $< -o $@
+ $(CROSS_PREFIX)gcc -I.. -m32 -march=i486 -c $< -o $@
clean:
@rm -rf *.boot *.o *.bootsect
diff --git a/tests/migration/i386/a-b-bootblock.S b/tests/migration/i386/a-b-bootblock.S
index 3d464c7..62d79b2 100644
--- a/tests/migration/i386/a-b-bootblock.S
+++ b/tests/migration/i386/a-b-bootblock.S
@@ -9,6 +9,23 @@
#
# Author: dgilbert@redhat.com
+#include "migration-test.h"
+
+#define ACPI_ENABLE 0xf1
+#define ACPI_PORT_SMI_CMD 0xb2
+#define ACPI_PM_BASE 0x600
+#define PM1A_CNT_OFFSET 4
+
+#define ACPI_SCI_ENABLE 0x0001
+#define ACPI_SLEEP_TYPE 0x0400
+#define ACPI_SLEEP_ENABLE 0x2000
+#define SLEEP (ACPI_SCI_ENABLE + ACPI_SLEEP_TYPE + ACPI_SLEEP_ENABLE)
+
+#define LOW_ADDR X86_TEST_MEM_START
+#define HIGH_ADDR X86_TEST_MEM_END
+
+/* Save the suspended status at an address that is not written in the loop. */
+#define suspended (X86_TEST_MEM_START + 4)
.code16
.org 0x7c00
@@ -41,12 +58,11 @@ start: # at 0x7c00 ?
# bl keeps a counter so we limit the output speed
mov $0, %bl
mainloop:
- # Start from 1MB
- mov $(1024*1024),%eax
+ mov $LOW_ADDR,%eax
innerloop:
incb (%eax)
add $4096,%eax
- cmp $(100*1024*1024),%eax
+ cmp $HIGH_ADDR,%eax
jl innerloop
inc %bl
@@ -57,7 +73,30 @@ innerloop:
mov $0x3f8,%dx
outb %al,%dx
- jmp mainloop
+ # should this test suspend?
+ mov (suspend_me),%eax
+ cmp $0,%eax
+ je mainloop
+
+ # are we waking after suspend? do not suspend again.
+ mov $suspended,%eax
+ mov (%eax),%eax
+ cmp $1,%eax
+ je mainloop
+
+ # enable acpi
+ mov $ACPI_ENABLE,%al
+ outb %al,$ACPI_PORT_SMI_CMD
+
+ # suspend to ram
+ mov $suspended,%eax
+ movl $1,(%eax)
+ mov $SLEEP,%ax
+ mov $(ACPI_PM_BASE + PM1A_CNT_OFFSET),%dx
+ outw %ax,%dx
+ # not reached. The wakeup causes reset and restart at 0x7c00, and we
+ # do not save and restore registers as a real kernel would do.
+
# GDT magic from old (GPLv2) Grub startup.S
.p2align 2 /* force 4-byte alignment */
@@ -83,6 +122,10 @@ gdtdesc:
.word 0x27 /* limit */
.long gdt /* addr */
+ /* test launcher can poke a 1 here to exercise suspend */
+suspend_me:
+ .int 0
+
/* I'm a bootable disk */
.org 0x7dfe
.byte 0x55
diff --git a/tests/migration/i386/a-b-bootblock.h b/tests/migration/i386/a-b-bootblock.h
index b7b0fce..4d46873 100644
--- a/tests/migration/i386/a-b-bootblock.h
+++ b/tests/migration/i386/a-b-bootblock.h
@@ -4,20 +4,20 @@
* the header and the assembler differences in your patch submission.
*/
unsigned char x86_bootsect[] = {
- 0xfa, 0x0f, 0x01, 0x16, 0x78, 0x7c, 0x66, 0xb8, 0x01, 0x00, 0x00, 0x00,
+ 0xfa, 0x0f, 0x01, 0x16, 0xa4, 0x7c, 0x66, 0xb8, 0x01, 0x00, 0x00, 0x00,
0x0f, 0x22, 0xc0, 0x66, 0xea, 0x20, 0x7c, 0x00, 0x00, 0x08, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe4, 0x92, 0x0c, 0x02,
0xe6, 0x92, 0xb8, 0x10, 0x00, 0x00, 0x00, 0x8e, 0xd8, 0x66, 0xb8, 0x41,
0x00, 0x66, 0xba, 0xf8, 0x03, 0xee, 0xb3, 0x00, 0xb8, 0x00, 0x00, 0x10,
0x00, 0xfe, 0x00, 0x05, 0x00, 0x10, 0x00, 0x00, 0x3d, 0x00, 0x00, 0x40,
0x06, 0x7c, 0xf2, 0xfe, 0xc3, 0x80, 0xe3, 0x3f, 0x75, 0xe6, 0x66, 0xb8,
- 0x42, 0x00, 0x66, 0xba, 0xf8, 0x03, 0xee, 0xeb, 0xdb, 0x8d, 0x76, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
- 0x00, 0x9a, 0xcf, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x92, 0xcf, 0x00,
- 0x27, 0x00, 0x60, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x42, 0x00, 0x66, 0xba, 0xf8, 0x03, 0xee, 0xa1, 0xaa, 0x7c, 0x00, 0x00,
+ 0x83, 0xf8, 0x00, 0x74, 0xd3, 0xb8, 0x04, 0x00, 0x10, 0x00, 0x8b, 0x00,
+ 0x83, 0xf8, 0x01, 0x74, 0xc7, 0xb0, 0xf1, 0xe6, 0xb2, 0xb8, 0x04, 0x00,
+ 0x10, 0x00, 0xc7, 0x00, 0x01, 0x00, 0x00, 0x00, 0x66, 0xb8, 0x01, 0x24,
+ 0x66, 0xba, 0x04, 0x06, 0x66, 0xef, 0x66, 0x90, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x9a, 0xcf, 0x00,
+ 0xff, 0xff, 0x00, 0x00, 0x00, 0x92, 0xcf, 0x00, 0x27, 0x00, 0x8c, 0x7c,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -49,3 +49,9 @@ unsigned char x86_bootsect[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0xaa
};
+#define SYM_gdt 0x00007c8c
+#define SYM_gdtdesc 0x00007ca4
+#define SYM_innerloop 0x00007c3d
+#define SYM_mainloop 0x00007c38
+#define SYM_start 0x00007c00
+#define SYM_suspend_me 0x00007caa
diff --git a/tests/qtest/migration-test.c b/tests/qtest/migration-test.c
index 526a1b7..32fea73 100644
--- a/tests/qtest/migration-test.c
+++ b/tests/qtest/migration-test.c
@@ -608,6 +608,8 @@ typedef struct {
bool use_dirty_ring;
const char *opts_source;
const char *opts_target;
+ /* suspend the src before migrating to dest. */
+ bool suspend_me;
} MigrateStart;
/*
@@ -725,6 +727,8 @@ static int test_migrate_start(QTestState **from, QTestState **to,
dst_state = (QTestMigrationState) { };
src_state = (QTestMigrationState) { };
+ x86_bootsect[SYM_suspend_me - SYM_start] = args->suspend_me;
+
bootpath = g_strdup_printf("%s/bootsect", tmpfs);
if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
/* the assembled x86 boot sector should be exactly one sector large */
--
1.8.3.1
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH V3 08/10] tests/qtest: precopy migration with suspend
2023-08-14 18:54 [PATCH V3 00/10] fix migration of suspended runstate Steve Sistare
` (6 preceding siblings ...)
2023-08-14 18:54 ` [PATCH V3 07/10] tests/qtest: option to suspend during migration Steve Sistare
@ 2023-08-14 18:54 ` Steve Sistare
2023-08-14 18:54 ` [PATCH V3 09/10] tests/qtest: postcopy " Steve Sistare
` (2 subsequent siblings)
10 siblings, 0 replies; 18+ messages in thread
From: Steve Sistare @ 2023-08-14 18:54 UTC (permalink / raw)
To: qemu-devel
Cc: Juan Quintela, Peter Xu, Paolo Bonzini, Thomas Huth,
Daniel P. Berrangé, Steve Sistare
Add a test case to verify that the suspended state is handled correctly
during live migration precopy. The test suspends the src, migrates, then
wakes the dest.
Signed-off-by: Steve Sistare <steven.sistare@oracle.com>
---
tests/qtest/migration-helpers.c | 3 ++
tests/qtest/migration-helpers.h | 3 +-
tests/qtest/migration-test.c | 72 +++++++++++++++++++++++++++++++++++++----
3 files changed, 70 insertions(+), 8 deletions(-)
diff --git a/tests/qtest/migration-helpers.c b/tests/qtest/migration-helpers.c
index b541108..d1fec49 100644
--- a/tests/qtest/migration-helpers.c
+++ b/tests/qtest/migration-helpers.c
@@ -31,6 +31,9 @@ bool migrate_watch_for_events(QTestState *who, const char *name,
if (g_str_equal(name, "STOP")) {
state->stop_seen = true;
return true;
+ } else if (g_str_equal(name, "SUSPEND")) {
+ state->suspend_seen = true;
+ return true;
} else if (g_str_equal(name, "RESUME")) {
state->resume_seen = true;
return true;
diff --git a/tests/qtest/migration-helpers.h b/tests/qtest/migration-helpers.h
index 59fbb83..bac8699 100644
--- a/tests/qtest/migration-helpers.h
+++ b/tests/qtest/migration-helpers.h
@@ -16,7 +16,8 @@
#include "libqtest.h"
typedef struct QTestMigrationState {
- bool stop_seen, resume_seen;
+ bool suspend_me;
+ bool stop_seen, suspend_seen, resume_seen;
} QTestMigrationState;
bool migrate_watch_for_events(QTestState *who, const char *name,
diff --git a/tests/qtest/migration-test.c b/tests/qtest/migration-test.c
index 32fea73..e3fc71e 100644
--- a/tests/qtest/migration-test.c
+++ b/tests/qtest/migration-test.c
@@ -135,7 +135,7 @@ static void init_bootfile(const char *bootpath, void *content, size_t len)
/*
* Wait for some output in the serial output file,
* we get an 'A' followed by an endless string of 'B's
- * but on the destination we won't have the A.
+ * but on the destination we won't have the A (unless we enabled suspend/resume)
*/
static void wait_for_serial(const char *side)
{
@@ -195,6 +195,13 @@ static void wait_for_stop(QTestState *who, QTestMigrationState *state)
}
}
+static void wait_for_suspend(QTestState *who, QTestMigrationState *state)
+{
+ if (!state->suspend_seen) {
+ qtest_qmp_eventwait(who, "SUSPEND");
+ }
+}
+
/*
* It's tricky to use qemu's migration event capability with qtest,
* events suddenly appearing confuse the qmp()/hmp() responses.
@@ -249,7 +256,7 @@ static void wait_for_migration_pass(QTestState *who)
{
uint64_t pass, prev_pass = 0, changes = 0;
- while (changes < 2 && !src_state.stop_seen) {
+ while (changes < 2 && !src_state.stop_seen && !src_state.suspend_seen) {
usleep(1000);
pass = get_migration_pass(who);
changes += (pass != prev_pass);
@@ -545,7 +552,8 @@ static void migrate_wait_for_dirty_mem(QTestState *from,
watch_byte = qtest_readb(from, watch_address);
do {
usleep(1000 * 10);
- } while (qtest_readb(from, watch_address) == watch_byte);
+ } while (qtest_readb(from, watch_address) == watch_byte &&
+ !src_state.suspend_seen);
}
@@ -727,6 +735,7 @@ static int test_migrate_start(QTestState **from, QTestState **to,
dst_state = (QTestMigrationState) { };
src_state = (QTestMigrationState) { };
+ src_state.suspend_me = args->suspend_me;
x86_bootsect[SYM_suspend_me - SYM_start] = args->suspend_me;
bootpath = g_strdup_printf("%s/bootsect", tmpfs);
@@ -1522,8 +1531,12 @@ static void test_precopy_common(MigrateCommon *args)
* change anything.
*/
if (args->result == MIG_TEST_SUCCEED) {
- qtest_qmp_assert_success(from, "{ 'execute' : 'stop'}");
- wait_for_stop(from, &src_state);
+ if (src_state.suspend_me) {
+ wait_for_suspend(from, &src_state);
+ } else {
+ qtest_qmp_assert_success(from, "{ 'execute' : 'stop'}");
+ wait_for_stop(from, &src_state);
+ }
migrate_ensure_converge(from);
}
}
@@ -1565,7 +1578,11 @@ static void test_precopy_common(MigrateCommon *args)
*/
wait_for_migration_complete(from);
- wait_for_stop(from, &src_state);
+ if (src_state.suspend_me) {
+ wait_for_suspend(from, &src_state);
+ } else {
+ wait_for_stop(from, &src_state);
+ }
} else {
wait_for_migration_complete(from);
@@ -1579,6 +1596,11 @@ static void test_precopy_common(MigrateCommon *args)
qtest_qmp_assert_success(to, "{ 'execute' : 'cont'}");
}
+ if (args->start.suspend_me) {
+ /* wakeup succeeds only if guest is suspended */
+ qtest_qmp_assert_success(to, "{'execute': 'system_wakeup'}");
+ }
+
if (!dst_state.resume_seen) {
qtest_qmp_eventwait(to, "RESUME");
}
@@ -1609,6 +1631,34 @@ static void test_precopy_unix_plain(void)
test_precopy_common(&args);
}
+static void test_precopy_unix_suspend_live(void)
+{
+ g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
+ MigrateCommon args = {
+ .listen_uri = uri,
+ .connect_uri = uri,
+ /*
+ * despite being live, the test is fast because the src
+ * suspends immediately.
+ */
+ .live = true,
+ .start.suspend_me = true,
+ };
+
+ test_precopy_common(&args);
+}
+
+static void test_precopy_unix_suspend_notlive(void)
+{
+ g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
+ MigrateCommon args = {
+ .listen_uri = uri,
+ .connect_uri = uri,
+ .start.suspend_me = true,
+ };
+
+ test_precopy_common(&args);
+}
static void test_precopy_unix_dirty_ring(void)
{
@@ -2765,7 +2815,7 @@ static bool kvm_dirty_ring_supported(void)
int main(int argc, char **argv)
{
bool has_kvm, has_tcg;
- bool has_uffd;
+ bool has_uffd, is_x86;
const char *arch;
g_autoptr(GError) err = NULL;
int ret;
@@ -2782,6 +2832,7 @@ int main(int argc, char **argv)
has_uffd = ufd_version_check();
arch = qtest_get_arch();
+ is_x86 = !strcmp(arch, "i386") || !strcmp(arch, "x86_64");
/*
* On ppc64, the test only works with kvm-hv, but not with kvm-pr and TCG
@@ -2812,6 +2863,13 @@ int main(int argc, char **argv)
module_call_init(MODULE_INIT_QOM);
+ if (is_x86) {
+ qtest_add_func("/migration/precopy/unix/suspend/live",
+ test_precopy_unix_suspend_live);
+ qtest_add_func("/migration/precopy/unix/suspend/notlive",
+ test_precopy_unix_suspend_notlive);
+ }
+
if (has_uffd) {
qtest_add_func("/migration/postcopy/plain", test_postcopy);
qtest_add_func("/migration/postcopy/recovery/plain",
--
1.8.3.1
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH V3 09/10] tests/qtest: postcopy migration with suspend
2023-08-14 18:54 [PATCH V3 00/10] fix migration of suspended runstate Steve Sistare
` (7 preceding siblings ...)
2023-08-14 18:54 ` [PATCH V3 08/10] tests/qtest: precopy migration with suspend Steve Sistare
@ 2023-08-14 18:54 ` Steve Sistare
2023-08-14 18:54 ` [PATCH V3 10/10] tests/qtest: background " Steve Sistare
2023-08-17 18:23 ` [PATCH V3 00/10] fix migration of suspended runstate Peter Xu
10 siblings, 0 replies; 18+ messages in thread
From: Steve Sistare @ 2023-08-14 18:54 UTC (permalink / raw)
To: qemu-devel
Cc: Juan Quintela, Peter Xu, Paolo Bonzini, Thomas Huth,
Daniel P. Berrangé, Steve Sistare
Add a test case to verify that the suspended state is handled correctly by
live migration postcopy. The test suspends the src, migrates, then wakes
the dest.
Signed-off-by: Steve Sistare <steven.sistare@oracle.com>
---
tests/qtest/migration-test.c | 26 ++++++++++++++++++++++++--
1 file changed, 24 insertions(+), 2 deletions(-)
diff --git a/tests/qtest/migration-test.c b/tests/qtest/migration-test.c
index e3fc71e..d99620a 100644
--- a/tests/qtest/migration-test.c
+++ b/tests/qtest/migration-test.c
@@ -599,8 +599,12 @@ static void migrate_postcopy_start(QTestState *from, QTestState *to)
{
qtest_qmp_assert_success(from, "{ 'execute': 'migrate-start-postcopy' }");
- wait_for_stop(from, &src_state);
- qtest_qmp_eventwait(to, "RESUME");
+ if (src_state.suspend_me) {
+ wait_for_suspend(from, &src_state);
+ } else {
+ wait_for_stop(from, &src_state);
+ qtest_qmp_eventwait(to, "RESUME");
+ }
}
typedef struct {
@@ -1299,6 +1303,11 @@ static void migrate_postcopy_complete(QTestState *from, QTestState *to,
{
wait_for_migration_complete(from);
+ if (args->start.suspend_me) {
+ /* wakeup succeeds only if guest is suspended */
+ qtest_qmp_assert_success(to, "{'execute': 'system_wakeup'}");
+ }
+
/* Make sure we get at least one "B" on destination */
wait_for_serial("dest_serial");
@@ -1332,6 +1341,15 @@ static void test_postcopy(void)
test_postcopy_common(&args);
}
+static void test_postcopy_suspend(void)
+{
+ MigrateCommon args = {
+ .start.suspend_me = true,
+ };
+
+ test_postcopy_common(&args);
+}
+
static void test_postcopy_compress(void)
{
MigrateCommon args = {
@@ -2883,6 +2901,10 @@ int main(int argc, char **argv)
qtest_add_func("/migration/postcopy/recovery/compress/plain",
test_postcopy_recovery_compress);
}
+ if (is_x86) {
+ qtest_add_func("/migration/postcopy/suspend",
+ test_postcopy_suspend);
+ }
}
qtest_add_func("/migration/bad_dest", test_baddest);
--
1.8.3.1
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH V3 10/10] tests/qtest: background migration with suspend
2023-08-14 18:54 [PATCH V3 00/10] fix migration of suspended runstate Steve Sistare
` (8 preceding siblings ...)
2023-08-14 18:54 ` [PATCH V3 09/10] tests/qtest: postcopy " Steve Sistare
@ 2023-08-14 18:54 ` Steve Sistare
2023-08-17 18:23 ` [PATCH V3 00/10] fix migration of suspended runstate Peter Xu
10 siblings, 0 replies; 18+ messages in thread
From: Steve Sistare @ 2023-08-14 18:54 UTC (permalink / raw)
To: qemu-devel
Cc: Juan Quintela, Peter Xu, Paolo Bonzini, Thomas Huth,
Daniel P. Berrangé, Steve Sistare
Add a test case to verify that the suspended state is handled correctly by
a background migration. The test suspends the src, migrates, then wakes
the dest.
Signed-off-by: Steve Sistare <steven.sistare@oracle.com>
---
tests/qtest/migration-test.c | 21 +++++++++++++++++++++
1 file changed, 21 insertions(+)
diff --git a/tests/qtest/migration-test.c b/tests/qtest/migration-test.c
index d99620a..3c9e487 100644
--- a/tests/qtest/migration-test.c
+++ b/tests/qtest/migration-test.c
@@ -1678,6 +1678,26 @@ static void test_precopy_unix_suspend_notlive(void)
test_precopy_common(&args);
}
+static void *test_bg_suspend_start(QTestState *from, QTestState *to)
+{
+ migrate_set_capability(from, "background-snapshot", true);
+ return NULL;
+}
+
+static void test_bg_suspend(void)
+{
+ g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
+ MigrateCommon args = {
+ .listen_uri = uri,
+ .connect_uri = uri,
+ .live = true, /* runs fast, the src suspends immediately. */
+ .start.suspend_me = true,
+ .start_hook = test_bg_suspend_start
+ };
+
+ test_precopy_common(&args);
+}
+
static void test_precopy_unix_dirty_ring(void)
{
g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
@@ -2904,6 +2924,7 @@ int main(int argc, char **argv)
if (is_x86) {
qtest_add_func("/migration/postcopy/suspend",
test_postcopy_suspend);
+ qtest_add_func("/migration/bg/suspend", test_bg_suspend);
}
}
--
1.8.3.1
^ permalink raw reply related [flat|nested] 18+ messages in thread
* Re: [PATCH V3 00/10] fix migration of suspended runstate
2023-08-14 18:54 [PATCH V3 00/10] fix migration of suspended runstate Steve Sistare
` (9 preceding siblings ...)
2023-08-14 18:54 ` [PATCH V3 10/10] tests/qtest: background " Steve Sistare
@ 2023-08-17 18:23 ` Peter Xu
2023-08-24 21:09 ` Steven Sistare
10 siblings, 1 reply; 18+ messages in thread
From: Peter Xu @ 2023-08-17 18:23 UTC (permalink / raw)
To: Steve Sistare
Cc: qemu-devel, Juan Quintela, Paolo Bonzini, Thomas Huth,
Daniel P. Berrangé
On Mon, Aug 14, 2023 at 11:54:26AM -0700, Steve Sistare wrote:
> Migration of a guest in the suspended runstate is broken. The incoming
> migration code automatically tries to wake the guest, which is wrong;
> the guest should end migration in the same runstate it started. Further,
> for a restored snapshot, the automatic wakeup fails. The runstate is
> RUNNING, but the guest is not. See the commit messages for the details.
Hi Steve,
I drafted two small patches to show what I meant, on top of this series.
Before applying these two, one needs to revert patch 1 in this series.
After applied, it should also pass all three new suspend tests. We can
continue the discussion here based on the patches.
Thanks,
=======
From 2e495b08be4c56d5d8a47ba1657bae6e316c6254 Mon Sep 17 00:00:00 2001
From: Peter Xu <peterx@redhat.com>
Date: Thu, 17 Aug 2023 12:32:00 -0400
Subject: [PATCH 1/2] cpus: Allow vm_prepare_start() to take vm state as input
It was by default always setting the state as RUNNING, but logically
SUSPENDED (acpi s1) should also fall into "vm running" case, where it's
only the vcpus that are stopped running (while everything else is).
Adding such a state parameter to be prepared when we want to prepare start
when not allowing vcpus to start yet (RUN_STATE_SUSPENDED).
Note: I found that not all vm state notifiers are ready for SUSPENDED when
having running=true set. Here let's always pass in RUNNING irrelevant of
the state passed into vm_prepare_start(), and leave that for later to
figure out. So far there should have (hopefully) no impact functional
wise.
For this specific patch, no functional change at all should be intended,
because all callers are still passing over RUNNING.
Signed-off-by: Peter Xu <peterx@redhat.com>
---
include/sysemu/runstate.h | 3 ++-
gdbstub/softmmu.c | 2 +-
softmmu/cpus.c | 12 +++++++++---
3 files changed, 12 insertions(+), 5 deletions(-)
diff --git a/include/sysemu/runstate.h b/include/sysemu/runstate.h
index 7beb29c2e2..7d889ab7c7 100644
--- a/include/sysemu/runstate.h
+++ b/include/sysemu/runstate.h
@@ -39,8 +39,9 @@ void vm_start(void);
* vm_prepare_start: Prepare for starting/resuming the VM
*
* @step_pending: whether any of the CPUs is about to be single-stepped by gdb
+ * @state: the vm state to setup
*/
-int vm_prepare_start(bool step_pending);
+int vm_prepare_start(bool step_pending, RunState state);
int vm_stop(RunState state);
int vm_stop_force_state(RunState state);
int vm_shutdown(void);
diff --git a/gdbstub/softmmu.c b/gdbstub/softmmu.c
index f509b7285d..a43e8328c0 100644
--- a/gdbstub/softmmu.c
+++ b/gdbstub/softmmu.c
@@ -565,7 +565,7 @@ int gdb_continue_partial(char *newstates)
}
}
- if (vm_prepare_start(step_requested)) {
+ if (vm_prepare_start(step_requested, RUN_STATE_RUNNING)) {
return 0;
}
diff --git a/softmmu/cpus.c b/softmmu/cpus.c
index fed20ffb5d..000fac79b7 100644
--- a/softmmu/cpus.c
+++ b/softmmu/cpus.c
@@ -681,7 +681,7 @@ int vm_stop(RunState state)
* Returns -1 if the vCPUs are not to be restarted (e.g. if they are already
* running or in case of an error condition), 0 otherwise.
*/
-int vm_prepare_start(bool step_pending)
+int vm_prepare_start(bool step_pending, RunState state)
{
RunState requested;
@@ -713,14 +713,20 @@ int vm_prepare_start(bool step_pending)
qapi_event_send_resume();
cpu_enable_ticks();
- runstate_set(RUN_STATE_RUNNING);
+ runstate_set(state);
+ /*
+ * FIXME: ignore "state" being passed in for now, notify always with
+ * RUNNING. Because some of the vm state change handlers may not expect
+ * other states (e.g. SUSPENDED) passed in with running=true. This can
+ * be modified after proper investigation over all vm state notifiers.
+ */
vm_state_notify(1, RUN_STATE_RUNNING);
return 0;
}
void vm_start(void)
{
- if (!vm_prepare_start(false)) {
+ if (!vm_prepare_start(false, RUN_STATE_RUNNING)) {
resume_all_vcpus();
}
}
--
2.41.0
=======
From 4a0936eafd03952d58ab380271559c4a2049b96e Mon Sep 17 00:00:00 2001
From: Peter Xu <peterx@redhat.com>
Date: Thu, 17 Aug 2023 12:44:29 -0400
Subject: [PATCH 2/2] fixup
Signed-off-by: Peter Xu <peterx@redhat.com>
---
migration/migration.c | 9 +++++----
tests/qtest/migration-test.c | 9 +++++----
2 files changed, 10 insertions(+), 8 deletions(-)
diff --git a/migration/migration.c b/migration/migration.c
index e6b8024b03..b004475af6 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -497,7 +497,7 @@ static void process_incoming_migration_bh(void *opaque)
migration_incoming_disable_colo();
vm_start();
} else {
- runstate_set(global_state_get_runstate());
+ vm_prepare_start(false, global_state_get_runstate());
}
/*
* This must happen after any state changes since as soon as an external
@@ -1143,15 +1143,16 @@ void migrate_set_state(int *state, int old_state, int new_state)
void migrate_set_runstate(void)
{
- if (!global_state_received() ||
- global_state_get_runstate() == RUN_STATE_RUNNING) {
+ RunState state = global_state_get_runstate();
+
+ if (!global_state_received() || state == RUN_STATE_RUNNING) {
if (autostart) {
vm_start();
} else {
runstate_set(RUN_STATE_PAUSED);
}
} else {
- runstate_set(global_state_get_runstate());
+ vm_prepare_start(false, state);
}
}
diff --git a/tests/qtest/migration-test.c b/tests/qtest/migration-test.c
index 3c9e487754..5cc8b914df 100644
--- a/tests/qtest/migration-test.c
+++ b/tests/qtest/migration-test.c
@@ -1614,15 +1614,16 @@ static void test_precopy_common(MigrateCommon *args)
qtest_qmp_assert_success(to, "{ 'execute' : 'cont'}");
}
+ /* Always get RESUME first after switchover */
+ if (!dst_state.resume_seen) {
+ qtest_qmp_eventwait(to, "RESUME");
+ }
+
if (args->start.suspend_me) {
/* wakeup succeeds only if guest is suspended */
qtest_qmp_assert_success(to, "{'execute': 'system_wakeup'}");
}
- if (!dst_state.resume_seen) {
- qtest_qmp_eventwait(to, "RESUME");
- }
-
wait_for_serial("dest_serial");
}
--
2.41.0
--
Peter Xu
^ permalink raw reply related [flat|nested] 18+ messages in thread
* Re: [PATCH V3 00/10] fix migration of suspended runstate
2023-08-17 18:23 ` [PATCH V3 00/10] fix migration of suspended runstate Peter Xu
@ 2023-08-24 21:09 ` Steven Sistare
2023-08-25 13:28 ` Steven Sistare
0 siblings, 1 reply; 18+ messages in thread
From: Steven Sistare @ 2023-08-24 21:09 UTC (permalink / raw)
To: Peter Xu
Cc: qemu-devel, Juan Quintela, Paolo Bonzini, Thomas Huth,
Daniel P. Berrangé
On 8/17/2023 2:23 PM, Peter Xu wrote:
> On Mon, Aug 14, 2023 at 11:54:26AM -0700, Steve Sistare wrote:
>> Migration of a guest in the suspended runstate is broken. The incoming
>> migration code automatically tries to wake the guest, which is wrong;
>> the guest should end migration in the same runstate it started. Further,
>> for a restored snapshot, the automatic wakeup fails. The runstate is
>> RUNNING, but the guest is not. See the commit messages for the details.
>
> Hi Steve,
>
> I drafted two small patches to show what I meant, on top of this series.
> Before applying these two, one needs to revert patch 1 in this series.
>
> After applied, it should also pass all three new suspend tests. We can
> continue the discussion here based on the patches.
Your 2 patches look good. I suggest we keep patch 1, and I squash patch 2
into the other patches.
There is one more fix needed: on the sending side, if the state is suspended,
then ticks must be disabled so the tick globals are updated before they are
written to vmstate. Otherwise, tick starts at 0 in the receiver when
cpu_enable_ticks is called.
-------------------------------------------
diff --git a/migration/migration.c b/migration/migration.c
index b004475..89d56a8 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -63,6 +63,7 @@
#include "sysemu/cpus.h"
#include "yank_functions.h"
#include "sysemu/qtest.h"
+#include "sysemu/cpu-timers.h"
#include "options.h"
#include "sysemu/dirtylimit.h"
@@ -2125,6 +2126,9 @@ static int postcopy_start(MigrationState *ms, Error **errp
trace_postcopy_start_set_run();
global_state_store();
+ if (runstate_check(RUN_STATE_SUSPENDED)) {
+ cpu_disable_ticks();
+ }
ret = vm_stop_force_state(RUN_STATE_FINISH_MIGRATE);
if (ret < 0) {
goto fail;
@@ -2333,6 +2337,9 @@ static void migration_completion(MigrationState *s)
s->vm_old_state = runstate_get();
global_state_store();
+ if (runstate_check(RUN_STATE_SUSPENDED)) {
+ cpu_disable_ticks();
+ }
ret = vm_stop_force_state(RUN_STATE_FINISH_MIGRATE);
trace_migration_completion_vm_stop(ret);
if (ret >= 0) {
diff --git a/migration/savevm.c b/migration/savevm.c
index 7b9c477..eff6976 100644
--- a/migration/savevm.c
+++ b/migration/savevm.c
@@ -58,6 +58,7 @@
#include "qemu/cutils.h"
#include "io/channel-buffer.h"
#include "io/channel-file.h"
+#include "sysemu/cpu-timers.h"
#include "sysemu/replay.h"
#include "sysemu/runstate.h"
#include "sysemu/sysemu.h"
@@ -2969,6 +2970,9 @@ bool save_snapshot(const char *name, bool overwrite, const
saved_vm_running = runstate_is_running();
global_state_store();
+ if (runstate_check(RUN_STATE_SUSPENDED)) {
+ cpu_disable_ticks();
+ }
vm_stop(RUN_STATE_SAVE_VM);
bdrv_drain_all_begin();
@@ -3037,6 +3041,8 @@ bool save_snapshot(const char *name, bool overwrite, const
if (saved_vm_running) {
vm_start();
+ } else if (runstate_check(RUN_STATE_SUSPENDED)) {
+ cpu_enable_ticks();
}
return ret == 0;
}
-------------------------------------------
- Steve
^ permalink raw reply related [flat|nested] 18+ messages in thread
* Re: [PATCH V3 00/10] fix migration of suspended runstate
2023-08-24 21:09 ` Steven Sistare
@ 2023-08-25 13:28 ` Steven Sistare
2023-08-25 15:07 ` Peter Xu
0 siblings, 1 reply; 18+ messages in thread
From: Steven Sistare @ 2023-08-25 13:28 UTC (permalink / raw)
To: Peter Xu
Cc: qemu-devel, Juan Quintela, Paolo Bonzini, Thomas Huth,
Daniel P. Berrangé
On 8/24/2023 5:09 PM, Steven Sistare wrote:
> On 8/17/2023 2:23 PM, Peter Xu wrote:
>> On Mon, Aug 14, 2023 at 11:54:26AM -0700, Steve Sistare wrote:
>>> Migration of a guest in the suspended runstate is broken. The incoming
>>> migration code automatically tries to wake the guest, which is wrong;
>>> the guest should end migration in the same runstate it started. Further,
>>> for a restored snapshot, the automatic wakeup fails. The runstate is
>>> RUNNING, but the guest is not. See the commit messages for the details.
>>
>> Hi Steve,
>>
>> I drafted two small patches to show what I meant, on top of this series.
>> Before applying these two, one needs to revert patch 1 in this series.
>>
>> After applied, it should also pass all three new suspend tests. We can
>> continue the discussion here based on the patches.
>
> Your 2 patches look good. I suggest we keep patch 1, and I squash patch 2
> into the other patches.
>
> There is one more fix needed: on the sending side, if the state is suspended,
> then ticks must be disabled so the tick globals are updated before they are
> written to vmstate. Otherwise, tick starts at 0 in the receiver when
> cpu_enable_ticks is called.
>
> -------------------------------------------
> diff --git a/migration/migration.c b/migration/migration.c
[...]
> -------------------------------------------
This diff is just a rough draft. I need to resume ticks if the migration
fails or is cancelled, and I am trying to push the logic into vm_stop,
vm_stop_force_state, and vm_start, and/or vm_prepare_start.
- Steve
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH V3 00/10] fix migration of suspended runstate
2023-08-25 13:28 ` Steven Sistare
@ 2023-08-25 15:07 ` Peter Xu
2023-08-25 17:56 ` Steven Sistare
0 siblings, 1 reply; 18+ messages in thread
From: Peter Xu @ 2023-08-25 15:07 UTC (permalink / raw)
To: Steven Sistare
Cc: qemu-devel, Juan Quintela, Paolo Bonzini, Thomas Huth,
Daniel P. Berrangé
On Fri, Aug 25, 2023 at 09:28:28AM -0400, Steven Sistare wrote:
> On 8/24/2023 5:09 PM, Steven Sistare wrote:
> > On 8/17/2023 2:23 PM, Peter Xu wrote:
> >> On Mon, Aug 14, 2023 at 11:54:26AM -0700, Steve Sistare wrote:
> >>> Migration of a guest in the suspended runstate is broken. The incoming
> >>> migration code automatically tries to wake the guest, which is wrong;
> >>> the guest should end migration in the same runstate it started. Further,
> >>> for a restored snapshot, the automatic wakeup fails. The runstate is
> >>> RUNNING, but the guest is not. See the commit messages for the details.
> >>
> >> Hi Steve,
> >>
> >> I drafted two small patches to show what I meant, on top of this series.
> >> Before applying these two, one needs to revert patch 1 in this series.
> >>
> >> After applied, it should also pass all three new suspend tests. We can
> >> continue the discussion here based on the patches.
> >
> > Your 2 patches look good. I suggest we keep patch 1, and I squash patch 2
> > into the other patches.
Yes. Feel free to reorganize / modify /.. the changes in whatever way you
prefer in the final patchset.
> >
> > There is one more fix needed: on the sending side, if the state is suspended,
> > then ticks must be disabled so the tick globals are updated before they are
> > written to vmstate. Otherwise, tick starts at 0 in the receiver when
> > cpu_enable_ticks is called.
> >
> > -------------------------------------------
> > diff --git a/migration/migration.c b/migration/migration.c
> [...]
> > -------------------------------------------
>
> This diff is just a rough draft. I need to resume ticks if the migration
> fails or is cancelled, and I am trying to push the logic into vm_stop,
> vm_stop_force_state, and vm_start, and/or vm_prepare_start.
Yes this sounds better than hard code things into migration codes, thanks.
Maybe at least all the migration related code paths should always use
vm_stop_force_state() (e.g. save_snapshot)?
At the meantime, AFAIU we should allow runstate_is_running() to return true
even for suspended, matching current usages of vm_start() / vm_stop(). But
again that can have risk of breaking existing users.
I bet you may have a better grasp of what it should look like to solve the
current "migrate suspended VM" problem at the minimum but hopefully still
in a clean way, so I assume I'll just wait and see.
Thanks,
--
Peter Xu
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH V3 00/10] fix migration of suspended runstate
2023-08-25 15:07 ` Peter Xu
@ 2023-08-25 17:56 ` Steven Sistare
0 siblings, 0 replies; 18+ messages in thread
From: Steven Sistare @ 2023-08-25 17:56 UTC (permalink / raw)
To: Peter Xu
Cc: qemu-devel, Juan Quintela, Paolo Bonzini, Thomas Huth,
Daniel P. Berrangé
On 8/25/2023 11:07 AM, Peter Xu wrote:
> On Fri, Aug 25, 2023 at 09:28:28AM -0400, Steven Sistare wrote:
>> On 8/24/2023 5:09 PM, Steven Sistare wrote:
>>> On 8/17/2023 2:23 PM, Peter Xu wrote:
>>>> On Mon, Aug 14, 2023 at 11:54:26AM -0700, Steve Sistare wrote:
>>>>> Migration of a guest in the suspended runstate is broken. The incoming
>>>>> migration code automatically tries to wake the guest, which is wrong;
>>>>> the guest should end migration in the same runstate it started. Further,
>>>>> for a restored snapshot, the automatic wakeup fails. The runstate is
>>>>> RUNNING, but the guest is not. See the commit messages for the details.
>>>>
>>>> Hi Steve,
>>>>
>>>> I drafted two small patches to show what I meant, on top of this series.
>>>> Before applying these two, one needs to revert patch 1 in this series.
>>>>
>>>> After applied, it should also pass all three new suspend tests. We can
>>>> continue the discussion here based on the patches.
>>>
>>> Your 2 patches look good. I suggest we keep patch 1, and I squash patch 2
>>> into the other patches.
>
> Yes. Feel free to reorganize / modify /.. the changes in whatever way you
> prefer in the final patchset.
>
>>>
>>> There is one more fix needed: on the sending side, if the state is suspended,
>>> then ticks must be disabled so the tick globals are updated before they are
>>> written to vmstate. Otherwise, tick starts at 0 in the receiver when
>>> cpu_enable_ticks is called.
>>>
>>> -------------------------------------------
>>> diff --git a/migration/migration.c b/migration/migration.c
>> [...]
>>> -------------------------------------------
>>
>> This diff is just a rough draft. I need to resume ticks if the migration
>> fails or is cancelled, and I am trying to push the logic into vm_stop,
>> vm_stop_force_state, and vm_start, and/or vm_prepare_start.
>
> Yes this sounds better than hard code things into migration codes, thanks.
>
> Maybe at least all the migration related code paths should always use
> vm_stop_force_state() (e.g. save_snapshot)?
>
> At the meantime, AFAIU we should allow runstate_is_running() to return true
> even for suspended, matching current usages of vm_start() / vm_stop(). But
> again that can have risk of breaking existing users.
>
> I bet you may have a better grasp of what it should look like to solve the
> current "migrate suspended VM" problem at the minimum but hopefully still
> in a clean way, so I assume I'll just wait and see.
I found a better way.
Rather than disabling ticks, I added a pre_save handler to capture and save
the correct timer state even if the timer is running, using the logic from
cpr_disable_ticks. No changes needed in the migration code:
------------------------------------
diff --git a/softmmu/cpu-timers.c b/softmmu/cpu-timers.c
index 117408c..d5af317 100644
--- a/softmmu/cpu-timers.c
+++ b/softmmu/cpu-timers.c
@@ -157,6 +157,36 @@ static bool icount_shift_state_needed(void *opaque)
return icount_enabled() == 2;
}
+static int cpu_pre_save_ticks(void *opaque)
+{
+ TimersState *t = &timers_state;
+ TimersState *snap = opaque;
+
+ seqlock_write_lock(&t->vm_clock_seqlock, &t->vm_clock_lock);
+
+ if (t->cpu_ticks_enabled) {
+ snap->cpu_ticks_offset = t->cpu_ticks_offset + cpu_get_host_ticks();
+ snap->cpu_clock_offset = cpu_get_clock_locked();
+ } else {
+ snap->cpu_ticks_offset = t->cpu_ticks_offset;
+ snap->cpu_clock_offset = t->cpu_clock_offset;
+ }
+ seqlock_write_unlock(&t->vm_clock_seqlock, &t->vm_clock_lock);
+ return 0;
+}
+
+static int cpu_post_load_ticks(void *opaque, int version_id)
+{
+ TimersState *t = &timers_state;
+ TimersState *snap = opaque;
+
+ seqlock_write_lock(&t->vm_clock_seqlock, &t->vm_clock_lock);
+ t->cpu_ticks_offset = snap->cpu_ticks_offset;
+ t->cpu_clock_offset = snap->cpu_clock_offset;
+ seqlock_write_unlock(&t->vm_clock_seqlock, &t->vm_clock_lock);
+ return 0;
+}
+
/*
* Subsection for warp timer migration is optional, because may not be created
*/
@@ -221,6 +251,8 @@ static const VMStateDescription vmstate_timers = {
.name = "timer",
.version_id = 2,
.minimum_version_id = 1,
+ .pre_save = cpu_pre_save_ticks,
+ .post_load = cpu_post_load_ticks,
.fields = (VMStateField[]) {
VMSTATE_INT64(cpu_ticks_offset, TimersState),
VMSTATE_UNUSED(8),
@@ -269,9 +301,11 @@ TimersState timers_state;
/* initialize timers state and the cpu throttle for convenience */
void cpu_timers_init(void)
{
+ static TimersState timers_snapshot;
+
seqlock_init(&timers_state.vm_clock_seqlock);
qemu_spin_init(&timers_state.vm_clock_lock);
- vmstate_register(NULL, 0, &vmstate_timers, &timers_state);
+ vmstate_register(NULL, 0, &vmstate_timers, &timers_snapshot);
cpu_throttle_init();
}
------------------------------------
- Steve
^ permalink raw reply related [flat|nested] 18+ messages in thread