[libvirt] [RFC v1 4/6] migration: Migration support for ephemeral hostdevs

Chen Fan chen.fan.fnst at cn.fujitsu.com
Wed May 13 03:36:30 UTC 2015


add migration support for ephemeral host devices, introduce
two 'detach' and 'restore' functions to unplug/plug host devices
during migration.

Signed-off-by: Chen Fan <chen.fan.fnst at cn.fujitsu.com>
---
 src/qemu/qemu_migration.c | 171 ++++++++++++++++++++++++++++++++++++++++++++--
 src/qemu/qemu_migration.h |   9 +++
 src/qemu/qemu_process.c   |  11 +++
 3 files changed, 187 insertions(+), 4 deletions(-)

diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c
index 56112f9..d5a698f 100644
--- a/src/qemu/qemu_migration.c
+++ b/src/qemu/qemu_migration.c
@@ -3384,6 +3384,158 @@ qemuMigrationPrepareDef(virQEMUDriverPtr driver,
     return def;
 }
 
+int
+qemuMigrationDetachEphemeralDevices(virQEMUDriverPtr driver,
+                                    virDomainObjPtr vm,
+                                    bool live)
+{
+    qemuDomainObjPrivatePtr priv = vm->privateData;
+    virDomainHostdevDefPtr hostdev;
+    virDomainNetDefPtr net;
+    virDomainDeviceDef dev;
+    virDomainDeviceDefPtr dev_copy = NULL;
+    virCapsPtr caps = NULL;
+    int actualType;
+    int ret = -1;
+    size_t i;
+
+    VIR_DEBUG("Rum domain detach ephemeral devices");
+
+    if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
+        return ret;
+
+    for (i = 0; i < vm->def->nnets;) {
+        net = vm->def->nets[i];
+
+        actualType = virDomainNetGetActualType(net);
+        if (actualType != VIR_DOMAIN_NET_TYPE_HOSTDEV) {
+            i++;
+            continue;
+        }
+
+        hostdev = virDomainNetGetActualHostdev(net);
+        if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS ||
+            hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI ||
+            !hostdev->ephemeral) {
+            i++;
+            continue;
+        }
+
+        dev.type = VIR_DOMAIN_DEVICE_NET;
+        dev.data.net = net;
+
+        dev_copy = virDomainDeviceDefCopy(&dev, vm->def,
+                                          caps, driver->xmlopt);
+        if (!dev_copy)
+            goto cleanup;
+
+        if (live) {
+            /* nnets reduced */
+            if (qemuDomainDetachNetDevice(driver, vm, dev_copy) < 0)
+                goto cleanup;
+        } else {
+            virDomainNetDefFree(virDomainNetRemove(vm->def, i));
+        }
+        if (VIR_APPEND_ELEMENT(priv->ephemeralDevices,
+                               priv->nEphemeralDevices,
+                               dev_copy) < 0) {
+            goto cleanup;
+        }
+        dev_copy = NULL;
+    }
+
+    for (i = 0; i < vm->def->nhostdevs;) {
+        hostdev = vm->def->hostdevs[i];
+
+        if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS ||
+            hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI ||
+            !hostdev->ephemeral) {
+            i++;
+            continue;
+        }
+
+        dev.type = VIR_DOMAIN_DEVICE_HOSTDEV;
+        dev.data.hostdev = hostdev;
+
+        VIR_FREE(dev_copy);
+        dev_copy = virDomainDeviceDefCopy(&dev, vm->def,
+                                          caps, driver->xmlopt);
+        if (!dev_copy)
+            goto cleanup;
+
+        if (live) {
+            /* nhostdevs reduced */
+            if (qemuDomainDetachHostDevice(driver, vm, dev_copy) < 0)
+                goto cleanup;
+        } else {
+            virDomainHostdevDefFree(virDomainHostdevRemove(vm->def, i));
+        }
+        if (VIR_APPEND_ELEMENT(priv->ephemeralDevices,
+                               priv->nEphemeralDevices,
+                               dev_copy) < 0) {
+            goto cleanup;
+        }
+        dev_copy = NULL;
+    }
+
+    ret = 0;
+ cleanup:
+    virDomainDeviceDefFree(dev_copy);
+    virObjectUnref(caps);
+
+    return ret;
+}
+
+void
+qemuMigrationRestoreEphemeralDevices(virQEMUDriverPtr driver,
+                                     virConnectPtr conn,
+                                     virDomainObjPtr vm,
+                                     bool live)
+{
+    qemuDomainObjPrivatePtr priv = vm->privateData;
+    virDomainDeviceDefPtr dev;
+    int ret = -1;
+    size_t i;
+
+    VIR_DEBUG("Rum domain restore ephemeral devices");
+
+    for (i = 0; i < priv->nEphemeralDevices; i++) {
+        dev = priv->ephemeralDevices[i];
+
+        switch ((virDomainDeviceType) dev->type) {
+        case VIR_DOMAIN_DEVICE_NET:
+            if (live) {
+                ret = qemuDomainAttachNetDevice(conn, driver, vm,
+                                                dev->data.net);
+            } else {
+                ret = virDomainNetInsert(vm->def, dev->data.net);
+            }
+
+            if (!ret)
+                dev->data.net = NULL;
+            break;
+        case VIR_DOMAIN_DEVICE_HOSTDEV:
+            if (live) {
+                ret = qemuDomainAttachHostDevice(conn, driver, vm,
+                                                 dev->data.hostdev);
+           } else {
+                ret =virDomainHostdevInsert(vm->def, dev->data.hostdev);
+            }
+            if (!ret)
+                dev->data.hostdev = NULL;
+            break;
+        default:
+            ret = -1;
+        }
+
+        if (ret == -1)
+            VIR_WARN("Unable to restore ephemeral device on domain %s ",
+                     vm->def->name);
+        virDomainDeviceDefFree(dev);
+    }
+    VIR_FREE(priv->ephemeralDevices);
+    priv->nEphemeralDevices = 0;
+}
 
 static int
 qemuMigrationConfirmPhase(virQEMUDriverPtr driver,
@@ -3454,6 +3606,7 @@ qemuMigrationConfirmPhase(virQEMUDriverPtr driver,
 
         /* cancel any outstanding NBD jobs */
         qemuMigrationCancelDriveMirror(mig, driver, vm);
+        qemuMigrationRestoreEphemeralDevices(driver, conn, vm, true);
 
         if (qemuMigrationRestoreDomainState(conn, vm)) {
             event = virDomainEventLifecycleNewFromObj(vm,
@@ -4842,6 +4995,9 @@ qemuMigrationPerformJob(virQEMUDriverPtr driver,
 
     qemuMigrationStoreDomainState(vm);
 
+    if (qemuMigrationDetachEphemeralDevices(driver, vm, true) < 0)
+        goto endjob;
+
     if ((flags & (VIR_MIGRATE_TUNNELLED | VIR_MIGRATE_PEER2PEER))) {
         ret = doPeer2PeerMigrate(driver, conn, vm, xmlin,
                                  dconnuri, uri, graphicsuri, listenAddress,
@@ -4931,6 +5087,9 @@ qemuMigrationPerformPhase(virQEMUDriverPtr driver,
     virCloseCallbacksUnset(driver->closeCallbacks, vm,
                            qemuMigrationCleanup);
 
+    if (qemuMigrationDetachEphemeralDevices(driver, vm, true) < 0)
+        goto endjob;
+
     ret = doNativeMigrate(driver, vm, uri, cookiein, cookieinlen,
                           cookieout, cookieoutlen,
                           flags, resource, NULL, graphicsuri);
@@ -5272,10 +5431,14 @@ qemuMigrationFinish(virQEMUDriverPtr driver,
             }
         }
 
-        if (virDomainObjIsActive(vm) &&
-            virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0) {
-            VIR_WARN("Failed to save status on vm %s", vm->def->name);
-            goto endjob;
+        if (virDomainObjIsActive(vm)) {
+            /* Check whether exist ephemeral devices, hotplug them. */
+            qemuMigrationRestoreEphemeralDevices(driver, dconn, vm, true);
+
+            if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0) {
+                VIR_WARN("Failed to save status on vm %s", vm->def->name);
+                goto endjob;
+            }
         }
 
         /* Guest is successfully running, so cancel previous auto destroy */
diff --git a/src/qemu/qemu_migration.h b/src/qemu/qemu_migration.h
index 1726455..e378b30 100644
--- a/src/qemu/qemu_migration.h
+++ b/src/qemu/qemu_migration.h
@@ -177,4 +177,13 @@ int qemuMigrationToFile(virQEMUDriverPtr driver, virDomainObjPtr vm,
     ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(5)
     ATTRIBUTE_RETURN_CHECK;
 
+int
+qemuMigrationDetachEphemeralDevices(virQEMUDriverPtr driver,
+                                    virDomainObjPtr vm,
+                                    bool live);
+void
+qemuMigrationRestoreEphemeralDevices(virQEMUDriverPtr driver,
+                                     virConnectPtr conn,
+                                     virDomainObjPtr vm,
+                                     bool live);
 #endif /* __QEMU_MIGRATION_H__ */
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index d1f089d..904c447 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -4496,6 +4496,15 @@ int qemuProcessStart(virConnectPtr conn,
     if (qemuNetworkPrepareDevices(vm->def) < 0)
        goto cleanup;
 
+    /*
+     * Ephemeral device would be hotplugged at a later stage
+     * during migration. hence we should remove the reserved
+     * PCI address for ephemeral device.
+     */
+    if (vmop == VIR_NETDEV_VPORT_PROFILE_OP_MIGRATE_IN_START)
+        if (qemuMigrationDetachEphemeralDevices(driver, vm, false) < 0)
+            goto cleanup;
+
     /* Must be run before security labelling */
     VIR_DEBUG("Preparing host devices");
     if (!cfg->relaxedACS)
@@ -5288,6 +5297,8 @@ void qemuProcessStop(virQEMUDriverPtr driver,
         priv->ccwaddrs = NULL;
     }
 
+    qemuMigrationRestoreEphemeralDevices(driver, NULL, vm, false);
+
     qemuDomainReAttachHostDevices(driver, vm->def);
 
     def = vm->def;
-- 
1.9.3




More information about the libvir-list mailing list