[libvirt] [PATCH 08/12] qemu: Separate host device removal into a standalone function

Jiri Denemark jdenemar at redhat.com
Mon Jul 15 17:11:09 UTC 2013


---
 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




More information about the libvir-list mailing list