migration: Postpone postcopy preempt channel to be after main

Postcopy with preempt-mode enabled needs two channels to communicate.  The
order of channel establishment is not guaranteed.  It can happen that the
dest QEMU got the preempt channel connection request before the main
channel is established, then the migration may make no progress even during
precopy due to the wrong order.

To fix it, create the preempt channel only if we know the main channel is
established.

For a general postcopy migration, we delay it until postcopy_start(),
that's where we already went through some part of precopy on the main
channel.  To make sure dest QEMU has already established the channel, we
wait until we got the first PONG received.  That's something we do at the
start of precopy when postcopy enabled so it's guaranteed to happen sooner
or later.

For a postcopy recovery, we delay it to qemu_savevm_state_resume_prepare()
where we'll have round trips of data on bitmap synchronizations, which
means the main channel must have been established.

Signed-off-by: Peter Xu <peterx@redhat.com>
Reviewed-by: Juan Quintela <quintela@redhat.com>
Signed-off-by: Juan Quintela <quintela@redhat.com>
This commit is contained in:
Peter Xu 2023-02-08 15:28:13 -05:00 committed by Juan Quintela
parent b28fb58227
commit 5655aab079
5 changed files with 82 additions and 21 deletions

View file

@ -1197,6 +1197,11 @@ int postcopy_ram_incoming_setup(MigrationIncomingState *mis)
}
if (migrate_postcopy_preempt()) {
/*
* The preempt channel is established in asynchronous way. Wait
* for its completion.
*/
qemu_sem_wait(&mis->postcopy_qemufile_dst_done);
/*
* This thread needs to be created after the temp pages because
* it'll fetch RAM_CHANNEL_POSTCOPY PostcopyTmpPage immediately.
@ -1544,6 +1549,7 @@ void postcopy_preempt_new_channel(MigrationIncomingState *mis, QEMUFile *file)
*/
qemu_file_set_blocking(file, true);
mis->postcopy_qemufile_dst = file;
qemu_sem_post(&mis->postcopy_qemufile_dst_done);
trace_postcopy_preempt_new_channel();
}
@ -1612,14 +1618,21 @@ out:
postcopy_preempt_send_channel_done(s, ioc, local_err);
}
/* Returns 0 if channel established, -1 for error. */
int postcopy_preempt_wait_channel(MigrationState *s)
/*
* This function will kick off an async task to establish the preempt
* channel, and wait until the connection setup completed. Returns 0 if
* channel established, -1 for error.
*/
int postcopy_preempt_establish_channel(MigrationState *s)
{
/* If preempt not enabled, no need to wait */
if (!migrate_postcopy_preempt()) {
return 0;
}
/* Kick off async task to establish preempt channel */
postcopy_preempt_setup(s);
/*
* We need the postcopy preempt channel to be established before
* starting doing anything.