[libvirt] [PATCH v2 10/11] qemu: auto-add bridges and allow using them
Ján Tomko
jtomko at redhat.com
Fri Apr 19 08:12:12 UTC 2013
On 04/19/2013 01:02 AM, Eric Blake wrote:
> On 04/17/2013 01:00 PM, Ján Tomko wrote:
>> @@ -1321,7 +1363,39 @@ qemuDomainAssignPCIAddresses(virDomainDefPtr def,
>> qemuDomainObjPrivatePtr priv = NULL;
>>
>> if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE)) {
>> - if (!(addrs = qemuDomainPCIAddressSetCreate(def)))
>> + int nbuses = 1;
>> + int i;
>> + int rv;
>> +
>> + for (i = 0; i < def->ncontrollers; i++) {
>> + if (def->controllers[i]->type == VIR_DOMAIN_CONTROLLER_TYPE_PCI &&
>> + def->controllers[i]->model == VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE)
>> + nbuses++;
>> + }
>> + if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_PCI_BRIDGE)) {
>> + virDomainDeviceInfo info;
>> + /* 1st pass to figure out how many PCI bridges we need */
>> + if (!(addrs = qemuDomainPCIAddressSetCreate(def, nbuses, true)))
>> + goto cleanup;
>> + if (nbuses && qemuAssignDevicePCISlots(def, qemuCaps, addrs) < 0)
>> + goto cleanup;
>> + /* Reserve 1 extra slot for a (potential) bridge */
>> + if (qemuDomainPCIAddressSetNextAddr(addrs, &info) < 0)
>> + goto cleanup;
>> +
>> + for (i = 1; i < addrs->nbuses; i++) {
>> + if ((rv = virDomainDefMaybeAddController(
>> + def, VIR_DOMAIN_CONTROLLER_TYPE_PCI,
>> + i, VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE)) < 0)
>> + goto cleanup;
>> + /* If we added a new bridge, we will need one more address */
>> + if (rv > 0 && qemuDomainPCIAddressSetNextAddr(addrs, &info) < 0)
>> + goto cleanup;
>> + }
>> + qemuDomainPCIAddressSetFree(addrs);
>> + addrs = NULL;
>> + }
>
> Do we need an else that fails if we have no pci bridge support, but more
> than one pci controller is present?
>
I'd rather disallow multiple PCI controllers with the same index (and
check if pci-root has index 0).
Specifying two bridges with indexes 1 and 3 also doesn't mean that buses
0-2 are available (which is what my code above would think if bus 3
would be unused).
And it would also be nice to add them to qemu command line without
referencing bridges that don't exist yet by requiring that bus < index
in the bridge address and inserting them in order (but I'm worried that
doing so in virDomainDefMaybeAddController might break other things).
>> + if (!(addrs = qemuDomainPCIAddressSetCreate(def, addrs->nbuses, false)))
>> goto cleanup;
>>
>> if (qemuAssignDevicePCISlots(def, qemuCaps, addrs) < 0)
>> @@ -1503,30 +1593,44 @@ qemuDomainPCIAddressGetNextSlot(qemuDomainPCIAddressSetPtr addrs,
>> virDevicePCIAddressPtr next_addr)
>> {
>> virDevicePCIAddress tmp_addr = addrs->lastaddr;
>> - int i;
>> + int i,j;
>
> Space after comma.
>
>> char *addr;
>>
>> tmp_addr.slot++;
>> - for (i = 0; i < QEMU_PCI_ADDRESS_SLOT_LAST; i++, tmp_addr.slot++) {
>> - if (QEMU_PCI_ADDRESS_SLOT_LAST <= tmp_addr.slot) {
>> - tmp_addr.slot = 0;
>> - }
>> + for (j = 0; j < addrs->nbuses; j++) {
>> + for (i = 0; i < QEMU_PCI_ADDRESS_SLOT_LAST; i++, tmp_addr.slot++) {
>> + if (QEMU_PCI_ADDRESS_SLOT_LAST <= tmp_addr.slot) {
>> + /* slot 0 is unusable */
>> + tmp_addr.slot = 1;
>> + i++;
>> + }
>
> I found this use of 'i' a bit confusing - any time you change the
> iteration conditions inside the loop body, it becomes trickier to follow
> the logic. I think you got it right, in that basically you want to
> iterate over 31 slots, instead of 32 (by skipping slot 0), but where the
> slot you probe starts from addrs->lastaddr and wraps around rather than
> starting at 1.
>
> Would it be any clearer if the inner loop iterated over i=1; i <
> SLOT_LAST, so that the only increment of i is in the loop header?
Yes, that would make it slightly less disgusting. Or maybe i=0; i <
SLOT_LAST-1?
>
> Also, I think I see why keeping this cache logic is essential for bus 0
> for back-compat reasons (we want to avoid hot-plugging a new device into
> a previously-used but now unplugged slot, at least until we have run out
> of unique slots to plug into, in order to minimize guest confusion about
> different devices trying to reuse a slot). But do we really need to
> extend it to bus 1? That is, if one call fills the last slot of bus 0
> and sets addrs->lastaddr to 5, do we really want the next call to start
> at slot 5 of bus 1, or even though nothing has ever probed slots 1-4 of
> bus 1? I'm worried that your caching of last-used slot is not quite
> right; in fact, I wonder if you need to cache both last-used bus and
> last-used slot on that bus, or even last-used slot on all buses, rather
> than just a single last-used slot without relation to bus.
>
It does cache the domain, bus and slot.
>>
>> - if (!(addr = qemuPCIAddressAsString(&tmp_addr)))
>> - return -1;
>> + if (!(addr = qemuPCIAddressAsString(&tmp_addr)))
>> + return -1;
>>
>> - if (qemuDomainPCIAddressSlotInUse(addrs, &tmp_addr)) {
>> - VIR_DEBUG("PCI addr %s already in use", addr);
>> - VIR_FREE(addr);
>> - continue;
>> - }
>> + if (qemuDomainPCIAddressSlotInUse(addrs, &tmp_addr)) {
>> + VIR_DEBUG("PCI addr %s already in use", addr);
>> + VIR_FREE(addr);
>> + continue;
>> + }
>>
>> - VIR_DEBUG("Found free PCI addr %s", addr);
>> - VIR_FREE(addr);
>> + VIR_DEBUG("Found free PCI addr %s", addr);
>> + VIR_FREE(addr);
>>
>> - addrs->lastaddr = tmp_addr;
>> - *next_addr = tmp_addr;
>> - return 0;
>> + addrs->lastaddr = tmp_addr;
>> + *next_addr = tmp_addr;
>> + return 0;
>
> Again, thinking about last-used slot, it seems like if this filled up
> all available slots on the bus, wouldn't it be better to set
> addrs->lastaddr to 1 (to start the next bus correctly)? Does the outer
> loop (on 'j') need to start iterating from the last-used bus instead of
> starting at bus 0 and finding all 31 slots full?
j is just there to make sure we stop if all the buses are full.
tmp_addr.bus will be set to whatever bus was in lastaddr and yes,
advancing to the next bus and starting from slot 1 would make more
sense. And it might even make the loop look like it's from this planet.
>
> Or is caching the last-used slot something that we can completely avoid
> in the case of a multibus support, and only worry about it for older qemu?
>
Without it, we'd need to go over all the buses every time a new address
is needed. But I'm not sure if we want to cache reservation of slot 7
when slot 6 is empty (which could only happen with hotplug, since
addresses from the XML config are not cached and the rest is assigned
sequentially).
(Btw: I accidentally removed the caching from ReserveSlot in 5/11 which
is where explicitly specified addresses of hotplugged devices are cached).
>> + }
>> + tmp_addr.bus++;
>> + if (addrs->nbuses <= tmp_addr.bus) {
>> + if (addrs->dryRun) {
>> + if (qemuPCIAddressSetGrow(addrs, &tmp_addr) < 0)
>> + return -1;
>> + } else {
>> + tmp_addr.bus = 0;
>> + }
>> + tmp_addr.slot = 1;
>> + }
>> }
>>
>> virReportError(VIR_ERR_INTERNAL_ERROR,
More information about the libvir-list
mailing list