mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
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:
@@ -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>
|
||||
|
||||
@@ -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*
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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 */
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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()
|
||||
},
|
||||
};
|
||||
|
||||
@@ -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
@@ -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();
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
Reference in New Issue
Block a user