The Multifunction PCI devices cant be hotplugged when the other
functions are bound to host driver. So, detach them all together
once as part of preparation for Multifunction hotplug. The second
attempt should just verify if the device was prepared for the
same domain and if yes, return.
Signed-off-by: Shivaprasad G Bhat <sbhat(a)linux.vnet.ibm.com>
---
src/qemu/qemu_hotplug.c | 14 +++++++++++++-
src/util/virhostdev.c | 16 ++++++++++++++++
2 files changed, 29 insertions(+), 1 deletion(-)
diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
index 5b822f9..24f1731 100644
--- a/src/qemu/qemu_hotplug.c
+++ b/src/qemu/qemu_hotplug.c
@@ -1193,9 +1193,21 @@ qemuDomainAttachHostPCIDevice(virQEMUDriverPtr driver,
int backend;
virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
unsigned int flags = 0;
+ size_t i;
+ virPCIDeviceAddress hostdevaddr = hostdev->source.subsys.u.pci.addr;
+
+ for (i = 0; i < vm->def->nhostdevs; i++) {
+ virPCIDeviceAddress curaddr =
vm->def->hostdevs[i]->source.subsys.u.pci.addr;
+ if (virPCIDeviceAddressEqual(&curaddr, &hostdevaddr)) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("PCI device already assigned to "
+ "currrent domain"));
+ goto cleanup;
+ }
+ }
if (VIR_REALLOC_N(vm->def->hostdevs, vm->def->nhostdevs + 1) < 0)
- return -1;
+ goto cleanup;
if (!cfg->relaxedACS)
flags |= VIR_HOSTDEV_STRICT_ACS_CHECK;
diff --git a/src/util/virhostdev.c b/src/util/virhostdev.c
index 980e590..3f84f82 100644
--- a/src/util/virhostdev.c
+++ b/src/util/virhostdev.c
@@ -542,9 +542,25 @@ virHostdevPreparePCIDevices(virHostdevManagerPtr mgr,
* have already been taken care of */
for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
virPCIDevicePtr pci = virPCIDeviceListGet(pcidevs, i);
+ virPCIDevicePtr actual;
if (virPCIDeviceGetManaged(pci)) {
+ /* Its possible that the device attempted to be prepared from
+ * two paths once from the Multifunction device preparation
+ * and again before the hotplug. Let this function pass if the
+ * device is already in the active list assigned to current domain.
+ */
+ if (mgr->activePCIHostdevs &&
+ (actual = virPCIDeviceListFind(mgr->activePCIHostdevs, pci))) {
+ const char *actual_drvname = NULL;
+ const char *actual_domname = NULL;
+ virPCIDeviceGetUsedBy(actual, &actual_drvname, &actual_domname);
+ if (actual_domname && dom_name &&
+ STREQ(actual_domname, dom_name))
+ ret = 0;
+ goto cleanup;
+ }
/* We can't look up the actual device because it has not been
* created yet: virPCIDeviceDetach() will insert a copy of 'pci'
* into the list of inactive devices, and that copy will be the