]> xenbits.xensource.com Git - people/liuw/libxenctrl-split/libvirt.git/commitdiff
qemu: Cancel disk mirrors after libvirtd restart
authorJiri Denemark <jdenemar@redhat.com>
Tue, 19 May 2015 15:28:25 +0000 (17:28 +0200)
committerJiri Denemark <jdenemar@redhat.com>
Fri, 19 Jun 2015 13:15:11 +0000 (15:15 +0200)
When libvirtd is restarted during migration, we properly cancel the
ongoing migration (unless it managed to almost finished before the
restart). But if we were also migrating storage using NBD, we would
completely forget about the running disk mirrors.

Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
src/qemu/qemu_domain.c
src/qemu/qemu_migration.c
src/qemu/qemu_migration.h
src/qemu/qemu_process.c

index 9bb3cee9350f3f3e84a4cd7fead618dd9d450c5c..e459c186801c27bb3c93b39a6fc563e694e574f6 100644 (file)
@@ -578,7 +578,27 @@ qemuDomainObjPrivateXMLFormat(virBufferPtr buf,
                               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;
 
@@ -736,6 +756,29 @@ qemuDomainObjPrivateXMLParse(xmlXPathContextPtr ctxt,
         }
     }
 
+    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) {
index b3223fb6284f8c24e18c11f4a8f2990766ae43c5..0f1d2382eeaa166fdce9a0b383d626bf23cdb662 100644 (file)
@@ -2026,6 +2026,7 @@ qemuMigrationDriveMirror(virQEMUDriverPtr driver,
     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);
 
@@ -2075,6 +2076,11 @@ qemuMigrationDriveMirror(virQEMUDriverPtr driver,
             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) {
@@ -2102,6 +2108,7 @@ qemuMigrationDriveMirror(virQEMUDriverPtr driver,
     ret = 0;
 
  cleanup:
+    virObjectUnref(cfg);
     VIR_FREE(diskAlias);
     VIR_FREE(nbd_dest);
     VIR_FREE(hoststr);
@@ -5817,6 +5824,84 @@ qemuMigrationToFile(virQEMUDriverPtr driver, virDomainObjPtr vm,
     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,
index 030b32fdfd5f3d9a06b324e34642931fb1f06bd8..78fb6487b13ae89b77bed07e1b5e5bd89f500805 100644 (file)
@@ -185,4 +185,7 @@ int qemuMigrationToFile(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__ */
index 3c9d4bc40e585bda06852b137e878c29ca6199b8..5be0002bd791e8f4d0b87b532e69771ba6ee30a4 100644 (file)
@@ -3354,8 +3354,6 @@ qemuProcessRecoverMigration(virQEMUDriverPtr driver,
                             virDomainState state,
                             int reason)
 {
-    qemuDomainObjPrivatePtr priv = vm->privateData;
-
     if (job == QEMU_ASYNC_JOB_MIGRATION_IN) {
         switch (phase) {
         case QEMU_MIGRATION_PHASE_NONE:
@@ -3409,11 +3407,7 @@ qemuProcessRecoverMigration(virQEMUDriverPtr driver,
         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 */