[libvirt] [PATCH 7/7] Assign PCI addresses before hotplugging devices

Daniel P. Berrange berrange at redhat.com
Wed Jan 27 19:23:00 UTC 2010


PCI disk, disk controllers, net devices and host devices need to
have PCI addresses assigned before they are hot-plugged

* src/qemu/qemu_conf.c: Add APIs for ensuring a device has an
  address and releasing unused addresses
* src/qemu/qemu_driver.c: Ensure all devices have addresses
  when hotplugging.
---
 src/qemu/qemu_conf.c   |   60 ++++++++++++++++++++++++++++++++++++++---------
 src/qemu/qemu_conf.h   |   11 +++++++-
 src/qemu/qemu_driver.c |   43 ++++++++++++++++++++++++++++++++--
 3 files changed, 97 insertions(+), 17 deletions(-)

diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c
index 7de28be..c93e473 100644
--- a/src/qemu/qemu_conf.c
+++ b/src/qemu/qemu_conf.c
@@ -1651,17 +1651,12 @@ error:
     return NULL;
 }
 
-int qemuDomainPCIAddressReserve(qemuDomainPCIAddressSetPtr addrs,
-                                int slot)
+int qemuDomainPCIAddressReserveAddr(qemuDomainPCIAddressSetPtr addrs,
+                                    virDomainDeviceInfoPtr dev)
 {
-    virDomainDeviceInfo dev;
     char *addr;
 
-    dev.addr.pci.domain = 0;
-    dev.addr.pci.bus = 0;
-    dev.addr.pci.slot = slot;
-
-    addr = qemuPCIAddressAsString(&dev);
+    addr = qemuPCIAddressAsString(dev);
     if (!addr)
         return -1;
 
@@ -1680,6 +1675,29 @@ int qemuDomainPCIAddressReserve(qemuDomainPCIAddressSetPtr addrs,
     return 0;
 }
 
+int qemuDomainPCIAddressReserveSlot(qemuDomainPCIAddressSetPtr addrs,
+                                    int slot)
+{
+    virDomainDeviceInfo dev;
+
+    dev.addr.pci.domain = 0;
+    dev.addr.pci.bus = 0;
+    dev.addr.pci.slot = slot;
+
+    return qemuDomainPCIAddressReserveAddr(addrs, &dev);
+}
+
+
+int qemuDomainPCIAddressEnsureAddr(qemuDomainPCIAddressSetPtr addrs,
+                                    virDomainDeviceInfoPtr dev)
+{
+    int ret = 0;
+    if (dev->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI)
+        ret = qemuDomainPCIAddressReserveAddr(addrs, dev);
+    else
+        ret = qemuDomainPCIAddressSetNextAddr(addrs, dev);
+    return ret;
+}
 
 static void qemuDomainPCIAddressSetFreeEntry(void *payload, const char *name ATTRIBUTE_UNUSED)
 {
@@ -1687,6 +1705,24 @@ static void qemuDomainPCIAddressSetFreeEntry(void *payload, const char *name ATT
 }
 
 
+int qemuDomainPCIAddressReleaseAddr(qemuDomainPCIAddressSetPtr addrs,
+                                    virDomainDeviceInfoPtr dev)
+{
+    char *addr;
+    int ret;
+
+    addr = qemuPCIAddressAsString(dev);
+    if (!addr)
+        return -1;
+
+    ret = virHashRemoveEntry(addrs->used, addr, qemuDomainPCIAddressSetFreeEntry);
+
+    VIR_FREE(addr);
+
+    return ret;
+}
+
+
 void qemuDomainPCIAddressSetFree(qemuDomainPCIAddressSetPtr addrs)
 {
     if (!addrs)
@@ -1744,16 +1780,16 @@ qemuAssignDevicePCISlots(virDomainDefPtr def, qemuDomainPCIAddressSetPtr addrs)
     int i;
 
     /* Host bridge */
-    if (qemuDomainPCIAddressReserve(addrs, 0) < 0)
+    if (qemuDomainPCIAddressReserveSlot(addrs, 0) < 0)
         goto error;
     /* PIIX3 (ISA bridge, IDE controller, something else unknown, USB controller) */
-    if (qemuDomainPCIAddressReserve(addrs, 1) < 0)
+    if (qemuDomainPCIAddressReserveSlot(addrs, 1) < 0)
         goto error;
     /* VGA */
-    if (qemuDomainPCIAddressReserve(addrs, 2) < 0)
+    if (qemuDomainPCIAddressReserveSlot(addrs, 2) < 0)
         goto error;
     /* VirtIO Balloon */
-    if (qemuDomainPCIAddressReserve(addrs, 3) < 0)
+    if (qemuDomainPCIAddressReserveSlot(addrs, 3) < 0)
         goto error;
 
     for (i = 0; i < def->ndisks ; i++) {
diff --git a/src/qemu/qemu_conf.h b/src/qemu/qemu_conf.h
index bcddf3c..b94153f 100644
--- a/src/qemu/qemu_conf.h
+++ b/src/qemu/qemu_conf.h
@@ -275,10 +275,17 @@ virDomainDefPtr qemuParseCommandLineString(virConnectPtr conn,
                                            const char *args);
 
 qemuDomainPCIAddressSetPtr qemuDomainPCIAddressSetCreate(virDomainDefPtr def);
-int qemuDomainPCIAddressReserve(qemuDomainPCIAddressSetPtr addrs,
-                                int slot);
+int qemuDomainPCIAddressReserveSlot(qemuDomainPCIAddressSetPtr addrs,
+                                    int slot);
+int qemuDomainPCIAddressReserveAddr(qemuDomainPCIAddressSetPtr addrs,
+                                    virDomainDeviceInfoPtr dev);
 int qemuDomainPCIAddressSetNextAddr(qemuDomainPCIAddressSetPtr addrs,
                                     virDomainDeviceInfoPtr dev);
+int qemuDomainPCIAddressEnsureAddr(qemuDomainPCIAddressSetPtr addrs,
+                                   virDomainDeviceInfoPtr dev);
+int qemuDomainPCIAddressReleaseAddr(qemuDomainPCIAddressSetPtr addrs,
+                                    virDomainDeviceInfoPtr dev);
+
 void qemuDomainPCIAddressSetFree(qemuDomainPCIAddressSetPtr addrs);
 int  qemuAssignDevicePCISlots(virDomainDefPtr def, qemuDomainPCIAddressSetPtr addrs);
 
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 465beaf..8debe20 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -5231,6 +5231,9 @@ static int qemudDomainAttachPciDiskDevice(virConnectPtr conn,
         return -1;
 
     if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
+        if (qemuDomainPCIAddressEnsureAddr(priv->pciaddrs, &disk->info) < 0)
+            goto error;
+
         if (!(drivestr = qemuBuildDriveStr(disk, 0, qemuCmdFlags)))
             goto error;
 
@@ -5276,6 +5279,11 @@ error:
     VIR_FREE(devstr);
     VIR_FREE(drivestr);
 
+    if ((qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) &&
+        (disk->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) &&
+        qemuDomainPCIAddressReleaseAddr(priv->pciaddrs, &disk->info) < 0)
+        VIR_WARN("Unable to release PCI address on %s", disk->src);
+
     if (driver->securityDriver &&
         driver->securityDriver->domainRestoreSecurityImageLabel &&
         driver->securityDriver->domainRestoreSecurityImageLabel(conn, vm, disk) < 0)
@@ -5307,6 +5315,10 @@ static int qemudDomainAttachPciControllerDevice(virConnectPtr conn,
         }
     }
 
+    if ((qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) &&
+        qemuDomainPCIAddressEnsureAddr(priv->pciaddrs, &controller->info) < 0)
+        goto cleanup;
+
     if (!(devstr = qemuBuildControllerDevStr(controller))) {
         virReportOOMError(NULL);
         goto cleanup;
@@ -5333,6 +5345,12 @@ static int qemudDomainAttachPciControllerDevice(virConnectPtr conn,
     }
 
 cleanup:
+    if ((ret != 0) &&
+        (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) &&
+        (controller->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) &&
+        qemuDomainPCIAddressReleaseAddr(priv->pciaddrs, &controller->info) < 0)
+        VIR_WARN0("Unable to release PCI address on controller");
+
     VIR_FREE(devstr);
     return ret;
 }
@@ -5603,6 +5621,10 @@ static int qemudDomainAttachNetDevice(virConnectPtr conn,
         qemuAssignNetNames(vm->def, net) < 0)
         goto no_memory;
 
+    if ((qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) &&
+        qemuDomainPCIAddressEnsureAddr(priv->pciaddrs, &net->info) < 0)
+        goto cleanup;
+
     /* Choose a vlan value greater than all other values since
      * older versions did not store the value in the state file.
      */
@@ -5656,6 +5678,12 @@ static int qemudDomainAttachNetDevice(virConnectPtr conn,
     vm->def->nets[vm->def->nnets++] = net;
 
 cleanup:
+    if ((ret != 0) &&
+        (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) &&
+        (net->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) &&
+        qemuDomainPCIAddressReleaseAddr(priv->pciaddrs, &net->info) < 0)
+        VIR_WARN0("Unable to release PCI address on NIC");
+
     VIR_FREE(nicstr);
     VIR_FREE(netstr);
     VIR_FREE(tapfd_name);
@@ -5729,9 +5757,13 @@ static int qemudDomainAttachHostPciDevice(virConnectPtr conn,
         return -1;
     }
 
-    if ((qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) &&
-        !(devstr = qemuBuildPCIHostdevDevStr(hostdev)))
-        goto error;
+    if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
+        if (qemuDomainPCIAddressEnsureAddr(priv->pciaddrs, &hostdev->info) < 0)
+            goto error;
+
+        if (!(devstr = qemuBuildPCIHostdevDevStr(hostdev)))
+            goto error;
+    }
 
     qemuDomainObjEnterMonitorWithDriver(driver, vm);
     if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE)
@@ -5753,6 +5785,11 @@ static int qemudDomainAttachHostPciDevice(virConnectPtr conn,
     return 0;
 
 error:
+    if ((qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) &&
+        (hostdev->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) &&
+        qemuDomainPCIAddressReleaseAddr(priv->pciaddrs, &hostdev->info) < 0)
+        VIR_WARN0("Unable to release PCI address on host device");
+
     VIR_FREE(devstr);
     pciDeviceListDel(conn, driver->activePciHostdevs, pci);
 
-- 
1.6.5.2




More information about the libvir-list mailing list