This function mirrors reattachPCIDevices().
The handling of active and inactive devices is updated and made more
explicit, which means virHostdevPreparePCIDevices() has to be
updated as well.
---
src/util/virhostdev.c | 125 ++++++++++++++++++++++++++++++--------------------
1 file changed, 76 insertions(+), 49 deletions(-)
diff --git a/src/util/virhostdev.c b/src/util/virhostdev.c
index 74c43f2..2d219dd 100644
--- a/src/util/virhostdev.c
+++ b/src/util/virhostdev.c
@@ -593,6 +593,56 @@ reattachPCIDevices(virHostdevManagerPtr mgr,
return ret;
}
+/**
+ * detachPCIDevices:
+ * @mgr: hostdev manager
+ * @pcidevs: PCI devices to be detached
+ * @skipUnmanaged: whether to skip unmanaged devices
+ *
+ * Detach PCI devices from the host.
+ *
+ * The PCI related parts of @mgr (inactivePCIHostdevs, activePCIHostdevs)
+ * must have been locked beforehand using virObjectLock().
+ *
+ * Returns: 0 on success, <0 on failure
+ */
+static int
+detachPCIDevices(virHostdevManagerPtr mgr,
+ virPCIDeviceListPtr pcidevs,
+ bool skipUnmanaged)
+{
+ size_t i;
+ int ret = -1;
+
+ for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
+ virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i);
+
+ /* Skip unmanaged devices if asked to do so */
+ if (!virPCIDeviceGetManaged(dev) && skipUnmanaged) {
+ VIR_DEBUG("Not detaching unmanaged PCI device %s",
+ virPCIDeviceGetName(dev));
+ continue;
+ }
+
+ VIR_DEBUG("Detaching managed PCI device %s",
+ virPCIDeviceGetName(dev));
+ if (virPCIDeviceDetach(dev,
+ mgr->activePCIHostdevs,
+ mgr->inactivePCIHostdevs) < 0) {
+ virErrorPtr err = virGetLastError();
+ VIR_ERROR(_("Failed to detach PCI device: %s"),
+ err ? err->message : _("unknown error"));
+ virResetError(err);
+ goto out;
+ }
+ }
+
+ ret = 0;
+
+ out:
+ return ret;
+}
+
int
virHostdevPreparePCIDevices(virHostdevManagerPtr hostdev_mgr,
const char *drv_name,
@@ -624,11 +674,10 @@ virHostdevPreparePCIDevices(virHostdevManagerPtr hostdev_mgr,
* must be reset before being marked as active.
*/
- /* Loop 1: validate that non-managed device isn't in use, eg
- * by checking that device is either un-bound, or bound
- * to pci-stub.ko
- */
+ /* Detaching devices from the host involves several steps; each of them
+ * is described at length below */
+ /* Step 1: perform safety checks, eg. ensure the devices are assignable */
for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i);
bool strict_acs_check = !!(flags & VIR_HOSTDEV_STRICT_ACS_CHECK);
@@ -659,28 +708,15 @@ virHostdevPreparePCIDevices(virHostdevManagerPtr hostdev_mgr,
}
}
- /* Loop 2: detach managed devices (i.e. bind to appropriate stub driver) */
- for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
- virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i);
-
- if (virPCIDeviceGetManaged(dev)) {
- VIR_DEBUG("Detaching managed PCI device %s",
- virPCIDeviceGetName(dev));
- if (virPCIDeviceDetach(dev,
- hostdev_mgr->activePCIHostdevs,
- hostdev_mgr->inactivePCIHostdevs) < 0)
- goto reattachdevs;
- } else {
- VIR_DEBUG("Not detaching unmanaged PCI device %s",
- virPCIDeviceGetName(dev));
- }
- }
+ /* Step 2: detach managed devices (i.e. bind to appropriate stub driver).
+ * detachPCIDevices() will also mark devices as inactive */
+ if (detachPCIDevices(hostdev_mgr, pcidevs, true) < 0)
+ goto reattachdevs;
- /* At this point, all devices are attached to the stub driver and have
+ /* At this point, devices are attached to the stub driver and have
* been marked as inactive */
- /* Loop 3: Now that all the PCI hostdevs have been detached, we
- * can safely reset them */
+ /* Step 3: perform a PCI reset on all devices */
for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i);
@@ -690,8 +726,7 @@ virHostdevPreparePCIDevices(virHostdevManagerPtr hostdev_mgr,
goto reattachdevs;
}
- /* Loop 4: For SRIOV network devices, Now that we have detached the
- * the network device, set the netdev config */
+ /* Step 4: set the netdev config for SRIOV network devices */
for (i = 0; i < nhostdevs; i++) {
virDomainHostdevDefPtr hostdev = hostdevs[i];
if (!virHostdevIsPCINetDevice(hostdev))
@@ -703,9 +738,16 @@ virHostdevPreparePCIDevices(virHostdevManagerPtr hostdev_mgr,
last_processed_hostdev_vf = i;
}
- /* Loop 5: Now mark all the devices as active */
+ /* Step 5: move all devices from the inactive list to the active list */
for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
- virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i);
+ virPCIDevicePtr tmp = virPCIDeviceListGet(pcidevs, i);
+ virPCIDevicePtr dev;
+
+ VIR_DEBUG("Removing PCI device %s from inactive list",
+ virPCIDeviceGetName(tmp));
+ if (!(dev = virPCIDeviceListSteal(hostdev_mgr->inactivePCIHostdevs,
+ tmp)))
+ goto inactivedevs;
VIR_DEBUG("Adding PCI device %s to active list",
virPCIDeviceGetName(dev));
@@ -713,18 +755,7 @@ virHostdevPreparePCIDevices(virHostdevManagerPtr hostdev_mgr,
goto inactivedevs;
}
- /* Loop 6: Now remove the devices from inactive list. */
- for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
- virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i);
-
- VIR_DEBUG("Removing PCI device %s from inactive list",
- virPCIDeviceGetName(dev));
- virPCIDeviceListDel(hostdev_mgr->inactivePCIHostdevs, dev);
- }
-
- /* Loop 7: Now set the used_by_domain of the device in
- * activePCIHostdevs as domain name.
- */
+ /* Step 6: set driver and domain information */
for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
virPCIDevicePtr dev, activeDev;
@@ -737,7 +768,7 @@ virHostdevPreparePCIDevices(virHostdevManagerPtr hostdev_mgr,
virPCIDeviceSetUsedBy(activeDev, drv_name, dom_name);
}
- /* Loop 8: Now set the original states for hostdev def */
+ /* Step 7: set the original states for hostdev def */
for (i = 0; i < nhostdevs; i++) {
virPCIDevicePtr dev;
virPCIDevicePtr pcidev;
@@ -752,10 +783,9 @@ virHostdevPreparePCIDevices(virHostdevManagerPtr hostdev_mgr,
dev = virPCIDeviceNew(pcisrc->addr.domain, pcisrc->addr.bus,
pcisrc->addr.slot, pcisrc->addr.function);
- /* original states "unbind_from_stub", "remove_slot",
- * "reprobe" were already set by pciDettachDevice in
- * loop 2.
- */
+ /* original states for "unbind_from_stub", "remove_slot" and
+ * "reprobe" (used when reattaching) were already set by
+ * detachPCIDevices() in a previous step */
VIR_DEBUG("Saving network configuration of PCI device %s",
virPCIDeviceGetName(dev));
if ((pcidev = virPCIDeviceListFind(pcidevs, dev))) {
@@ -770,10 +800,6 @@ virHostdevPreparePCIDevices(virHostdevManagerPtr hostdev_mgr,
virPCIDeviceFree(dev);
}
- /* Loop 9: Now steal all the devices from pcidevs */
- while (virPCIDeviceListCount(pcidevs) > 0)
- virPCIDeviceListStealIndex(pcidevs, 0);
-
ret = 0;
goto cleanup;
@@ -798,9 +824,10 @@ virHostdevPreparePCIDevices(virHostdevManagerPtr hostdev_mgr,
ignore_value(reattachPCIDevices(hostdev_mgr, pcidevs, true));
cleanup:
+ virObjectUnref(pcidevs);
virObjectUnlock(hostdev_mgr->activePCIHostdevs);
virObjectUnlock(hostdev_mgr->inactivePCIHostdevs);
- virObjectUnref(pcidevs);
+
return ret;
}
--
2.5.0