--- src/qemu/qemu_hotplug.c | 240 ++++++++++++++++++++++++++++-------------------- 1 file changed, 142 insertions(+), 98 deletions(-) diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c index 26a6d42..169cce2 100644 --- a/src/qemu/qemu_hotplug.c +++ b/src/qemu/qemu_hotplug.c @@ -2217,6 +2217,136 @@ qemuDomainRemoveNetDevice(virQEMUDriverPtr driver, } +static void +qemuDomainRemovePCIHostDevice(virQEMUDriverPtr driver, + virDomainObjPtr vm, + virDomainHostdevDefPtr hostdev) +{ + virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver); + virDomainHostdevSubsysPtr subsys = &hostdev->source.subsys; + virPCIDevicePtr pci; + virPCIDevicePtr activePci; + + /* + * For SRIOV net host devices, unset mac and port profile before + * reset and reattach device + */ + if (hostdev->parent.data.net) + qemuDomainHostdevNetConfigRestore(hostdev, cfg->stateDir); + + virObjectLock(driver->activePciHostdevs); + virObjectLock(driver->inactivePciHostdevs); + pci = virPCIDeviceNew(subsys->u.pci.addr.domain, subsys->u.pci.addr.bus, + subsys->u.pci.addr.slot, subsys->u.pci.addr.function); + if (pci) { + activePci = virPCIDeviceListSteal(driver->activePciHostdevs, pci); + if (activePci && + virPCIDeviceReset(activePci, driver->activePciHostdevs, + driver->inactivePciHostdevs) == 0) { + qemuReattachPciDevice(activePci, driver); + } else { + /* reset of the device failed, treat it as if it was returned */ + virPCIDeviceFree(activePci); + } + virPCIDeviceFree(pci); + } + virObjectUnlock(driver->activePciHostdevs); + virObjectUnlock(driver->inactivePciHostdevs); + + qemuDomainReleaseDeviceAddress(vm, hostdev->info, NULL); + virObjectUnref(cfg); +} + +static void +qemuDomainRemoveUSBHostDevice(virQEMUDriverPtr driver, + virDomainObjPtr vm ATTRIBUTE_UNUSED, + virDomainHostdevDefPtr hostdev) +{ + virDomainHostdevSubsysPtr subsys = &hostdev->source.subsys; + virUSBDevicePtr usb; + + usb = virUSBDeviceNew(subsys->u.usb.bus, subsys->u.usb.device, NULL); + if (usb) { + virObjectLock(driver->activeUsbHostdevs); + virUSBDeviceListDel(driver->activeUsbHostdevs, usb); + virObjectUnlock(driver->activeUsbHostdevs); + virUSBDeviceFree(usb); + } else { + VIR_WARN("Unable to find device %03d.%03d in list of used USB devices", + subsys->u.usb.bus, subsys->u.usb.device); + } +} + +static void +qemuDomainRemoveSCSIHostDevice(virQEMUDriverPtr driver, + virDomainObjPtr vm, + virDomainHostdevDefPtr hostdev) +{ + qemuDomainReAttachHostScsiDevices(driver, vm->def->name, &hostdev, 1); +} + +static void +qemuDomainRemoveHostDevice(virQEMUDriverPtr driver, + virDomainObjPtr vm, + virDomainHostdevDefPtr hostdev) +{ + virDomainNetDefPtr net = NULL; + size_t i; + + VIR_DEBUG("Removing host device %s from domain %p %s", + hostdev->info->alias, vm, vm->def->name); + + if (hostdev->parent.type == VIR_DOMAIN_DEVICE_NET) { + net = hostdev->parent.data.net; + + for (i = 0; i < vm->def->nnets; i++) { + if (vm->def->nets[i] == net) { + virDomainNetRemove(vm->def, i); + break; + } + } + } + + for (i = 0; i < vm->def->nhostdevs; i++) { + if (vm->def->hostdevs[i] == hostdev) { + virDomainHostdevRemove(vm->def, i); + break; + } + } + + virDomainAuditHostdev(vm, hostdev, "detach", true); + + switch ((enum virDomainHostdevSubsysType) hostdev->source.subsys.type) { + case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI: + qemuDomainRemovePCIHostDevice(driver, vm, hostdev); + break; + case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB: + qemuDomainRemoveUSBHostDevice(driver, vm, hostdev); + break; + case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI: + qemuDomainRemoveSCSIHostDevice(driver, vm, hostdev); + break; + case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST: + break; + } + + if (qemuTeardownHostdevCgroup(vm, hostdev) < 0) + VIR_WARN("Failed to remove host device cgroup ACL"); + + if (virSecurityManagerRestoreHostdevLabel(driver->securityManager, + vm->def, hostdev, NULL) < 0) { + VIR_WARN("Failed to restore host device labelling"); + } + + virDomainHostdevDefFree(hostdev); + + if (net) { + networkReleaseActualDevice(net); + virDomainNetDefFree(net); + } +} + + int qemuDomainDetachVirtioDiskDevice(virQEMUDriverPtr driver, virDomainObjPtr vm, virDomainDiskDefPtr detach) @@ -2457,68 +2587,31 @@ qemuDomainDetachHostPciDevice(virQEMUDriverPtr driver, { qemuDomainObjPrivatePtr priv = vm->privateData; virDomainHostdevSubsysPtr subsys = &detach->source.subsys; - int ret = -1, rv; - virPCIDevicePtr pci; - virPCIDevicePtr activePci; - virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver); + int ret; if (qemuIsMultiFunctionDevice(vm->def, detach->info)) { virReportError(VIR_ERR_OPERATION_FAILED, _("cannot hot unplug multifunction PCI device: %.4x:%.2x:%.2x.%.1x"), subsys->u.pci.addr.domain, subsys->u.pci.addr.bus, subsys->u.pci.addr.slot, subsys->u.pci.addr.function); - goto cleanup; + return -1; } if (!virDomainDeviceAddressIsValid(detach->info, VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI)) { virReportError(VIR_ERR_OPERATION_FAILED, "%s", _("device cannot be detached without a PCI address")); - goto cleanup; + return -1; } qemuDomainObjEnterMonitor(driver, vm); if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE)) { - rv = qemuMonitorDelDevice(priv->mon, detach->info->alias); + ret = qemuMonitorDelDevice(priv->mon, detach->info->alias); } else { - rv = qemuMonitorRemovePCIDevice(priv->mon, &detach->info->addr.pci); + ret = qemuMonitorRemovePCIDevice(priv->mon, &detach->info->addr.pci); } qemuDomainObjExitMonitor(driver, vm); - virDomainAuditHostdev(vm, detach, "detach", rv == 0); - if (rv < 0) - goto cleanup; - - /* - * For SRIOV net host devices, unset mac and port profile before - * reset and reattach device - */ - if (detach->parent.data.net) - qemuDomainHostdevNetConfigRestore(detach, cfg->stateDir); - - virObjectLock(driver->activePciHostdevs); - virObjectLock(driver->inactivePciHostdevs); - pci = virPCIDeviceNew(subsys->u.pci.addr.domain, subsys->u.pci.addr.bus, - subsys->u.pci.addr.slot, subsys->u.pci.addr.function); - if (pci) { - activePci = virPCIDeviceListSteal(driver->activePciHostdevs, pci); - if (activePci && - virPCIDeviceReset(activePci, driver->activePciHostdevs, - driver->inactivePciHostdevs) == 0) { - qemuReattachPciDevice(activePci, driver); - ret = 0; - } else { - /* reset of the device failed, treat it as if it was returned */ - virPCIDeviceFree(activePci); - } - virPCIDeviceFree(pci); - } - virObjectUnlock(driver->activePciHostdevs); - virObjectUnlock(driver->inactivePciHostdevs); - - qemuDomainReleaseDeviceAddress(vm, detach->info, NULL); -cleanup: - virObjectUnref(cfg); return ret; } @@ -2528,8 +2621,6 @@ qemuDomainDetachHostUsbDevice(virQEMUDriverPtr driver, virDomainHostdevDefPtr detach) { qemuDomainObjPrivatePtr priv = vm->privateData; - virDomainHostdevSubsysPtr subsys = &detach->source.subsys; - virUSBDevicePtr usb; int ret; if (!detach->info->alias) { @@ -2547,20 +2638,7 @@ qemuDomainDetachHostUsbDevice(virQEMUDriverPtr driver, qemuDomainObjEnterMonitor(driver, vm); ret = qemuMonitorDelDevice(priv->mon, detach->info->alias); qemuDomainObjExitMonitor(driver, vm); - virDomainAuditHostdev(vm, detach, "detach", ret == 0); - if (ret < 0) - return -1; - usb = virUSBDeviceNew(subsys->u.usb.bus, subsys->u.usb.device, NULL); - if (usb) { - virObjectLock(driver->activeUsbHostdevs); - virUSBDeviceListDel(driver->activeUsbHostdevs, usb); - virObjectUnlock(driver->activeUsbHostdevs); - virUSBDeviceFree(usb); - } else { - VIR_WARN("Unable to find device %03d.%03d in list of used USB devices", - subsys->u.usb.bus, subsys->u.usb.device); - } return ret; } @@ -2608,11 +2686,6 @@ qemuDomainDetachHostScsiDevice(virQEMUDriverPtr driver, } qemuDomainObjExitMonitor(driver, vm); - virDomainAuditHostdev(vm, detach, "detach", ret == 0); - - if (ret == 0) - qemuDomainReAttachHostScsiDevices(driver, vm->def->name, &detach, 1); - cleanup: VIR_FREE(drvstr); VIR_FREE(devstr); @@ -2622,27 +2695,10 @@ cleanup: static int qemuDomainDetachThisHostDevice(virQEMUDriverPtr driver, virDomainObjPtr vm, - virDomainHostdevDefPtr detach, - int idx) + virDomainHostdevDefPtr detach) { int ret = -1; - if (idx < 0) { - /* caller didn't know index of hostdev in hostdevs list, so we - * need to find it. - */ - for (idx = 0; idx < vm->def->nhostdevs; idx++) { - if (vm->def->hostdevs[idx] == detach) - break; - } - if (idx >= vm->def->nhostdevs) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("device not found in hostdevs list (%zu entries)"), - vm->def->nhostdevs); - return ret; - } - } - switch (detach->source.subsys.type) { case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI: ret = qemuDomainDetachHostPciDevice(driver, vm, detach); @@ -2660,17 +2716,11 @@ qemuDomainDetachThisHostDevice(virQEMUDriverPtr driver, return -1; } - if (!ret) { - if (qemuTeardownHostdevCgroup(vm, detach) < 0) - VIR_WARN("Failed to remove host device cgroup ACL"); + if (ret < 0) + virDomainAuditHostdev(vm, detach, "detach", false); + else + qemuDomainRemoveHostDevice(driver, vm, detach); - if (virSecurityManagerRestoreHostdevLabel(driver->securityManager, - vm->def, detach, NULL) < 0) { - VIR_WARN("Failed to restore host device labelling"); - } - virDomainHostdevRemove(vm->def, idx); - virDomainHostdevDefFree(detach); - } return ret; } @@ -2732,7 +2782,7 @@ int qemuDomainDetachHostDevice(virQEMUDriverPtr driver, if (detach->parent.type == VIR_DOMAIN_DEVICE_NET) return qemuDomainDetachNetDevice(driver, vm, &detach->parent); else - return qemuDomainDetachThisHostDevice(driver, vm, detach, idx); + return qemuDomainDetachThisHostDevice(driver, vm, detach); } int @@ -2765,13 +2815,7 @@ qemuDomainDetachNetDevice(virQEMUDriverPtr driver, if (virDomainNetGetActualType(detach) == VIR_DOMAIN_NET_TYPE_HOSTDEV) { /* coverity[negative_returns] */ ret = qemuDomainDetachThisHostDevice(driver, vm, - virDomainNetGetActualHostdev(detach), - -1); - if (!ret) { - networkReleaseActualDevice(detach); - virDomainNetRemove(vm->def, detachidx); - virDomainNetDefFree(detach); - } + virDomainNetGetActualHostdev(detach)); goto cleanup; } if (STREQLEN(vm->def->os.machine, "s390-ccw", 8) && -- 1.8.3.2 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list