"prepare",
"finish2",
"finish3",
+ "postcopy_failed",
+ "begin_resume",
+ "perform_resume",
+ "confirm_resume",
+ "prepare_resume",
+ "finish_resume",
);
{
qemuDomainObjPrivate *priv = vm->privateData;
- if (phase < priv->job.phase) {
+ if (phase < QEMU_MIGRATION_PHASE_POSTCOPY_FAILED &&
+ phase < priv->job.phase) {
VIR_ERROR(_("migration protocol going backwards %s => %s"),
qemuMigrationJobPhaseTypeToString(priv->job.phase),
qemuMigrationJobPhaseTypeToString(phase));
}
break;
+ case QEMU_MIGRATION_PHASE_BEGIN_RESUME:
+ case QEMU_MIGRATION_PHASE_PERFORM_RESUME:
+ qemuMigrationSrcPostcopyFailed(vm);
+ qemuDomainCleanupAdd(vm, qemuProcessCleanupMigrationJob);
+ qemuMigrationJobContinue(vm);
+ break;
+
case QEMU_MIGRATION_PHASE_PERFORM3:
/* cannot be seen without an active migration API; unreachable */
case QEMU_MIGRATION_PHASE_CONFIRM3:
case QEMU_MIGRATION_PHASE_CONFIRM3_CANCELLED:
+ case QEMU_MIGRATION_PHASE_CONFIRM_RESUME:
/* all done; unreachable */
case QEMU_MIGRATION_PHASE_PREPARE:
case QEMU_MIGRATION_PHASE_FINISH2:
case QEMU_MIGRATION_PHASE_FINISH3:
+ case QEMU_MIGRATION_PHASE_PREPARE_RESUME:
+ case QEMU_MIGRATION_PHASE_FINISH_RESUME:
/* incoming migration; unreachable */
case QEMU_MIGRATION_PHASE_PERFORM2:
/* single phase outgoing migration; unreachable */
case QEMU_MIGRATION_PHASE_NONE:
+ case QEMU_MIGRATION_PHASE_POSTCOPY_FAILED:
case QEMU_MIGRATION_PHASE_LAST:
/* unreachable */
;
QEMU_MIGRATION_PHASE_PREPARE,
QEMU_MIGRATION_PHASE_FINISH2,
QEMU_MIGRATION_PHASE_FINISH3,
+ QEMU_MIGRATION_PHASE_POSTCOPY_FAILED, /* marker for resume phases */
+ QEMU_MIGRATION_PHASE_BEGIN_RESUME,
+ QEMU_MIGRATION_PHASE_PERFORM_RESUME,
+ QEMU_MIGRATION_PHASE_CONFIRM_RESUME,
+ QEMU_MIGRATION_PHASE_PREPARE_RESUME,
+ QEMU_MIGRATION_PHASE_FINISH_RESUME,
QEMU_MIGRATION_PHASE_LAST
} qemuMigrationJobPhase;
case QEMU_MIGRATION_PHASE_PERFORM3_DONE:
case QEMU_MIGRATION_PHASE_CONFIRM3_CANCELLED:
case QEMU_MIGRATION_PHASE_CONFIRM3:
+ case QEMU_MIGRATION_PHASE_POSTCOPY_FAILED:
+ case QEMU_MIGRATION_PHASE_BEGIN_RESUME:
+ case QEMU_MIGRATION_PHASE_PERFORM_RESUME:
+ case QEMU_MIGRATION_PHASE_CONFIRM_RESUME:
case QEMU_MIGRATION_PHASE_LAST:
/* N/A for incoming migration */
break;
return -1;
}
break;
+
+ case QEMU_MIGRATION_PHASE_PREPARE_RESUME:
+ case QEMU_MIGRATION_PHASE_FINISH_RESUME:
+ return 1;
}
return 0;
/*
* Returns
- * -1 on error, the domain will be killed,
+ * -1 the domain should be killed (either after a successful migration or
+ * on error),
* 0 the domain should remain running with the migration job discarded,
* 1 the daemon was restarted during post-copy phase
*/
qemuProcessRecoverMigrationOut(virQEMUDriver *driver,
virDomainObj *vm,
qemuDomainJobObj *job,
+ virDomainJobStatus migStatus,
virDomainState state,
int reason,
unsigned int *stopFlags)
case QEMU_MIGRATION_PHASE_PREPARE:
case QEMU_MIGRATION_PHASE_FINISH2:
case QEMU_MIGRATION_PHASE_FINISH3:
+ case QEMU_MIGRATION_PHASE_POSTCOPY_FAILED:
+ case QEMU_MIGRATION_PHASE_PREPARE_RESUME:
+ case QEMU_MIGRATION_PHASE_FINISH_RESUME:
case QEMU_MIGRATION_PHASE_LAST:
/* N/A for outgoing migration */
break;
/* migration completed, we need to kill the domain here */
*stopFlags |= VIR_QEMU_PROCESS_STOP_MIGRATED;
return -1;
+
+ case QEMU_MIGRATION_PHASE_CONFIRM_RESUME:
+ if (migStatus == VIR_DOMAIN_JOB_STATUS_HYPERVISOR_COMPLETED) {
+ /* migration completed, we need to kill the domain here */
+ *stopFlags |= VIR_QEMU_PROCESS_STOP_MIGRATED;
+ return -1;
+ }
+ return 1;
+
+ case QEMU_MIGRATION_PHASE_BEGIN_RESUME:
+ case QEMU_MIGRATION_PHASE_PERFORM_RESUME:
+ return 1;
}
if (resume) {
qemuMigrationAnyRefreshStatus(driver, vm, VIR_ASYNC_JOB_NONE, &migStatus);
if (job->asyncJob == VIR_ASYNC_JOB_MIGRATION_OUT) {
- rc = qemuProcessRecoverMigrationOut(driver, vm, job,
+ rc = qemuProcessRecoverMigrationOut(driver, vm, job, migStatus,
state, reason, stopFlags);
} else {
rc = qemuProcessRecoverMigrationIn(driver, vm, job, state);