This patch uses the ephemeral flag to prevent the hybrid hostdev from
being formatted into the xml.
Before migration the hybrid hostdev is hot unplugged and hotplugged
again after migration is the specific hostdev is available on the
destination host.
---
src/qemu/qemu_migration.c | 102 ++++++++++++++++++++++++++++++++++++++++++--
1 files changed, 97 insertions(+), 5 deletions(-)
diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c
index d8aefa0..21894e8 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_HYBRID) {
+ if (qemuDomainAttachHostDevice(driver, vm,
+ virDomainNetGetActualHostdev(net)) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Hybrid Hostdev cannot be attached after
migration"));
+ 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_HYBRID) {
+ if (qemuDomainAttachHostDevice(driver, vm,
+ virDomainNetGetActualHostdev(net)) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Hybrid 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 host devices
cannot be migrated"));
+ return false;
+ }
}
return true;
@@ -2042,6 +2120,8 @@ 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 +2149,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);
@@ -2106,6 +2189,8 @@ static int doTunnelMigrate(struct qemud_driver *driver,
_("Source qemu is too old to support tunnelled
migration"));
return -1;
}
+
+ qemuMigrationRemoveEphemeralDevices(driver, vm);
spec.fwdType = MIGRATION_FWD_STREAM;
spec.fwd.stream = st;
@@ -2153,6 +2238,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);
@@ -2197,7 +2284,8 @@ static int doPeer2PeerMigrate2(struct qemud_driver *driver,
*/
if (!(dom_xml = qemuDomainFormatXML(driver, vm,
VIR_DOMAIN_XML_SECURE |
- VIR_DOMAIN_XML_UPDATE_CPU,
+ VIR_DOMAIN_XML_UPDATE_CPU |
+ VIR_DOMAIN_XML_NO_EPHEMERAL_DEVICES,
true)))
return -1;
@@ -3057,6 +3145,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 +3244,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