[libvirt] [PATCH 0/5] Support ephemeral passthrough hostdevs

The ephemeral flag helps support migration with PCI-passthrough. An ephemeral hostdev is automatically unplugged before migration and replugged (if one is available on the destination) after migration. Shradha Shah (5): Added ephemeral flag for hostdev in domain conf. Adding ephemeral flag for hostdev in network conf. Ephemeral flag mofication within the network driver. Ephemeral flag modification within the qemu driver. Migration support for ephemeral hostdevs. docs/schemas/domaincommon.rng | 16 +++ docs/schemas/network.rng | 8 ++ src/conf/domain_conf.c | 23 ++++- src/conf/domain_conf.h | 1 + src/conf/network_conf.c | 11 ++ src/conf/network_conf.h | 1 + src/network/bridge_driver.c | 1 + src/qemu/qemu_command.c | 49 +++++----- src/qemu/qemu_migration.c | 98 +++++++++++++++++++- tests/networkxml2xmlin/hostdev-pf.xml | 2 +- tests/networkxml2xmlin/hostdev.xml | 2 +- tests/networkxml2xmlout/hostdev-pf.xml | 2 +- tests/networkxml2xmlout/hostdev.xml | 2 +- .../qemuxml2argv-hostdev-pci-address.xml | 2 +- .../qemuxml2argv-hostdev-usb-address.xml | 2 +- .../qemuxml2argvdata/qemuxml2argv-net-hostdev.xml | 2 +- tests/qemuxml2argvdata/qemuxml2argv-pci-rom.xml | 4 +- 17 files changed, 188 insertions(+), 38 deletions(-) -- 1.7.4.4

The ephemeral flag helps support migration with PCI-passthrough. An ephemeral hostdev is automatically unplugged before migration and replugged (if one is available on the destination) after migration. --- docs/schemas/domaincommon.rng | 16 +++++++++++++ src/conf/domain_conf.c | 23 ++++++++++++++++++- src/conf/domain_conf.h | 1 + src/qemu/qemu_command.c | 1 + .../qemuxml2argv-hostdev-pci-address.xml | 2 +- .../qemuxml2argv-hostdev-usb-address.xml | 2 +- .../qemuxml2argvdata/qemuxml2argv-net-hostdev.xml | 2 +- tests/qemuxml2argvdata/qemuxml2argv-pci-rom.xml | 4 +- 8 files changed, 44 insertions(+), 7 deletions(-) diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng index aafb10c..349f22b 100644 --- a/docs/schemas/domaincommon.rng +++ b/docs/schemas/domaincommon.rng @@ -1644,6 +1644,14 @@ </choice> </attribute> </optional> + <optional> + <attribute name="ephemeral"> + <choice> + <value>yes</value> + <value>no</value> + </choice> + </attribute> + </optional> <interleave> <element name="source"> <choice> @@ -2750,6 +2758,14 @@ </choice> </attribute> </optional> + <optional> + <attribute name="ephemeral"> + <choice> + <value>yes</value> + <value>no</value> + </choice> + </attribute> + </optional> <group> <element name="source"> <choice> diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index b8ba0e2..0b6332a 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -2888,6 +2888,7 @@ virDomainHostdevPartsParse(xmlNodePtr node, { xmlNodePtr sourcenode; char *managed = NULL; + char *ephemeral = NULL; int ret = -1; /* @mode is passed in separately from the caller, since an @@ -2914,6 +2915,16 @@ virDomainHostdevPartsParse(xmlNodePtr node, def->managed = 1; } + /* @ephemeral can be read from the xml document - it is always an + * attribute of the toplevel element, no matter what type of + * element that might be (pure hostdev, or higher level device + * (e.g. <interface>) with type='hostdev') + */ + if ((ephemeral = virXMLPropString(node, "ephemeral"))!= NULL) { + if (STREQ(ephemeral,"yes")) + def->ephemeral = 1; + } + /* @type is passed in from the caller rather than read from the * xml document, because it is specified in different places for * different kinds of defs - it is an attribute of @@ -12027,6 +12038,10 @@ virDomainActualNetDefFormat(virBufferPtr buf, def->data.hostdev.def.managed) { virBufferAddLit(buf, " managed='yes'"); } + if (def->type == VIR_DOMAIN_NET_TYPE_HOSTDEV && + def->data.hostdev.def.ephemeral) { + virBufferAddLit(buf, " ephemeral='yes'"); + } virBufferAddLit(buf, ">\n"); virBufferAdjustIndent(buf, 2); @@ -12097,6 +12112,10 @@ virDomainNetDefFormat(virBufferPtr buf, def->data.hostdev.def.managed) { virBufferAddLit(buf, " managed='yes'"); } + if (def->type == VIR_DOMAIN_NET_TYPE_HOSTDEV && + def->data.hostdev.def.ephemeral) { + virBufferAddLit(buf, " ephemeral='yes'"); + } virBufferAddLit(buf, ">\n"); virBufferAdjustIndent(buf, 6); @@ -13063,8 +13082,8 @@ virDomainHostdevDefFormat(virBufferPtr buf, return -1; } - virBufferAsprintf(buf, " <hostdev mode='%s' type='%s' managed='%s'>\n", - mode, type, def->managed ? "yes" : "no"); + virBufferAsprintf(buf, " <hostdev mode='%s' type='%s' managed='%s' ephemeral='%s'>\n", + mode, type, def->managed ? "yes" : "no", def->ephemeral ? "yes" : "no"); virBufferAdjustIndent(buf, 6); if (virDomainHostdevSourceFormat(buf, def, flags, false) < 0) diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index f0dea48..8263711 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -385,6 +385,7 @@ struct _virDomainHostdevDef { virDomainDeviceDef parent; /* higher level Def containing this */ int mode; /* enum virDomainHostdevMode */ unsigned int managed : 1; + unsigned int ephemeral : 1; union { virDomainHostdevSubsys subsys; struct { diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index cbf4aee..b7fbe75 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -7410,6 +7410,7 @@ qemuParseCommandLinePCI(const char *val) def->mode = VIR_DOMAIN_HOSTDEV_MODE_SUBSYS; def->managed = 1; + def->ephemeral = 1; def->source.subsys.type = VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI; def->source.subsys.u.pci.bus = bus; def->source.subsys.u.pci.slot = slot; diff --git a/tests/qemuxml2argvdata/qemuxml2argv-hostdev-pci-address.xml b/tests/qemuxml2argvdata/qemuxml2argv-hostdev-pci-address.xml index 3c69f83..fc7ea5c 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-hostdev-pci-address.xml +++ b/tests/qemuxml2argvdata/qemuxml2argv-hostdev-pci-address.xml @@ -21,7 +21,7 @@ </disk> <controller type='usb' index='0'/> <controller type='ide' index='0'/> - <hostdev mode='subsystem' type='pci' managed='yes'> + <hostdev mode='subsystem' type='pci' managed='yes' ephemeral='yes'> <source> <address domain='0x0000' bus='0x06' slot='0x12' function='0x5'/> </source> diff --git a/tests/qemuxml2argvdata/qemuxml2argv-hostdev-usb-address.xml b/tests/qemuxml2argvdata/qemuxml2argv-hostdev-usb-address.xml index 811e987..d07dbe3 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-hostdev-usb-address.xml +++ b/tests/qemuxml2argvdata/qemuxml2argv-hostdev-usb-address.xml @@ -21,7 +21,7 @@ </disk> <controller type='usb' index='0'/> <controller type='ide' index='0'/> - <hostdev mode='subsystem' type='usb' managed='no'> + <hostdev mode='subsystem' type='usb' managed='no' ephemeral='no'> <source> <address bus='14' device='6'/> </source> diff --git a/tests/qemuxml2argvdata/qemuxml2argv-net-hostdev.xml b/tests/qemuxml2argvdata/qemuxml2argv-net-hostdev.xml index 81f70d0..54aa5e6 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-net-hostdev.xml +++ b/tests/qemuxml2argvdata/qemuxml2argv-net-hostdev.xml @@ -21,7 +21,7 @@ </disk> <controller type='usb' index='0'/> <controller type='ide' index='0'/> - <interface type='hostdev' managed='yes'> + <interface type='hostdev' managed='yes' ephemeral='yes'> <mac address='00:11:22:33:44:55'/> <source> <address type='pci' domain='0x0002' bus='0x03' slot='0x07' function='0x1'/> diff --git a/tests/qemuxml2argvdata/qemuxml2argv-pci-rom.xml b/tests/qemuxml2argvdata/qemuxml2argv-pci-rom.xml index 371835d..cce0d7f 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-pci-rom.xml +++ b/tests/qemuxml2argvdata/qemuxml2argv-pci-rom.xml @@ -31,13 +31,13 @@ <model type='virtio'/> <rom file='/etc/fake/bootrom.bin'/> </interface> - <hostdev mode='subsystem' type='pci' managed='yes'> + <hostdev mode='subsystem' type='pci' managed='yes' ephemeral='no'> <source> <address domain='0x0000' bus='0x06' slot='0x12' function='0x5'/> </source> <rom bar='off'/> </hostdev> - <hostdev mode='subsystem' type='pci' managed='yes'> + <hostdev mode='subsystem' type='pci' managed='yes' ephemeral='no'> <source> <address domain='0x0000' bus='0x06' slot='0x12' function='0x6'/> </source> -- 1.7.4.4

The ephemeral flag helps support migration with PCI-passthrough. An ephemeral hostdev is automatically unplugged before migration and replugged (if one is available on the destination) after migration. --- docs/schemas/network.rng | 8 ++++++++ src/conf/network_conf.c | 11 +++++++++++ src/conf/network_conf.h | 1 + tests/networkxml2xmlin/hostdev-pf.xml | 2 +- tests/networkxml2xmlin/hostdev.xml | 2 +- tests/networkxml2xmlout/hostdev-pf.xml | 2 +- tests/networkxml2xmlout/hostdev.xml | 2 +- 7 files changed, 24 insertions(+), 4 deletions(-) diff --git a/docs/schemas/network.rng b/docs/schemas/network.rng index 4abfd91..c86ade8 100644 --- a/docs/schemas/network.rng +++ b/docs/schemas/network.rng @@ -100,6 +100,14 @@ </choice> </attribute> </optional> + <optional> + <attribute name="ephemeral"> + <choice> + <value>yes</value> + <value>no</value> + </choice> + </attribute> + </optional> <interleave> <choice> <group> diff --git a/src/conf/network_conf.c b/src/conf/network_conf.c index db398ae..7168c66 100644 --- a/src/conf/network_conf.c +++ b/src/conf/network_conf.c @@ -1206,6 +1206,7 @@ virNetworkDefParseXML(xmlXPathContextPtr ctxt) int nIps, nPortGroups, nForwardIfs, nForwardPfs, nForwardAddrs; char *forwardDev = NULL; char *forwardManaged = NULL; + char *forwardEphemeral = NULL; char *type = NULL; xmlNodePtr save = ctxt->node; xmlNodePtr bandwidthNode = NULL; @@ -1364,6 +1365,11 @@ virNetworkDefParseXML(xmlXPathContextPtr ctxt) if (STRCASEEQ(forwardManaged, "yes")) def->managed = 1; } + forwardEphemeral = virXPathString("string(./@ephemeral)", ctxt); + if(forwardEphemeral != NULL) { + if (STRCASEEQ(forwardEphemeral, "yes")) + def->ephemeral = 1; + } /* all of these modes can use a pool of physical interfaces */ nForwardIfs = virXPathNodeSet("./interface", ctxt, &forwardIfNodes); @@ -1511,6 +1517,7 @@ virNetworkDefParseXML(xmlXPathContextPtr ctxt) VIR_FREE(type); VIR_FREE(forwardDev); VIR_FREE(forwardManaged); + VIR_FREE(forwardEphemeral); VIR_FREE(forwardPfNodes); VIR_FREE(forwardIfNodes); VIR_FREE(forwardAddrNodes); @@ -1845,6 +1852,10 @@ char *virNetworkDefFormat(const virNetworkDefPtr def, unsigned int flags) virBufferAddLit(&buf, " managed='yes'"); else virBufferAddLit(&buf, " managed='no'"); + if (def->ephemeral == 1) + virBufferAddLit(&buf, " ephemeral='yes'"); + else + virBufferAddLit(&buf, " ephemeral='no'"); } virBufferAsprintf(&buf, "%s>\n", (def->nForwardIfs || def->nForwardPfs) ? "" : "/"); diff --git a/src/conf/network_conf.h b/src/conf/network_conf.h index c8ed2ea..3a65772 100644 --- a/src/conf/network_conf.h +++ b/src/conf/network_conf.h @@ -186,6 +186,7 @@ struct _virNetworkDef { int forwardType; /* One of virNetworkForwardType constants */ int managed; /* managed attribute for hostdev mode */ + int ephemeral; /* ephemeral attribute for hostdev mode */ /* If there are multiple forward devices (i.e. a pool of * interfaces), they will be listed here. diff --git a/tests/networkxml2xmlin/hostdev-pf.xml b/tests/networkxml2xmlin/hostdev-pf.xml index 7bf857d..6b928a6 100644 --- a/tests/networkxml2xmlin/hostdev-pf.xml +++ b/tests/networkxml2xmlin/hostdev-pf.xml @@ -1,7 +1,7 @@ <network> <name>hostdev</name> <uuid>81ff0d90-c91e-6742-64da-4a736edb9a9b</uuid> - <forward mode='hostdev' managed='yes'> + <forward mode='hostdev' managed='yes' ephemeral='yes'> <pf dev='eth2'/> </forward> </network> diff --git a/tests/networkxml2xmlin/hostdev.xml b/tests/networkxml2xmlin/hostdev.xml index 03f1411..406c2df 100644 --- a/tests/networkxml2xmlin/hostdev.xml +++ b/tests/networkxml2xmlin/hostdev.xml @@ -1,7 +1,7 @@ <network> <name>hostdev</name> <uuid>81ff0d90-c91e-6742-64da-4a736edb9a9b</uuid> - <forward mode='hostdev' managed='yes'> + <forward mode='hostdev' managed='yes' ephemeral='yes'> <address type='pci' domain='0x0000' bus='0x03' slot='0x00' function='0x1'/> <address type='pci' domain='0x0000' bus='0x03' slot='0x00' function='0x2'/> <address type='pci' domain='0x0000' bus='0x03' slot='0x00' function='0x3'/> diff --git a/tests/networkxml2xmlout/hostdev-pf.xml b/tests/networkxml2xmlout/hostdev-pf.xml index 7bf857d..6b928a6 100644 --- a/tests/networkxml2xmlout/hostdev-pf.xml +++ b/tests/networkxml2xmlout/hostdev-pf.xml @@ -1,7 +1,7 @@ <network> <name>hostdev</name> <uuid>81ff0d90-c91e-6742-64da-4a736edb9a9b</uuid> - <forward mode='hostdev' managed='yes'> + <forward mode='hostdev' managed='yes' ephemeral='yes'> <pf dev='eth2'/> </forward> </network> diff --git a/tests/networkxml2xmlout/hostdev.xml b/tests/networkxml2xmlout/hostdev.xml index 03f1411..406c2df 100644 --- a/tests/networkxml2xmlout/hostdev.xml +++ b/tests/networkxml2xmlout/hostdev.xml @@ -1,7 +1,7 @@ <network> <name>hostdev</name> <uuid>81ff0d90-c91e-6742-64da-4a736edb9a9b</uuid> - <forward mode='hostdev' managed='yes'> + <forward mode='hostdev' managed='yes' ephemeral='yes'> <address type='pci' domain='0x0000' bus='0x03' slot='0x00' function='0x1'/> <address type='pci' domain='0x0000' bus='0x03' slot='0x00' function='0x2'/> <address type='pci' domain='0x0000' bus='0x03' slot='0x00' function='0x3'/> -- 1.7.4.4

--- src/network/bridge_driver.c | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c index 0e38016..61d5b13 100644 --- a/src/network/bridge_driver.c +++ b/src/network/bridge_driver.c @@ -3456,6 +3456,7 @@ networkAllocateActualDevice(virDomainNetDefPtr iface) iface->data.network.actual->data.hostdev.def.info = &iface->info; iface->data.network.actual->data.hostdev.def.mode = VIR_DOMAIN_HOSTDEV_MODE_SUBSYS; iface->data.network.actual->data.hostdev.def.managed = netdef->managed; + iface->data.network.actual->data.hostdev.def.ephemeral = netdef->ephemeral; iface->data.network.actual->data.hostdev.def.source.subsys.type = dev->type; iface->data.network.actual->data.hostdev.def.source.subsys.u.pci = dev->device.pci; -- 1.7.4.4

--- 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

When a guest with ephemeral device is migrated the PCI- passthrough of the ephemeral device should take place after migration and hence we check for the vmop in qemuBuildCommandLine. --- src/qemu/qemu_command.c | 48 ++++++++++++++++++++++++---------------------- 1 files changed, 25 insertions(+), 23 deletions(-) diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index b7fbe75..e585ab1 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -5343,34 +5343,36 @@ qemuBuildCommandLine(virConnectPtr conn, /* For a network with <forward mode='hostdev'>, there is a need to * add the newly minted hostdev to the hostdevs array. */ - if (qemuAssignDeviceHostdevAlias(def, hostdev, - (def->nhostdevs-1)) < 0) { - goto error; - } - - if (virDomainHostdevFind(def, hostdev, &found) < 0) { - if (virDomainHostdevInsert(def, hostdev) < 0) { - virReportOOMError(); + if (vmop == VIR_NETDEV_VPORT_PROFILE_OP_CREATE) { + if (qemuAssignDeviceHostdevAlias(def, hostdev, + (def->nhostdevs-1)) < 0) { goto error; } - if (qemuPrepareHostdevPCIDevices(driver, def->name, def->uuid, - &hostdev, 1) < 0) { + + if (virDomainHostdevFind(def, hostdev, &found) < 0) { + if (virDomainHostdevInsert(def, hostdev) < 0) { + virReportOOMError(); + goto error; + } + if (qemuPrepareHostdevPCIDevices(driver, def->name, def->uuid, + &hostdev, 1) < 0) { + goto error; + } + } + else { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("PCI device %04x:%02x:%02x.%x " + "allocated from network %s is already " + "in use by domain %s"), + hostdev->source.subsys.u.pci.domain, + hostdev->source.subsys.u.pci.bus, + hostdev->source.subsys.u.pci.slot, + hostdev->source.subsys.u.pci.function, + net->data.network.name, + def->name); goto error; } } - else { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("PCI device %04x:%02x:%02x.%x " - "allocated from network %s is already " - "in use by domain %s"), - hostdev->source.subsys.u.pci.domain, - hostdev->source.subsys.u.pci.bus, - hostdev->source.subsys.u.pci.slot, - hostdev->source.subsys.u.pci.function, - net->data.network.name, - def->name); - goto error; - } } continue; } -- 1.7.4.4
participants (1)
-
Shradha Shah