
On Tue, 2016-10-25 at 09:49 -0400, Laine Stump wrote:
Set pciConnectFlags in each device's DeviceInfo and then use those flags later when validating existing addresses in qemuDomainCollectPCIAddress() and when assigning new addresses with qemuDomainPCIAddressReserveNextAddr() (rather than scattering the logic about which devices need which type of slot all over the place). Note that the exact flags set by qemuDomainDeviceCalculatePCIConnectFlags() are different from the flags previously set manually in qemuDomainCollectPCIAddress(), but this doesn't matter because all validation of addresses in that case ignores the setting of the HOTPLUGGABLE flag, and treats PCIE_DEVICE and PCI_DEVICE the same (this lax checking was done on purpose, because there are some things that we want to allow the user to specify manually, e.g. assigning a PCIe device to a PCI slot, that we *don't* ever want libvirt to do automatically. The flag settings that we *really* want to match are 1) the old flag settings in qemuDomainAssignDevicePCISlots() (which is HOTPLUGGABLE | PCI_DEVICE for everything except PCI controllers) and the new flag settings done
[...] and 2) the new [...]
by qemuDomainDeviceCalculatePCIConnectFlags() (which are currently exactly that - HOTPLUGGABLE | PCI_DEVICE for everything except PCI controllers). --- src/qemu/qemu_domain_address.c | 205 +++++++++++++++-------------------------- 1 file changed, 74 insertions(+), 131 deletions(-) diff --git a/src/qemu/qemu_domain_address.c b/src/qemu/qemu_domain_address.c index 602179c..d731b19 100644 --- a/src/qemu/qemu_domain_address.c +++ b/src/qemu/qemu_domain_address.c @@ -721,7 +721,7 @@ qemuDomainFillDevicePCIConnectFlagsIter(virDomainDefPtr def ATTRIBUTE_UNUSED, * failure would be some internal problem with * virDomainDeviceInfoIterate()) */ -static int ATTRIBUTE_UNUSED +static int qemuDomainFillAllPCIConnectFlags(virDomainDefPtr def, virQEMUCapsPtr qemuCaps) {
You should remove ATTRIBUTE_UNUSED from qemuDomainFillDevicePCIConnectFlags() as well. [...]
@@ -926,7 +857,7 @@ qemuDomainCollectPCIAddress(virDomainDefPtr def ATTRIBUTE_UNUSED, entireSlot = (addr->function == 0 && addr->multi != VIR_TRISTATE_SWITCH_ON); - if (virDomainPCIAddressReserveAddr(addrs, addr, flags, + if (virDomainPCIAddressReserveAddr(addrs, addr, info->pciConnectFlags, entireSlot, true) < 0)
Would it be cleaner to have a qemuDomainPCIAddressReserveAddr() function that takes @info directly? It would be used only a single time, so it could very well be argued that it would be overkill... On the other hand, it would be neat not to use virDomainPCIAddressReserve*() functions at all in the qemu driver and rely solely on the wrappers instead. Speaking of which, even with the full series applied there are still a bunch of uses of virDomainPCIAddressReserveAddr() and virDomainPCIAddressReserveSlot(), mostly in qemuDomainValidateDevicePCISlots{PIIX3,Q35}(). The attached patch makes all of them go away, except a few that actually make sense because they set aside addresses for potential future devices and as such don't have access to a virDomainDeviceInfo yet. I'm not saying we should deal with this right away: I'd rather go back later to tidy up the whole thing than hold up the series or go through another round of reviews for what is ultimately a cosmetic issue. [...]
@@ -1878,24 +1795,50 @@ qemuDomainAssignPCIAddresses(virDomainDefPtr def, */ if (!buses_reserved && !qemuDomainMachineIsVirt(def) && - qemuDomainPCIAddressReserveNextSlot(addrs, &info, flags) < 0) + qemuDomainPCIAddressReserveNextSlot(addrs, &info) < 0) goto cleanup; if (qemuDomainAssignDevicePCISlots(def, qemuCaps, addrs) < 0) goto cleanup; for (i = 1; i < addrs->nbuses; i++) { + virDomainDeviceDef dev; + int contIndex; virDomainPCIAddressBusPtr bus = &addrs->buses[i]; if ((rv = virDomainDefMaybeAddController( def, VIR_DOMAIN_CONTROLLER_TYPE_PCI, i, bus->model)) < 0) goto cleanup; - /* If we added a new bridge, we will need one more address */ - if (rv > 0 && - qemuDomainPCIAddressReserveNextSlot(addrs, &info, flags) < 0) + + if (rv == 0) + continue; /* no new controller added */
Alternatively, you could turn this into if (rv > 0) { virDomainDeviceDef dev; int contIndex; /* The code below */ } but I leave up to you whether to go one way or the other.
+ + /* We did add a new controller, so we will need one more + * address (and we need to set the new controller's + * pciConnectFlags) + */ + contIndex = virDomainControllerFind(def, + VIR_DOMAIN_CONTROLLER_TYPE_PCI, + i); + if (contIndex < 0) { + /* this should never happen - we just added it */ + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Could not find auto-added %s controller " + "with index %zu"), + virDomainControllerModelPCITypeToString(bus->model), + i); + goto cleanup; + } + dev.type = VIR_DOMAIN_DEVICE_CONTROLLER; + dev.data.controller = def->controllers[contIndex]; + /* set connect flags so it will be properly addressed */ + qemuDomainFillDevicePCIConnectFlags(def, &dev, qemuCaps); + if (qemuDomainPCIAddressReserveNextSlot(addrs, + &dev.data.controller->info) < 0) goto cleanup; } + nbuses = addrs->nbuses; virDomainPCIAddressSetFree(addrs); addrs = NULL;
ACK -- Andrea Bolognani / Red Hat / Virtualization