From 12b4dbbe297bd4191281b32891976d90cb92b723b14d7be45fd4c223892375da Mon Sep 17 00:00:00 2001 From: James Fehlig Date: Tue, 12 Jun 2012 20:22:26 +0000 Subject: [PATCH] - VUL-1: Fix hotplug support for usb devices with same vendorID, productID 9914477e-usb-search-funcs.patch 05abd150-usb-improve-hotplug.patch bnc#766559 OBS-URL: https://build.opensuse.org/package/show/Virtualization/libvirt?expand=0&rev=211 --- 05abd150-usb-improve-hotplug.patch | 325 ++++++++++++++++++++++ 9914477e-usb-search-funcs.patch | 423 +++++++++++++++++++++++++++++ libvirt.changes | 9 + libvirt.spec | 4 + 4 files changed, 761 insertions(+) create mode 100644 05abd150-usb-improve-hotplug.patch create mode 100644 9914477e-usb-search-funcs.patch diff --git a/05abd150-usb-improve-hotplug.patch b/05abd150-usb-improve-hotplug.patch new file mode 100644 index 0000000..c77ab59 --- /dev/null +++ b/05abd150-usb-improve-hotplug.patch @@ -0,0 +1,325 @@ +commit 05abd1507d66aabb6cad12eeafeb4c4d1911c585 +Author: Guannan Ren +Date: Sun May 6 22:45:05 2012 +0800 + + qemu: call usb search function for hostdev initialization and hotplug + + src/qemu/qemu_hostdev.c: + refactor qemuPrepareHostdevUSBDevices function, make it focus on + adding usb device to activeUsbHostdevs after check. After that, + the usb hotplug function qemuDomainAttachHostDevice also could use + it. + expand qemuPrepareHostUSBDevices to perform the usb search, + rollback on failure. + + src/qemu/qemu_hotplug.c: + If there are multiple usb devices available with same vendorID and productID, + but with different value of "bus, device", we give an error to let user + use
to specify the desired one. + +Index: libvirt-0.9.11.3/src/qemu/qemu_hostdev.c +=================================================================== +--- libvirt-0.9.11.3.orig/src/qemu/qemu_hostdev.c ++++ libvirt-0.9.11.3/src/qemu/qemu_hostdev.c +@@ -565,13 +565,53 @@ qemuPrepareHostPCIDevices(struct qemud_d + int + qemuPrepareHostdevUSBDevices(struct qemud_driver *driver, + const char *name, +- virDomainHostdevDefPtr *hostdevs, +- int nhostdevs) ++ usbDeviceList *list) + { +- int ret = -1; + int i; ++ unsigned int count; ++ usbDevice *tmp; ++ ++ count = usbDeviceListCount(list); ++ ++ for (i = 0; i < count; i++) { ++ usbDevice *usb = usbDeviceListGet(list, i); ++ if ((tmp = usbDeviceListFind(driver->activeUsbHostdevs, usb))) { ++ const char *other_name = usbDeviceGetUsedBy(tmp); ++ ++ if (other_name) ++ qemuReportError(VIR_ERR_OPERATION_INVALID, ++ _("USB device %s is in use by domain %s"), ++ usbDeviceGetName(tmp), other_name); ++ else ++ qemuReportError(VIR_ERR_OPERATION_INVALID, ++ _("USB device %s is already in use"), ++ usbDeviceGetName(tmp)); ++ return -1; ++ } ++ ++ usbDeviceSetUsedBy(usb, name); ++ VIR_DEBUG("Adding %03d.%03d dom=%s to activeUsbHostdevs", ++ usbDeviceGetBus(usb), usbDeviceGetDevno(usb), name); ++ /* ++ * The caller is responsible to steal these usb devices ++ * from the usbDeviceList that passed in on success, ++ * perform rollback on failure. ++ */ ++ if (usbDeviceListAdd(driver->activeUsbHostdevs, usb) < 0) ++ return -1; ++ } ++ return 0; ++} ++ ++static int ++qemuPrepareHostUSBDevices(struct qemud_driver *driver, ++ virDomainDefPtr def) ++{ ++ int i, ret = -1; + usbDeviceList *list; + usbDevice *tmp; ++ virDomainHostdevDefPtr *hostdevs = def->hostdevs; ++ int nhostdevs = def->nhostdevs; + + /* To prevent situation where USB device is assigned to two domains + * we need to keep a list of currently assigned USB devices. +@@ -586,70 +626,61 @@ qemuPrepareHostdevUSBDevices(struct qemu + */ + for (i = 0 ; i < nhostdevs ; i++) { + virDomainHostdevDefPtr hostdev = hostdevs[i]; ++ usbDevice *usb = NULL; + + if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) + continue; + if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB) + continue; + +- /* Resolve a vendor/product to bus/device */ +- if (hostdev->source.subsys.u.usb.vendor) { +- usbDevice *usb; +- usbDeviceList *devs; ++ unsigned vendor = hostdev->source.subsys.u.usb.vendor; ++ unsigned product = hostdev->source.subsys.u.usb.product; ++ unsigned bus = hostdev->source.subsys.u.usb.bus; ++ unsigned device = hostdev->source.subsys.u.usb.device; + +- devs = usbFindDeviceByVendor(hostdev->source.subsys.u.usb.vendor, +- hostdev->source.subsys.u.usb.product); ++ if (vendor && bus) { ++ usb = usbFindDevice(vendor, product, bus, device); + ++ } else if (vendor && !bus) { ++ usbDeviceList *devs = usbFindDeviceByVendor(vendor, product); + if (!devs) + goto cleanup; + ++ if (usbDeviceListCount(devs) > 1) { ++ qemuReportError(VIR_ERR_OPERATION_FAILED, ++ _("multiple USB devices for %x:%x, " ++ "use
to specify one"), vendor, product); ++ usbDeviceListFree(devs); ++ goto cleanup; ++ } + usb = usbDeviceListGet(devs, 0); + usbDeviceListSteal(devs, usb); + usbDeviceListFree(devs); + +- if ((tmp = usbDeviceListFind(driver->activeUsbHostdevs, usb))) { +- const char *other_name = usbDeviceGetUsedBy(tmp); +- +- if (other_name) +- qemuReportError(VIR_ERR_OPERATION_INVALID, +- _("USB device %s is in use by domain %s"), +- usbDeviceGetName(tmp), other_name); +- else +- qemuReportError(VIR_ERR_OPERATION_INVALID, +- _("USB device %s is already in use"), +- usbDeviceGetName(tmp)); +- usbFreeDevice(usb); +- goto cleanup; +- } +- + hostdev->source.subsys.u.usb.bus = usbDeviceGetBus(usb); + hostdev->source.subsys.u.usb.device = usbDeviceGetDevno(usb); + +- if (usbDeviceListAdd(list, usb) < 0) { +- usbFreeDevice(usb); +- goto cleanup; +- } ++ } else if (!vendor && bus) { ++ usb = usbFindDeviceByBus(bus, device); ++ } ++ ++ if (!usb) ++ goto cleanup; + ++ if (usbDeviceListAdd(list, usb) < 0) { ++ usbFreeDevice(usb); ++ goto cleanup; + } + } + +- /* Loop 2: Mark devices in temporary list as used by @name ++ /* Mark devices in temporary list as used by @name + * and add them do driver list. However, if something goes + * wrong, perform rollback. + */ +- for (i = 0; i < usbDeviceListCount(list); i++) { +- tmp = usbDeviceListGet(list, i); +- usbDeviceSetUsedBy(tmp, name); ++ if (qemuPrepareHostdevUSBDevices(driver, def->name, list) < 0) ++ goto inactivedevs; + +- VIR_DEBUG("Adding %03d.%03d dom=%s to activeUsbHostdevs", +- usbDeviceGetBus(tmp), usbDeviceGetDevno(tmp), name); +- if (usbDeviceListAdd(driver->activeUsbHostdevs, tmp) < 0) { +- usbFreeDevice(tmp); +- goto inactivedevs; +- } +- } +- +- /* Loop 3: Temporary list was successfully merged with ++ /* Loop 2: Temporary list was successfully merged with + * driver list, so steal all items to avoid freeing them + * in cleanup label. + */ +@@ -675,13 +706,6 @@ cleanup: + return ret; + } + +-static int +-qemuPrepareHostUSBDevices(struct qemud_driver *driver, +- virDomainDefPtr def) +-{ +- return qemuPrepareHostdevUSBDevices(driver, def->name, def->hostdevs, def->nhostdevs); +-} +- + int qemuPrepareHostDevices(struct qemud_driver *driver, + virDomainDefPtr def) + { +Index: libvirt-0.9.11.3/src/qemu/qemu_hostdev.h +=================================================================== +--- libvirt-0.9.11.3.orig/src/qemu/qemu_hostdev.h ++++ libvirt-0.9.11.3/src/qemu/qemu_hostdev.h +@@ -38,8 +38,7 @@ int qemuPrepareHostdevPCIDevices(struct + int nhostdevs); + int qemuPrepareHostdevUSBDevices(struct qemud_driver *driver, + const char *name, +- virDomainHostdevDefPtr *hostdevs, +- int nhostdevs); ++ usbDeviceList *list); + int qemuPrepareHostDevices(struct qemud_driver *driver, + virDomainDefPtr def); + void qemuReattachPciDevice(pciDevice *dev, struct qemud_driver *driver); +Index: libvirt-0.9.11.3/src/qemu/qemu_hotplug.c +=================================================================== +--- libvirt-0.9.11.3.orig/src/qemu/qemu_hotplug.c ++++ libvirt-0.9.11.3/src/qemu/qemu_hotplug.c +@@ -1116,11 +1116,13 @@ error: + return -1; + } + +- + int qemuDomainAttachHostDevice(struct qemud_driver *driver, + virDomainObjPtr vm, + virDomainHostdevDefPtr hostdev) + { ++ usbDeviceList *list; ++ usbDevice *usb = NULL; ++ + if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) { + qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("hostdev mode '%s' not supported"), +@@ -1128,35 +1130,58 @@ int qemuDomainAttachHostDevice(struct qe + return -1; + } + +- /* Resolve USB product/vendor to bus/device */ +- if (hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB && +- hostdev->source.subsys.u.usb.vendor) { +- usbDevice *usb; +- usbDeviceList *list; +- +- if (qemuPrepareHostdevUSBDevices(driver, vm->def->name, &hostdev, 1) < 0) +- goto error; ++ if (!(list = usbDeviceListNew())) ++ goto cleanup; + +- list = usbFindDeviceByVendor(hostdev->source.subsys.u.usb.vendor, +- hostdev->source.subsys.u.usb.product); ++ if (hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB) { ++ unsigned vendor = hostdev->source.subsys.u.usb.vendor; ++ unsigned product = hostdev->source.subsys.u.usb.product; ++ unsigned bus = hostdev->source.subsys.u.usb.bus; ++ unsigned device = hostdev->source.subsys.u.usb.device; ++ ++ if (vendor && bus) { ++ usb = usbFindDevice(vendor, product, bus, device); ++ ++ } else if (vendor && !bus) { ++ usbDeviceList *devs = usbFindDeviceByVendor(vendor, product); ++ if (!devs) ++ goto cleanup; ++ ++ if (usbDeviceListCount(devs) > 1) { ++ qemuReportError(VIR_ERR_OPERATION_FAILED, ++ _("multiple USB devices for %x:%x, " ++ "use
to specify one"), vendor, product); ++ usbDeviceListFree(devs); ++ goto cleanup; ++ } ++ usb = usbDeviceListGet(devs, 0); ++ usbDeviceListSteal(devs, usb); ++ usbDeviceListFree(devs); ++ ++ hostdev->source.subsys.u.usb.bus = usbDeviceGetBus(usb); ++ hostdev->source.subsys.u.usb.device = usbDeviceGetDevno(usb); ++ ++ } else if (!vendor && bus) { ++ usb = usbFindDeviceByBus(bus, device); ++ } ++ ++ if (!usb) ++ goto cleanup; ++ ++ if (usbDeviceListAdd(list, usb) < 0) { ++ usbFreeDevice(usb); ++ goto cleanup; ++ } + +- if (!list) +- return -1; ++ if (qemuPrepareHostdevUSBDevices(driver, vm->def->name, list) < 0) ++ goto cleanup; + +- usb = usbDeviceListGet(list, 0); + usbDeviceListSteal(list, usb); +- usbDeviceListFree(list); +- +- hostdev->source.subsys.u.usb.bus = usbDeviceGetBus(usb); +- hostdev->source.subsys.u.usb.device = usbDeviceGetDevno(usb); +- +- usbFreeDevice(usb); + } + +- + if (virSecurityManagerSetHostdevLabel(driver->securityManager, + vm->def, hostdev) < 0) +- return -1; ++ goto cleanup; + + switch (hostdev->source.subsys.type) { + case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI: +@@ -1178,6 +1203,7 @@ int qemuDomainAttachHostDevice(struct qe + goto error; + } + ++ usbDeviceListFree(list); + return 0; + + error: +@@ -1185,6 +1211,9 @@ error: + vm->def, hostdev) < 0) + VIR_WARN("Unable to restore host device labelling on hotplug fail"); + ++cleanup: ++ usbDeviceListFree(list); ++ usbDeviceListSteal(driver->activeUsbHostdevs, usb); + return -1; + } + diff --git a/9914477e-usb-search-funcs.patch b/9914477e-usb-search-funcs.patch new file mode 100644 index 0000000..41f4a7f --- /dev/null +++ b/9914477e-usb-search-funcs.patch @@ -0,0 +1,423 @@ +commit 9914477efc9764f691ca50faca6592a2d4fecec8 +Author: Guannan Ren +Date: Fri May 4 15:49:58 2012 +0800 + + usb: create functions to search usb device accurately + + usbFindDevice():get usb device according to + idVendor, idProduct, bus, device + it is the exact match of the four parameters + + usbFindDeviceByBus():get usb device according to bus, device + it returns only one usb device same as usbFindDevice + + usbFindDeviceByVendor():get usb device according to idVendor,idProduct + it probably returns multiple usb devices. + + usbDeviceSearch(): a helper function to do the actual search + +Index: libvirt-0.9.11.3/src/libvirt_private.syms +=================================================================== +--- libvirt-0.9.11.3.orig/src/libvirt_private.syms ++++ libvirt-0.9.11.3/src/libvirt_private.syms +@@ -1084,6 +1084,8 @@ usbDeviceListNew; + usbDeviceListSteal; + usbDeviceSetUsedBy; + usbFindDevice; ++usbFindDeviceByBus; ++usbFindDeviceByVendor; + usbFreeDevice; + usbGetDevice; + +Index: libvirt-0.9.11.3/src/qemu/qemu_hostdev.c +=================================================================== +--- libvirt-0.9.11.3.orig/src/qemu/qemu_hostdev.c ++++ libvirt-0.9.11.3/src/qemu/qemu_hostdev.c +@@ -594,13 +594,19 @@ qemuPrepareHostdevUSBDevices(struct qemu + + /* Resolve a vendor/product to bus/device */ + if (hostdev->source.subsys.u.usb.vendor) { +- usbDevice *usb +- = usbFindDevice(hostdev->source.subsys.u.usb.vendor, +- hostdev->source.subsys.u.usb.product); ++ usbDevice *usb; ++ usbDeviceList *devs; + +- if (!usb) ++ devs = usbFindDeviceByVendor(hostdev->source.subsys.u.usb.vendor, ++ hostdev->source.subsys.u.usb.product); ++ ++ if (!devs) + goto cleanup; + ++ usb = usbDeviceListGet(devs, 0); ++ usbDeviceListSteal(devs, usb); ++ usbDeviceListFree(devs); ++ + if ((tmp = usbDeviceListFind(driver->activeUsbHostdevs, usb))) { + const char *other_name = usbDeviceGetUsedBy(tmp); + +Index: libvirt-0.9.11.3/src/qemu/qemu_hotplug.c +=================================================================== +--- libvirt-0.9.11.3.orig/src/qemu/qemu_hotplug.c ++++ libvirt-0.9.11.3/src/qemu/qemu_hotplug.c +@@ -1131,16 +1131,22 @@ int qemuDomainAttachHostDevice(struct qe + /* Resolve USB product/vendor to bus/device */ + if (hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB && + hostdev->source.subsys.u.usb.vendor) { ++ usbDevice *usb; ++ usbDeviceList *list; ++ + if (qemuPrepareHostdevUSBDevices(driver, vm->def->name, &hostdev, 1) < 0) + goto error; + +- usbDevice *usb +- = usbFindDevice(hostdev->source.subsys.u.usb.vendor, +- hostdev->source.subsys.u.usb.product); ++ list = usbFindDeviceByVendor(hostdev->source.subsys.u.usb.vendor, ++ hostdev->source.subsys.u.usb.product); + +- if (!usb) ++ if (!list) + return -1; + ++ usb = usbDeviceListGet(list, 0); ++ usbDeviceListSteal(list, usb); ++ usbDeviceListFree(list); ++ + hostdev->source.subsys.u.usb.bus = usbDeviceGetBus(usb); + hostdev->source.subsys.u.usb.device = usbDeviceGetDevno(usb); + +Index: libvirt-0.9.11.3/src/util/hostusb.c +=================================================================== +--- libvirt-0.9.11.3.orig/src/util/hostusb.c ++++ libvirt-0.9.11.3/src/util/hostusb.c +@@ -1,5 +1,5 @@ + /* +- * Copyright (C) 2009-2011 Red Hat, Inc. ++ * Copyright (C) 2009-2012 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public +@@ -42,9 +42,16 @@ + #define USB_ID_LEN 10 /* "1234 5678" */ + #define USB_ADDR_LEN 8 /* "123:456" */ + ++/* For virReportOOMError() and virReportSystemError() */ ++#define VIR_FROM_THIS VIR_FROM_NONE ++ ++#define usbReportError(code, ...) \ ++ virReportErrorHelper(VIR_FROM_NONE, code, __FILE__, \ ++ __FUNCTION__, __LINE__, __VA_ARGS__) ++ + struct _usbDevice { +- unsigned bus; +- unsigned dev; ++ unsigned int bus; ++ unsigned int dev; + + char name[USB_ADDR_LEN]; /* domain:bus:slot.function */ + char id[USB_ID_LEN]; /* product vendor */ +@@ -57,15 +64,14 @@ struct _usbDeviceList { + usbDevice **devs; + }; + +-/* For virReportOOMError() and virReportSystemError() */ +-#define VIR_FROM_THIS VIR_FROM_NONE +- +-#define usbReportError(code, ...) \ +- virReportErrorHelper(VIR_FROM_NONE, code, __FILE__, \ +- __FUNCTION__, __LINE__, __VA_ARGS__) ++typedef enum { ++ USB_DEVICE_ALL = 0, ++ USB_DEVICE_FIND_BY_VENDOR = 1 << 0, ++ USB_DEVICE_FIND_BY_BUS = 1 << 1, ++} usbDeviceFindFlags; + + static int usbSysReadFile(const char *f_name, const char *d_name, +- int base, unsigned *value) ++ int base, unsigned int *value) + { + int ret = -1, tmp; + char *buf = NULL; +@@ -94,13 +100,22 @@ cleanup: + return ret; + } + +-static int usbFindBusByVendor(unsigned vendor, unsigned product, +- unsigned *bus, unsigned *devno) ++static usbDeviceList * ++usbDeviceSearch(unsigned int vendor, ++ unsigned int product, ++ unsigned int bus, ++ unsigned int devno, ++ unsigned int flags) + { + DIR *dir = NULL; +- int ret = -1, found = 0; ++ bool found = false; + char *ignore = NULL; + struct dirent *de; ++ usbDeviceList *list = NULL, *ret = NULL; ++ usbDevice *usb; ++ ++ if (!(list = usbDeviceListNew())) ++ goto cleanup; + + dir = opendir(USB_SYSFS "/devices"); + if (!dir) { +@@ -111,61 +126,145 @@ static int usbFindBusByVendor(unsigned v + } + + while ((de = readdir(dir))) { +- unsigned found_prod, found_vend; ++ unsigned int found_prod, found_vend, found_bus, found_devno; ++ char *tmpstr = de->d_name; ++ + if (de->d_name[0] == '.' || strchr(de->d_name, ':')) + continue; + + if (usbSysReadFile("idVendor", de->d_name, + 16, &found_vend) < 0) + goto cleanup; ++ + if (usbSysReadFile("idProduct", de->d_name, + 16, &found_prod) < 0) + goto cleanup; + +- if (found_prod == product && found_vend == vendor) { +- /* Lookup bus.addr info */ +- char *tmpstr = de->d_name; +- unsigned found_bus, found_addr; +- +- if (STRPREFIX(de->d_name, "usb")) +- tmpstr += 3; +- +- if (virStrToLong_ui(tmpstr, &ignore, 10, &found_bus) < 0) { +- usbReportError(VIR_ERR_INTERNAL_ERROR, +- _("Failed to parse dir name '%s'"), +- de->d_name); +- goto cleanup; +- } +- +- if (usbSysReadFile("devnum", de->d_name, +- 10, &found_addr) < 0) +- goto cleanup; +- +- *bus = found_bus; +- *devno = found_addr; +- found = 1; +- break; ++ if (STRPREFIX(de->d_name, "usb")) ++ tmpstr += 3; ++ ++ if (virStrToLong_ui(tmpstr, &ignore, 10, &found_bus) < 0) { ++ usbReportError(VIR_ERR_INTERNAL_ERROR, ++ _("Failed to parse dir name '%s'"), ++ de->d_name); ++ goto cleanup; + } +- } + +- if (!found) +- usbReportError(VIR_ERR_INTERNAL_ERROR, +- _("Did not find USB device %x:%x"), vendor, product); +- else +- ret = 0; ++ if (usbSysReadFile("devnum", de->d_name, ++ 10, &found_devno) < 0) ++ goto cleanup; ++ ++ if ((flags & USB_DEVICE_FIND_BY_VENDOR) && ++ (found_prod != product || found_vend != vendor)) ++ continue; ++ ++ if (flags & USB_DEVICE_FIND_BY_BUS) { ++ if (found_bus != bus || found_devno != devno) ++ continue; ++ found = true; ++ } ++ ++ usb = usbGetDevice(found_bus, found_devno); ++ if (!usb) ++ goto cleanup; ++ ++ if (usbDeviceListAdd(list, usb) < 0) { ++ usbFreeDevice(usb); ++ goto cleanup; ++ } ++ ++ if (found) ++ break; ++ } ++ ret = list; + + cleanup: + if (dir) { + int saved_errno = errno; +- closedir (dir); ++ closedir(dir); + errno = saved_errno; + } ++ ++ if (!ret) ++ usbDeviceListFree(list); + return ret; + } + ++usbDeviceList * ++usbFindDeviceByVendor(unsigned int vendor, unsigned product) ++{ ++ ++ usbDeviceList *list; ++ if (!(list = usbDeviceSearch(vendor, product, 0 , 0, ++ USB_DEVICE_FIND_BY_VENDOR))) ++ return NULL; ++ ++ if (list->count == 0) { ++ usbReportError(VIR_ERR_INTERNAL_ERROR, ++ _("Did not find USB device %x:%x"), vendor, product); ++ usbDeviceListFree(list); ++ return NULL; ++ } ++ ++ return list; ++} ++ + usbDevice * +-usbGetDevice(unsigned bus, +- unsigned devno) ++usbFindDeviceByBus(unsigned int bus, unsigned devno) ++{ ++ usbDevice *usb; ++ usbDeviceList *list; ++ ++ if (!(list = usbDeviceSearch(0, 0, bus, devno, ++ USB_DEVICE_FIND_BY_BUS))) ++ return NULL; ++ ++ if (list->count == 0) { ++ usbReportError(VIR_ERR_INTERNAL_ERROR, ++ _("Did not find USB device bus:%u device:%u"), ++ bus, devno); ++ usbDeviceListFree(list); ++ return NULL; ++ } ++ ++ usb = usbDeviceListGet(list, 0); ++ usbDeviceListSteal(list, usb); ++ usbDeviceListFree(list); ++ ++ return usb; ++} ++ ++usbDevice * ++usbFindDevice(unsigned int vendor, ++ unsigned int product, ++ unsigned int bus, ++ unsigned int devno) ++{ ++ usbDevice *usb; ++ usbDeviceList *list; ++ ++ unsigned int flags = USB_DEVICE_FIND_BY_VENDOR|USB_DEVICE_FIND_BY_BUS; ++ if (!(list = usbDeviceSearch(vendor, product, bus, devno, flags))) ++ return NULL; ++ ++ if (list->count == 0) { ++ usbReportError(VIR_ERR_INTERNAL_ERROR, ++ _("Did not find USB device %x:%x bus:%u device:%u"), ++ vendor, product, bus, devno); ++ usbDeviceListFree(list); ++ return NULL; ++ } ++ ++ usb = usbDeviceListGet(list, 0); ++ usbDeviceListSteal(list, usb); ++ usbDeviceListFree(list); ++ ++ return usb; ++} ++ ++usbDevice * ++usbGetDevice(unsigned int bus, ++ unsigned int devno) + { + usbDevice *dev; + +@@ -207,21 +306,6 @@ usbGetDevice(unsigned bus, + return dev; + } + +- +-usbDevice * +-usbFindDevice(unsigned vendor, +- unsigned product) +-{ +- unsigned bus = 0, devno = 0; +- +- if (usbFindBusByVendor(vendor, product, &bus, &devno) < 0) { +- return NULL; +- } +- +- return usbGetDevice(bus, devno); +-} +- +- + void + usbFreeDevice(usbDevice *dev) + { +@@ -247,13 +331,13 @@ const char *usbDeviceGetName(usbDevice * + return dev->name; + } + +-unsigned usbDeviceGetBus(usbDevice *dev) ++unsigned int usbDeviceGetBus(usbDevice *dev) + { + return dev->bus; + } + + +-unsigned usbDeviceGetDevno(usbDevice *dev) ++unsigned int usbDeviceGetDevno(usbDevice *dev) + { + return dev->dev; + } +Index: libvirt-0.9.11.3/src/util/hostusb.h +=================================================================== +--- libvirt-0.9.11.3.orig/src/util/hostusb.h ++++ libvirt-0.9.11.3/src/util/hostusb.h +@@ -28,17 +28,27 @@ + typedef struct _usbDevice usbDevice; + typedef struct _usbDeviceList usbDeviceList; + +-usbDevice *usbGetDevice(unsigned bus, +- unsigned devno); +-usbDevice *usbFindDevice(unsigned vendor, +- unsigned product); ++usbDevice *usbGetDevice(unsigned int bus, ++ unsigned int devno); ++ ++usbDevice *usbFindDeviceByBus(unsigned int bus, ++ unsigned int devno); ++ ++usbDeviceList *usbFindDeviceByVendor(unsigned int vendor, ++ unsigned int product); ++ ++usbDevice *usbFindDevice(unsigned int vendor, ++ unsigned int product, ++ unsigned int bus, ++ unsigned int devno); ++ + void usbFreeDevice (usbDevice *dev); + void usbDeviceSetUsedBy(usbDevice *dev, const char *name); + const char *usbDeviceGetUsedBy(usbDevice *dev); + const char *usbDeviceGetName(usbDevice *dev); + +-unsigned usbDeviceGetBus(usbDevice *dev); +-unsigned usbDeviceGetDevno(usbDevice *dev); ++unsigned int usbDeviceGetBus(usbDevice *dev); ++unsigned int usbDeviceGetDevno(usbDevice *dev); + + /* + * Callback that will be invoked once for each file diff --git a/libvirt.changes b/libvirt.changes index 176e14b..1e8cdd4 100644 --- a/libvirt.changes +++ b/libvirt.changes @@ -1,3 +1,12 @@ +------------------------------------------------------------------- +Tue Jun 12 14:18:23 MDT 2012 - jfehlig@suse.com + +- VUL-1: Fix hotplug support for usb devices with same vendorID, + productID + 9914477e-usb-search-funcs.patch + 05abd150-usb-improve-hotplug.patch + bnc#766559 + ------------------------------------------------------------------- Wed May 30 16:00:38 MDT 2012 - jfehlig@suse.com diff --git a/libvirt.spec b/libvirt.spec index 2419ce8..86367fa 100644 --- a/libvirt.spec +++ b/libvirt.spec @@ -410,6 +410,8 @@ Source1: libvirtd.init Source2: libvirtd-relocation-server.fw Source99: baselibs.conf # Upstream patches +Patch0: 9914477e-usb-search-funcs.patch +Patch1: 05abd150-usb-improve-hotplug.patch # Need to go upstream Patch100: xen-name-for-devid.patch Patch101: clone.patch @@ -545,6 +547,8 @@ Authors: %prep %setup -q +%patch0 -p1 +%patch1 -p1 %patch100 -p1 %patch101 %patch102 -p1