---
src/qemu/qemu_migration.c | 94 +++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 91 insertions(+), 3 deletions(-)
diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c
index d52ec59..dd1a2a7 100644
--- a/src/qemu/qemu_migration.c
+++ b/src/qemu/qemu_migration.c
@@ -32,6 +32,7 @@
#include "qemu_monitor.h"
#include "qemu_domain.h"
#include "qemu_process.h"
+#include "qemu_hotplug.h"
#include "qemu_capabilities.h"
#include "qemu_cgroup.h"
@@ -50,6 +51,7 @@
#include "storage_file.h"
#include "viruri.h"
#include "hooks.h"
+#include "network/bridge_driver.h"
#define VIR_FROM_THIS VIR_FROM_QEMU
@@ -149,6 +151,79 @@ struct _qemuMigrationCookie {
qemuMigrationCookieNetworkPtr network;
};
+static void
+qemuMigrationRemoveEphemeralDevices(struct qemud_driver *driver,
+ virDomainObjPtr vm)
+{
+ virDomainHostdevDefPtr dev;
+ virDomainDeviceDef def;
+ unsigned int i;
+
+ for (i = 0; i < vm->def->nhostdevs; i++) {
+ dev = vm->def->hostdevs[i];
+ if (dev->ephemeral == 1) {
+ def.type = VIR_DOMAIN_DEVICE_HOSTDEV;
+ def.data.hostdev = dev;
+
+ if (qemuDomainDetachHostDevice(driver, vm, &def) >= 0) {
+ continue; /* nhostdevs reduced */
+ }
+ }
+ }
+}
+
+static void
+qemuMigrationRestoreEphemeralDevices(struct qemud_driver *driver,
+ virDomainObjPtr vm)
+{
+ virDomainNetDefPtr net;
+ unsigned int i;
+
+ /* Do nothing if ephemeral devices are present in which case this
+ function was called before qemuMigrationRemoveEphemeralDevices */
+
+ for (i = 0; i < vm->def->nhostdevs; i++) {
+ if (vm->def->hostdevs[i]->ephemeral == 1)
+ return;
+ }
+
+ for (i = 0; i < vm->def->nnets; i++) {
+ net = vm->def->nets[i];
+
+ if (virDomainNetGetActualType(net) == VIR_DOMAIN_NET_TYPE_HOSTDEV) {
+ if (qemuDomainAttachHostDevice(driver, vm,
+ virDomainNetGetActualHostdev(net)) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Hostdev cannot be restored"));
+ networkReleaseActualDevice(net);
+ }
+ }
+ return;
+ }
+}
+
+static void
+qemuMigrationAttachEphemeralDevices(struct qemud_driver *driver,
+ virDomainObjPtr vm)
+{
+ virDomainNetDefPtr net;
+ unsigned int i;
+
+ for (i = 0; i < vm->def->nnets; i++) {
+ net = vm->def->nets[i];
+
+ if (virDomainNetGetActualType(net) == VIR_DOMAIN_NET_TYPE_HOSTDEV) {
+ if (qemuDomainAttachHostDevice(driver, vm,
+ virDomainNetGetActualHostdev(net)) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Hostdev cannot be attached after
migration"));
+ networkReleaseActualDevice(net);
+ }
+ }
+ }
+ return;
+}
+
static void qemuMigrationCookieGraphicsFree(qemuMigrationCookieGraphicsPtr grap)
{
if (!grap)
@@ -1041,21 +1116,22 @@ qemuMigrationIsAllowed(struct qemud_driver *driver,
virDomainObjPtr vm,
def = vm->def;
}
- /* Migration with USB host devices is allowed, all other devices are
+ /* Migration with USB and ephemeral PCI host devices is allowed, all other devices
are
* forbidden.
*/
forbid = false;
for (i = 0; i < def->nhostdevs; i++) {
virDomainHostdevDefPtr hostdev = def->hostdevs[i];
if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS ||
- hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB) {
+ ((hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB)
&&
+ (hostdev->ephemeral == 0))) {
forbid = true;
break;
}
}
if (forbid) {
virReportError(VIR_ERR_OPERATION_INVALID, "%s",
- _("Domain with assigned non-USB host devices "
+ _("Domain with assigned non-USB and non-ephemeral host
devices "
"cannot be migrated"));
return false;
}
@@ -2347,6 +2423,7 @@ static int doNativeMigrate(struct qemud_driver *driver,
"cookieout=%p, cookieoutlen=%p, flags=%lx, resource=%lu",
driver, vm, uri, NULLSTR(cookiein), cookieinlen,
cookieout, cookieoutlen, flags, resource);
+ qemuMigrationRemoveEphemeralDevices(driver, vm);
if (STRPREFIX(uri, "tcp:") && !STRPREFIX(uri, "tcp://"))
{
char *tmp;
@@ -2374,6 +2451,9 @@ static int doNativeMigrate(struct qemud_driver *driver,
ret = qemuMigrationRun(driver, vm, cookiein, cookieinlen, cookieout,
cookieoutlen, flags, resource, &spec, dconn);
+ if (ret != 0)
+ qemuMigrationRestoreEphemeralDevices(driver, vm);
+
if (spec.destType == MIGRATION_DEST_FD)
VIR_FORCE_CLOSE(spec.dest.fd.qemu);
@@ -2412,6 +2492,8 @@ static int doTunnelMigrate(struct qemud_driver *driver,
return -1;
}
+ qemuMigrationRemoveEphemeralDevices(driver, vm);
+
spec.fwdType = MIGRATION_FWD_STREAM;
spec.fwd.stream = st;
@@ -2458,6 +2540,8 @@ static int doTunnelMigrate(struct qemud_driver *driver,
cookieoutlen, flags, resource, &spec, dconn);
cleanup:
+ if (ret != 0)
+ qemuMigrationRestoreEphemeralDevices(driver, vm);
if (spec.destType == MIGRATION_DEST_FD) {
VIR_FORCE_CLOSE(spec.dest.fd.qemu);
VIR_FORCE_CLOSE(spec.dest.fd.local);
@@ -3366,6 +3450,8 @@ qemuMigrationFinish(struct qemud_driver *driver,
goto endjob;
}
+ qemuMigrationAttachEphemeralDevices(driver, vm);
+
/* Guest is successfully running, so cancel previous auto destroy */
qemuProcessAutoDestroyRemove(driver, vm);
} else {
@@ -3463,6 +3549,8 @@ int qemuMigrationConfirm(struct qemud_driver *driver,
VIR_WARN("Failed to save status on vm %s", vm->def->name);
goto cleanup;
}
+
+ qemuMigrationRestoreEphemeralDevices(driver, vm);
}
qemuMigrationCookieFree(mig);
--
1.7.4.4