case MIGRATION_STATUS_ACTIVE:
case MIGRATION_STATUS_POSTCOPY_ACTIVE:
case MIGRATION_STATUS_POSTCOPY_PAUSED:
+ case MIGRATION_STATUS_POSTCOPY_RECOVER_SETUP:
case MIGRATION_STATUS_POSTCOPY_RECOVER:
case MIGRATION_STATUS_SETUP:
case MIGRATION_STATUS_PRE_SWITCHOVER:
case MIGRATION_STATUS_ACTIVE:
case MIGRATION_STATUS_POSTCOPY_ACTIVE:
case MIGRATION_STATUS_POSTCOPY_PAUSED:
+ case MIGRATION_STATUS_POSTCOPY_RECOVER_SETUP:
case MIGRATION_STATUS_POSTCOPY_RECOVER:
case MIGRATION_STATUS_SETUP:
case MIGRATION_STATUS_PRE_SWITCHOVER:
case MIGRATION_STATUS_PRE_SWITCHOVER:
case MIGRATION_STATUS_DEVICE:
case MIGRATION_STATUS_POSTCOPY_PAUSED:
+ case MIGRATION_STATUS_POSTCOPY_RECOVER_SETUP:
case MIGRATION_STATUS_POSTCOPY_RECOVER:
/* TODO add some postcopy stats */
populate_time_info(info, s);
static void migrate_fd_error(MigrationState *s, const Error *error)
{
+ MigrationStatus current = s->state;
+ MigrationStatus next;
+
assert(s->to_dst_file == NULL);
- migrate_set_state(&s->state, MIGRATION_STATUS_SETUP,
- MIGRATION_STATUS_FAILED);
+
+ switch (current) {
+ case MIGRATION_STATUS_SETUP:
+ next = MIGRATION_STATUS_FAILED;
+ break;
+ case MIGRATION_STATUS_POSTCOPY_RECOVER_SETUP:
+ /* Never fail a postcopy migration; switch back to PAUSED instead */
+ next = MIGRATION_STATUS_POSTCOPY_PAUSED;
+ break;
+ default:
+ /*
+ * This really shouldn't happen. Just be careful to not crash a VM
+ * just for this. Instead, dump something.
+ */
+ error_report("%s: Illegal migration status (%s) detected",
+ __func__, MigrationStatus_str(current));
+ return;
+ }
+
+ migrate_set_state(&s->state, current, next);
migrate_set_error(s, error);
}
switch (s->state) {
case MIGRATION_STATUS_POSTCOPY_ACTIVE:
case MIGRATION_STATUS_POSTCOPY_PAUSED:
+ case MIGRATION_STATUS_POSTCOPY_RECOVER_SETUP:
case MIGRATION_STATUS_POSTCOPY_RECOVER:
return true;
default:
return false;
}
+ migrate_set_state(&s->state, MIGRATION_STATUS_POSTCOPY_PAUSED,
+ MIGRATION_STATUS_POSTCOPY_RECOVER_SETUP);
+
/* This is a resume, skip init status */
return true;
}
* We wait until things fixed up. Then someone will setup the
* status back for us.
*/
- while (s->state == MIGRATION_STATUS_POSTCOPY_PAUSED) {
+ do {
qemu_sem_wait(&s->postcopy_pause_sem);
- }
+ } while (postcopy_is_paused(s->state));
if (s->state == MIGRATION_STATUS_POSTCOPY_RECOVER) {
/* Woken up by a recover procedure. Give it a shot */
{
Error *local_err = NULL;
uint64_t rate_limit;
- bool resume = s->state == MIGRATION_STATUS_POSTCOPY_PAUSED;
+ bool resume = (s->state == MIGRATION_STATUS_POSTCOPY_RECOVER_SETUP);
int ret;
/*
if (resume) {
/* Wakeup the main migration thread to do the recovery */
- migrate_set_state(&s->state, MIGRATION_STATUS_POSTCOPY_PAUSED,
+ migrate_set_state(&s->state, MIGRATION_STATUS_POSTCOPY_RECOVER_SETUP,
MIGRATION_STATUS_POSTCOPY_RECOVER);
qemu_sem_post(&s->postcopy_pause_sem);
return;
#
# @postcopy-paused: during postcopy but paused. (since 3.0)
#
+# @postcopy-recover-setup: setup phase for a postcopy recovery process,
+# preparing for a recovery phase to start. (since 9.1)
+#
# @postcopy-recover: trying to recover from a paused postcopy. (since
# 3.0)
#
{ 'enum': 'MigrationStatus',
'data': [ 'none', 'setup', 'cancelling', 'cancelled',
'active', 'postcopy-active', 'postcopy-paused',
+ 'postcopy-recover-setup',
'postcopy-recover', 'completed', 'failed', 'colo',
'pre-switchover', 'device', 'wait-unplug' ] }
##