12b4dbbe29
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
326 lines
12 KiB
Diff
326 lines
12 KiB
Diff
commit 05abd1507d66aabb6cad12eeafeb4c4d1911c585
|
|
Author: Guannan Ren <gren@redhat.com>
|
|
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 <address> 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 <address> 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 <address> 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;
|
|
}
|
|
|