
2013/8/12 Jim Fehlig <jfehlig@suse.com>
+int +virHostdevPrepareScsiHostdevs(virHostdevManagerPtr mgr, + const char *drv_name, + const char *dom_name, + virDomainHostdevDefPtr *hostdevs, + int nhostdevs) +{ + size_t i, j; + int count; + virSCSIDeviceListPtr list; + virSCSIDevicePtr tmp; + + /* To prevent situation where SCSI device is assigned to two domains + * we need to keep a list of currently assigned SCSI devices. + */ + if (!(list = virSCSIDeviceListNew())) + goto cleanup; + + /* Loop 1: build temporary list */ + for (i = 0; i < nhostdevs; i++) { + virDomainHostdevDefPtr hostdev = hostdevs[i]; + virSCSIDevicePtr scsi; + + if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS || + hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI) + continue; + + if (hostdev->managed) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("SCSI host device doesn't support managed mode")); + goto cleanup; + } + + if (!(scsi = virSCSIDeviceNew(hostdev->source.subsys.u.scsi.adapter, + hostdev->source.subsys.u.scsi.bus, + hostdev->source.subsys.u.scsi.target, + hostdev->source.subsys.u.scsi.unit, + hostdev->readonly))) + goto cleanup; + + if (scsi && virSCSIDeviceListAdd(list, scsi) < 0) { + virSCSIDeviceFree(scsi); + goto cleanup; + } + } + + /* Loop 2: Mark devices in temporary list as used by + * and add them to driver list. However, if something goes + * wrong, perform rollback. + */ + virObjectLock(mgr->activeScsiHostdevs); + count = virSCSIDeviceListCount(list); + + for (i = 0; i < count; i++) { + virSCSIDevicePtr scsi = virSCSIDeviceListGet(list, i); + if ((tmp = virSCSIDeviceListFind(mgr->activeScsiHostdevs, scsi))) { + char *other_drvname = NULL; + char *other_domname = NULL; + virSCSIDeviceGetUsedBy(tmp, &other_drvname, &other_domname); + + if (other_drvname && other_domname) + virReportError(VIR_ERR_OPERATION_INVALID, + _("SCSI device %s is in use by driver %s domain %s"), + virSCSIDeviceGetName(tmp), other_drvname, other_domname); + else + virReportError(VIR_ERR_OPERATION_INVALID, + _("SCSI device %s is already in use"), + virSCSIDeviceGetName(tmp)); + goto error; + } + + virSCSIDeviceSetUsedBy(scsi, drv_name, dom_name); + VIR_DEBUG("Adding %s to activeScsiHostdevs", virSCSIDeviceGetName(scsi)); + + if (virSCSIDeviceListAdd(mgr->activeScsiHostdevs, scsi) < 0) + goto error; + } + + virObjectUnlock(mgr->activeScsiHostdevs); + + /* Loop 3: Temporary list was successfully merged with + * driver list, so steal all items to avoid freeing them + * when freeing temporary list. + */ + while (virSCSIDeviceListCount(list) > 0) { + tmp = virSCSIDeviceListGet(list, 0); + virSCSIDeviceListSteal(list, tmp); + } + + virObjectUnref(list); + return 0; + +error: + for (j = 0; j < i; j++) { + tmp = virSCSIDeviceListGet(list, i);
Shouldn't this be 'virSCSIDeviceListGet(list, j)'?
Oh, shamed. Yes, should be 'virSCSIDeviceListGet(list, j)'. I copied it
from qemu_hostdev.c, wrong in qemu_hostdev.c too.
+ virSCSIDeviceListSteal(mgr->activeScsiHostdevs, tmp);
+ } + virObjectUnlock(mgr->activeScsiHostdevs); +cleanup: + virObjectUnref(list); + return -1; +} + + +int +virHostdevPrepareDomainHostdevs(virHostdevManagerPtr mgr, + const char *driver, + virDomainDefPtr def, + unsigned int flags)
Parameter whitespace alignment.
+{ + if (!def->nhostdevs) + return 0; + + if (flags & VIR_SP_PCI_HOSTDEV) { + if (virHostdevPreparePciHostdevs(mgr, driver, + def->name, def->uuid, + def->hostdevs, + def->nhostdevs, + flags) < 0) + return -1; + } + + if (flags & VIR_SP_USB_HOSTDEV) { + bool coldBoot = (flags & VIR_COLD_BOOT)?true:false; + if (virHostdevPrepareUsbHostdevs(mgr, driver, def->name, + def->hostdevs, def->nhostdevs, + coldBoot) < 0) + return -1; + } + + if (flags & VIR_SP_SCSI_HOSTDEV) { + if (virHostdevPrepareScsiHostdevs(mgr, driver, def->name, + def->hostdevs, def->nhostdevs) < 0) + return -1; + } + + return 0; +} + +/* + * Pre-condition: mgr->inactivePciHostdevs & mgr->activePciHostdevs + * are locked + */ +static void +virHostdevReAttachPciDevice(virHostdevManagerPtr mgr, virPCIDevicePtr dev, const char *driver)
This line is > 80 columns.
+{ + /* If the device is not managed and was attached to guest + * successfully, it must have been inactive. + */ + if (!virPCIDeviceGetManaged(dev)) { + if (virPCIDeviceListAdd(mgr->inactivePciHostdevs, dev) < 0) + virPCIDeviceFree(dev); + return; + } + + /* Wait for device cleanup if it is qemu/kvm */ + if (STREQ(driver, QEMU_DRIVER_NAME) && + STREQ(virPCIDeviceGetStubDriver(dev), "pci-stub")) { + int retries = 100; + while (virPCIDeviceWaitForCleanup(dev, "kvm_assigned_device") + && retries) { + usleep(100*1000); + retries--; + } + } + + if (virPCIDeviceReattach(dev, mgr->activePciHostdevs, + mgr->inactivePciHostdevs) < 0) { + virErrorPtr err = virGetLastError(); + VIR_ERROR(_("Failed to re-attach PCI device: %s"), + err ? err->message : _("unknown error")); + virResetError(err); + } + virPCIDeviceFree(dev); +} + +/* + * Pre-condition: mgr->activePciHostdevs is locked + */ +static virPCIDeviceListPtr +virHostdevGetActivePciHostDeviceList(virHostdevManagerPtr mgr, + virDomainHostdevDefPtr *hostdevs, + int nhostdevs) +{ + virPCIDeviceListPtr list; + size_t i; + + if (!(list = virPCIDeviceListNew())) + return NULL; + + for (i = 0; i < nhostdevs; i++) { + virDomainHostdevDefPtr hostdev = hostdevs[i]; + virPCIDevicePtr dev; + virPCIDevicePtr activeDev; + + if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) + continue; + if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) + continue; + + dev = virPCIDeviceNew(hostdev->source.subsys.u.pci.addr.domain, + hostdev->source.subsys.u.pci.addr.bus, + hostdev->source.subsys.u.pci.addr.slot, + hostdev->source.subsys.u.pci.addr.function); + if (!dev) { + virObjectUnref(list); + return NULL; + } + + if ((activeDev = virPCIDeviceListFind(mgr->activePciHostdevs, dev))) { + if (virPCIDeviceListAdd(list, activeDev) < 0) { + virPCIDeviceFree(dev); + virObjectUnref(list); + return NULL; + } + } + + virPCIDeviceFree(dev); + } + + return list; +} + +void +virHostdevReAttachPciHostdevs(virHostdevManagerPtr mgr, + const char *drv_name, + const char *dom_name, + virDomainHostdevDefPtr *hostdevs, + int nhostdevs) +{ + virPCIDeviceListPtr pcidevs; + size_t i; + + virObjectLock(mgr->activePciHostdevs); + virObjectLock(mgr->inactivePciHostdevs); + + if (!(pcidevs = virHostdevGetActivePciHostDeviceList(mgr, + hostdevs, + nhostdevs))) { + virErrorPtr err = virGetLastError(); + VIR_ERROR(_("Failed to allocate PCI device list: %s"), + err ? err->message : _("unknown error")); + virResetError(err); + goto cleanup; + } + + /* Again 4 loops; mark all devices as inactive before reset + * them and reset all the devices before re-attach. + * Attach mac and port profile parameters to devices + */ + for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) { + virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i); + virPCIDevicePtr activeDev = NULL; + char *usedby_drvname = NULL; + char *usedby_domname = NULL; + + /* Never delete the dev from list driver->activePciHostdevs + * if it's used by other domain. + */ + activeDev = virPCIDeviceListFind(mgr->activePciHostdevs, dev); + if (activeDev) { + if (virPCIDeviceGetUsedBy(activeDev, &usedby_drvname, &usedby_domname) < 0) { + VIR_WARN("Unable to get driver and domain name " + "using PCI device %s", + virPCIDeviceGetName(dev)); + VIR_FREE(usedby_drvname); + VIR_FREE(usedby_domname); + continue; + } + + if (STRNEQ_NULLABLE(drv_name, usedby_drvname) || + STRNEQ_NULLABLE(dom_name, usedby_domname)) { + virPCIDeviceListSteal(pcidevs, dev); + VIR_FREE(usedby_drvname); + VIR_FREE(usedby_domname); + continue; + } + } + + /* virObjectUnref() will take care of freeing the dev. */ + virPCIDeviceListSteal(mgr->activePciHostdevs, dev); + + VIR_FREE(usedby_drvname); + VIR_FREE(usedby_domname); + } + + /* + * For SRIOV net host devices, unset mac and port profile before + * reset and reattach device + */ + for (i = 0; i < nhostdevs; i++) { + virDomainHostdevDefPtr hostdev = hostdevs[i]; + if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) + continue; + if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) + continue; + if (hostdev->parent.type == VIR_DOMAIN_DEVICE_NET && + hostdev->parent.data.net) { + virHostdevNetConfigRestore(hostdev, mgr->stateDir); + } + } + + for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) { + virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i); + if (virPCIDeviceReset(dev, mgr->activePciHostdevs, + mgr->inactivePciHostdevs) < 0) { + virErrorPtr err = virGetLastError(); + VIR_ERROR(_("Failed to reset PCI device: %s"), + err ? err->message : _("unknown error")); + virResetError(err); + } + } + + while (virPCIDeviceListCount(pcidevs) > 0) { + virPCIDevicePtr dev = virPCIDeviceListStealIndex(pcidevs, 0); + virHostdevReAttachPciDevice(mgr, dev, drv_name); + } + + virObjectUnref(pcidevs); +cleanup: + virObjectUnlock(mgr->activePciHostdevs); + virObjectUnlock(mgr->inactivePciHostdevs); +} + +void +virHostdevReAttachUsbHostdevs(virHostdevManagerPtr mgr, + const char *drv_name, + const char *dom_name, + virDomainHostdevDefPtr *hostdevs, + int nhostdevs) +{ + size_t i; + + virObjectLock(mgr->activeUsbHostdevs); + for (i = 0; i < nhostdevs; i++) { + virDomainHostdevDefPtr hostdev = hostdevs[i]; + virUSBDevicePtr usb, tmp; + char *usedby_drvname = NULL; + char *usedby_domname = NULL; + + if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) + continue; + if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB) + continue; + if (hostdev->missing) + continue; + + usb = virUSBDeviceNew(hostdev->source.subsys.u.usb.bus, + hostdev->source.subsys.u.usb.device, + NULL); + + if (!usb) { + VIR_WARN("Unable to reattach USB device %03d.%03d on driver %s domain %s", + hostdev->source.subsys.u.usb.bus, + hostdev->source.subsys.u.usb.device, + drv_name, dom_name); + continue; + } + + /* Delete only those USB devices which belongs + * to domain. Therefore we want to steal only + * those devices from the list which were taken + * by domain */ + + tmp = virUSBDeviceListFind(mgr->activeUsbHostdevs, usb); + virUSBDeviceFree(usb); + + if (!tmp) { + VIR_WARN("Unable to find device %03d.%03d " + "in list of active USB devices", + hostdev->source.subsys.u.usb.bus, + hostdev->source.subsys.u.usb.device); + continue; + } + + if (virUSBDeviceGetUsedBy(tmp, &usedby_drvname, &usedby_domname) < 0) { + VIR_WARN("Unable to get driver and domain name " + "using USB device %03d.%03d", + hostdev->source.subsys.u.usb.bus, + hostdev->source.subsys.u.usb.device); + + VIR_FREE(usedby_drvname); + VIR_FREE(usedby_domname); + continue; + } + + if (STREQ_NULLABLE(drv_name, usedby_drvname) && + STREQ_NULLABLE(dom_name, usedby_domname)) { + VIR_DEBUG("Removing %03d.%03d dom=%s:%s", + hostdev->source.subsys.u.usb.bus, + hostdev->source.subsys.u.usb.device, + drv_name, dom_name); + virUSBDeviceListDel(mgr->activeUsbHostdevs, tmp); + } + + VIR_FREE(usedby_drvname); + VIR_FREE(usedby_domname); + + } + + virObjectUnlock(mgr->activeUsbHostdevs); +} + +void +virHostdevReAttachScsiHostdevs(virHostdevManagerPtr mgr, + const char *drv_name, + const char *dom_name, + virDomainHostdevDefPtr *hostdevs, + int nhostdevs) +{ + size_t i; + + virObjectLock(mgr->activeScsiHostdevs); + for (i = 0; i < nhostdevs; i++) { + virDomainHostdevDefPtr hostdev = hostdevs[i]; + virSCSIDevicePtr scsi, tmp; + char *usedby_drvname = NULL; + char *usedby_domname = NULL; + + if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS || + hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI) + continue; + + if (!(scsi = virSCSIDeviceNew(hostdev->source.subsys.u.scsi.adapter, + hostdev->source.subsys.u.scsi.bus, + hostdev->source.subsys.u.scsi.target, + hostdev->source.subsys.u.scsi.unit, + hostdev->readonly))) { + VIR_WARN("Unable to reattach SCSI device %s:%d:%d:%d on driver %s domain %s", + hostdev->source.subsys.u.scsi.adapter, + hostdev->source.subsys.u.scsi.bus, + hostdev->source.subsys.u.scsi.target, + hostdev->source.subsys.u.scsi.unit, + drv_name, dom_name); + continue; + } + + tmp = virSCSIDeviceListFind(mgr->activeScsiHostdevs, scsi); + virSCSIDeviceFree(scsi); + + if (!tmp) { + VIR_WARN("Unable to find device %s:%d:%d:%d " + "in list of active SCSI devices", + hostdev->source.subsys.u.scsi.adapter, + hostdev->source.subsys.u.scsi.bus, + hostdev->source.subsys.u.scsi.target, + hostdev->source.subsys.u.scsi.unit); + continue; + } + + if (virSCSIDeviceGetUsedBy(tmp, &usedby_drvname, &usedby_domname) < 0) { + VIR_WARN("Unable to get driver and domain name " + "using SCSI device %s:%d:%d:%d ", + hostdev->source.subsys.u.scsi.adapter, + hostdev->source.subsys.u.scsi.bus, + hostdev->source.subsys.u.scsi.target, + hostdev->source.subsys.u.scsi.unit); + VIR_FREE(usedby_drvname); + VIR_FREE(usedby_domname); + continue; + } + + if (STREQ_NULLABLE(usedby_drvname, drv_name) && + STREQ_NULLABLE(usedby_domname, dom_name)) { + VIR_DEBUG("Removing %s:%d:%d:%d driver:%s dom:%s from activeScsiHostdevs", + hostdev->source.subsys.u.scsi.adapter, + hostdev->source.subsys.u.scsi.bus, + hostdev->source.subsys.u.scsi.target, + hostdev->source.subsys.u.scsi.unit, + drv_name, dom_name); + virSCSIDeviceListDel(mgr->activeScsiHostdevs, tmp); + } + + VIR_FREE(usedby_drvname); + VIR_FREE(usedby_domname); + } + + virObjectUnlock(mgr->activeScsiHostdevs); +} + +void +virHostdevReAttachDomainHostdevs(virHostdevManagerPtr mgr, + const char *driver, + virDomainDefPtr def, + unsigned int flags)
Parameter whitespace alignment.
+{ + if (!def->nhostdevs) + return; + + if (flags & VIR_SP_PCI_HOSTDEV) { + virHostdevReAttachPciHostdevs(mgr, driver, def->name, def->hostdevs, def->nhostdevs); + } + + if (flags & VIR_SP_USB_HOSTDEV) { + virHostdevReAttachUsbHostdevs(mgr, driver, def->name, def->hostdevs, def->nhostdevs); + } + + if (flags & VIR_SP_SCSI_HOSTDEV) { + virHostdevReAttachScsiHostdevs(mgr, driver, def->name, def->hostdevs, def->nhostdevs); + } +} + +/* following functions are used by NodeDevDetach/Reattach/Reset */ +int +virHostdevPciNodeDeviceDetach(virHostdevManagerPtr mgr, + virPCIDevicePtr pci) +{ + int ret;
Needs a line after local variable declaration.
+ virObjectLock(mgr->activePciHostdevs); + virObjectLock(mgr->inactivePciHostdevs); + if (virPCIDeviceDetach(pci, mgr->activePciHostdevs, + mgr->inactivePciHostdevs) < 0) + ret = -1; + else + ret = 0; + + virObjectUnlock(mgr->inactivePciHostdevs); + virObjectUnlock(mgr->activePciHostdevs); + return ret; +} + +int +virHostdevPciNodeDeviceReAttach(virHostdevManagerPtr mgr, + virPCIDevicePtr pci) +{ + int ret = -1; + virPCIDevicePtr other; + + virObjectLock(mgr->activePciHostdevs); + virObjectLock(mgr->inactivePciHostdevs); + other = virPCIDeviceListFind(mgr->activePciHostdevs, pci); + if (other) { + char *other_drvname = NULL; + char *other_domname = NULL; + virPCIDeviceGetUsedBy(other, &other_drvname, &other_domname); + + if (other_drvname && other_domname) + virReportError(VIR_ERR_OPERATION_INVALID, + _("PCI device %s is still in use by driver %s, domain %s"), + virPCIDeviceGetName(pci), other_drvname, other_domname); + else + virReportError(VIR_ERR_OPERATION_INVALID, + _("PCI device %s is still in use"), + virPCIDeviceGetName(pci)); + goto out; + } + + virPCIDeviceReattachInit(pci); + + if (virPCIDeviceReattach(pci, mgr->activePciHostdevs, + mgr->inactivePciHostdevs) < 0) + goto out; + + ret = 0; +out: + virObjectUnlock(mgr->inactivePciHostdevs); + virObjectUnlock(mgr->activePciHostdevs); + return ret; +} + +int +virHostdevPciNodeDeviceReset(virHostdevManagerPtr mgr, + virPCIDevicePtr pci) +{ + int ret;
Needs line after local variable declaration.
+ virObjectLock(mgr->activePciHostdevs); + virObjectLock(mgr->inactivePciHostdevs); + if (virPCIDeviceReset(pci, mgr->activePciHostdevs, + mgr->inactivePciHostdevs) < 0) + ret = -1; + else + ret = 0; + + virObjectUnlock(mgr->inactivePciHostdevs); + virObjectUnlock(mgr->activePciHostdevs); + return ret; +} + +/* this function is used to free memory after using following + * get_active/inactive_list functions + */ +void +virHostdevNameListFree(virHostdevNameListPtr list) +{ + size_t i; + + if (list && list->names) { + for (i = 0; i < list->nnames; i++) { + VIR_FREE(list->names[i]); + } + VIR_FREE(list->names); + } + VIR_FREE(list); +} + +virHostdevNameListPtr +virHostdevGetActivePciHostdevs(virHostdevManagerPtr mgr) +{ + size_t i; + int count; + virHostdevNameListPtr list = NULL; + virObjectLock(mgr->activePciHostdevs); + + count = virPCIDeviceListCount(mgr->activePciHostdevs); + if (count > 0) { + if (VIR_ALLOC_N(list, 1) < 0) { + virReportOOMError();
No need to explicitly report OOM error now.
+ goto cleanup; + } + + if (VIR_ALLOC_N(list->names,count) < 0) { + virReportOOMError();
Same here.
+ goto cleanup; + } + list->nnames = 0; + + for (i = 0; i < count; i++) { + virPCIDevicePtr dev = virPCIDeviceListGet(mgr->activePciHostdevs, i); + if (VIR_STRDUP(list->names[list->nnames++], virPCIDeviceGetName(dev)) < 0) + goto cleanup; + } + } + + goto end; + +cleanup: + virHostdevNameListFree(list); + +end: + virObjectUnlock(mgr->activePciHostdevs); + return list; +} + +virHostdevNameListPtr +virHostdevGetActiveUsbHostdevs(virHostdevManagerPtr mgr) +{ + size_t i; + int count; + virHostdevNameListPtr list = NULL; + virObjectLock(mgr->activeUsbHostdevs); + + count = virUSBDeviceListCount(mgr->activeUsbHostdevs); + if (count > 0) { + if (VIR_ALLOC_N(list, 1) < 0) { + virReportOOMError();
Same, no need for OOM error reporting.
+ goto cleanup; + } + + if (VIR_ALLOC_N(list->names,count) < 0) { + virReportOOMError();
And again.
+ goto cleanup; + } + list->nnames = 0; + + for (i = 0; i < count; i++) { + virUSBDevicePtr usb = virUSBDeviceListGet(mgr->activeUsbHostdevs, i); + if (VIR_STRDUP(list->names[list->nnames++], virUSBDeviceGetName(usb)) < 0) + goto cleanup; + } + } + + goto end; + +cleanup: + virHostdevNameListFree(list); +end: + virObjectUnlock(mgr->activeUsbHostdevs); + return list; +} + +virHostdevNameListPtr +virHostdevGetActiveScsiHostdevs(virHostdevManagerPtr mgr) +{ + size_t i; + int count; + virHostdevNameListPtr list = NULL; + virObjectLock(mgr->activeScsiHostdevs); + + count = virSCSIDeviceListCount(mgr->activeScsiHostdevs); + if (count > 0) { + if (VIR_ALLOC_N(list, 1) < 0) { + virReportOOMError();
And again.
+ goto cleanup; + } + + if (VIR_ALLOC_N(list->names,count) < 0) { + virReportOOMError();
Here too.
+ goto cleanup; + } + list->nnames = 0; + + for (i = 0; i < count; i++) { + virSCSIDevicePtr dev = virSCSIDeviceListGet(mgr->activeScsiHostdevs, i); + if (VIR_STRDUP(list->names[list->nnames++], virSCSIDeviceGetName(dev)) < 0) + goto cleanup; + } + } + + goto end; + +cleanup: + virHostdevNameListFree(list); +end: + virObjectUnlock(mgr->activeScsiHostdevs); + return list; +} + +virHostdevNameListPtr +virHostdevGetDomainActivePciHostdevs(virHostdevManagerPtr mgr, + const char *drv_name, + const char *dom_name) +{ + size_t i, count; + virHostdevNameListPtr list = NULL; + virObjectLock(mgr->activePciHostdevs); + + count = virPCIDeviceListCount(mgr->activePciHostdevs); + if (count > 0) { + if (VIR_ALLOC_N(list, 1) < 0) { + virReportOOMError();
Same.
+ goto cleanup; + } + + if (VIR_ALLOC_N(list->names,count) < 0) { + virReportOOMError();
Same.
+ goto cleanup; + } + list->nnames = 0; + + for (i = 0; i < count; i++) { + virPCIDevicePtr dev = virPCIDeviceListGet(mgr->activePciHostdevs, i); + char *usedby_drvname = NULL; + char *usedby_domname = NULL; + int ret; + + if (virPCIDeviceGetUsedBy(dev, &usedby_drvname, &usedby_domname) < 0) { + VIR_FREE(usedby_drvname); + VIR_FREE(usedby_domname); + + goto cleanup; + } + + if (STREQ(drv_name, usedby_drvname) && + STREQ(dom_name, usedby_domname)) { + ret = VIR_STRDUP(list->names[list->nnames++], virPCIDeviceGetName(dev)); + if (ret < 0) { + VIR_FREE(usedby_drvname); + VIR_FREE(usedby_domname); + goto cleanup; + } + } + + VIR_FREE(usedby_drvname); + VIR_FREE(usedby_domname); + } + + VIR_SHRINK_N(list->names, count, count - list->nnames); + } + + goto end; + +cleanup: + virHostdevNameListFree(list); +end: + virObjectUnlock(mgr->activePciHostdevs); + return list; +} + +virHostdevNameListPtr +virHostdevGetDomainActiveUsbHostdevs(virHostdevManagerPtr mgr, + const char *drv_name, + const char *dom_name) +{ + size_t i, count; + virHostdevNameListPtr list = NULL; + virObjectLock(mgr->activeUsbHostdevs); + + count = virUSBDeviceListCount(mgr->activeUsbHostdevs); + if (count > 0) { + if (VIR_ALLOC_N(list, 1) < 0) { + virReportOOMError(); + goto cleanup; + } + + if (VIR_ALLOC_N(list->names,count) < 0) { + virReportOOMError();
A few more cases of unneeded OOM error reporting.
+ goto cleanup; + } + list->nnames = 0; + + for (i = 0; i < count; i++) { + virUSBDevicePtr usb = virUSBDeviceListGet(mgr->activeUsbHostdevs, i); + char *usedby_drvname = NULL; + char *usedby_domname = NULL; + int ret; + + if (virUSBDeviceGetUsedBy(usb, &usedby_drvname, &usedby_domname) < 0) { + VIR_FREE(usedby_drvname); + VIR_FREE(usedby_domname); + goto cleanup; + } + + if (STREQ(drv_name, usedby_drvname) && + STREQ(dom_name, usedby_domname)) { + ret = VIR_STRDUP(list->names[list->nnames++], virUSBDeviceGetName(usb)); + if (ret < 0) { + VIR_FREE(usedby_drvname); + VIR_FREE(usedby_domname); + goto cleanup; + } + } + + VIR_FREE(usedby_drvname); + VIR_FREE(usedby_domname); + } + + VIR_SHRINK_N(list->names, count, count - list->nnames); + } + + goto end; + +cleanup: + virHostdevNameListFree(list); +end: + virObjectUnlock(mgr->activeUsbHostdevs); + return list; +} + +virHostdevNameListPtr +virHostdevGetDomainActiveScsiHostdevs(virHostdevManagerPtr mgr, + const char *drv_name, + const char *dom_name) +{ + size_t i, count; + virHostdevNameListPtr list = NULL; + virObjectLock(mgr->activeScsiHostdevs); + + count = virSCSIDeviceListCount(mgr->activeScsiHostdevs); + if (count > 0) { + if (VIR_ALLOC_N(list, 1) < 0) { + virReportOOMError(); + goto cleanup; + } + + if (VIR_ALLOC_N(list->names,count) < 0) { + virReportOOMError();
You're probably getting tired of this comment by now :).
+ goto cleanup; + } + list->nnames = 0; + + for (i = 0; i < count; i++) { + virSCSIDevicePtr dev = virSCSIDeviceListGet(mgr->activeScsiHostdevs, i); + char *usedby_drvname = NULL; + char *usedby_domname = NULL; + int ret; + + if (virSCSIDeviceGetUsedBy(dev, &usedby_drvname, &usedby_domname) < 0) { + VIR_FREE(usedby_drvname); + VIR_FREE(usedby_domname); + goto cleanup; + } + + if (STREQ(drv_name, usedby_drvname) && + STREQ(dom_name, usedby_domname)) { + ret = VIR_STRDUP(list->names[list->nnames++], virSCSIDeviceGetName(dev)); + if (ret < 0){ + VIR_FREE(usedby_drvname); + VIR_FREE(usedby_domname); + goto cleanup; + } + } + + VIR_FREE(usedby_drvname); + VIR_FREE(usedby_domname); + } + + VIR_SHRINK_N(list->names, count, count - list->nnames); + } + + goto end; + +cleanup: + virHostdevNameListFree(list); +end: + virObjectUnlock(mgr->activeScsiHostdevs); + return list; +} diff --git a/src/util/virhostdev.h b/src/util/virhostdev.h new file mode 100644 index 0000000..09377db --- /dev/null +++ b/src/util/virhostdev.h @@ -0,0 +1,123 @@ +/* virhostdev.h: hostdev management + * + * Copyright (C) 2013 SUSE LINUX Products GmbH, Nuernberg, Germany. + * Copyright (C) 2006-2007, 2009-2013 Red Hat, Inc. + * Copyright (C) 2006 Daniel P. Berrange + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * <http://www.gnu.org/licenses/>. + * + * Author: Chunyan Liu <cyliu@suse.com> + * Author: Daniel P. Berrange <berrange@redhat.com> + */ + +#ifndef __VIR_HOSTDEV_MANAGER_H__ +# define __VIR_HOSTDEV_MANAGER_H__ + +# include "internal.h" +# include "configmake.h" + +# include "domain_conf.h" +# include "virpci.h" + +# define HOSTDEV_STATE_DIR LOCALSTATEDIR "/run/libvirt/hostdevmanager"
This could be moved to virhostdev.c right?
Yeah, could be.
+ +typedef enum { + VIR_SP_PCI_HOSTDEV = (1 << 0), /* support pci passthrough */ + VIR_SP_USB_HOSTDEV = (1 << 1), /* support usb passthrough */ + VIR_SP_SCSI_HOSTDEV = (1 << 2), /* support scsi passthrough */ + + VIR_COLD_BOOT = (1 << 8), /* cold boot */ + VIR_STRICT_ACS_CHECK = (1 << 9), /* strict acs check */ +} virHostdevManagerFlag; + +typedef struct _virHostdevManager virHostdevManager; +typedef virHostdevManager *virHostdevManagerPtr; + +struct virHostdevNameList { + char **names; + size_t nnames; +}; +typedef struct virHostdevNameList *virHostdevNameListPtr; + +virHostdevManagerPtr virHostdevManagerGetDefault(void); + +/* functions used to prepare/unprepare hostdevs for domain */ +int virHostdevPrepareDomainHostdevs(virHostdevManagerPtr mgr, + const char *driver, + virDomainDefPtr def, + unsigned int flags); +void virHostdevReAttachDomainHostdevs(virHostdevManagerPtr mgr, + const char *driver, + virDomainDefPtr def, + unsigned int flags);
Parameter whitespace alignment in these two function declarations.
+int virHostdevPreparePciHostdevs(virHostdevManagerPtr mgr, + const char *drv_name, + const char *dom_name, + const unsigned char *uuid, + virDomainHostdevDefPtr *hostdevs, + int nhostdevs, + unsigned int flags); +int virHostdevPrepareUsbHostdevs(virHostdevManagerPtr mgr, + const char *drv_name, + const char *dom_name, + virDomainHostdevDefPtr *hostdevs, + int nhostdevs, + bool coldBoot); +int virHostdevPrepareScsiHostdevs(virHostdevManagerPtr mgr, + const char *drv_name, + const char *dom_name, + virDomainHostdevDefPtr *hostdevs, + int nhostdevs); +void virHostdevReAttachPciHostdevs(virHostdevManagerPtr mgr, + const char *drv_name, + const char *dom_name, + virDomainHostdevDefPtr *hostdevs, + int nhostdevs); +void virHostdevReAttachUsbHostdevs(virHostdevManagerPtr mgr, + const char *drv_name, + const char *dom_name, + virDomainHostdevDefPtr *hostdevs, + int nhostdevs); +void virHostdevReAttachScsiHostdevs(virHostdevManagerPtr mgr, + const char *drv_name, + const char *dom_name, + virDomainHostdevDefPtr *hostdevs, + int nhostdevs); + +/* functions used by NodeDevDetach/Reattach/Reset */ +int virHostdevPciNodeDeviceDetach(virHostdevManagerPtr mgr, + virPCIDevicePtr pci); +int virHostdevPciNodeDeviceReAttach(virHostdevManagerPtr mgr, + virPCIDevicePtr pci); +int virHostdevPciNodeDeviceReset(virHostdevManagerPtr mgr, + virPCIDevicePtr pci); + +/* functions to get active/inactive lists */ +virHostdevNameListPtr virHostdevGetActivePciHostdevs(virHostdevManagerPtr mgr); +virHostdevNameListPtr virHostdevGetActiveUsbHostdevs(virHostdevManagerPtr mgr); +virHostdevNameListPtr virHostdevGetActiveScsiHostdevs(virHostdevManagerPtr mgr); +virHostdevNameListPtr virHostdevGetDomainActivePciHostdevs(virHostdevManagerPtr mgr, + const char *drv_name, + const char *dom_name); +virHostdevNameListPtr virHostdevGetDomainActiveUsbHostdevs(virHostdevManagerPtr mgr, + const char *drv_name, + const char *dom_name); +virHostdevNameListPtr virHostdevGetDomainActiveScsiHostdevs(virHostdevManagerPtr mgr, + const char *drv_name, + const char *dom_name); +/* function to free memory after get active/inactive lists */ +void virHostdevNameListFree(virHostdevNameListPtr list); + +#endif /* __VIR_HOSTDEV_MANAGER_H__ */ diff --git a/src/util/virpci.c b/src/util/virpci.c index be50b4f..dc38efe 100644 --- a/src/util/virpci.c +++ b/src/util/virpci.c @@ -62,7 +62,10 @@ struct _virPCIDevice { char name[PCI_ADDR_LEN]; /* domain:bus:slot.function */ char id[PCI_ID_LEN]; /* product vendor */ char *path; - const char *used_by; /* The domain which uses the device */ + + /* The driver:domain which uses the device */ + const char *used_by_drvname; + const char *used_by_domname;
unsigned int pcie_cap_pos; unsigned int pci_pm_cap_pos; @@ -1642,15 +1645,21 @@ virPCIDeviceSetReprobe(virPCIDevicePtr dev, bool reprobe) }
void -virPCIDeviceSetUsedBy(virPCIDevicePtr dev, const char *name) +virPCIDeviceSetUsedBy(virPCIDevicePtr dev, const char *drv_name, const char *dom_name) { - dev->used_by = name; + dev->used_by_drvname = drv_name; + dev->used_by_domname = dom_name; }
-const char * -virPCIDeviceGetUsedBy(virPCIDevicePtr dev) +int +virPCIDeviceGetUsedBy(virPCIDevicePtr dev, char **drv_name, char **dom_name) { - return dev->used_by; + if (VIR_STRDUP(*drv_name, dev->used_by_drvname) < 0) + return -1; + if (VIR_STRDUP(*dom_name, dev->used_by_domname) < 0) + return -1; + + return 0; }
void virPCIDeviceReattachInit(virPCIDevicePtr pci) diff --git a/src/util/virpci.h b/src/util/virpci.h index 0aa6fee..dc1a80b 100644 --- a/src/util/virpci.h +++ b/src/util/virpci.h @@ -66,8 +66,11 @@ int virPCIDeviceSetStubDriver(virPCIDevicePtr dev, const char *driver); const char *virPCIDeviceGetStubDriver(virPCIDevicePtr dev); void virPCIDeviceSetUsedBy(virPCIDevice *dev, - const char *used_by); -const char *virPCIDeviceGetUsedBy(virPCIDevice *dev); + const char *drv_name, + const char *dom_name); +int virPCIDeviceGetUsedBy(virPCIDevice *dev, + char **drv_name, + char **dom_name);
Parameters not aligned properly in these two function declarations.
unsigned int virPCIDeviceGetUnbindFromStub(virPCIDevicePtr dev); void virPCIDeviceSetUnbindFromStub(virPCIDevice *dev, bool unbind); diff --git a/src/util/virscsi.c b/src/util/virscsi.c index 32e438b..dc1eebb 100644 --- a/src/util/virscsi.c +++ b/src/util/virscsi.c @@ -55,7 +55,10 @@ struct _virSCSIDevice { char *name; /* adapter:bus:target:unit */ char *id; /* model:vendor */ char *sg_path; /* e.g. /dev/sg2 */ - const char *used_by; /* name of the domain using this dev */ + + /* driver:domain using this dev */ + const char *used_by_drvname; + const char *used_by_domname;
bool readonly; }; @@ -267,15 +270,22 @@ virSCSIDeviceFree(virSCSIDevicePtr dev)
void virSCSIDeviceSetUsedBy(virSCSIDevicePtr dev, - const char *name) + const char *drvname, + const char *domname) { - dev->used_by = name; + dev->used_by_drvname = drvname; + dev->used_by_domname = domname; }
-const char * -virSCSIDeviceGetUsedBy(virSCSIDevicePtr dev) +int +virSCSIDeviceGetUsedBy(virSCSIDevicePtr dev, char **drvname, char **domname) { - return dev->used_by; + if (VIR_STRDUP(*drvname, dev->used_by_drvname) < 0) + return -1; + if (VIR_STRDUP(*domname, dev->used_by_domname) < 0) + return -1; + + return 0; }
const char * diff --git a/src/util/virscsi.h b/src/util/virscsi.h index cce5df4..89b3e5d 100644 --- a/src/util/virscsi.h +++ b/src/util/virscsi.h @@ -49,8 +49,12 @@ virSCSIDevicePtr virSCSIDeviceNew(const char *adapter, bool readonly);
void virSCSIDeviceFree(virSCSIDevicePtr dev); -void virSCSIDeviceSetUsedBy(virSCSIDevicePtr dev, const char *name); -const char *virSCSIDeviceGetUsedBy(virSCSIDevicePtr dev); +void virSCSIDeviceSetUsedBy(virSCSIDevicePtr dev, + const char *drvname, + const char *domname); +int virSCSIDeviceGetUsedBy(virSCSIDevicePtr dev, + char **drvname, + char **domname); const char *virSCSIDeviceGetName(virSCSIDevicePtr dev); unsigned int virSCSIDeviceGetAdapter(virSCSIDevicePtr dev); unsigned int virSCSIDeviceGetBus(virSCSIDevicePtr dev); diff --git a/src/util/virusb.c b/src/util/virusb.c index e901618..54d836d 100644 --- a/src/util/virusb.c +++ b/src/util/virusb.c @@ -55,7 +55,10 @@ struct _virUSBDevice { char name[USB_ADDR_LEN]; /* domain:bus:slot.function */ char id[USB_ID_LEN]; /* product vendor */ char *path; - const char *used_by; /* name of the domain using this dev */ + + /* driver:domain using this dev */ + const char *used_by_drvname; + const char *used_by_domname; };
struct _virUSBDeviceList { @@ -378,16 +381,24 @@ virUSBDeviceFree(virUSBDevicePtr dev) VIR_FREE(dev); }
- void virUSBDeviceSetUsedBy(virUSBDevicePtr dev, - const char *name) + const char *drv_name, + const char *dom_name) { - dev->used_by = name; + dev->used_by_drvname = drv_name; + dev->used_by_domname = dom_name; }
-const char * virUSBDeviceGetUsedBy(virUSBDevicePtr dev) +int virUSBDeviceGetUsedBy(virUSBDevicePtr dev, + char **drv_name, + char **dom_name)
Parameter alignment.
This patch is looking good, but since I'm not terribly familiar with this area of libvirt and historically there have been quite a few bugs related to passthrough, it would be best if one of the devs familiar with this code (Laine, Osier) could also review it.
Regards, Jim
Thanks a lot for your review and comment. Since this patch affect existing qemu/lxc driver too, I also hope some one expert in that could review and point out problem if there is. Thanks, Chunyan
{ - return dev->used_by; + if (VIR_STRDUP(*drv_name, dev->used_by_drvname) < 0) + return -1; + if (VIR_STRDUP(*dom_name, dev->used_by_domname) < 0) + return -1; + + return 0; }
const char *virUSBDeviceGetName(virUSBDevicePtr dev) diff --git a/src/util/virusb.h b/src/util/virusb.h index aa59d12..5f1df58 100644 --- a/src/util/virusb.h +++ b/src/util/virusb.h @@ -60,8 +60,12 @@ int virUSBDeviceFind(unsigned int vendor, virUSBDevicePtr *usb);
void virUSBDeviceFree(virUSBDevicePtr dev); -void virUSBDeviceSetUsedBy(virUSBDevicePtr dev, const char *name); -const char *virUSBDeviceGetUsedBy(virUSBDevicePtr dev); +void virUSBDeviceSetUsedBy(virUSBDevicePtr dev, + const char *drv_name, + const char *dom_name); +int virUSBDeviceGetUsedBy(virUSBDevicePtr dev, + char **drv_name, + char **dom_name); const char *virUSBDeviceGetName(virUSBDevicePtr dev);
unsigned int virUSBDeviceGetBus(virUSBDevicePtr dev);