Add a "dry run" address allocation to figure out how many bridges
will be needed for all the devices without explicit addresses.
Auto-add just enough bridges to put all the devices on, or up to the
bridge with the largest specified index.
---
src/qemu/qemu_command.c | 138 ++++++++++++++++++++++++++++++++++++++----------
src/qemu/qemu_command.h | 3 +-
2 files changed, 111 insertions(+), 30 deletions(-)
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index 7073844..19fdf39 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -1197,6 +1197,8 @@ struct _qemuDomainPCIAddressSet {
_qemuDomainPCIAddressBus *used;
size_t nbuses; /* allocation of used */
unsigned int maxbus; /* maximum used bus number */
+ bool dryRun; /* on a dry run, new buses are auto-added
+ and addresses aren't saved in device infos */
virDevicePCIAddress lastaddr;
};
@@ -1308,7 +1310,7 @@ static int qemuCollectPCIAddress(virDomainDefPtr def
ATTRIBUTE_UNUSED,
return 0;
}
- if (qemuPCIAddressSetGrow(addrs, addr) < 0)
+ if (addrs->dryRun && qemuPCIAddressSetGrow(addrs, addr) < 0)
return -1;
if (qemuPCIAddressCheck(addrs, addr) < 0)
@@ -1472,6 +1474,57 @@ cleanup:
}
+/*
+ * Add bridges from 1 to addrs->nbuses
+ * or the highest bridge index in def
+ */
+static int
+qemuDomainMaybeAddPCIBridges(virDomainDefPtr def,
+ qemuDomainPCIAddressSetPtr addrs)
+{
+ virDomainControllerDefPtr cont = NULL;
+ int i;
+ int max = addrs->nbuses - 1;
+
+ for (i = 0; i < def->ncontrollers; i++) {
+ if (def->controllers[i]->type == VIR_DOMAIN_CONTROLLER_TYPE_PCI_BRIDGE)
+ if (def->controllers[i]->idx > max)
+ max = def->controllers[i]->idx;
+ }
+
+ for (max++, i = 1; i < max; i++) {
+ if (virDomainControllerFind(def,
+ VIR_DOMAIN_CONTROLLER_TYPE_PCI_BRIDGE,
+ i) >= 0)
+ continue;
+
+ if (VIR_ALLOC(cont) < 0)
+ goto no_memory;
+
+ cont->type = VIR_DOMAIN_CONTROLLER_TYPE_PCI_BRIDGE;
+ cont->idx = i;
+ cont->model = -1;
+
+ if (virDomainControllerInsert(def, cont) < 0)
+ goto no_memory;
+
+ /* This might change addrs->nbuses */
+ if (qemuDomainPCIAddressSetNextAddr(addrs, &cont->info) < 0)
+ goto cleanup;
+
+ if (addrs->nbuses > max)
+ max = addrs->nbuses;
+ }
+ return max;
+
+no_memory:
+ virReportOOMError();
+cleanup:
+ VIR_FREE(cont);
+ return -1;
+}
+
+
int
qemuDomainAssignPCIAddresses(virDomainDefPtr def,
virQEMUCapsPtr qemuCaps,
@@ -1480,21 +1533,33 @@ qemuDomainAssignPCIAddresses(virDomainDefPtr def,
int ret = -1;
qemuDomainPCIAddressSetPtr addrs = NULL;
qemuDomainObjPrivatePtr priv = NULL;
+ int nbuses = 1;
if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE)) {
- if (!(addrs = qemuDomainPCIAddressSetCreate(def, 1)))
+ 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, 1, true)))
+ goto cleanup;
+ /* Reserve 1 extra slot for a bridge */
+ if (qemuDomainPCIAddressSetNextAddr(addrs, &info) < 0)
+ goto cleanup;
+
+ nbuses = qemuDomainMaybeAddPCIBridges(def, addrs);
+ if (nbuses < 0)
+ goto cleanup;
+ qemuDomainPCIAddressSetFree(addrs);
+ addrs = NULL;
+ }
+ if (!(addrs = qemuDomainPCIAddressSetCreate(def, nbuses, false)))
goto cleanup;
if (qemuAssignDevicePCISlots(def, qemuCaps, addrs) < 0)
goto cleanup;
if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_PCI_BRIDGE)) {
- if (qemuDomainVerifyPCIBridges(def, addrs->maxbus + 1) < 0)
+ if (qemuDomainVerifyPCIBridges(def, addrs->nbuses) < 0)
goto cleanup;
- } else if (addrs->maxbus) {
- virReportError(VIR_ERR_XML_ERROR, "%s",
- _("Only PCI bus 0 is available"));
- goto cleanup;
}
}
@@ -1537,7 +1602,8 @@ int qemuDomainAssignAddresses(virDomainDefPtr def,
}
qemuDomainPCIAddressSetPtr qemuDomainPCIAddressSetCreate(virDomainDefPtr def,
- unsigned int nbuses)
+ unsigned int nbuses,
+ bool dryRun)
{
qemuDomainPCIAddressSetPtr addrs;
int i;
@@ -1548,6 +1614,7 @@ qemuDomainPCIAddressSetPtr
qemuDomainPCIAddressSetCreate(virDomainDefPtr def,
if (VIR_ALLOC_N(addrs->used, nbuses) < 0)
goto no_memory;
addrs->nbuses = nbuses;
+ addrs->dryRun = dryRun;
/* reserve slot 0 in every bus - it's used by the host bridge on bus 0
* and unusable on PCI bridges */
@@ -1587,7 +1654,7 @@ int qemuDomainPCIAddressReserveAddr(qemuDomainPCIAddressSetPtr
addrs,
{
char *str;
- if (qemuPCIAddressSetGrow(addrs, addr) < 0)
+ if (addrs->dryRun && qemuPCIAddressSetGrow(addrs, addr) < 0)
return -1;
if (qemuPCIAddressCheck(addrs, addr) < 0)
@@ -1620,7 +1687,7 @@ int qemuDomainPCIAddressReserveSlot(qemuDomainPCIAddressSetPtr
addrs,
{
char *str;
- if (qemuPCIAddressSetGrow(addrs, addr) < 0)
+ if (addrs->dryRun && qemuPCIAddressSetGrow(addrs, addr) < 0)
return -1;
if (qemuPCIAddressCheck(addrs, addr) < 0)
@@ -1702,32 +1769,43 @@ qemuDomainPCIAddressGetNextSlot(qemuDomainPCIAddressSetPtr addrs,
virDevicePCIAddressPtr next_addr)
{
virDevicePCIAddress tmp_addr = addrs->lastaddr;
- int i;
+ int i,j;
char *addr;
tmp_addr.slot++;
- for (i = 0; i < QEMU_PCI_ADDRESS_LAST_SLOT; i++, tmp_addr.slot++) {
- if (QEMU_PCI_ADDRESS_LAST_SLOT <= tmp_addr.slot) {
- /* slot 0 is unusable */
+ for (j = 0; j < addrs->nbuses; j++, 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;
- i++;
}
+ for (i = 0; i < QEMU_PCI_ADDRESS_LAST_SLOT; i++, tmp_addr.slot++) {
+ if (QEMU_PCI_ADDRESS_LAST_SLOT <= tmp_addr.slot) {
+ /* slot 0 is unusable */
+ tmp_addr.slot = 1;
+ i++;
+ }
- if (!(addr = qemuPCIAddressAsString(&tmp_addr)))
- return -1;
+ if (!(addr = qemuPCIAddressAsString(&tmp_addr)))
+ return -1;
- if (qemuDomainPCIAddressCheckSlot(addrs, &tmp_addr) < 0) {
- VIR_DEBUG("PCI addr %s already in use", addr);
- VIR_FREE(addr);
- continue;
- }
+ if (qemuDomainPCIAddressCheckSlot(addrs, &tmp_addr) < 0) {
+ 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;
+ }
}
virReportError(VIR_ERR_INTERNAL_ERROR,
@@ -1745,8 +1823,10 @@ int qemuDomainPCIAddressSetNextAddr(qemuDomainPCIAddressSetPtr
addrs,
if (qemuDomainPCIAddressReserveSlot(addrs, &addr) < 0)
return -1;
- dev->type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
- dev->addr.pci = addr;
+ if (!addrs->dryRun) {
+ dev->type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
+ dev->addr.pci = addr;
+ }
addrs->lastaddr = addr;
return 0;
diff --git a/src/qemu/qemu_command.h b/src/qemu/qemu_command.h
index 56da69d..0f8a248 100644
--- a/src/qemu/qemu_command.h
+++ b/src/qemu/qemu_command.h
@@ -197,7 +197,8 @@ int qemuDomainAssignPCIAddresses(virDomainDefPtr def,
virQEMUCapsPtr qemuCaps,
virDomainObjPtr obj);
qemuDomainPCIAddressSetPtr qemuDomainPCIAddressSetCreate(virDomainDefPtr def,
- unsigned int nbuses);
+ unsigned int nbuses,
+ bool dryRun);
int qemuDomainPCIAddressReserveSlot(qemuDomainPCIAddressSetPtr addrs,
virDevicePCIAddressPtr addr);
int qemuDomainPCIAddressReserveAddr(qemuDomainPCIAddressSetPtr addrs,
--
1.8.1.5