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 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list