This ensures the behavior for detach is consistent, no matter how it
was triggered (eg. 'virsh nodedev-detach', 'virsh attach-device' or
startup of a domain that is configured to use hostdevs).
---
src/util/virhostdev.c | 31 ++++++++++++++++++++++++++-----
1 file changed, 26 insertions(+), 5 deletions(-)
diff --git a/src/util/virhostdev.c b/src/util/virhostdev.c
index 2d219dd..bc7dd77 100644
--- a/src/util/virhostdev.c
+++ b/src/util/virhostdev.c
@@ -1630,6 +1630,7 @@ int
virHostdevPCINodeDeviceDetach(virHostdevManagerPtr hostdev_mgr,
virPCIDevicePtr pci)
{
+ virPCIDeviceListPtr pcidevs = NULL;
struct virHostdevIsPCINodeDeviceUsedData data = { hostdev_mgr, NULL,
false };
int ret = -1;
@@ -1638,17 +1639,37 @@ virHostdevPCINodeDeviceDetach(virHostdevManagerPtr hostdev_mgr,
virObjectLock(hostdev_mgr->inactivePCIHostdevs);
if (virHostdevIsPCINodeDeviceUsed(virPCIDeviceGetAddress(pci), &data))
- goto out;
+ goto cleanup;
- if (virPCIDeviceDetach(pci, hostdev_mgr->activePCIHostdevs,
- hostdev_mgr->inactivePCIHostdevs) < 0) {
- goto out;
+ /* We want this function to be idempotent, so if the device has already
+ * been added to the inactive list (and is not active, as per the check
+ * above) just return right away */
+ if (virPCIDeviceListFind(hostdev_mgr->inactivePCIHostdevs, pci)) {
+ VIR_DEBUG("PCI device %s is already detached from the host",
+ virPCIDeviceGetName(pci));
+ ret = 0;
+ goto cleanup;
}
+ /* Create a temporary device list */
+ if (!(pcidevs = virPCIDeviceListNew()))
+ goto cleanup;
+ if (virPCIDeviceListAddCopy(pcidevs, pci) < 0)
+ goto cleanup;
+
+ /* Detach the device. We don't want to skip unmanaged devices in
+ * this case, because the user explicitly asked for the device to
+ * be detached from the host driver */
+ if (detachPCIDevices(hostdev_mgr, pcidevs, false) < 0)
+ goto cleanup;
+
ret = 0;
- out:
+
+ cleanup:
+ virObjectUnref(pcidevs);
virObjectUnlock(hostdev_mgr->inactivePCIHostdevs);
virObjectUnlock(hostdev_mgr->activePCIHostdevs);
+
return ret;
}
--
2.5.0