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; return NULL;
} }
int qemuDomainPCIAddressReserve(qemuDomainPCIAddressSetPtr addrs, int qemuDomainPCIAddressReserveAddr(qemuDomainPCIAddressSetPtr addrs,
int slot) virDomainDeviceInfoPtr dev)
{ {
virDomainDeviceInfo dev;
char *addr; char *addr;
dev.addr.pci.domain = 0; addr = qemuPCIAddressAsString(dev);
dev.addr.pci.bus = 0;
dev.addr.pci.slot = slot;
addr = qemuPCIAddressAsString(&dev);
if (!addr) if (!addr)
return -1; return -1;
@ -1681,6 +1676,29 @@ int qemuDomainPCIAddressReserve(qemuDomainPCIAddressSetPtr addrs,
return 0; 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) 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) void qemuDomainPCIAddressSetFree(qemuDomainPCIAddressSetPtr addrs)
{ {
if (!addrs) if (!addrs)
@ -1746,16 +1782,16 @@ qemuAssignDevicePCISlots(virDomainDefPtr def, qemuDomainPCIAddressSetPtr addrs)
int i; int i;
/* Host bridge */ /* Host bridge */
if (qemuDomainPCIAddressReserve(addrs, 0) < 0) if (qemuDomainPCIAddressReserveSlot(addrs, 0) < 0)
goto error; goto error;
/* PIIX3 (ISA bridge, IDE controller, something else unknown, USB controller) */ /* PIIX3 (ISA bridge, IDE controller, something else unknown, USB controller) */
if (qemuDomainPCIAddressReserve(addrs, 1) < 0) if (qemuDomainPCIAddressReserveSlot(addrs, 1) < 0)
goto error; goto error;
/* VGA */ /* VGA */
if (qemuDomainPCIAddressReserve(addrs, 2) < 0) if (qemuDomainPCIAddressReserveSlot(addrs, 2) < 0)
goto error; goto error;
/* VirtIO Balloon */ /* VirtIO Balloon */
if (qemuDomainPCIAddressReserve(addrs, 3) < 0) if (qemuDomainPCIAddressReserveSlot(addrs, 3) < 0)
goto error; goto error;
for (i = 0; i < def->ndisks ; i++) { for (i = 0; i < def->ndisks ; i++) {

View File

@ -275,10 +275,17 @@ virDomainDefPtr qemuParseCommandLineString(virConnectPtr conn,
const char *args); const char *args);
qemuDomainPCIAddressSetPtr qemuDomainPCIAddressSetCreate(virDomainDefPtr def); qemuDomainPCIAddressSetPtr qemuDomainPCIAddressSetCreate(virDomainDefPtr def);
int qemuDomainPCIAddressReserve(qemuDomainPCIAddressSetPtr addrs, int qemuDomainPCIAddressReserveSlot(qemuDomainPCIAddressSetPtr addrs,
int slot); int slot);
int qemuDomainPCIAddressReserveAddr(qemuDomainPCIAddressSetPtr addrs,
virDomainDeviceInfoPtr dev);
int qemuDomainPCIAddressSetNextAddr(qemuDomainPCIAddressSetPtr addrs, int qemuDomainPCIAddressSetNextAddr(qemuDomainPCIAddressSetPtr addrs,
virDomainDeviceInfoPtr dev); virDomainDeviceInfoPtr dev);
int qemuDomainPCIAddressEnsureAddr(qemuDomainPCIAddressSetPtr addrs,
virDomainDeviceInfoPtr dev);
int qemuDomainPCIAddressReleaseAddr(qemuDomainPCIAddressSetPtr addrs,
virDomainDeviceInfoPtr dev);
void qemuDomainPCIAddressSetFree(qemuDomainPCIAddressSetPtr addrs); void qemuDomainPCIAddressSetFree(qemuDomainPCIAddressSetPtr addrs);
int qemuAssignDevicePCISlots(virDomainDefPtr def, qemuDomainPCIAddressSetPtr addrs); int qemuAssignDevicePCISlots(virDomainDefPtr def, qemuDomainPCIAddressSetPtr addrs);

View File

@ -5238,6 +5238,9 @@ static int qemudDomainAttachPciDiskDevice(virConnectPtr conn,
return -1; return -1;
if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) { if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
if (qemuDomainPCIAddressEnsureAddr(priv->pciaddrs, &disk->info) < 0)
goto error;
if (!(drivestr = qemuBuildDriveStr(disk, 0, qemuCmdFlags))) if (!(drivestr = qemuBuildDriveStr(disk, 0, qemuCmdFlags)))
goto error; goto error;
@ -5283,6 +5286,11 @@ error:
VIR_FREE(devstr); VIR_FREE(devstr);
VIR_FREE(drivestr); 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 && if (driver->securityDriver &&
driver->securityDriver->domainRestoreSecurityImageLabel && driver->securityDriver->domainRestoreSecurityImageLabel &&
driver->securityDriver->domainRestoreSecurityImageLabel(conn, vm, disk) < 0) 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))) { if (!(devstr = qemuBuildControllerDevStr(controller))) {
virReportOOMError(NULL); virReportOOMError(NULL);
goto cleanup; goto cleanup;
@ -5340,6 +5352,12 @@ static int qemudDomainAttachPciControllerDevice(virConnectPtr conn,
} }
cleanup: 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); VIR_FREE(devstr);
return ret; return ret;
} }
@ -5610,6 +5628,10 @@ static int qemudDomainAttachNetDevice(virConnectPtr conn,
qemuAssignNetNames(vm->def, net) < 0) qemuAssignNetNames(vm->def, net) < 0)
goto no_memory; 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 /* Choose a vlan value greater than all other values since
* older versions did not store the value in the state file. * 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; vm->def->nets[vm->def->nnets++] = net;
cleanup: 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(nicstr);
VIR_FREE(netstr); VIR_FREE(netstr);
VIR_FREE(tapfd_name); VIR_FREE(tapfd_name);
@ -5736,9 +5764,13 @@ static int qemudDomainAttachHostPciDevice(virConnectPtr conn,
return -1; return -1;
} }
if ((qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) && if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
!(devstr = qemuBuildPCIHostdevDevStr(hostdev))) if (qemuDomainPCIAddressEnsureAddr(priv->pciaddrs, &hostdev->info) < 0)
goto error; goto error;
if (!(devstr = qemuBuildPCIHostdevDevStr(hostdev)))
goto error;
}
qemuDomainObjEnterMonitorWithDriver(driver, vm); qemuDomainObjEnterMonitorWithDriver(driver, vm);
if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE)
@ -5760,6 +5792,11 @@ static int qemudDomainAttachHostPciDevice(virConnectPtr conn,
return 0; return 0;
error: 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); VIR_FREE(devstr);
pciDeviceListDel(conn, driver->activePciHostdevs, pci); pciDeviceListDel(conn, driver->activePciHostdevs, pci);