[libvirt] [PATCH 4/7] hostdev: Add detachPCIDevices()

Andrea Bolognani abologna at redhat.com
Tue Jan 19 15:36:06 UTC 2016


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




More information about the libvir-list mailing list