summaryrefslogtreecommitdiffstats
path: root/migration/migration.c
diff options
context:
space:
mode:
Diffstat (limited to 'migration/migration.c')
-rw-r--r--migration/migration.c41
1 files changed, 36 insertions, 5 deletions
diff --git a/migration/migration.c b/migration/migration.c
index 5ff7ba9d5c..2d306582eb 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -1855,6 +1855,15 @@ void migrate_set_error(MigrationState *s, const Error *error)
}
}
+static void migrate_error_free(MigrationState *s)
+{
+ QEMU_LOCK_GUARD(&s->error_mutex);
+ if (s->error) {
+ error_free(s->error);
+ s->error = NULL;
+ }
+}
+
void migrate_fd_error(MigrationState *s, const Error *error)
{
trace_migrate_fd_error(error_get_pretty(error));
@@ -2818,12 +2827,12 @@ out:
* Maybe there is something we can do: it looks like a
* network down issue, and we pause for a recovery.
*/
+ qemu_fclose(rp);
+ ms->rp_state.from_dst_file = NULL;
+ rp = NULL;
if (postcopy_pause_return_path_thread(ms)) {
/* Reload rp, reset the rest */
- if (rp != ms->rp_state.from_dst_file) {
- qemu_fclose(rp);
- rp = ms->rp_state.from_dst_file;
- }
+ rp = ms->rp_state.from_dst_file;
ms->rp_state.error = false;
goto retry;
}
@@ -3701,6 +3710,10 @@ static void qemu_savevm_wait_unplug(MigrationState *s, int old_state,
while (timeout-- && qemu_savevm_state_guest_unplug_pending()) {
qemu_sem_timedwait(&s->wait_unplug_sem, 250);
}
+ if (qemu_savevm_state_guest_unplug_pending()) {
+ warn_report("migration: partially unplugged device on "
+ "failure");
+ }
}
migrate_set_state(&s->state, MIGRATION_STATUS_WAIT_UNPLUG, new_state);
@@ -3966,6 +3979,13 @@ void migrate_fd_connect(MigrationState *s, Error *error_in)
int64_t rate_limit;
bool resume = s->state == MIGRATION_STATUS_POSTCOPY_PAUSED;
+ /*
+ * If there's a previous error, free it and prepare for another one.
+ * Meanwhile if migration completes successfully, there won't have an error
+ * dumped when calling migrate_fd_cleanup().
+ */
+ migrate_error_free(s);
+
s->expected_downtime = s->parameters.downtime_limit;
if (resume) {
assert(s->cleanup_bh);
@@ -3975,7 +3995,18 @@ void migrate_fd_connect(MigrationState *s, Error *error_in)
}
if (error_in) {
migrate_fd_error(s, error_in);
- migrate_fd_cleanup(s);
+ if (resume) {
+ /*
+ * Don't do cleanup for resume if channel is invalid, but only dump
+ * the error. We wait for another channel connect from the user.
+ * The error_report still gives HMP user a hint on what failed.
+ * It's normally done in migrate_fd_cleanup(), but call it here
+ * explicitly.
+ */
+ error_report_err(error_copy(s->error));
+ } else {
+ migrate_fd_cleanup(s);
+ }
return;
}