On 10/13/2016 01:43 PM, Laine Stump wrote:
On 10/11/2016 05:34 AM, Andrea Bolognani wrote:
> On Mon, 2016-10-10 at 15:43 -0400, Laine Stump wrote:
>>>> 3) Although it is strongly discouraged, it is legal for a pci-bridge
>>>> to be directly plugged into pcie-root, and we don't want to
>>>> auto-add a dmi-to-pci-bridge if there is already a pci-bridge
>>>> that's been forced directly into pcie-root. Finally,
>>>> although I
>>>> fail to see the utility of it, it is legal to have
>>>> something like
>>>> this in the xml:
>>>> <controller type='pci' model='pcie-root'
index='0'/>
>>>> <controller type='pci' model='pci-bridge'
index='2'/>
>>>> and that will lead to an automatically added
>>>> dmi-to-pci-bridge at
>>>> index=1 (to give the unaddressed pci-bridge a proper place
>>>> to plug
>>>> in):
>>>> <controller type='pci'
model='dmi-to-pci-bridge'
>>>> index='1'/>
>>>> (for example, see the existing test case
>>>> "usb-controller-default-q35"). This is handled in
>>>> qemuDomainPCIAddressSetCreate() when it's adding in
>>>> controllers to
>>>> fill holes in the indexes.
>>> I wonder how this "feature" came to be... It seems to be the
>>> reason for quite a bit of convoluted code down below, which
>>> we could avoid if this had never worked at all. As is so
>>> often the case, too late for that :(
>> Maybe not. The only place I ever saw that was in the above test case,
>> and another named "usb-controller-explicit-q35", and the author of
both
>> of those tests was (wait for it!), no, not Albert Einstein. Andrea
>> Bolognani!
> Oh, *that* guy! It's always *that* guy, isn't it? :P
>
>> The only reason it worked in the past was because we always
>> automatically added the dmi-to-pci-bridge very early in the post-parse
>> processing. This implies that any saved config anywhere will already
>> have the necessary dmi-to-pci-bridge at index='1', so we only need to
>> preserve the behavior for new domain definitions that have a pci-bridge
>> at index='2' but nothing at index='1'.
>> Since you're the only person documented to have ever created a config
>> like that, and it would only be problematic if someone tried to create
>> another new config, maybe we should just stop accidentally
>> supporting it
>> and count it as a bug that's being fixed. What's your opinion?
> Given the evidence you're presenting, I'm all for getting
> rid of it, especially since it will make the code below
> much simpler and hence more maintainable.
>
> Considering how critical that part of libvirt is, anything
> we can do to make it leaner and meaner is going to be a huge
> win in the long run.
I'm looking back through the code and wondering how to simplify it -
it may be that the alternate method I had initially used (which failed
that one test) is just as complicated as what I have now;
unfortunately I didn't save it.
Okay, now I've reminded myself of what I did. Basically everything
necessary for that is the changes to qemuDomainPCIAddressSetCreate()
dealing with "lowest*Bridge" (see the patch excerpt below). I would
still need to patch this function even if we didn't support "auto-adding
dmi-to-pci-bridge when a pci-bridge is present in the config", but it
would be slightly simpler.
I'll split it into a separate patch so that it's more apparent, and we
can decide based on that.
On 09/20/2016 03:14 PM, Laine Stump wrote:
diff --git a/src/qemu/qemu_domain_address.c
b/src/qemu/qemu_domain_address.c
index 1ff80e3..a9c4c32 100644
--- a/src/qemu/qemu_domain_address.c
+++ b/src/qemu/qemu_domain_address.c
@@ -797,6 +797,11 @@ qemuDomainPCIAddressSetCreate(virDomainDefPtr def,
{
virDomainPCIAddressSetPtr addrs;
size_t i;
+ bool hasPCIeRoot = false;
+ int lowestDMIToPCIBridge = nbuses;
+ int lowestUnaddressedPCIBridge = nbuses;
+ int lowestAddressedPCIBridge = nbuses;
+ virDomainControllerModelPCI defaultModel;
if ((addrs = virDomainPCIAddressSetAlloc(nbuses)) == NULL)
return NULL;
@@ -804,38 +809,84 @@ qemuDomainPCIAddressSetCreate(virDomainDefPtr def,
addrs->nbuses = nbuses;
addrs->dryRun = dryRun;
- /* As a safety measure, set default model='pci-root' for first pci
- * controller and 'pci-bridge' for all subsequent. After setting
- * those defaults, then scan the config and set the actual model
- * for all addrs[idx]->bus that already have a corresponding
- * controller in the config.
- *
- */
- if (nbuses > 0)
- virDomainPCIAddressBusSetModel(&addrs->buses[0],
- VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT);
- for (i = 1; i < nbuses; i++) {
- virDomainPCIAddressBusSetModel(&addrs->buses[i],
- VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE);
- }
-
for (i = 0; i < def->ncontrollers; i++) {
- size_t idx = def->controllers[i]->idx;
+ virDomainControllerDefPtr cont = def->controllers[i];
+ size_t idx = cont->idx;
- if (def->controllers[i]->type != VIR_DOMAIN_CONTROLLER_TYPE_PCI)
+ if (cont->type != VIR_DOMAIN_CONTROLLER_TYPE_PCI)
continue;
if (idx >= addrs->nbuses) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("Inappropriate new pci controller index %zu "
- "not found in addrs"), idx);
+ "exceeds addrs array length"), idx);
goto error;
}
- if (virDomainPCIAddressBusSetModel(&addrs->buses[idx],
- def->controllers[i]->model) < 0)
+ if (virDomainPCIAddressBusSetModel(&addrs->buses[idx], cont->model)
< 0)
goto error;
+
+ /* we'll use all this info later to determine if we need
+ * to add a dmi-to-pci-bridge due to unaddressed pci-bridge controllers
+ */
+ if (cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT) {
+ hasPCIeRoot = true;
+ } else if (cont->model ==
+ VIR_DOMAIN_CONTROLLER_MODEL_DMI_TO_PCI_BRIDGE) {
+ if (lowestDMIToPCIBridge > idx)
+ lowestDMIToPCIBridge = idx;
+ } else if (cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE) {
+ if (virDeviceInfoPCIAddressWanted(&cont->info)) {
+ if (lowestUnaddressedPCIBridge > idx)
+ lowestUnaddressedPCIBridge = idx;
+ } else {
+ if (lowestAddressedPCIBridge > idx)
+ lowestAddressedPCIBridge = idx;
+ }
}
+ }
+
+ if (nbuses > 0 && !addrs->buses[0].model) {
+ if (virDomainPCIAddressBusSetModel(&addrs->buses[0],
+ VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT) <
0)
+ goto error;
+ }
+
+ /* Now fill in a reasonable model for all the buses in the set
+ * that don't yet have a corresponding controller in the domain
+ * config. In the rare (and actually fairly idiotic, but still
+ * allowed for some reason) case that a domain has 1) a pcie-root
+ * at index 0, 2)*no* dmi-to-pci-bridge (or pci-bridge that was
+ * manually addressed to sit directly on pcie-root), and 3) does
+ * have an unaddressed pci-bridge at an index > 1, then we need to
+ * add a dmi-to-pci-bridge.
+ */
+
+ if (!hasPCIeRoot)
+ defaultModel = VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE;
+
+ else if (lowestUnaddressedPCIBridge < MIN(lowestAddressedPCIBridge,
+ lowestDMIToPCIBridge))
+ defaultModel = VIR_DOMAIN_CONTROLLER_MODEL_DMI_TO_PCI_BRIDGE;
+ else
+ defaultModel = VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT_PORT;
+
+ for (i = 1; i < addrs->nbuses; i++) {
+
+ if (addrs->buses[i].model)
+ continue;
+
+ if (virDomainPCIAddressBusSetModel(&addrs->buses[i], defaultModel) <
0)
+ goto error;
+
+ VIR_DEBUG("Auto-adding <controller type='pci' model='%s'
index='%zu'/>",
+ virDomainControllerModelPCITypeToString(defaultModel), i);
+ /* only add a single dmi-to-pci-bridge, then add pcie-root-port
+ * for any other unspecified controller indexes.
+ */
+ if (hasPCIeRoot)
+ defaultModel = VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT_PORT;
+ }