[libvirt] [PATCH 12/17] qemu: refactor hotplug detach of hostdevs

Laine Stump laine at laine.org
Tue Feb 28 20:14:43 UTC 2012


This refactoring is necessary to support hotplug detach of
type=hostdev network devices, but needs to be in a separate patch to
make potential debugging of regressions more practical.

Rather than the lowest level functions searching for a matching
device, the search is now done in the toplevel function, and an
intermediate-level function (qemuDomainDetachThisHostDevice()), which
expects that the device's entry is already found, is called (this
intermediate function will be called by qemuDomainDetachNetDevice() in
order to support detach of type=hostdev net devices)

This patch should result in 0 differences in functionality.
---
New patch for V2.

 src/qemu/qemu_hotplug.c |  228 +++++++++++++++++++----------------------------
 1 files changed, 93 insertions(+), 135 deletions(-)

diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
index e9df537..cb41388 100644
--- a/src/qemu/qemu_hotplug.c
+++ b/src/qemu/qemu_hotplug.c
@@ -1,7 +1,7 @@
 /*
  * qemu_hotplug.h: QEMU device hotplug management
  *
- * Copyright (C) 2006-2011 Red Hat, Inc.
+ * Copyright (C) 2006-2012 Red Hat, Inc.
  * Copyright (C) 2006 Daniel P. Berrange
  *
  * This library is free software; you can redistribute it and/or
@@ -1836,48 +1836,20 @@ cleanup:
 static int
 qemuDomainDetachHostPciDevice(struct qemud_driver *driver,
                               virDomainObjPtr vm,
-                              virDomainDeviceDefPtr dev,
-                              virDomainHostdevDefPtr *detach_ret)
+                              virDomainHostdevDefPtr detach,
+                              int idx)
 {
-    virDomainHostdevDefPtr detach = NULL;
     qemuDomainObjPrivatePtr priv = vm->privateData;
-    int i, ret;
+    virDomainHostdevSubsysPtr subsys = &detach->source.subsys;
+    int ret;
     pciDevice *pci;
     pciDevice *activePci;
 
-    for (i = 0 ; i < vm->def->nhostdevs ; i++) {
-        if (vm->def->hostdevs[i]->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS ||
-            vm->def->hostdevs[i]->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI)
-            continue;
-
-        unsigned domain   = vm->def->hostdevs[i]->source.subsys.u.pci.domain;
-        unsigned bus      = vm->def->hostdevs[i]->source.subsys.u.pci.bus;
-        unsigned slot     = vm->def->hostdevs[i]->source.subsys.u.pci.slot;
-        unsigned function = vm->def->hostdevs[i]->source.subsys.u.pci.function;
-
-        if (dev->data.hostdev->source.subsys.u.pci.domain   == domain &&
-            dev->data.hostdev->source.subsys.u.pci.bus      == bus &&
-            dev->data.hostdev->source.subsys.u.pci.slot     == slot &&
-            dev->data.hostdev->source.subsys.u.pci.function == function) {
-            detach = vm->def->hostdevs[i];
-            break;
-        }
-    }
-
-    if (!detach) {
-        qemuReportError(VIR_ERR_OPERATION_FAILED,
-                        _("host pci device %.4x:%.2x:%.2x.%.1x not found"),
-                        dev->data.hostdev->source.subsys.u.pci.domain,
-                        dev->data.hostdev->source.subsys.u.pci.bus,
-                        dev->data.hostdev->source.subsys.u.pci.slot,
-                        dev->data.hostdev->source.subsys.u.pci.function);
-        return -1;
-    }
-
     if (qemuIsMultiFunctionDevice(vm->def, detach->info)) {
         qemuReportError(VIR_ERR_OPERATION_FAILED,
-                        _("cannot hot unplug multifunction PCI device: %s"),
-                        dev->data.disk->dst);
+                        _("cannot hot unplug multifunction PCI device: %.4x:%.2x:%.2x.%.1x"),
+                        subsys->u.pci.domain, subsys->u.pci.bus,
+                        subsys->u.pci.slot,   subsys->u.pci.function);
         return -1;
     }
 
@@ -1899,10 +1871,8 @@ qemuDomainDetachHostPciDevice(struct qemud_driver *driver,
     if (ret < 0)
         return -1;
 
-    pci = pciGetDevice(detach->source.subsys.u.pci.domain,
-                       detach->source.subsys.u.pci.bus,
-                       detach->source.subsys.u.pci.slot,
-                       detach->source.subsys.u.pci.function);
+    pci = pciGetDevice(subsys->u.pci.domain, subsys->u.pci.bus,
+                       subsys->u.pci.slot,   subsys->u.pci.function);
     if (pci) {
         activePci = pciDeviceListSteal(driver->activePciHostdevs, pci);
         if (pciResetDevice(activePci, driver->activePciHostdevs,
@@ -1921,71 +1891,20 @@ qemuDomainDetachHostPciDevice(struct qemud_driver *driver,
                                         detach->info->addr.pci.slot) < 0)
         VIR_WARN("Unable to release PCI address on host device");
 
-    if (vm->def->nhostdevs > 1) {
-        memmove(vm->def->hostdevs + i,
-                vm->def->hostdevs + i + 1,
-                sizeof(*vm->def->hostdevs) *
-                (vm->def->nhostdevs - (i + 1)));
-        vm->def->nhostdevs--;
-        if (VIR_REALLOC_N(vm->def->hostdevs, vm->def->nhostdevs) < 0) {
-            /* ignore, harmless */
-        }
-    } else {
-        VIR_FREE(vm->def->hostdevs);
-        vm->def->nhostdevs = 0;
-    }
-    if (detach_ret)
-        *detach_ret = detach;
-    else
-        virDomainHostdevDefFree(detach);
-
+    virDomainHostdevRemove(vm->def, idx);
     return ret;
 }
 
 static int
 qemuDomainDetachHostUsbDevice(struct qemud_driver *driver,
                               virDomainObjPtr vm,
-                              virDomainDeviceDefPtr dev,
-                              virDomainHostdevDefPtr *detach_ret)
+                              virDomainHostdevDefPtr detach,
+                              int idx)
 {
-    virDomainHostdevDefPtr detach = NULL;
     qemuDomainObjPrivatePtr priv = vm->privateData;
+    virDomainHostdevSubsysPtr subsys = &detach->source.subsys;
     usbDevice *usb;
-    int i, ret;
-
-    for (i = 0 ; i < vm->def->nhostdevs ; i++) {
-        if (vm->def->hostdevs[i]->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS ||
-            vm->def->hostdevs[i]->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB)
-            continue;
-
-        unsigned bus = vm->def->hostdevs[i]->source.subsys.u.usb.bus;
-        unsigned device = vm->def->hostdevs[i]->source.subsys.u.usb.device;
-        unsigned product = vm->def->hostdevs[i]->source.subsys.u.usb.product;
-        unsigned vendor = vm->def->hostdevs[i]->source.subsys.u.usb.vendor;
-
-        if (dev->data.hostdev->source.subsys.u.usb.bus &&
-            dev->data.hostdev->source.subsys.u.usb.device) {
-            if (dev->data.hostdev->source.subsys.u.usb.bus == bus &&
-                dev->data.hostdev->source.subsys.u.usb.device == device) {
-                detach = vm->def->hostdevs[i];
-                break;
-            }
-        } else {
-            if (dev->data.hostdev->source.subsys.u.usb.product == product &&
-                dev->data.hostdev->source.subsys.u.usb.vendor == vendor) {
-                detach = vm->def->hostdevs[i];
-                break;
-            }
-        }
-    }
-
-    if (!detach) {
-        qemuReportError(VIR_ERR_OPERATION_FAILED,
-                        _("host usb device %03d.%03d not found"),
-                        dev->data.hostdev->source.subsys.u.usb.bus,
-                        dev->data.hostdev->source.subsys.u.usb.device);
-        return -1;
-    }
+    int ret;
 
     if (!detach->info->alias) {
         qemuReportError(VIR_ERR_OPERATION_FAILED,
@@ -2006,77 +1925,116 @@ qemuDomainDetachHostUsbDevice(struct qemud_driver *driver,
     if (ret < 0)
         return -1;
 
-    usb = usbGetDevice(detach->source.subsys.u.usb.bus,
-                       detach->source.subsys.u.usb.device);
+    usb = usbGetDevice(subsys->u.usb.bus, subsys->u.usb.device);
     if (usb) {
         usbDeviceListDel(driver->activeUsbHostdevs, usb);
         usbFreeDevice(usb);
     } else {
         VIR_WARN("Unable to find device %03d.%03d in list of used USB devices",
-                 detach->source.subsys.u.usb.bus,
-                 detach->source.subsys.u.usb.device);
-    }
-
-    if (vm->def->nhostdevs > 1) {
-        memmove(vm->def->hostdevs + i,
-                vm->def->hostdevs + i + 1,
-                sizeof(*vm->def->hostdevs) *
-                (vm->def->nhostdevs - (i + 1)));
-        vm->def->nhostdevs--;
-        if (VIR_REALLOC_N(vm->def->hostdevs, vm->def->nhostdevs) < 0) {
-            /* ignore, harmless */
-        }
-    } else {
-        VIR_FREE(vm->def->hostdevs);
-        vm->def->nhostdevs = 0;
+                 subsys->u.usb.bus, subsys->u.usb.device);
     }
-    if (detach_ret)
-        *detach_ret = detach;
-    else
-        virDomainHostdevDefFree(detach);
 
+    virDomainHostdevRemove(vm->def, idx);
     return ret;
 }
 
-int qemuDomainDetachHostDevice(struct qemud_driver *driver,
-                               virDomainObjPtr vm,
-                               virDomainDeviceDefPtr dev)
+static
+int qemuDomainDetachThisHostDevice(struct qemud_driver *driver,
+                                   virDomainObjPtr vm,
+                                   virDomainHostdevDefPtr detach,
+                                   int idx)
 {
-    virDomainHostdevDefPtr hostdev = dev->data.hostdev;
-    virDomainHostdevDefPtr detach = NULL;
-    int ret;
+    int ret = -1;
 
-    if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) {
-        qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
-                        _("hostdev mode '%s' not supported"),
-                        virDomainHostdevModeTypeToString(hostdev->mode));
-        return -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) {
+            qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                            _("device not found in hostdevs list (%d entries)"),
+                            vm->def->nhostdevs);
+            return ret;
+        }
     }
 
-    switch (hostdev->source.subsys.type) {
+    switch (detach->source.subsys.type) {
     case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI:
-        ret = qemuDomainDetachHostPciDevice(driver, vm, dev, &detach);
+        ret = qemuDomainDetachHostPciDevice(driver, vm, detach, idx);
        break;
     case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB:
-        ret = qemuDomainDetachHostUsbDevice(driver, vm, dev, &detach);
+        ret = qemuDomainDetachHostUsbDevice(driver, vm, detach, idx);
         break;
     default:
         qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                         _("hostdev subsys type '%s' not supported"),
-                        virDomainHostdevSubsysTypeToString(hostdev->source.subsys.type));
+                        virDomainHostdevSubsysTypeToString(detach->source.subsys.type));
         return -1;
     }
 
     if (ret == 0 &&
         virSecurityManagerRestoreHostdevLabel(driver->securityManager,
-                                              vm->def, detach) < 0)
+                                              vm->def, detach) < 0) {
         VIR_WARN("Failed to restore host device labelling");
+    }
 
     virDomainHostdevDefFree(detach);
-
     return ret;
 }
 
+/* search for a hostdev matching dev and detach it */
+int qemuDomainDetachHostDevice(struct qemud_driver *driver,
+                               virDomainObjPtr vm,
+                               virDomainDeviceDefPtr dev)
+{
+    virDomainHostdevDefPtr hostdev = dev->data.hostdev;
+    virDomainHostdevSubsysPtr subsys = &hostdev->source.subsys;
+    virDomainHostdevDefPtr detach = NULL;
+    int idx;
+
+    if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) {
+        qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                        _("hostdev mode '%s' not supported"),
+                        virDomainHostdevModeTypeToString(hostdev->mode));
+        return -1;
+    }
+
+    idx = virDomainHostdevFind(vm->def, hostdev, &detach);
+
+    if (idx < 0) {
+        switch(subsys->type) {
+        case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI:
+            qemuReportError(VIR_ERR_OPERATION_FAILED,
+                            _("host pci device %.4x:%.2x:%.2x.%.1x not found"),
+                            subsys->u.pci.domain, subsys->u.pci.bus,
+                            subsys->u.pci.slot, subsys->u.pci.function);
+            break;
+        case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB:
+            if (subsys->u.usb.bus && subsys->u.usb.device) {
+                qemuReportError(VIR_ERR_OPERATION_FAILED,
+                                _("host usb device %03d.%03d not found"),
+                                subsys->u.usb.bus, subsys->u.usb.device);
+            } else {
+                qemuReportError(VIR_ERR_OPERATION_FAILED,
+                                _("host usb device vendor=0x%.4x product=0x%.4x not found"),
+                                subsys->u.usb.vendor, subsys->u.usb.product);
+            }
+            break;
+        default:
+            qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                            _("unexpected hostdev type %d"), subsys->type);
+            break;
+        }
+        return -1;
+    }
+
+    return qemuDomainDetachThisHostDevice(driver, vm, detach, idx);
+}
+
 int
 qemuDomainDetachNetDevice(struct qemud_driver *driver,
                           virDomainObjPtr vm,
-- 
1.7.7.6




More information about the libvir-list mailing list