This function replaces virHostdevReattachPCIDevice() and, unlike it,
does not perform list manipulation, leaving it to the calling function.
This means virHostdevReAttachPCIDevices() had to be updated to cope
with the updated requirements.
---
src/util/virhostdev.c | 136 +++++++++++++++++++++++++++++++++-----------------
1 file changed, 90 insertions(+), 46 deletions(-)
diff --git a/src/util/virhostdev.c b/src/util/virhostdev.c
index f31ad41..66629b4 100644
--- a/src/util/virhostdev.c
+++ b/src/util/virhostdev.c
@@ -526,6 +526,74 @@ virHostdevNetConfigRestore(virDomainHostdevDefPtr hostdev,
return ret;
}
+/**
+ * virHostdevOnlyReattachPCIDevice:
+ * @mgr: hostdev manager
+ * @pci: PCI device to be reattached
+ * @skipUnmanaged: whether to skip unmanaged devices
+ *
+ * Reattach a PCI device to the host.
+ *
+ * This function only performs the base reattach steps that are required
+ * regardless of whether the device is being detached from a domain or
+ * had been simply detached from the host earlier.
+ *
+ * @pci must have already been marked as inactive, and the PCI related
+ * parts of @mgr (inactivePCIHostdevs, activePCIHostdevs) must have been
+ * locked beforehand using virObjectLock().
+ *
+ * Returns: 0 on success, <0 on failure
+ */
+static int
+virHostdevOnlyReattachPCIDevice(virHostdevManagerPtr mgr,
+ virPCIDevicePtr pci,
+ bool skipUnmanaged)
+{
+ virPCIDevicePtr actual;
+ int ret = -1;
+
+ /* Retrieve the actual device from the inactive list */
+ if (!(actual = virPCIDeviceListFind(mgr->inactivePCIHostdevs, pci))) {
+ VIR_DEBUG("PCI device %s is not marked as inactive",
+ virPCIDeviceGetName(pci));
+ goto out;
+ }
+
+ /* Skip unmanaged devices if asked to do so */
+ if (!virPCIDeviceGetManaged(actual) && skipUnmanaged) {
+ VIR_DEBUG("Not reattaching unmanaged PCI device %s",
+ virPCIDeviceGetName(actual));
+ ret = 0;
+ goto out;
+ }
+
+ /* Wait for device cleanup if it is qemu/kvm */
+ if (virPCIDeviceGetStubDriver(actual) == VIR_PCI_STUB_DRIVER_KVM) {
+ int retries = 100;
+ while (virPCIDeviceWaitForCleanup(actual, "kvm_assigned_device")
+ && retries) {
+ usleep(100*1000);
+ retries--;
+ }
+ }
+
+ VIR_DEBUG("Reattaching PCI device %s", virPCIDeviceGetName(actual));
+ if (virPCIDeviceReattach(actual, mgr->activePCIHostdevs,
+ mgr->inactivePCIHostdevs) < 0) {
+ virErrorPtr err = virGetLastError();
+ VIR_ERROR(_("Failed to reattach PCI device %s: %s"),
+ virPCIDeviceGetName(actual),
+ err ? err->message : _("unknown error"));
+ virResetError(err);
+ goto out;
+ }
+
+ ret = 0;
+
+ out:
+ return ret;
+}
+
int
virHostdevPreparePCIDevices(virHostdevManagerPtr hostdev_mgr,
const char *drv_name,
@@ -753,45 +821,6 @@ virHostdevPreparePCIDevices(virHostdevManagerPtr hostdev_mgr,
return ret;
}
-/*
- * Pre-condition: inactivePCIHostdevs & activePCIHostdevs
- * are locked
- */
-static void
-virHostdevReattachPCIDevice(virPCIDevicePtr dev, virHostdevManagerPtr mgr)
-{
- /* If the device is not managed and was attached to guest
- * successfully, it must have been inactive.
- */
- if (!virPCIDeviceGetManaged(dev)) {
- VIR_DEBUG("Adding unmanaged PCI device %s to inactive list",
- virPCIDeviceGetName(dev));
- if (virPCIDeviceListAdd(mgr->inactivePCIHostdevs, dev) < 0)
- virPCIDeviceFree(dev);
- return;
- }
-
- /* Wait for device cleanup if it is qemu/kvm */
- if (virPCIDeviceGetStubDriver(dev) == VIR_PCI_STUB_DRIVER_KVM) {
- int retries = 100;
- while (virPCIDeviceWaitForCleanup(dev, "kvm_assigned_device")
- && retries) {
- usleep(100*1000);
- retries--;
- }
- }
-
- VIR_DEBUG("Reattaching PCI device %s", virPCIDeviceGetName(dev));
- if (virPCIDeviceReattach(dev, mgr->activePCIHostdevs,
- mgr->inactivePCIHostdevs) < 0) {
- virErrorPtr err = virGetLastError();
- VIR_ERROR(_("Failed to re-attach PCI device: %s"),
- err ? err->message : _("unknown error"));
- virResetError(err);
- }
- virPCIDeviceFree(dev);
-}
-
/* @oldStateDir:
* For upgrade purpose: see virHostdevNetConfigRestore
*/
@@ -803,7 +832,7 @@ virHostdevReAttachPCIDevices(virHostdevManagerPtr hostdev_mgr,
int nhostdevs,
const char *oldStateDir)
{
- virPCIDeviceListPtr pcidevs;
+ virPCIDeviceListPtr pcidevs = NULL;
size_t i;
if (!nhostdevs)
@@ -848,11 +877,25 @@ virHostdevReAttachPCIDevices(virHostdevManagerPtr hostdev_mgr,
continue;
}
}
+ i++;
+ }
+
+ /* Step 2: move all devices from the active list to the inactive list */
+ for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
+ virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i);
+ virPCIDevicePtr actual;
VIR_DEBUG("Removing PCI device %s from active list",
virPCIDeviceGetName(dev));
- virPCIDeviceListDel(hostdev_mgr->activePCIHostdevs, dev);
- i++;
+ if (!(actual = virPCIDeviceListSteal(hostdev_mgr->activePCIHostdevs,
+ dev)))
+ goto cleanup;
+
+ VIR_DEBUG("Adding PCI device %s to inactive list",
+ virPCIDeviceGetName(actual));
+ if (virPCIDeviceListAdd(hostdev_mgr->inactivePCIHostdevs,
+ actual) < 0)
+ goto cleanup;
}
/* At this point, any device that had been used by the guest is in
@@ -900,13 +943,14 @@ virHostdevReAttachPCIDevices(virHostdevManagerPtr hostdev_mgr,
/* Loop 4: reattach devices to their host drivers (if managed) or place
* them on the inactive list (if not managed)
*/
- while (virPCIDeviceListCount(pcidevs) > 0) {
- virPCIDevicePtr dev = virPCIDeviceListStealIndex(pcidevs, 0);
- virHostdevReattachPCIDevice(dev, hostdev_mgr);
+ for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
+ virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i);
+
+ ignore_value(virHostdevOnlyReattachPCIDevice(hostdev_mgr, dev, true));
}
- virObjectUnref(pcidevs);
cleanup:
+ virObjectUnref(pcidevs);
virObjectUnlock(hostdev_mgr->activePCIHostdevs);
virObjectUnlock(hostdev_mgr->inactivePCIHostdevs);
}
--
2.5.0