Assign PCI addresses before hotplugging devices

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.
This commit is contained in:
Daniel P. Berrange 2010-01-27 17:49:19 +00:00
parent 9258ec0a2e
commit d8acc44672
3 changed files with 97 additions and 17 deletions

View File

@ -1652,17 +1652,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;
@ -1681,6 +1676,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)
{
@ -1688,6 +1706,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)
@ -1746,16 +1782,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++) {

View File

@ -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);

View File

@ -5238,6 +5238,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;
@ -5283,6 +5286,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)
@ -5314,6 +5322,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;
@ -5340,6 +5352,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;
}
@ -5610,6 +5628,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.
*/
@ -5663,6 +5685,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);
@ -5736,9 +5764,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)
@ -5760,6 +5792,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);