After this patch, ownership of virPCIDevice instances is very easy to keep track of: for each host PCI device, the only instance that actually matters is the one inside one of the bookkeeping list. Whenever some operation needs to be performed on a PCI device, the actual device is looked up first; when this is not the case, a comment explains the reason. --- src/util/virhostdev.c | 118 +++++++++++++++++++++++++++----------------------- 1 file changed, 65 insertions(+), 53 deletions(-) diff --git a/src/util/virhostdev.c b/src/util/virhostdev.c index d1529c5..b2f54cd 100644 --- a/src/util/virhostdev.c +++ b/src/util/virhostdev.c @@ -618,28 +618,22 @@ virHostdevPreparePCIDevices(virHostdevManagerPtr mgr, last_processed_hostdev_vf = i; } - /* Step 5: Now mark all the devices as active */ + /* Step 5: Move devices from the inactive list to the active list */ for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) { virPCIDevicePtr pci = virPCIDeviceListGet(pcidevs, i); + virPCIDevicePtr actual; - VIR_DEBUG("Adding PCI device %s to active list", + VIR_DEBUG("Removing PCI device %s from inactive list", virPCIDeviceGetName(pci)); - if (virPCIDeviceListAdd(mgr->activePCIHostdevs, pci) < 0) - goto inactivedevs; - } - - /* Step 6: Now remove the devices from inactive list. */ - for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) { - virPCIDevicePtr pci = virPCIDeviceListGet(pcidevs, i); + actual = virPCIDeviceListSteal(mgr->inactivePCIHostdevs, pci); - VIR_DEBUG("Removing PCI device %s from inactive list", + VIR_DEBUG("Adding PCI device %s to active list", virPCIDeviceGetName(pci)); - virPCIDeviceListDel(mgr->inactivePCIHostdevs, pci); + if (!actual || virPCIDeviceListAdd(mgr->activePCIHostdevs, actual) < 0) + goto inactivedevs; } - /* Step 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 pci, actual; @@ -655,7 +649,7 @@ virHostdevPreparePCIDevices(virHostdevManagerPtr mgr, virPCIDeviceSetUsedBy(actual, drv_name, dom_name); } - /* Step 8: Now set the original states for hostdev def */ + /* Step 7: Now set the original states for hostdev def */ for (i = 0; i < nhostdevs; i++) { virPCIDevicePtr actual; virDomainHostdevDefPtr hostdev = hostdevs[i]; @@ -690,23 +684,25 @@ virHostdevPreparePCIDevices(virHostdevManagerPtr mgr, } } - /* Step 9: Now steal all the devices from pcidevs */ - while (virPCIDeviceListCount(pcidevs) > 0) - virPCIDeviceListStealIndex(pcidevs, 0); - ret = 0; goto cleanup; inactivedevs: - /* Only steal all the devices from activePCIHostdevs. We will - * free them in virObjectUnref(). - */ + /* Move devices back to the inactive list so that they can be + * processed properly below (reattachdevs label) */ for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) { virPCIDevicePtr pci = virPCIDeviceListGet(pcidevs, i); + virPCIDevicePtr actual; VIR_DEBUG("Removing PCI device %s from active list", virPCIDeviceGetName(pci)); - virPCIDeviceListSteal(mgr->activePCIHostdevs, pci); + if (!(actual = virPCIDeviceListSteal(mgr->activePCIHostdevs, pci))) + continue; + + VIR_DEBUG("Adding PCI device %s to inactive list", + virPCIDeviceGetName(pci)); + if (virPCIDeviceListAdd(mgr->inactivePCIHostdevs, actual) < 0) + continue; } resetvfnetconfig: @@ -716,16 +712,22 @@ virHostdevPreparePCIDevices(virHostdevManagerPtr mgr, reattachdevs: for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) { virPCIDevicePtr pci = virPCIDeviceListGet(pcidevs, i); + virPCIDevicePtr actual; - if (virPCIDeviceGetManaged(pci)) { + /* We need to look up the actual device because that's what + * virPCIDeviceReattach() exepects as its argument */ + if (!(actual = virPCIDeviceListFind(mgr->inactivePCIHostdevs, pci))) + continue; + + if (virPCIDeviceGetManaged(actual)) { VIR_DEBUG("Reattaching managed PCI device %s", - virPCIDeviceGetName(pci)); - ignore_value(virPCIDeviceReattach(pci, + virPCIDeviceGetName(actual)); + ignore_value(virPCIDeviceReattach(actual, mgr->activePCIHostdevs, mgr->inactivePCIHostdevs)); } else { VIR_DEBUG("Not reattaching unmanaged PCI device %s", - virPCIDeviceGetName(pci)); + virPCIDeviceGetName(actual)); } } @@ -745,17 +747,6 @@ static void virHostdevReattachPCIDevice(virHostdevManagerPtr mgr, virPCIDevicePtr actual) { - /* If the device is not managed and was attached to guest - * successfully, it must have been inactive. - */ - if (!virPCIDeviceGetManaged(actual)) { - VIR_DEBUG("Adding unmanaged PCI device %s to inactive list", - virPCIDeviceGetName(actual)); - if (virPCIDeviceListAdd(mgr->inactivePCIHostdevs, actual) < 0) - virPCIDeviceFree(actual); - return; - } - /* Wait for device cleanup if it is qemu/kvm */ if (virPCIDeviceGetStubDriver(actual) == VIR_PCI_STUB_DRIVER_KVM) { int retries = 100; @@ -774,7 +765,6 @@ virHostdevReattachPCIDevice(virHostdevManagerPtr mgr, err ? err->message : _("unknown error")); virResetError(err); } - virPCIDeviceFree(actual); } /* @oldStateDir: @@ -836,17 +826,29 @@ virHostdevReAttachPCIDevices(virHostdevManagerPtr mgr, continue; } + i++; + } + + /* Step 2: Move devices from the active list to the inactive list */ + for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) { + virPCIDevicePtr pci = virPCIDeviceListGet(pcidevs, i); + virPCIDevicePtr actual; + VIR_DEBUG("Removing PCI device %s from active list", virPCIDeviceGetName(pci)); - virPCIDeviceListDel(mgr->activePCIHostdevs, pci); - i++; + actual = virPCIDeviceListSteal(mgr->activePCIHostdevs, pci); + + if (actual) { + VIR_DEBUG("Adding PCI device %s to inactive list", + virPCIDeviceGetName(pci)); + virPCIDeviceListAdd(mgr->inactivePCIHostdevs, actual); + } } - /* At this point, any device that had been used by the guest is in - * pcidevs, but has been removed from activePCIHostdevs. - */ + /* At this point, any device that had been used by the guest has been + * moved to the inactive list */ - /* Step 2: restore original network config of hostdevs that used + /* Step 3: restore original network config of hostdevs that used * <interface type='hostdev'> */ for (i = 0; i < nhostdevs; i++) { @@ -871,7 +873,7 @@ virHostdevReAttachPCIDevices(virHostdevManagerPtr mgr, } } - /* Step 3: perform a PCI Reset on all devices */ + /* Step 4: perform a PCI Reset on all devices */ for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) { virPCIDevicePtr pci = virPCIDeviceListGet(pcidevs, i); @@ -888,16 +890,26 @@ virHostdevReAttachPCIDevices(virHostdevManagerPtr mgr, } } - /* Step 4: reattach devices to their host drivers (if managed) or place - * them on the inactive list (if not managed) - */ - while (virPCIDeviceListCount(pcidevs) > 0) { - virPCIDevicePtr pci = virPCIDeviceListStealIndex(pcidevs, 0); - virHostdevReattachPCIDevice(mgr, pci); + /* Step 5: Reattach managed devices to their host drivers; unmanaged + * devices don't need to be processed further */ + for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) { + virPCIDevicePtr pci = virPCIDeviceListGet(pcidevs, i); + virPCIDevicePtr actual; + + /* We need to look up the actual device because that's what + * virHostdevReattachPCIDevice() expects as its argument */ + if (!(actual = virPCIDeviceListFind(mgr->inactivePCIHostdevs, pci))) + continue; + + if (virPCIDeviceGetManaged(actual)) + virHostdevReattachPCIDevice(mgr, actual); + else + VIR_DEBUG("Not reattaching unmanaged PCI device %s", + virPCIDeviceGetName(actual)); } - virObjectUnref(pcidevs); cleanup: + virObjectUnref(pcidevs); virObjectUnlock(mgr->activePCIHostdevs); virObjectUnlock(mgr->inactivePCIHostdevs); } -- 2.5.0 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list