qemuDomainAsyncJobPhaseToString(
priv->job.asyncJob, priv->job.phase));
}
- virBufferAddLit(buf, "/>\n");
+ if (priv->job.asyncJob != QEMU_ASYNC_JOB_MIGRATION_OUT) {
+ virBufferAddLit(buf, "/>\n");
+ } else {
+ size_t i;
+ virDomainDiskDefPtr disk;
+ qemuDomainDiskPrivatePtr diskPriv;
+
+ virBufferAddLit(buf, ">\n");
+ virBufferAdjustIndent(buf, 2);
+
+ for (i = 0; i < vm->def->ndisks; i++) {
+ disk = vm->def->disks[i];
+ diskPriv = QEMU_DOMAIN_DISK_PRIVATE(disk);
+ virBufferAsprintf(buf, "<disk dev='%s' migrating='%s'/>\n",
+ disk->dst,
+ diskPriv->migrating ? "yes" : "no");
+ }
+
+ virBufferAdjustIndent(buf, -2);
+ virBufferAddLit(buf, "</job>\n");
+ }
}
priv->job.active = job;
}
}
+ if ((n = virXPathNodeSet("./job[1]/disk[@migrating='yes']",
+ ctxt, &nodes)) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("failed to parse list of disks marked for migration"));
+ goto error;
+ }
+ if (n > 0) {
+ if (priv->job.asyncJob != QEMU_ASYNC_JOB_MIGRATION_OUT) {
+ VIR_WARN("Found disks marked for migration but we were not "
+ "migrating");
+ n = 0;
+ }
+ for (i = 0; i < n; i++) {
+ char *dst = virXMLPropString(nodes[i], "dev");
+ virDomainDiskDefPtr disk;
+
+ if (dst && (disk = virDomainDiskByName(vm->def, dst, false)))
+ QEMU_DOMAIN_DISK_PRIVATE(disk)->migrating = true;
+ VIR_FREE(dst);
+ }
+ }
+ VIR_FREE(nodes);
+
priv->fakeReboot = virXPathBoolean("boolean(./fakereboot)", ctxt) == 1;
if ((n = virXPathNodeSet("./devices/device", ctxt, &nodes)) < 0) {
char *hoststr = NULL;
unsigned int mirror_flags = VIR_DOMAIN_BLOCK_REBASE_REUSE_EXT;
int rv;
+ virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
VIR_DEBUG("Starting drive mirrors for domain %s", vm->def->name);
goto cleanup;
}
diskPriv->migrating = true;
+
+ if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0) {
+ VIR_WARN("Failed to save status on vm %s", vm->def->name);
+ goto cleanup;
+ }
}
while ((rv = qemuMigrationDriveMirrorReady(driver, vm)) != 1) {
ret = 0;
cleanup:
+ virObjectUnref(cfg);
VIR_FREE(diskAlias);
VIR_FREE(nbd_dest);
VIR_FREE(hoststr);
return ret;
}
+
+int
+qemuMigrationCancel(virQEMUDriverPtr driver,
+ virDomainObjPtr vm)
+{
+ qemuDomainObjPrivatePtr priv = vm->privateData;
+ virHashTablePtr blockJobs = NULL;
+ bool storage = false;
+ size_t i;
+ int ret = -1;
+
+ VIR_DEBUG("Canceling unfinished outgoing migration of domain %s",
+ vm->def->name);
+
+ for (i = 0; i < vm->def->ndisks; i++) {
+ virDomainDiskDefPtr disk = vm->def->disks[i];
+ if (QEMU_DOMAIN_DISK_PRIVATE(disk)->migrating) {
+ qemuBlockJobSyncBegin(disk);
+ storage = true;
+ }
+ }
+
+ qemuDomainObjEnterMonitor(driver, vm);
+
+ ignore_value(qemuMonitorMigrateCancel(priv->mon));
+ if (storage)
+ blockJobs = qemuMonitorGetAllBlockJobInfo(priv->mon);
+
+ if (qemuDomainObjExitMonitor(driver, vm) < 0 || (storage && !blockJobs))
+ goto endsyncjob;
+
+ if (!storage) {
+ ret = 0;
+ goto cleanup;
+ }
+
+ for (i = 0; i < vm->def->ndisks; i++) {
+ virDomainDiskDefPtr disk = vm->def->disks[i];
+ qemuDomainDiskPrivatePtr diskPriv = QEMU_DOMAIN_DISK_PRIVATE(disk);
+
+ if (!diskPriv->migrating)
+ continue;
+
+ if (virHashLookup(blockJobs, disk->info.alias)) {
+ VIR_DEBUG("Drive mirror on disk %s is still running", disk->dst);
+ } else {
+ VIR_DEBUG("Drive mirror on disk %s is gone", disk->dst);
+ qemuBlockJobSyncEnd(driver, vm, disk);
+ diskPriv->migrating = false;
+ }
+ }
+
+ if (qemuMigrationCancelDriveMirror(driver, vm, false,
+ QEMU_ASYNC_JOB_NONE) < 0)
+ goto endsyncjob;
+
+ ret = 0;
+
+ cleanup:
+ virHashFree(blockJobs);
+ return ret;
+
+ endsyncjob:
+ if (storage) {
+ for (i = 0; i < vm->def->ndisks; i++) {
+ virDomainDiskDefPtr disk = vm->def->disks[i];
+ qemuDomainDiskPrivatePtr diskPriv = QEMU_DOMAIN_DISK_PRIVATE(disk);
+
+ if (diskPriv->migrating) {
+ qemuBlockJobSyncEnd(driver, vm, disk);
+ diskPriv->migrating = false;
+ }
+ }
+ }
+ goto cleanup;
+}
+
+
int
qemuMigrationJobStart(virQEMUDriverPtr driver,
virDomainObjPtr vm,
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(5)
ATTRIBUTE_RETURN_CHECK;
+int qemuMigrationCancel(virQEMUDriverPtr driver,
+ virDomainObjPtr vm);
+
#endif /* __QEMU_MIGRATION_H__ */
virDomainState state,
int reason)
{
- qemuDomainObjPrivatePtr priv = vm->privateData;
-
if (job == QEMU_ASYNC_JOB_MIGRATION_IN) {
switch (phase) {
case QEMU_MIGRATION_PHASE_NONE:
case QEMU_MIGRATION_PHASE_PERFORM3:
/* migration is still in progress, let's cancel it and resume the
* domain */
- VIR_DEBUG("Canceling unfinished outgoing migration of domain %s",
- vm->def->name);
- qemuDomainObjEnterMonitor(driver, vm);
- ignore_value(qemuMonitorMigrateCancel(priv->mon));
- if (qemuDomainObjExitMonitor(driver, vm) < 0)
+ if (qemuMigrationCancel(driver, vm) < 0)
return -1;
/* resume the domain but only if it was paused as a result of
* migration */