mirror of
https://github.com/libvirt/libvirt.git
synced 2025-02-25 18:55:26 -06:00
hostdev: Streamline device ownership tracking
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.
This commit is contained in:
parent
6da6bf2f30
commit
811286090f
@ -527,10 +527,7 @@ virHostdevPreparePCIDevices(virHostdevManagerPtr mgr,
|
|||||||
* impacts all devices on it. Also, all devices must be reset
|
* impacts all devices on it. Also, all devices must be reset
|
||||||
* before being marked as active */
|
* before being marked as active */
|
||||||
|
|
||||||
/* Step 1: validate that non-managed device isn't in use, eg
|
/* Step 1: Perform some initial checks on the devices */
|
||||||
* by checking that device is either un-bound, or bound
|
|
||||||
* to pci-stub.ko
|
|
||||||
*/
|
|
||||||
for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
|
for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
|
||||||
virPCIDevicePtr pci = virPCIDeviceListGet(pcidevs, i);
|
virPCIDevicePtr pci = virPCIDeviceListGet(pcidevs, i);
|
||||||
bool strict_acs_check = !!(flags & VIR_HOSTDEV_STRICT_ACS_CHECK);
|
bool strict_acs_check = !!(flags & VIR_HOSTDEV_STRICT_ACS_CHECK);
|
||||||
@ -659,28 +656,22 @@ virHostdevPreparePCIDevices(virHostdevManagerPtr mgr,
|
|||||||
last_processed_hostdev_vf = i;
|
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);
|
|
||||||
|
|
||||||
VIR_DEBUG("Adding PCI device %s to active 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++) {
|
for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
|
||||||
virPCIDevicePtr pci = virPCIDeviceListGet(pcidevs, i);
|
virPCIDevicePtr pci = virPCIDeviceListGet(pcidevs, i);
|
||||||
|
virPCIDevicePtr actual;
|
||||||
|
|
||||||
VIR_DEBUG("Removing PCI device %s from inactive list",
|
VIR_DEBUG("Removing PCI device %s from inactive list",
|
||||||
virPCIDeviceGetName(pci));
|
virPCIDeviceGetName(pci));
|
||||||
virPCIDeviceListDel(mgr->inactivePCIHostdevs, pci);
|
actual = virPCIDeviceListSteal(mgr->inactivePCIHostdevs, pci);
|
||||||
|
|
||||||
|
VIR_DEBUG("Adding PCI device %s to active list",
|
||||||
|
virPCIDeviceGetName(pci));
|
||||||
|
if (!actual || virPCIDeviceListAdd(mgr->activePCIHostdevs, actual) < 0)
|
||||||
|
goto inactivedevs;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Step 7: Now set the used_by_domain of the device in
|
/* Step 6: Set driver and domain information */
|
||||||
* activePCIHostdevs as domain name.
|
|
||||||
*/
|
|
||||||
for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
|
for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
|
||||||
virPCIDevicePtr pci, actual;
|
virPCIDevicePtr pci, actual;
|
||||||
|
|
||||||
@ -696,7 +687,7 @@ virHostdevPreparePCIDevices(virHostdevManagerPtr mgr,
|
|||||||
virPCIDeviceSetUsedBy(actual, drv_name, dom_name);
|
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++) {
|
for (i = 0; i < nhostdevs; i++) {
|
||||||
virPCIDevicePtr pci;
|
virPCIDevicePtr pci;
|
||||||
virDomainHostdevDefPtr hostdev = hostdevs[i];
|
virDomainHostdevDefPtr hostdev = hostdevs[i];
|
||||||
@ -728,23 +719,26 @@ virHostdevPreparePCIDevices(virHostdevManagerPtr mgr,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Step 9: Now steal all the devices from pcidevs */
|
|
||||||
while (virPCIDeviceListCount(pcidevs) > 0)
|
|
||||||
virPCIDeviceListStealIndex(pcidevs, 0);
|
|
||||||
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
inactivedevs:
|
inactivedevs:
|
||||||
/* Only steal all the devices from activePCIHostdevs. We will
|
/* Move devices back to the inactive list so that they can be
|
||||||
* free them in virObjectUnref().
|
* processed properly below (reattachdevs label) */
|
||||||
*/
|
|
||||||
for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
|
for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
|
||||||
virPCIDevicePtr pci = virPCIDeviceListGet(pcidevs, i);
|
virPCIDevicePtr pci = virPCIDeviceListGet(pcidevs, i);
|
||||||
|
virPCIDevicePtr actual;
|
||||||
|
|
||||||
VIR_DEBUG("Removing PCI device %s from active list",
|
VIR_DEBUG("Removing PCI device %s from active list",
|
||||||
virPCIDeviceGetName(pci));
|
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)
|
||||||
|
VIR_WARN("Failed to add PCI device %s to the inactive list",
|
||||||
|
virPCIDeviceGetName(pci));
|
||||||
}
|
}
|
||||||
|
|
||||||
resetvfnetconfig:
|
resetvfnetconfig:
|
||||||
@ -756,11 +750,17 @@ virHostdevPreparePCIDevices(virHostdevManagerPtr mgr,
|
|||||||
reattachdevs:
|
reattachdevs:
|
||||||
for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
|
for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
|
||||||
virPCIDevicePtr pci = virPCIDeviceListGet(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",
|
VIR_DEBUG("Reattaching managed PCI device %s",
|
||||||
virPCIDeviceGetName(pci));
|
virPCIDeviceGetName(pci));
|
||||||
ignore_value(virPCIDeviceReattach(pci,
|
ignore_value(virPCIDeviceReattach(actual,
|
||||||
mgr->activePCIHostdevs,
|
mgr->activePCIHostdevs,
|
||||||
mgr->inactivePCIHostdevs));
|
mgr->inactivePCIHostdevs));
|
||||||
} else {
|
} else {
|
||||||
@ -785,17 +785,6 @@ static void
|
|||||||
virHostdevReattachPCIDevice(virHostdevManagerPtr mgr,
|
virHostdevReattachPCIDevice(virHostdevManagerPtr mgr,
|
||||||
virPCIDevicePtr actual)
|
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 */
|
/* Wait for device cleanup if it is qemu/kvm */
|
||||||
if (virPCIDeviceGetStubDriver(actual) == VIR_PCI_STUB_DRIVER_KVM) {
|
if (virPCIDeviceGetStubDriver(actual) == VIR_PCI_STUB_DRIVER_KVM) {
|
||||||
int retries = 100;
|
int retries = 100;
|
||||||
@ -814,7 +803,6 @@ virHostdevReattachPCIDevice(virHostdevManagerPtr mgr,
|
|||||||
err ? err->message : _("unknown error"));
|
err ? err->message : _("unknown error"));
|
||||||
virResetError(err);
|
virResetError(err);
|
||||||
}
|
}
|
||||||
virPCIDeviceFree(actual);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* @oldStateDir:
|
/* @oldStateDir:
|
||||||
@ -848,9 +836,8 @@ virHostdevReAttachPCIDevices(virHostdevManagerPtr mgr,
|
|||||||
/* Reattaching devices to the host involves several steps; each
|
/* Reattaching devices to the host involves several steps; each
|
||||||
* of them is described at length below */
|
* of them is described at length below */
|
||||||
|
|
||||||
/* Step 1: verify that each device in the hostdevs list really was in use
|
/* Step 1: Filter out all devices that are either not active or not
|
||||||
* by this domain, and remove them all from the activePCIHostdevs list.
|
* used by the current domain and driver */
|
||||||
*/
|
|
||||||
i = 0;
|
i = 0;
|
||||||
while (i < virPCIDeviceListCount(pcidevs)) {
|
while (i < virPCIDeviceListCount(pcidevs)) {
|
||||||
virPCIDevicePtr pci = virPCIDeviceListGet(pcidevs, i);
|
virPCIDevicePtr pci = virPCIDeviceListGet(pcidevs, i);
|
||||||
@ -876,17 +863,34 @@ virHostdevReAttachPCIDevices(virHostdevManagerPtr mgr,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
VIR_DEBUG("Removing PCI device %s from active list",
|
|
||||||
virPCIDeviceGetName(pci));
|
|
||||||
virPCIDeviceListDel(mgr->activePCIHostdevs, pci);
|
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* At this point, any device that had been used by the guest is in
|
/* Step 2: Move devices from the active list to the inactive list */
|
||||||
* pcidevs, but has been removed from activePCIHostdevs.
|
for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
|
||||||
*/
|
virPCIDevicePtr pci = virPCIDeviceListGet(pcidevs, i);
|
||||||
|
virPCIDevicePtr actual;
|
||||||
|
|
||||||
/* Step 2: restore original network config of hostdevs that used
|
VIR_DEBUG("Removing PCI device %s from active list",
|
||||||
|
virPCIDeviceGetName(pci));
|
||||||
|
actual = virPCIDeviceListSteal(mgr->activePCIHostdevs, pci);
|
||||||
|
|
||||||
|
VIR_DEBUG("Adding PCI device %s to inactive list",
|
||||||
|
virPCIDeviceGetName(pci));
|
||||||
|
if (!actual ||
|
||||||
|
virPCIDeviceListAdd(mgr->inactivePCIHostdevs, actual) < 0) {
|
||||||
|
|
||||||
|
virErrorPtr err = virGetLastError();
|
||||||
|
VIR_ERROR(_("Failed to add PCI device %s to the inactive list"),
|
||||||
|
err ? err->message : _("unknown error"));
|
||||||
|
virResetError(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* At this point, any device that had been used by the guest has been
|
||||||
|
* moved to the inactive list */
|
||||||
|
|
||||||
|
/* Step 3: restore original network config of hostdevs that used
|
||||||
* <interface type='hostdev'>
|
* <interface type='hostdev'>
|
||||||
*/
|
*/
|
||||||
for (i = 0; i < nhostdevs; i++) {
|
for (i = 0; i < nhostdevs; i++) {
|
||||||
@ -911,7 +915,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++) {
|
for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
|
||||||
virPCIDevicePtr pci = virPCIDeviceListGet(pcidevs, i);
|
virPCIDevicePtr pci = virPCIDeviceListGet(pcidevs, i);
|
||||||
|
|
||||||
@ -928,16 +932,26 @@ virHostdevReAttachPCIDevices(virHostdevManagerPtr mgr,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Step 4: reattach devices to their host drivers (if managed) or place
|
/* Step 5: Reattach managed devices to their host drivers; unmanaged
|
||||||
* them on the inactive list (if not managed)
|
* devices don't need to be processed further */
|
||||||
*/
|
for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
|
||||||
while (virPCIDeviceListCount(pcidevs) > 0) {
|
virPCIDevicePtr pci = virPCIDeviceListGet(pcidevs, i);
|
||||||
virPCIDevicePtr pci = virPCIDeviceListStealIndex(pcidevs, 0);
|
virPCIDevicePtr actual;
|
||||||
virHostdevReattachPCIDevice(mgr, pci);
|
|
||||||
|
/* 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:
|
cleanup:
|
||||||
|
virObjectUnref(pcidevs);
|
||||||
virObjectUnlock(mgr->activePCIHostdevs);
|
virObjectUnlock(mgr->activePCIHostdevs);
|
||||||
virObjectUnlock(mgr->inactivePCIHostdevs);
|
virObjectUnlock(mgr->inactivePCIHostdevs);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user