migration: rebuild channel on source

This patch detects the "resume" flag of migration command, rebuild the
channels only if the flag is set.

Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
Signed-off-by: Peter Xu <peterx@redhat.com>
Message-Id: <20180502104740.12123-9-peterx@redhat.com>
Signed-off-by: Juan Quintela <quintela@redhat.com>
This commit is contained in:
Peter Xu 2018-05-02 18:47:24 +08:00 committed by Juan Quintela
parent 7a4da28b26
commit d3e35b8f62
1 changed files with 90 additions and 41 deletions

View File

@ -1411,6 +1411,61 @@ bool migration_is_blocked(Error **errp)
return false;
}
/* Returns true if continue to migrate, or false if error detected */
static bool migrate_prepare(MigrationState *s, bool blk, bool blk_inc,
bool resume, Error **errp)
{
Error *local_err = NULL;
if (resume) {
if (s->state != MIGRATION_STATUS_POSTCOPY_PAUSED) {
error_setg(errp, "Cannot resume if there is no "
"paused migration");
return false;
}
/* This is a resume, skip init status */
return true;
}
if (migration_is_setup_or_active(s->state) ||
s->state == MIGRATION_STATUS_CANCELLING ||
s->state == MIGRATION_STATUS_COLO) {
error_setg(errp, QERR_MIGRATION_ACTIVE);
return false;
}
if (runstate_check(RUN_STATE_INMIGRATE)) {
error_setg(errp, "Guest is waiting for an incoming migration");
return false;
}
if (migration_is_blocked(errp)) {
return false;
}
if (blk || blk_inc) {
if (migrate_use_block() || migrate_use_block_incremental()) {
error_setg(errp, "Command options are incompatible with "
"current migration capabilities");
return false;
}
migrate_set_block_enabled(true, &local_err);
if (local_err) {
error_propagate(errp, local_err);
return false;
}
s->must_remove_block_options = true;
}
if (blk_inc) {
migrate_set_block_incremental(s, true);
}
migrate_init(s);
return true;
}
void qmp_migrate(const char *uri, bool has_blk, bool blk,
bool has_inc, bool inc, bool has_detach, bool detach,
bool has_resume, bool resume, Error **errp)
@ -1419,40 +1474,11 @@ void qmp_migrate(const char *uri, bool has_blk, bool blk,
MigrationState *s = migrate_get_current();
const char *p;
if (migration_is_setup_or_active(s->state) ||
s->state == MIGRATION_STATUS_CANCELLING ||
s->state == MIGRATION_STATUS_COLO) {
error_setg(errp, QERR_MIGRATION_ACTIVE);
if (!migrate_prepare(s, has_blk && blk, has_inc && inc,
has_resume && resume, errp)) {
/* Error detected, put into errp */
return;
}
if (runstate_check(RUN_STATE_INMIGRATE)) {
error_setg(errp, "Guest is waiting for an incoming migration");
return;
}
if (migration_is_blocked(errp)) {
return;
}
if ((has_blk && blk) || (has_inc && inc)) {
if (migrate_use_block() || migrate_use_block_incremental()) {
error_setg(errp, "Command options are incompatible with "
"current migration capabilities");
return;
}
migrate_set_block_enabled(true, &local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
}
s->must_remove_block_options = true;
}
if (has_inc && inc) {
migrate_set_block_incremental(s, true);
}
migrate_init(s);
if (strstart(uri, "tcp:", &p)) {
tcp_start_outgoing_migration(s, p, &local_err);
@ -1928,7 +1954,8 @@ out:
return NULL;
}
static int open_return_path_on_source(MigrationState *ms)
static int open_return_path_on_source(MigrationState *ms,
bool create_thread)
{
ms->rp_state.from_dst_file = qemu_file_get_return_path(ms->to_dst_file);
@ -1937,6 +1964,12 @@ static int open_return_path_on_source(MigrationState *ms)
}
trace_open_return_path_on_source();
if (!create_thread) {
/* We're done */
return 0;
}
qemu_thread_create(&ms->rp_state.rp_thread, "return path",
source_return_path_thread, ms, QEMU_THREAD_JOINABLE);
@ -2593,6 +2626,9 @@ static void *migration_thread(void *opaque)
void migrate_fd_connect(MigrationState *s, Error *error_in)
{
int64_t rate_limit;
bool resume = s->state == MIGRATION_STATUS_POSTCOPY_PAUSED;
s->expected_downtime = s->parameters.downtime_limit;
s->cleanup_bh = qemu_bh_new(migrate_fd_cleanup, s);
if (error_in) {
@ -2601,12 +2637,21 @@ void migrate_fd_connect(MigrationState *s, Error *error_in)
return;
}
qemu_file_set_blocking(s->to_dst_file, true);
qemu_file_set_rate_limit(s->to_dst_file,
s->parameters.max_bandwidth / XFER_LIMIT_RATIO);
if (resume) {
/* This is a resumed migration */
rate_limit = INT64_MAX;
} else {
/* This is a fresh new migration */
rate_limit = s->parameters.max_bandwidth / XFER_LIMIT_RATIO;
s->expected_downtime = s->parameters.downtime_limit;
s->cleanup_bh = qemu_bh_new(migrate_fd_cleanup, s);
/* Notify before starting migration thread */
notifier_list_notify(&migration_state_notifiers, s);
/* Notify before starting migration thread */
notifier_list_notify(&migration_state_notifiers, s);
}
qemu_file_set_rate_limit(s->to_dst_file, rate_limit);
qemu_file_set_blocking(s->to_dst_file, true);
/*
* Open the return path. For postcopy, it is used exclusively. For
@ -2614,15 +2659,19 @@ void migrate_fd_connect(MigrationState *s, Error *error_in)
* QEMU uses the return path.
*/
if (migrate_postcopy_ram() || migrate_use_return_path()) {
if (open_return_path_on_source(s)) {
if (open_return_path_on_source(s, !resume)) {
error_report("Unable to open return-path for postcopy");
migrate_set_state(&s->state, MIGRATION_STATUS_SETUP,
MIGRATION_STATUS_FAILED);
migrate_set_state(&s->state, s->state, MIGRATION_STATUS_FAILED);
migrate_fd_cleanup(s);
return;
}
}
if (resume) {
/* TODO: do the resume logic */
return;
}
if (multifd_save_setup() != 0) {
migrate_set_state(&s->state, MIGRATION_STATUS_SETUP,
MIGRATION_STATUS_FAILED);