---
src/qemu/qemu_migration.c | 98 +++++++++++++++++++++++++++++++++++++++++++--
1 files changed, 94 insertions(+), 4 deletions(-)
diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c
index 99fc8ce..f3414b0 100644
--- a/src/qemu/qemu_migration.c
+++ b/src/qemu/qemu_migration.c
@@ -31,6 +31,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"
@@ -49,6 +50,7 @@
#include "storage_file.h"
#include "viruri.h"
#include "hooks.h"
+#include "network/bridge_driver.h"
#define VIR_FROM_THIS VIR_FROM_QEMU
@@ -122,6 +124,79 @@ struct _qemuMigrationCookie {
virDomainDefPtr persistent;
};
+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)
@@ -800,6 +875,7 @@ qemuMigrationIsAllowed(struct qemud_driver *driver, virDomainObjPtr
vm,
virDomainDefPtr def)
{
int nsnapshots;
+ unsigned int i;
if (vm) {
if (qemuProcessAutoDestroyActive(driver, vm)) {
@@ -817,10 +893,12 @@ qemuMigrationIsAllowed(struct qemud_driver *driver, virDomainObjPtr
vm,
def = vm->def;
}
- if (def->nhostdevs > 0) {
- virReportError(VIR_ERR_OPERATION_INVALID,
- "%s", _("Domain with assigned host devices cannot
be migrated"));
- return false;
+ for (i = 0; i < def->nhostdevs; i++) {
+ if (def->hostdevs[i]->ephemeral == 0) {
+ virReportError(VIR_ERR_OPERATION_INVALID,
+ "%s", _("Domain with assigned non-ephemeral
host devices cannot be migrated"));
+ return false;
+ }
}
return true;
@@ -2042,6 +2120,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;
@@ -2069,6 +2148,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);
@@ -2107,6 +2189,8 @@ static int doTunnelMigrate(struct qemud_driver *driver,
return -1;
}
+ qemuMigrationRemoveEphemeralDevices(driver, vm);
+
spec.fwdType = MIGRATION_FWD_STREAM;
spec.fwd.stream = st;
@@ -2153,6 +2237,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);
@@ -3057,6 +3143,8 @@ qemuMigrationFinish(struct qemud_driver *driver,
goto endjob;
}
+ qemuMigrationAttachEphemeralDevices(driver, vm);
+
/* Guest is successfully running, so cancel previous auto destroy */
qemuProcessAutoDestroyRemove(driver, vm);
} else {
@@ -3154,6 +3242,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