aboutsummaryrefslogtreecommitdiff
path: root/migration/migration.c
diff options
context:
space:
mode:
Diffstat (limited to 'migration/migration.c')
-rw-r--r--migration/migration.c72
1 files changed, 55 insertions, 17 deletions
diff --git a/migration/migration.c b/migration/migration.c
index a2e362541d..a5c22e327d 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -235,6 +235,8 @@ void migration_object_init(void)
qemu_sem_init(&current_incoming->postcopy_pause_sem_dst, 0);
qemu_sem_init(&current_incoming->postcopy_pause_sem_fault, 0);
qemu_sem_init(&current_incoming->postcopy_pause_sem_fast_load, 0);
+ qemu_sem_init(&current_incoming->postcopy_qemufile_dst_done, 0);
+
qemu_mutex_init(&current_incoming->page_request_mutex);
current_incoming->page_requested = g_tree_new(page_request_addr_cmp);
@@ -737,6 +739,31 @@ void migration_fd_process_incoming(QEMUFile *f, Error **errp)
migration_incoming_process();
}
+/*
+ * Returns true when we want to start a new incoming migration process,
+ * false otherwise.
+ */
+static bool migration_should_start_incoming(bool main_channel)
+{
+ /* Multifd doesn't start unless all channels are established */
+ if (migrate_use_multifd()) {
+ return migration_has_all_channels();
+ }
+
+ /* Preempt channel only starts when the main channel is created */
+ if (migrate_postcopy_preempt()) {
+ return main_channel;
+ }
+
+ /*
+ * For all the rest types of migration, we should only reach here when
+ * it's the main channel that's being created, and we should always
+ * proceed with this channel.
+ */
+ assert(main_channel);
+ return true;
+}
+
void migration_ioc_process_incoming(QIOChannel *ioc, Error **errp)
{
MigrationIncomingState *mis = migration_incoming_get_current();
@@ -798,7 +825,7 @@ void migration_ioc_process_incoming(QIOChannel *ioc, Error **errp)
}
}
- if (migration_has_all_channels()) {
+ if (migration_should_start_incoming(default_channel)) {
/* If it's a recovery, we're done */
if (postcopy_try_recover()) {
return;
@@ -3159,6 +3186,13 @@ static int await_return_path_close_on_source(MigrationState *ms)
return ms->rp_state.error;
}
+static inline void
+migration_wait_main_channel(MigrationState *ms)
+{
+ /* Wait until one PONG message received */
+ qemu_sem_wait(&ms->rp_state.rp_pong_acks);
+}
+
/*
* Switch from normal iteration to postcopy
* Returns non-0 on error
@@ -3173,9 +3207,12 @@ static int postcopy_start(MigrationState *ms)
bool restart_block = false;
int cur_state = MIGRATION_STATUS_ACTIVE;
- if (postcopy_preempt_wait_channel(ms)) {
- migrate_set_state(&ms->state, ms->state, MIGRATION_STATUS_FAILED);
- return -1;
+ if (migrate_postcopy_preempt()) {
+ migration_wait_main_channel(ms);
+ if (postcopy_preempt_establish_channel(ms)) {
+ migrate_set_state(&ms->state, ms->state, MIGRATION_STATUS_FAILED);
+ return -1;
+ }
}
if (!migrate_pause_before_switchover()) {
@@ -3587,6 +3624,20 @@ static int postcopy_do_resume(MigrationState *s)
}
/*
+ * If preempt is enabled, re-establish the preempt channel. Note that
+ * we do it after resume prepare to make sure the main channel will be
+ * created before the preempt channel. E.g. with weak network, the
+ * dest QEMU may get messed up with the preempt and main channels on
+ * the order of connection setup. This guarantees the correct order.
+ */
+ ret = postcopy_preempt_establish_channel(s);
+ if (ret) {
+ error_report("%s: postcopy_preempt_establish_channel(): %d",
+ __func__, ret);
+ return ret;
+ }
+
+ /*
* Last handshake with destination on the resume (destination will
* switch to postcopy-active afterwards)
*/
@@ -3647,14 +3698,6 @@ static MigThrError postcopy_pause(MigrationState *s)
if (s->state == MIGRATION_STATUS_POSTCOPY_RECOVER) {
/* Woken up by a recover procedure. Give it a shot */
- if (postcopy_preempt_wait_channel(s)) {
- /*
- * Preempt enabled, and new channel create failed; loop
- * back to wait for another recovery.
- */
- continue;
- }
-
/*
* Firstly, let's wake up the return path now, with a new
* return path channel.
@@ -4347,11 +4390,6 @@ void migrate_fd_connect(MigrationState *s, Error *error_in)
}
}
- /* This needs to be done before resuming a postcopy */
- if (migrate_postcopy_preempt()) {
- postcopy_preempt_setup(s);
- }
-
if (resume) {
/* Wakeup the main migration thread to do the recovery */
migrate_set_state(&s->state, MIGRATION_STATUS_POSTCOPY_PAUSED,