[libvirt] [PATCH 09/16] Merge tunnel & non-tunnel migration impl into one

Daniel P. Berrange berrange at redhat.com
Thu Apr 21 16:32:48 UTC 2011


Merge the doNonTunnelMigrate2 and doTunnelMigrate2 methods
into one doPeer2PeerMigrate2 method, since they are substantially
the same. With the introduction of v3 migration, this will be
even more important, to avoid massive code duplication.

* src/qemu/qemu_migration.c: Merge tunnel & non-tunnel migration
---
 src/qemu/qemu_migration.c |  210 ++++++++++++++++++++++-----------------------
 1 files changed, 103 insertions(+), 107 deletions(-)

diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c
index 7a17dfc..884e26d 100644
--- a/src/qemu/qemu_migration.c
+++ b/src/qemu/qemu_migration.c
@@ -1436,25 +1436,28 @@ cleanup:
 }
 
 
-static int doTunnelMigrate2(struct qemud_driver *driver,
-                            virConnectPtr dconn,
-                            virDomainObjPtr vm,
-                            const char *dom_xml,
-                            const char *uri,
-                            unsigned long flags,
-                            const char *dname,
-                            unsigned long resource)
+/* This is essentially a re-impl of virDomainMigrateVersion2
+ * from libvirt.c, but running in source libvirtd context,
+ * instead of client app context & also adding in tunnel
+ * handling */
+static int doPeer2PeerMigrate2(struct qemud_driver *driver,
+                               virConnectPtr sconn,
+                               virConnectPtr dconn,
+                               virDomainObjPtr vm,
+                               const char *uri,
+                               unsigned long flags,
+                               const char *dname,
+                               unsigned long resource)
 {
     virDomainPtr ddomain = NULL;
-    int retval = -1;
-    virStreamPtr st = NULL;
-    int internalret;
+    char *uri_out = NULL;
+    char *cookie = NULL;
+    char *dom_xml = NULL;
+    int cookielen = 0, ret;
+    virErrorPtr orig_err = NULL;
+    int cancelled;
     virBitmapPtr qemuCaps = NULL;
-
-    /*
-     * Tunnelled Migrate Version 2 does not support cookies
-     * due to missing parameters in the prepareTunnel() API.
-     */
+    virStreamPtr st = NULL;
 
     /* check that this qemu version supports the unix migration */
     if (qemuCapsExtractVersionInfo(vm->def->emulator, vm->def->os.arch,
@@ -1462,75 +1465,45 @@ static int doTunnelMigrate2(struct qemud_driver *driver,
         qemuReportError(VIR_ERR_INTERNAL_ERROR,
                         _("Cannot extract Qemu version from '%s'"),
                         vm->def->emulator);
-        goto cleanup;
+        return -1;
     }
 
-    if (!(st = virStreamNew(dconn, 0)))
-        goto cleanup;
-
-    qemuDomainObjEnterRemoteWithDriver(driver, vm);
-    internalret = dconn->driver->domainMigratePrepareTunnel(dconn, st,
-                                                            flags, dname,
-                                                            resource, dom_xml);
-    qemuDomainObjExitRemoteWithDriver(driver, vm);
-
-    if (internalret < 0)
-        /* domainMigratePrepareTunnel sets the error for us */
-        goto cleanup;
-
-    retval = doTunnelMigrate(driver, vm, st, qemuCaps, flags, resource);
 
-    dname = dname ? dname : vm->def->name;
-    qemuDomainObjEnterRemoteWithDriver(driver, vm);
-    ddomain = dconn->driver->domainMigrateFinish2
-        (dconn, dname, NULL, 0, uri, flags, retval);
-    qemuDomainObjExitRemoteWithDriver(driver, vm);
-
-cleanup:
-    qemuCapsFree(qemuCaps);
+    /* In version 2 of the protocol, the prepare step is slightly
+     * different.  We fetch the domain XML of the source domain
+     * and pass it to Prepare2.
+     */
+    if (!(dom_xml = qemuDomainFormatXML(driver, vm,
+                                        VIR_DOMAIN_XML_SECURE |
+                                        VIR_DOMAIN_XML_UPDATE_CPU)))
+        return -1;
 
-    if (ddomain)
-        virUnrefDomain(ddomain);
-
-    if (st)
-        /* don't call virStreamFree(), because that resets any pending errors */
-        virUnrefStream(st);
-    return retval;
-}
+    if (vm->state == VIR_DOMAIN_PAUSED)
+        flags |= VIR_MIGRATE_PAUSED;
 
+    VIR_DEBUG("Prepare2 %p", dconn);
+    if (flags & VIR_MIGRATE_TUNNELLED) {
+        /*
+         * Tunnelled Migrate Version 2 does not support cookies
+         * due to missing parameters in the prepareTunnel() API.
+         */
 
-/* This is essentially a simplified re-impl of
- * virDomainMigrateVersion2 from libvirt.c, but running in source
- * libvirtd context, instead of client app context */
-static int doNonTunnelMigrate2(struct qemud_driver *driver,
-                               virConnectPtr dconn,
-                               virDomainObjPtr vm,
-                               const char *dom_xml,
-                               const char *uri ATTRIBUTE_UNUSED,
-                               unsigned long flags,
-                               const char *dname,
-                               unsigned long resource)
-{
-    virDomainPtr ddomain = NULL;
-    int retval = -1;
-    char *uri_out = NULL;
-    char *cookie = NULL;
-    int cookielen = 0;
-    int rc;
+        if (!(st = virStreamNew(dconn, 0)))
+            goto cleanup;
 
-    qemuDomainObjEnterRemoteWithDriver(driver, vm);
-    /* NB we don't pass 'uri' into this, since that's the libvirtd
-     * URI in this context - so we let dest pick it */
-    rc = dconn->driver->domainMigratePrepare2(dconn,
-                                              &cookie,
-                                              &cookielen,
-                                              NULL, /* uri */
-                                              &uri_out,
-                                              flags, dname,
-                                              resource, dom_xml);
-    qemuDomainObjExitRemoteWithDriver(driver, vm);
-    if (rc < 0)
-        /* domainMigratePrepare2 sets the error for us */
+        qemuDomainObjEnterRemoteWithDriver(driver, vm);
+        ret = dconn->driver->domainMigratePrepareTunnel
+            (dconn, st, flags, dname, resource, dom_xml);
+        qemuDomainObjExitRemoteWithDriver(driver, vm);
+    } else {
+        qemuDomainObjEnterRemoteWithDriver(driver, vm);
+        ret = dconn->driver->domainMigratePrepare2
+            (dconn, &cookie, &cookielen, NULL, &uri_out,
+             flags, dname, resource, dom_xml);
+        qemuDomainObjExitRemoteWithDriver(driver, vm);
+    }
+    VIR_FREE(dom_xml);
+    if (ret == -1)
         goto cleanup;
 
     /* the domain may have shutdown or crashed while we had the locks dropped
@@ -1542,37 +1515,73 @@ static int doNonTunnelMigrate2(struct qemud_driver *driver,
         goto cleanup;
     }
 
-    if (uri_out == NULL) {
-        qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+    if (!(flags & VIR_MIGRATE_TUNNELLED) &&
+        (uri_out == NULL)) {
+        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                         _("domainMigratePrepare2 did not set uri"));
-        goto cleanup;
+        cancelled = 1;
+        goto finish;
     }
 
-    if (doNativeMigrate(driver, vm, uri_out,
-                        cookie, cookielen,
-                        NULL, NULL, /* No out cookie with v2 migration */
-                        flags, dname, resource) < 0)
-        goto finish;
+    /* Perform the migration.  The driver isn't supposed to return
+     * until the migration is complete.
+     */
+    VIR_DEBUG("Perform %p", sconn);
+    if (flags & VIR_MIGRATE_TUNNELLED)
+        ret = doTunnelMigrate(driver, vm, st, qemuCaps, flags, resource);
+    else
+        ret = doNativeMigrate(driver, vm, uri_out,
+                              cookie, cookielen,
+                              NULL, NULL, /* No out cookie with v2 migration */
+                              flags, dname, resource);
 
-    retval = 0;
+    /* Perform failed. Make sure Finish doesn't overwrite the error */
+    if (ret < 0)
+        orig_err = virSaveLastError();
+
+    /* If Perform returns < 0, then we need to cancel the VM
+     * startup on the destination
+     */
+    cancelled = ret < 0 ? 1 : 0;
 
 finish:
+    /* In version 2 of the migration protocol, we pass the
+     * status code from the sender to the destination host,
+     * so it can do any cleanup if the migration failed.
+     */
     dname = dname ? dname : vm->def->name;
+    VIR_DEBUG("Finish2 %p ret=%d", dconn, ret);
     qemuDomainObjEnterRemoteWithDriver(driver, vm);
     ddomain = dconn->driver->domainMigrateFinish2
-        (dconn, dname, cookie, cookielen, uri_out, flags, retval);
+        (dconn, dname, cookie, cookielen,
+         uri_out ? uri_out : uri, flags, cancelled);
     qemuDomainObjExitRemoteWithDriver(driver, vm);
 
-    if (ddomain)
+cleanup:
+    if (ddomain) {
         virUnrefDomain(ddomain);
+        ret = 0;
+    } else {
+        ret = -1;
+    }
+    qemuCapsFree(qemuCaps);
 
-cleanup:
+    if (st)
+        virUnrefStream(st);
+
+    if (orig_err) {
+        virSetError(orig_err);
+        virFreeError(orig_err);
+    }
+    VIR_FREE(uri_out);
     VIR_FREE(cookie);
-    return retval;
+
+    return ret;
 }
 
 
 static int doPeer2PeerMigrate(struct qemud_driver *driver,
+                              virConnectPtr sconn,
                               virDomainObjPtr vm,
                               const char *uri,
                               unsigned long flags,
@@ -1581,7 +1590,6 @@ static int doPeer2PeerMigrate(struct qemud_driver *driver,
 {
     int ret = -1;
     virConnectPtr dconn = NULL;
-    char *dom_xml;
     bool p2p;
 
     /* the order of operations is important here; we make sure the
@@ -1614,22 +1622,10 @@ static int doPeer2PeerMigrate(struct qemud_driver *driver,
         goto cleanup;
     }
 
-    dom_xml = qemuDomainFormatXML(driver, vm,
-                                  VIR_DOMAIN_XML_SECURE |
-                                  VIR_DOMAIN_XML_UPDATE_CPU);
-    if (!dom_xml) {
-        qemuReportError(VIR_ERR_OPERATION_FAILED,
-                        "%s", _("failed to get domain xml"));
-        goto cleanup;
-    }
-
-    if (flags & VIR_MIGRATE_TUNNELLED)
-        ret = doTunnelMigrate2(driver, dconn, vm, dom_xml, uri, flags, dname, resource);
-    else
-        ret = doNonTunnelMigrate2(driver, dconn, vm, dom_xml, uri, flags, dname, resource);
+    ret = doPeer2PeerMigrate2(driver, sconn, dconn, vm,
+                              uri, flags, dname, resource);
 
 cleanup:
-    VIR_FREE(dom_xml);
     /* don't call virConnectClose(), because that resets any pending errors */
     qemuDomainObjEnterRemoteWithDriver(driver, vm);
     virUnrefConnect(dconn);
@@ -1682,7 +1678,7 @@ int qemuMigrationPerform(struct qemud_driver *driver,
             goto endjob;
         }
 
-        if (doPeer2PeerMigrate(driver, vm, uri, flags, dname, resource) < 0)
+        if (doPeer2PeerMigrate(driver, conn, vm, uri, flags, dname, resource) < 0)
             /* doPeer2PeerMigrate already set the error, so just get out */
             goto endjob;
     } else {
-- 
1.7.4.4




More information about the libvir-list mailing list