[libvirt] [PATCH 7/7] qemu: auto-add and use bridges

Ján Tomko jtomko at redhat.com
Wed Apr 3 15:50:36 UTC 2013


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




More information about the libvir-list mailing list