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 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list