diff --git a/src/conf/domain_addr.c b/src/conf/domain_addr.c index 2be98c5edf..9519f79062 100644 --- a/src/conf/domain_addr.c +++ b/src/conf/domain_addr.c @@ -471,55 +471,66 @@ virDomainPCIAddressGetNextSlot(virDomainPCIAddressSetPtr addrs, virDomainPCIConnectFlags flags) { /* default to starting the search for a free slot from - * 0000:00:00.0 + * the first slot of domain 0 bus 0... */ virDevicePCIAddress a = { 0, 0, 0, 0, false }; char *addrStr = NULL; - /* except if this search is for the exact same type of device as - * last time, continue the search from the previous match - */ - if (flags == addrs->lastFlags) - a = addrs->lastaddr; - if (addrs->nbuses == 0) { virReportError(VIR_ERR_XML_ERROR, "%s", _("No PCI buses available")); goto error; } - /* Start the search at the last used bus and slot */ - for (a.slot++; a.bus < addrs->nbuses; a.bus++) { + /* ...unless this search is for the exact same type of device as + * last time, then continue the search from the next slot after + * the previous match (the "next slot" may possibly be the first + * slot of the next bus). + */ + if (flags == addrs->lastFlags) { + a = addrs->lastaddr; + if (++a.slot > addrs->buses[a.bus].maxSlot && + ++a.bus < addrs->nbuses) + a.slot = addrs->buses[a.bus].minSlot; + } else { + a.slot = addrs->buses[0].minSlot; + } + + while (a.bus < addrs->nbuses) { + VIR_FREE(addrStr); if (!(addrStr = virDomainPCIAddressAsString(&a))) goto error; if (!virDomainPCIAddressFlagsCompatible(&a, addrStr, addrs->buses[a.bus].flags, flags, false, false)) { - VIR_FREE(addrStr); VIR_DEBUG("PCI bus %.4x:%.2x is not compatible with the device", a.domain, a.bus); - continue; - } - for (; a.slot <= VIR_PCI_ADDRESS_SLOT_LAST; a.slot++) { - if (!virDomainPCIAddressSlotInUse(addrs, &a)) - goto success; + } else { + while (a.slot <= addrs->buses[a.bus].maxSlot) { + if (!virDomainPCIAddressSlotInUse(addrs, &a)) + goto success; - VIR_DEBUG("PCI slot %.4x:%.2x:%.2x already in use", - a.domain, a.bus, a.slot); + VIR_DEBUG("PCI slot %.4x:%.2x:%.2x already in use", + a.domain, a.bus, a.slot); + a.slot++; + } } - a.slot = 1; - VIR_FREE(addrStr); + if (++a.bus < addrs->nbuses) + a.slot = addrs->buses[a.bus].minSlot; } /* There were no free slots after the last used one */ if (addrs->dryRun) { - /* a is already set to the first new bus and slot 1 */ + /* a is already set to the first new bus */ if (virDomainPCIAddressSetGrow(addrs, &a, flags) < 0) goto error; + /* this device will use the first slot of the new bus */ + a.slot = addrs->buses[a.bus].minSlot; goto success; } else if (flags == addrs->lastFlags) { /* Check the buses from 0 up to the last used one */ for (a.bus = 0; a.bus <= addrs->lastaddr.bus; a.bus++) { - addrStr = NULL; + a.slot = addrs->buses[a.bus].minSlot; + VIR_FREE(addrStr); if (!(addrStr = virDomainPCIAddressAsString(&a))) goto error; if (!virDomainPCIAddressFlagsCompatible(&a, addrStr, @@ -527,14 +538,15 @@ virDomainPCIAddressGetNextSlot(virDomainPCIAddressSetPtr addrs, flags, false, false)) { VIR_DEBUG("PCI bus %.4x:%.2x is not compatible with the device", a.domain, a.bus); - continue; - } - for (a.slot = 1; a.slot <= VIR_PCI_ADDRESS_SLOT_LAST; a.slot++) { - if (!virDomainPCIAddressSlotInUse(addrs, &a)) - goto success; + } else { + while (a.slot <= addrs->buses[a.bus].maxSlot) { + if (!virDomainPCIAddressSlotInUse(addrs, &a)) + goto success; - VIR_DEBUG("PCI slot %.4x:%.2x:%.2x already in use", - a.domain, a.bus, a.slot); + VIR_DEBUG("PCI slot %.4x:%.2x:%.2x already in use", + a.domain, a.bus, a.slot); + a.slot++; + } } } }