--- 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 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list