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