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