Merge tag 'migration-20240104-pull-request' of https://gitlab.com/peterx/qemu into staging

migration 1st pull for 9.0

- We lost Juan and Leo in the maintainers file
- Steven's suspend state fix
- Steven's fix for coverity on migrate_mode
- Avihai's migration cleanup series

# -----BEGIN PGP SIGNATURE-----
#
# iIgEABYKADAWIQS5GE3CDMRX2s990ak7X8zN86vXBgUCZZY0TxIccGV0ZXJ4QHJl
# ZGhhdC5jb20ACgkQO1/MzfOr1wbSxgEAoM5g3wkc22lpAlRpU+hJUqT9NVOVQSK+
# Fk7XJYTdSgABAKzykA6hAmU5Kj+yVI6jI874SVZbs2FWpFs4osvsKk4D
# =sfuM
# -----END PGP SIGNATURE-----
# gpg: Signature made Thu 04 Jan 2024 04:30:07 GMT
# gpg:                using EDDSA key B9184DC20CC457DACF7DD1A93B5FCCCDF3ABD706
# gpg:                issuer "peterx@redhat.com"
# gpg: Good signature from "Peter Xu <xzpeter@gmail.com>" [unknown]
# gpg:                 aka "Peter Xu <peterx@redhat.com>" [unknown]
# gpg: WARNING: This key is not certified with a trusted signature!
# gpg:          There is no indication that the signature belongs to the owner.
# Primary key fingerprint: B918 4DC2 0CC4 57DA CF7D  D1A9 3B5F CCCD F3AB D706

* tag 'migration-20240104-pull-request' of https://gitlab.com/peterx/qemu: (26 commits)
  migration: fix coverity migrate_mode finding
  migration/multifd: Remove unnecessary usage of local Error
  migration: Remove unnecessary usage of local Error
  migration: Fix migration_channel_read_peek() error path
  migration/multifd: Remove error_setg() in migration_ioc_process_incoming()
  migration/multifd: Fix leaking of Error in TLS error flow
  migration/multifd: Simplify multifd_channel_connect() if else statement
  migration/multifd: Fix error message in multifd_recv_initial_packet()
  migration: Remove errp parameter in migration_fd_process_incoming()
  migration: Refactor migration_incoming_setup()
  migration: Remove nulling of hostname in migrate_init()
  migration: Remove migrate_max_downtime() declaration
  tests/qtest: postcopy migration with suspend
  tests/qtest: precopy migration with suspend
  tests/qtest: option to suspend during migration
  tests/qtest: migration events
  migration: preserve suspended for bg_migration
  migration: preserve suspended for snapshot
  migration: preserve suspended runstate
  migration: propagate suspended runstate
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell
2024-01-05 13:35:25 +00:00
28 changed files with 386 additions and 200 deletions
+1
View File
@@ -81,6 +81,7 @@ Greg Kurz <groug@kaod.org> <gkurz@linux.vnet.ibm.com>
Huacai Chen <chenhuacai@kernel.org> <chenhc@lemote.com>
Huacai Chen <chenhuacai@kernel.org> <chenhuacai@loongson.cn>
James Hogan <jhogan@kernel.org> <james.hogan@imgtec.com>
Juan Quintela <quintela@trasno.org> <quintela@redhat.com>
Leif Lindholm <quic_llindhol@quicinc.com> <leif.lindholm@linaro.org>
Leif Lindholm <quic_llindhol@quicinc.com> <leif@nuviainc.com>
Luc Michel <luc@lmichel.fr> <luc.michel@git.antfield.fr>
-5
View File
@@ -70,7 +70,6 @@ R: Daniel P. Berrangé <berrange@redhat.com>
R: Thomas Huth <thuth@redhat.com>
R: Markus Armbruster <armbru@redhat.com>
R: Philippe Mathieu-Daudé <philmd@linaro.org>
R: Juan Quintela <quintela@redhat.com>
W: https://www.qemu.org/docs/master/devel/index.html
S: Odd Fixes
F: docs/devel/style.rst
@@ -3355,10 +3354,8 @@ S: Odd Fixes
F: scripts/checkpatch.pl
Migration
M: Juan Quintela <quintela@redhat.com>
M: Peter Xu <peterx@redhat.com>
M: Fabiano Rosas <farosas@suse.de>
R: Leonardo Bras <leobras@redhat.com>
S: Maintained
F: hw/core/vmstate-if.c
F: include/hw/vmstate-if.h
@@ -3375,10 +3372,8 @@ F: util/userfaultfd.c
X: migration/rdma*
RDMA Migration
M: Juan Quintela <quintela@redhat.com>
R: Li Zhijian <lizhijian@fujitsu.com>
R: Peter Xu <peterx@redhat.com>
R: Leonardo Bras <leobras@redhat.com>
S: Odd Fixes
F: migration/rdma*
+1 -1
View File
@@ -904,7 +904,7 @@ static void tpm_emulator_vm_state_change(void *opaque, bool running,
trace_tpm_emulator_vm_state_change(running, state);
if (!running || state != RUN_STATE_RUNNING || !tpm_emu->relock_storage) {
if (!running || !tpm_emu->relock_storage) {
return;
}
+1 -1
View File
@@ -2451,7 +2451,7 @@ static void usb_ehci_vm_state_change(void *opaque, bool running, RunState state)
* USB-devices which have async handled packages have a packet in the
* ep queue to match the completion with.
*/
if (state == RUN_STATE_RUNNING) {
if (running) {
ehci_advance_async_state(ehci);
}
+1 -1
View File
@@ -1403,7 +1403,7 @@ static void usbredir_vm_state_change(void *priv, bool running, RunState state)
{
USBRedirDevice *dev = priv;
if (state == RUN_STATE_RUNNING && dev->parser != NULL) {
if (running && dev->parser != NULL) {
usbredirparser_do_write(dev->parser); /* Flush any pending writes */
}
}
+1 -1
View File
@@ -623,7 +623,7 @@ void xen_hvm_change_state_handler(void *opaque, bool running,
xen_set_ioreq_server_state(xen_domid,
state->ioservid,
(rstate == RUN_STATE_RUNNING));
running);
}
void xen_exit_notifier(Notifier *n, void *data)
+7
View File
@@ -16,6 +16,7 @@
#define QEMU_MIGRATION_SNAPSHOT_H
#include "qapi/qapi-builtin-types.h"
#include "qapi/qapi-types-run-state.h"
/**
* save_snapshot: Save an internal snapshot.
@@ -61,4 +62,10 @@ bool delete_snapshot(const char *name,
bool has_devices, strList *devices,
Error **errp);
/**
* load_snapshot_resume: Restore runstate after loading snapshot.
* @state: state to restore
*/
void load_snapshot_resume(RunState state);
#endif
+20
View File
@@ -40,6 +40,15 @@ static inline bool shutdown_caused_by_guest(ShutdownCause cause)
return cause >= SHUTDOWN_CAUSE_GUEST_SHUTDOWN;
}
/*
* In a "live" state, the vcpu clock is ticking, and the runstate notifiers
* think we are running.
*/
static inline bool runstate_is_live(RunState state)
{
return state == RUN_STATE_RUNNING || state == RUN_STATE_SUSPENDED;
}
void vm_start(void);
/**
@@ -48,9 +57,20 @@ void vm_start(void);
* @step_pending: whether any of the CPUs is about to be single-stepped by gdb
*/
int vm_prepare_start(bool step_pending);
/**
* vm_resume: If @state is a live state, start the vm and set the state,
* else just set the state.
*
* @state: the state to restore
*/
void vm_resume(RunState state);
int vm_stop(RunState state);
int vm_stop_force_state(RunState state);
int vm_shutdown(void);
void vm_set_suspended(bool suspended);
bool vm_get_suspended(void);
typedef enum WakeupReason {
/* Always keep QEMU_WAKEUP_REASON_NONE = 0 */
+6 -3
View File
@@ -117,9 +117,12 @@ int migration_channel_read_peek(QIOChannel *ioc,
len = qio_channel_readv_full(ioc, &iov, 1, NULL, NULL,
QIO_CHANNEL_READ_FLAG_MSG_PEEK, errp);
if (len <= 0 && len != QIO_CHANNEL_ERR_BLOCK) {
error_setg(errp,
"Failed to peek at channel");
if (len < 0 && len != QIO_CHANNEL_ERR_BLOCK) {
return -1;
}
if (len == 0) {
error_setg(errp, "Failed to peek at channel");
return -1;
}
+27 -20
View File
@@ -22,7 +22,16 @@
typedef struct {
uint32_t size;
uint8_t runstate[100];
/*
* runstate was 100 bytes, zero padded, but we trimmed it to add a
* few fields and maintain backwards compatibility.
*/
uint8_t runstate[32];
uint8_t has_vm_was_suspended;
uint8_t vm_was_suspended;
uint8_t unused[66];
RunState state;
bool received;
} GlobalState;
@@ -35,6 +44,10 @@ static void global_state_do_store(RunState state)
assert(strlen(state_str) < sizeof(global_state.runstate));
strpadcpy((char *)global_state.runstate, sizeof(global_state.runstate),
state_str, '\0');
global_state.has_vm_was_suspended = true;
global_state.vm_was_suspended = vm_get_suspended();
memset(global_state.unused, 0, sizeof(global_state.unused));
}
void global_state_store(void)
@@ -59,24 +72,7 @@ RunState global_state_get_runstate(void)
static bool global_state_needed(void *opaque)
{
GlobalState *s = opaque;
char *runstate = (char *)s->runstate;
/* If it is not optional, it is mandatory */
if (migrate_get_current()->store_global_state) {
return true;
}
/* If state is running or paused, it is not needed */
if (strcmp(runstate, "running") == 0 ||
strcmp(runstate, "paused") == 0) {
return false;
}
/* for any other state it is needed */
return true;
return migrate_get_current()->store_global_state;
}
static int global_state_post_load(void *opaque, int version_id)
@@ -93,7 +89,7 @@ static int global_state_post_load(void *opaque, int version_id)
sizeof(s->runstate)) == sizeof(s->runstate)) {
/*
* This condition should never happen during migration, because
* all runstate names are shorter than 100 bytes (the size of
* all runstate names are shorter than 32 bytes (the size of
* s->runstate). However, a malicious stream could overflow
* the qapi_enum_parse() call, so we force the last character
* to a NUL byte.
@@ -110,6 +106,14 @@ static int global_state_post_load(void *opaque, int version_id)
}
s->state = r;
/*
* global_state is saved on the outgoing side before forcing a stopped
* state, so it may have saved state=suspended and vm_was_suspended=0.
* Now we are in a paused state, and when we later call vm_start, it must
* restore the suspended state, so we must set vm_was_suspended=1 here.
*/
vm_set_suspended(s->vm_was_suspended || r == RUN_STATE_SUSPENDED);
return 0;
}
@@ -134,6 +138,9 @@ static const VMStateDescription vmstate_globalstate = {
.fields = (const VMStateField[]) {
VMSTATE_UINT32(size, GlobalState),
VMSTATE_BUFFER(runstate, GlobalState),
VMSTATE_UINT8(has_vm_was_suspended, GlobalState),
VMSTATE_UINT8(vm_was_suspended, GlobalState),
VMSTATE_BUFFER(unused, GlobalState),
VMSTATE_END_OF_LIST()
},
};
+5 -3
View File
@@ -399,15 +399,17 @@ void hmp_info_migrate_parameters(Monitor *mon, const QDict *qdict)
void hmp_loadvm(Monitor *mon, const QDict *qdict)
{
int saved_vm_running = runstate_is_running();
RunState saved_state = runstate_get();
const char *name = qdict_get_str(qdict, "name");
Error *err = NULL;
vm_stop(RUN_STATE_RESTORE_VM);
if (load_snapshot(name, NULL, false, NULL, &err) && saved_vm_running) {
vm_start();
if (load_snapshot(name, NULL, false, NULL, &err)) {
load_snapshot_resume(saved_state);
}
hmp_handle_error(mon, err);
}
+10 -32
View File
@@ -604,7 +604,7 @@ static void process_incoming_migration_bh(void *opaque)
*/
if (!migrate_late_block_activate() ||
(autostart && (!global_state_received() ||
global_state_get_runstate() == RUN_STATE_RUNNING))) {
runstate_is_live(global_state_get_runstate())))) {
/* Make sure all file formats throw away their mutable metadata.
* If we get an error here, just don't restart the VM yet. */
bdrv_activate_all(&local_err);
@@ -628,7 +628,7 @@ static void process_incoming_migration_bh(void *opaque)
dirty_bitmap_mig_before_vm_start();
if (!global_state_received() ||
global_state_get_runstate() == RUN_STATE_RUNNING) {
runstate_is_live(global_state_get_runstate())) {
if (autostart) {
vm_start();
} else {
@@ -724,11 +724,8 @@ fail:
/**
* migration_incoming_setup: Setup incoming migration
* @f: file for main migration channel
* @errp: where to put errors
*
* Returns: %true on success, %false on error.
*/
static bool migration_incoming_setup(QEMUFile *f, Error **errp)
static void migration_incoming_setup(QEMUFile *f)
{
MigrationIncomingState *mis = migration_incoming_get_current();
@@ -736,7 +733,6 @@ static bool migration_incoming_setup(QEMUFile *f, Error **errp)
mis->from_src_file = f;
}
qemu_file_set_blocking(f, false);
return true;
}
void migration_incoming_process(void)
@@ -778,11 +774,9 @@ static bool postcopy_try_recover(void)
return false;
}
void migration_fd_process_incoming(QEMUFile *f, Error **errp)
void migration_fd_process_incoming(QEMUFile *f)
{
if (!migration_incoming_setup(f, errp)) {
return;
}
migration_incoming_setup(f);
if (postcopy_try_recover()) {
return;
}
@@ -836,10 +830,9 @@ void migration_ioc_process_incoming(QIOChannel *ioc, Error **errp)
* issue is not possible.
*/
ret = migration_channel_read_peek(ioc, (void *)&channel_magic,
sizeof(channel_magic), &local_err);
sizeof(channel_magic), errp);
if (ret != 0) {
error_propagate(errp, local_err);
return;
}
@@ -849,16 +842,12 @@ void migration_ioc_process_incoming(QIOChannel *ioc, Error **errp)
}
if (multifd_load_setup(errp) != 0) {
error_setg(errp, "Failed to setup multifd channels");
return;
}
if (default_channel) {
f = qemu_file_new_input(ioc);
if (!migration_incoming_setup(f, errp)) {
return;
}
migration_incoming_setup(f);
} else {
/* Multiple connections */
assert(migration_needs_multiple_sockets());
@@ -1588,7 +1577,6 @@ int migrate_init(MigrationState *s, Error **errp)
s->migration_thread_running = false;
error_free(s->error);
s->error = NULL;
s->hostname = NULL;
s->vmdesc = NULL;
migrate_set_state(&s->state, MIGRATION_STATUS_NONE, MIGRATION_STATUS_SETUP);
@@ -1836,8 +1824,6 @@ bool migration_is_blocked(Error **errp)
static bool migrate_prepare(MigrationState *s, bool blk, bool blk_inc,
bool resume, Error **errp)
{
Error *local_err = NULL;
if (blk_inc) {
warn_report("parameter 'inc' is deprecated;"
" use blockdev-mirror with NBD instead");
@@ -1907,8 +1893,7 @@ static bool migrate_prepare(MigrationState *s, bool blk, bool blk_inc,
"current migration capabilities");
return false;
}
if (!migrate_cap_set(MIGRATION_CAPABILITY_BLOCK, true, &local_err)) {
error_propagate(errp, local_err);
if (!migrate_cap_set(MIGRATION_CAPABILITY_BLOCK, true, errp)) {
return false;
}
s->must_remove_block_options = true;
@@ -2416,7 +2401,6 @@ static int postcopy_start(MigrationState *ms, Error **errp)
migration_downtime_start(ms);
qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER, NULL);
global_state_store();
ret = migration_stop_vm(RUN_STATE_FINISH_MIGRATE);
if (ret < 0) {
@@ -2615,7 +2599,6 @@ static int migration_completion_precopy(MigrationState *s,
qemu_mutex_lock_iothread();
migration_downtime_start(s);
qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER, NULL);
s->vm_old_state = runstate_get();
global_state_store();
@@ -3136,7 +3119,7 @@ static void migration_iteration_finish(MigrationState *s)
case MIGRATION_STATUS_FAILED:
case MIGRATION_STATUS_CANCELLED:
case MIGRATION_STATUS_CANCELLING:
if (s->vm_old_state == RUN_STATE_RUNNING) {
if (runstate_is_live(s->vm_old_state)) {
if (!runstate_check(RUN_STATE_SHUTDOWN)) {
vm_start();
}
@@ -3392,7 +3375,7 @@ static void bg_migration_vm_start_bh(void *opaque)
qemu_bh_delete(s->vm_start_bh);
s->vm_start_bh = NULL;
vm_start();
vm_resume(s->vm_old_state);
migration_downtime_end(s);
}
@@ -3464,11 +3447,6 @@ 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();
+1 -3
View File
@@ -474,14 +474,12 @@ struct MigrationState {
void migrate_set_state(int *state, int old_state, int new_state);
void migration_fd_process_incoming(QEMUFile *f, Error **errp);
void migration_fd_process_incoming(QEMUFile *f);
void migration_ioc_process_incoming(QIOChannel *ioc, Error **errp);
void migration_incoming_process(void);
bool migration_has_all_channels(void);
uint64_t migrate_max_downtime(void);
void migrate_set_error(MigrationState *s, const Error *error);
bool migrate_has_error(MigrationState *s);
+12 -15
View File
@@ -228,8 +228,8 @@ static int multifd_recv_initial_packet(QIOChannel *c, Error **errp)
}
if (msg.id > migrate_multifd_channels()) {
error_setg(errp, "multifd: received channel version %u "
"expected %u", msg.version, MULTIFD_VERSION);
error_setg(errp, "multifd: received channel id %u is greater than "
"number of channels %u", msg.id, migrate_multifd_channels());
return -1;
}
@@ -787,6 +787,7 @@ static void multifd_tls_outgoing_handshake(QIOTask *task,
trace_multifd_tls_outgoing_handshake_error(ioc, error_get_pretty(err));
migrate_set_error(migrate_get_current(), err);
/*
* Error happen, mark multifd_send_thread status as 'quit' although it
* is not created, and then tell who pay attention to me.
@@ -794,6 +795,7 @@ static void multifd_tls_outgoing_handshake(QIOTask *task,
p->quit = true;
qemu_sem_post(&multifd_send_state->channels_ready);
qemu_sem_post(&p->sem_sync);
error_free(err);
}
static void *multifd_tls_handshake_thread(void *opaque)
@@ -847,14 +849,13 @@ static bool multifd_channel_connect(MultiFDSendParams *p,
* so we mustn't call multifd_send_thread until then
*/
return multifd_tls_channel_connect(p, ioc, errp);
} else {
migration_ioc_register_yank(ioc);
p->registered_yank = true;
p->c = ioc;
qemu_thread_create(&p->thread, p->name, multifd_send_thread, p,
QEMU_THREAD_JOINABLE);
}
migration_ioc_register_yank(ioc);
p->registered_yank = true;
p->c = ioc;
qemu_thread_create(&p->thread, p->name, multifd_send_thread, p,
QEMU_THREAD_JOINABLE);
return true;
}
@@ -950,12 +951,10 @@ int multifd_save_setup(Error **errp)
for (i = 0; i < thread_count; i++) {
MultiFDSendParams *p = &multifd_send_state->params[i];
Error *local_err = NULL;
int ret;
ret = multifd_send_state->ops->send_setup(p, &local_err);
ret = multifd_send_state->ops->send_setup(p, errp);
if (ret) {
error_propagate(errp, local_err);
return ret;
}
}
@@ -1194,12 +1193,10 @@ int multifd_load_setup(Error **errp)
for (i = 0; i < thread_count; i++) {
MultiFDRecvParams *p = &multifd_recv_state->params[i];
Error *local_err = NULL;
int ret;
ret = multifd_recv_state->ops->recv_setup(p, &local_err);
ret = multifd_recv_state->ops->recv_setup(p, errp);
if (ret) {
error_propagate(errp, local_err);
return ret;
}
}
+3 -1
View File
@@ -833,8 +833,10 @@ uint64_t migrate_max_postcopy_bandwidth(void)
MigMode migrate_mode(void)
{
MigrationState *s = migrate_get_current();
MigMode mode = s->parameters.mode;
return s->parameters.mode;
assert(mode >= 0 && mode < MIG_MODE__MAX);
return mode;
}
int migrate_multifd_channels(void)
+1 -5
View File
@@ -4035,7 +4035,6 @@ static void rdma_accept_incoming_migration(void *opaque)
{
RDMAContext *rdma = opaque;
QEMUFile *f;
Error *local_err = NULL;
trace_qemu_rdma_accept_incoming_migration();
if (qemu_rdma_accept(rdma) < 0) {
@@ -4057,10 +4056,7 @@ static void rdma_accept_incoming_migration(void *opaque)
}
rdma->migration_started_on_destination = 1;
migration_fd_process_incoming(f, &local_err);
if (local_err) {
error_reportf_err(local_err, "RDMA ERROR:");
}
migration_fd_process_incoming(f);
}
void rdma_start_incoming_migration(InetSocketAddress *host_port,
+13 -10
View File
@@ -3046,7 +3046,7 @@ bool save_snapshot(const char *name, bool overwrite, const char *vmstate,
QEMUSnapshotInfo sn1, *sn = &sn1;
int ret = -1, ret2;
QEMUFile *f;
int saved_vm_running;
RunState saved_state = runstate_get();
uint64_t vm_state_size;
g_autoptr(GDateTime) now = g_date_time_new_now_local();
@@ -3092,8 +3092,6 @@ bool save_snapshot(const char *name, bool overwrite, const char *vmstate,
return false;
}
saved_vm_running = runstate_is_running();
global_state_store();
vm_stop(RUN_STATE_SAVE_VM);
@@ -3147,9 +3145,7 @@ bool save_snapshot(const char *name, bool overwrite, const char *vmstate,
the_end:
bdrv_drain_all_end();
if (saved_vm_running) {
vm_start();
}
vm_resume(saved_state);
return ret == 0;
}
@@ -3317,6 +3313,14 @@ err_drain:
return false;
}
void load_snapshot_resume(RunState state)
{
vm_resume(state);
if (state == RUN_STATE_RUNNING && runstate_get() == RUN_STATE_SUSPENDED) {
qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER, &error_abort);
}
}
bool delete_snapshot(const char *name, bool has_devices,
strList *devices, Error **errp)
{
@@ -3381,16 +3385,15 @@ static void snapshot_load_job_bh(void *opaque)
{
Job *job = opaque;
SnapshotJob *s = container_of(job, SnapshotJob, common);
int orig_vm_running;
RunState orig_state = runstate_get();
job_progress_set_remaining(&s->common, 1);
orig_vm_running = runstate_is_running();
vm_stop(RUN_STATE_RESTORE_VM);
s->ret = load_snapshot(s->tag, s->vmstate, true, s->devices, s->errp);
if (s->ret && orig_vm_running) {
vm_start();
if (s->ret) {
load_snapshot_resume(orig_state);
}
job_progress_update(&s->common, 1);
+9 -2
View File
@@ -134,7 +134,7 @@
##
# @stop:
#
# Stop all guest VCPU execution.
# Stop guest VM execution.
#
# Since: 0.14
#
@@ -143,6 +143,9 @@
# the guest remains paused once migration finishes, as if the -S
# option was passed on the command line.
#
# In the "suspended" state, it will completely stop the VM and
# cause a transition to the "paused" state. (Since 9.0)
#
# Example:
#
# -> { "execute": "stop" }
@@ -153,7 +156,7 @@
##
# @cont:
#
# Resume guest VCPU execution.
# Resume guest VM execution.
#
# Since: 0.14
#
@@ -165,6 +168,10 @@
# guest starts once migration finishes, removing the effect of the
# -S command line option if it was passed.
#
# If the VM was previously suspended, and not been reset or woken,
# this command will transition back to the "suspended" state.
# (Since 9.0)
#
# Example:
#
# -> { "execute": "cont" }
+3 -3
View File
@@ -102,7 +102,7 @@
##
# @StatusInfo:
#
# Information about VCPU run state
# Information about VM run state
#
# @running: true if all VCPUs are runnable, false if not runnable
#
@@ -130,9 +130,9 @@
##
# @query-status:
#
# Query the run status of all VCPUs
# Query the run status of the VM
#
# Returns: @StatusInfo reflecting all VCPUs
# Returns: @StatusInfo reflecting the VM
#
# Since: 0.14
#
+39 -8
View File
@@ -259,14 +259,33 @@ void cpu_interrupt(CPUState *cpu, int mask)
}
}
/*
* True if the vm was previously suspended, and has not been woken or reset.
*/
static int vm_was_suspended;
void vm_set_suspended(bool suspended)
{
vm_was_suspended = suspended;
}
bool vm_get_suspended(void)
{
return vm_was_suspended;
}
static int do_vm_stop(RunState state, bool send_stop)
{
int ret = 0;
RunState oldstate = runstate_get();
if (runstate_is_running()) {
if (runstate_is_live(oldstate)) {
vm_was_suspended = (oldstate == RUN_STATE_SUSPENDED);
runstate_set(state);
cpu_disable_ticks();
pause_all_vcpus();
if (oldstate == RUN_STATE_RUNNING) {
pause_all_vcpus();
}
vm_state_notify(0, state);
if (send_stop) {
qapi_event_send_stop();
@@ -679,11 +698,13 @@ int vm_stop(RunState state)
/**
* Prepare for (re)starting the VM.
* 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.
* Returns 0 if the vCPUs should be restarted, -1 on an error condition,
* and 1 otherwise.
*/
int vm_prepare_start(bool step_pending)
{
int ret = vm_was_suspended ? 1 : 0;
RunState state = vm_was_suspended ? RUN_STATE_SUSPENDED : RUN_STATE_RUNNING;
RunState requested;
qemu_vmstop_requested(&requested);
@@ -714,9 +735,10 @@ int vm_prepare_start(bool step_pending)
qapi_event_send_resume();
cpu_enable_ticks();
runstate_set(RUN_STATE_RUNNING);
vm_state_notify(1, RUN_STATE_RUNNING);
return 0;
runstate_set(state);
vm_state_notify(1, state);
vm_was_suspended = false;
return ret;
}
void vm_start(void)
@@ -726,11 +748,20 @@ void vm_start(void)
}
}
void vm_resume(RunState state)
{
if (runstate_is_live(state)) {
vm_start();
} else {
runstate_set(state);
}
}
/* does a state transition even if the VM is already stopped,
current state is forgotten forever */
int vm_stop_force_state(RunState state)
{
if (runstate_is_running()) {
if (runstate_is_live(runstate_get())) {
return vm_stop(state);
} else {
int ret;

Some files were not shown because too many files have changed in this diff Show More