(This isn't as bad as it sounds - it's only a problem in case of an OOM error.) qemuGetActivePciHostDeviceList() had been creating a list that contained pointers to objects that were also on the activePciHostdevs list. In case of an OOM error, this newly created list would be virObjectUnref'ed, which would cause everything on the list to be freed. But all of those objects would still be on the activePciHostdevs list, which could have very bad consequences if that list was ever again accessed. The solution used here is to populate the new list with *copies* of the objects from the original list. It turns out that on return from qemuGetActivePciHostDeviceList(), the caller would almost immediately go through all the device objects and "steal" them (i.e. remove the pointer from the list but not delete it) all from either one list or the other; we now instead just *delete* (remove from the list and free) each device from one list or the other, so in the end we have the same state. --- src/qemu/qemu_hostdev.c | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/src/qemu/qemu_hostdev.c b/src/qemu/qemu_hostdev.c index d7d54d7..09ac6ad 100644 --- a/src/qemu/qemu_hostdev.c +++ b/src/qemu/qemu_hostdev.c @@ -86,6 +86,12 @@ qemuGetPciHostDeviceList(virDomainHostdevDefPtr *hostdevs, int nhostdevs) } /* + * qemuGetActivePciHostDeviceList - make a new list with a *copy* of + * every virPCIDevice object that is found on the activePciHostdevs + * list *and* is in the hostdev list for this domain. + * + * Return the new list, or NULL if there was a failure. + * * Pre-condition: driver->activePciHostdevs is locked */ static virPCIDeviceListPtr @@ -101,7 +107,7 @@ qemuGetActivePciHostDeviceList(virQEMUDriverPtr driver, for (i = 0; i < nhostdevs; i++) { virDomainHostdevDefPtr hostdev = hostdevs[i]; - virPCIDevicePtr dev; + virDevicePCIAddressPtr addr; virPCIDevicePtr activeDev; if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) @@ -109,24 +115,14 @@ qemuGetActivePciHostDeviceList(virQEMUDriverPtr driver, if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) continue; - dev = virPCIDeviceNew(hostdev->source.subsys.u.pci.addr.domain, - hostdev->source.subsys.u.pci.addr.bus, - hostdev->source.subsys.u.pci.addr.slot, - hostdev->source.subsys.u.pci.addr.function); - if (!dev) { + addr = &hostdev->source.subsys.u.pci.addr; + activeDev = virPCIDeviceListFindByIDs(driver->activePciHostdevs, + addr->domain, addr->bus, + addr->slot, addr->function); + if (activeDev && virPCIDeviceListAddCopy(list, activeDev) < 0) { virObjectUnref(list); return NULL; } - - if ((activeDev = virPCIDeviceListFind(driver->activePciHostdevs, dev))) { - if (virPCIDeviceListAdd(list, activeDev) < 0) { - virPCIDeviceFree(dev); - virObjectUnref(list); - return NULL; - } - } - - virPCIDeviceFree(dev); } return list; @@ -1084,20 +1080,24 @@ void qemuDomainReAttachHostdevDevices(virQEMUDriverPtr driver, virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i); virPCIDevicePtr activeDev = NULL; - /* Never delete the dev from list driver->activePciHostdevs - * if it's used by other domain. + /* delete the copy of the dev from pcidevs if it's used by + * other domain. Or delete it from activePciHostDevs if it had + * been used by this domain. */ activeDev = virPCIDeviceListFind(driver->activePciHostdevs, dev); if (activeDev && STRNEQ_NULLABLE(name, virPCIDeviceGetUsedBy(activeDev))) { - virPCIDeviceListSteal(pcidevs, dev); + virPCIDeviceListDel(pcidevs, dev); continue; } - /* virObjectUnref() will take care of freeing the dev. */ - virPCIDeviceListSteal(driver->activePciHostdevs, dev); + virPCIDeviceListDel(driver->activePciHostdevs, dev); } + /* At this point, any device that had been used by the guest is in + * pcidevs, but has been removed from activePciHostdevs. + */ + /* * For SRIOV net host devices, unset mac and port profile before * reset and reattach device -- 1.7.11.7 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list