diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 6cd35f8cb4..e8bfc2964e 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -876,10 +876,21 @@ int qemuDomainPCIAddressEnsureAddr(qemuDomainPCIAddressSetPtr addrs, virDomainDeviceInfoPtr dev) { int ret = 0; - if (dev->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) - ret = qemuDomainPCIAddressReserveAddr(addrs, dev); - else + if (dev->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) { + /* We do not support hotplug multi-function PCI device now, so we should + * reserve the whole slot. The function of the PCI device must be 0. + */ + if (dev->addr.pci.function != 0) { + qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Only PCI device addresses with function=0" + " are supported")); + return -1; + } + + ret = qemuDomainPCIAddressReserveSlot(addrs, dev->addr.pci.slot); + } else { ret = qemuDomainPCIAddressSetNextAddr(addrs, dev); + } return ret; } @@ -914,6 +925,36 @@ int qemuDomainPCIAddressReleaseFunction(qemuDomainPCIAddressSetPtr addrs, return qemuDomainPCIAddressReleaseAddr(addrs, &dev); } +int qemuDomainPCIAddressReleaseSlot(qemuDomainPCIAddressSetPtr addrs, int slot) +{ + virDomainDeviceInfo dev; + char *addr; + int function; + int ret = 0; + + dev.addr.pci.domain = 0; + dev.addr.pci.bus = 0; + dev.addr.pci.slot = slot; + + for (function = 0; function <= QEMU_PCI_ADDRESS_LAST_FUNCTION; function++) { + addr = qemuPCIAddressAsString(&dev); + if (!addr) + return -1; + + if (!virHashLookup(addrs->used, addr)) { + VIR_FREE(addr); + continue; + } + + VIR_FREE(addr); + + if (qemuDomainPCIAddressReleaseFunction(addrs, slot, function) < 0) + ret = -1; + } + + return ret; +} + void qemuDomainPCIAddressSetFree(qemuDomainPCIAddressSetPtr addrs) { if (!addrs) diff --git a/src/qemu/qemu_command.h b/src/qemu/qemu_command.h index 4c83182492..d7673adce3 100644 --- a/src/qemu/qemu_command.h +++ b/src/qemu/qemu_command.h @@ -160,6 +160,7 @@ int qemuDomainPCIAddressReleaseAddr(qemuDomainPCIAddressSetPtr addrs, virDomainDeviceInfoPtr dev); int qemuDomainPCIAddressReleaseFunction(qemuDomainPCIAddressSetPtr addrs, int slot, int function); +int qemuDomainPCIAddressReleaseSlot(qemuDomainPCIAddressSetPtr addrs, int slot); void qemuDomainPCIAddressSetFree(qemuDomainPCIAddressSetPtr addrs); int qemuAssignDevicePCISlots(virDomainDefPtr def, qemuDomainPCIAddressSetPtr addrs); diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c index e69c1a031e..e330d85b46 100644 --- a/src/qemu/qemu_hotplug.c +++ b/src/qemu/qemu_hotplug.c @@ -242,7 +242,8 @@ error: if (qemuCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE) && (disk->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) && releaseaddr && - qemuDomainPCIAddressReleaseAddr(priv->pciaddrs, &disk->info) < 0) + qemuDomainPCIAddressReleaseSlot(priv->pciaddrs, + disk->info.addr.pci.slot) < 0) VIR_WARN("Unable to release PCI address on %s", disk->src); if (virSecurityManagerRestoreImageLabel(driver->securityManager, @@ -314,7 +315,8 @@ cleanup: qemuCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE) && (controller->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) && releaseaddr && - qemuDomainPCIAddressReleaseAddr(priv->pciaddrs, &controller->info) < 0) + qemuDomainPCIAddressReleaseSlot(priv->pciaddrs, + controller->info.addr.pci.slot) < 0) VIR_WARN("Unable to release PCI address on controller"); VIR_FREE(devstr); @@ -739,7 +741,8 @@ cleanup: qemuCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE) && (net->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) && releaseaddr && - qemuDomainPCIAddressReleaseAddr(priv->pciaddrs, &net->info) < 0) + qemuDomainPCIAddressReleaseSlot(priv->pciaddrs, + net->info.addr.pci.slot) < 0) VIR_WARN("Unable to release PCI address on NIC"); if (ret != 0) @@ -870,7 +873,8 @@ error: if (qemuCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE) && (hostdev->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) && releaseaddr && - qemuDomainPCIAddressReleaseAddr(priv->pciaddrs, &hostdev->info) < 0) + qemuDomainPCIAddressReleaseSlot(priv->pciaddrs, + hostdev->info.addr.pci.slot) < 0) VIR_WARN("Unable to release PCI address on host device"); qemuDomainReAttachHostdevDevices(driver, &hostdev, 1); @@ -1257,7 +1261,8 @@ int qemuDomainDetachPciDiskDevice(struct qemud_driver *driver, qemuAuditDisk(vm, detach, NULL, "detach", true); if (qemuCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE) && - qemuDomainPCIAddressReleaseAddr(priv->pciaddrs, &detach->info) < 0) + qemuDomainPCIAddressReleaseSlot(priv->pciaddrs, + detach->info.addr.pci.slot) < 0) VIR_WARN("Unable to release PCI address on %s", dev->data.disk->src); virDomainDiskRemove(vm->def, i); @@ -1496,7 +1501,8 @@ int qemuDomainDetachPciControllerDevice(struct qemud_driver *driver, } if (qemuCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE) && - qemuDomainPCIAddressReleaseAddr(priv->pciaddrs, &detach->info) < 0) + qemuDomainPCIAddressReleaseSlot(priv->pciaddrs, + detach->info.addr.pci.slot) < 0) VIR_WARN("Unable to release PCI address on controller"); virDomainControllerDefFree(detach); @@ -1595,7 +1601,8 @@ int qemuDomainDetachNetDevice(struct qemud_driver *driver, qemuAuditNet(vm, detach, NULL, "detach", true); if (qemuCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE) && - qemuDomainPCIAddressReleaseAddr(priv->pciaddrs, &detach->info) < 0) + qemuDomainPCIAddressReleaseSlot(priv->pciaddrs, + detach->info.addr.pci.slot) < 0) VIR_WARN("Unable to release PCI address on NIC"); virDomainConfNWFilterTeardown(detach); @@ -1719,7 +1726,8 @@ int qemuDomainDetachHostPciDevice(struct qemud_driver *driver, } if (qemuCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE) && - qemuDomainPCIAddressReleaseAddr(priv->pciaddrs, &detach->info) < 0) + qemuDomainPCIAddressReleaseSlot(priv->pciaddrs, + detach->info.addr.pci.slot) < 0) VIR_WARN("Unable to release PCI address on host device"); if (vm->def->nhostdevs > 1) {