]> xenbits.xensource.com Git - people/liuw/libxenctrl-split/libvirt.git/commitdiff
Fix USB passthrough based on product/vendor
authorDaniel P. Berrange <berrange@redhat.com>
Thu, 4 Mar 2010 11:48:16 +0000 (11:48 +0000)
committerDaniel P. Berrange <berrange@redhat.com>
Fri, 5 Mar 2010 15:05:14 +0000 (15:05 +0000)
Changeset

  commit 5073aa994af460e775cb3e548528e28d7660fcc8
  Author: Cole Robinson <crobinso@redhat.com>
  Date:   Mon Jan 11 11:40:46 2010 -0500

Added support for product/vendor based passthrough, but it only
worked at the security driver layer. The main guest XML config
was not updated with the resolved bus/device ID. When the QEMU
argv refactoring removed use of product/vendor, this then broke
launching guests.

THe solution is to move the product/vendor resolution up a layer
into the QEMU driver. So the first thing QEMU does is resolve
the product/vendor to a bus/device and updates the XML config
with this info. The rest of the code, including security drivers
and QEMU argv generated can now rely on bus/device always being
set.

* src/util/hostusb.c, src/util/hostusb.h: Split vendor/product
  resolution code out of usbGetDevice and into usbFindDevice.
  Add accessors for bus/device ID
* src/security/virt-aa-helper.c, src/security/security_selinux.c,
  src/qemu/qemu_security_dac.c: Remove vendor/product from the
  usbGetDevice() calls
* src/qemu/qemu_driver.c: Use usbFindDevice to resolve vendor/product
  into a bus/device ID

src/libvirt_private.syms
src/qemu/qemu_driver.c
src/qemu/qemu_security_dac.c
src/security/security_selinux.c
src/security/virt-aa-helper.c
src/util/hostusb.c
src/util/hostusb.h

index ce9f01373f4949ad0ccbcdaea90836b909e0ce55..c5ee23dc6cd8ff31bd97e946493f4214161fab8f 100644 (file)
@@ -599,7 +599,10 @@ virArgvToString;
 
 # usb.h
 usbGetDevice;
+usbFindDevice;
 usbFreeDevice;
+usbDeviceGetBus;
+usbDeviceGetDevno;
 usbDeviceFileIterate;
 
 # uuid.h
index e11e9e88c6d261f3ff6e4023ac8ae54729b4f339..4707f721fe787f6df79ec575d582d7fef78d4b43 100644 (file)
@@ -2290,17 +2290,15 @@ cleanup:
     return ret;
 }
 
+
 static int
-qemuPrepareHostDevices(struct qemud_driver *driver,
-                       virDomainDefPtr def)
+qemuPrepareHostPCIDevices(struct qemud_driver *driver,
+                          virDomainDefPtr def)
 {
     pciDeviceList *pcidevs;
     int i;
     int ret = -1;
 
-    if (!def->nhostdevs)
-        return 0;
-
     if (!(pcidevs = qemuGetPciHostDeviceList(def)))
         return -1;
 
@@ -2351,6 +2349,56 @@ cleanup:
     return ret;
 }
 
+
+static int
+qemuPrepareHostUSBDevices(struct qemud_driver *driver ATTRIBUTE_UNUSED,
+                          virDomainDefPtr def)
+{
+    int i;
+    for (i = 0 ; i < def->nhostdevs ; i++) {
+        virDomainHostdevDefPtr hostdev = def->hostdevs[i];
+
+        if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
+            continue;
+        if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI)
+            continue;
+
+        /* 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);
+
+            if (!usb)
+                return -1;
+
+            hostdev->source.subsys.u.usb.bus = usbDeviceGetBus(usb);
+            hostdev->source.subsys.u.usb.device = usbDeviceGetDevno(usb);
+
+            usbFreeDevice(usb);
+        }
+    }
+
+    return 0;
+}
+
+static int
+qemuPrepareHostDevices(struct qemud_driver *driver,
+                       virDomainDefPtr def)
+{
+    if (!def->nhostdevs)
+        return 0;
+
+    if (qemuPrepareHostPCIDevices(driver, def) < 0)
+        return -1;
+
+    if (qemuPrepareHostUSBDevices(driver, def) < 0)
+        return -1;
+
+    return 0;
+}
+
+
 static void
 qemudReattachManagedDevice(pciDevice *dev)
 {
@@ -6478,6 +6526,23 @@ static int qemudDomainAttachHostDevice(struct qemud_driver *driver,
         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
+            = usbFindDevice(hostdev->source.subsys.u.usb.vendor,
+                            hostdev->source.subsys.u.usb.product);
+
+        if (!usb)
+            return -1;
+
+        hostdev->source.subsys.u.usb.bus = usbDeviceGetBus(usb);
+        hostdev->source.subsys.u.usb.device = usbDeviceGetDevno(usb);
+
+        usbFreeDevice(usb);
+    }
+
+
     if (driver->securityDriver &&
         driver->securityDriver->domainSetSecurityHostdevLabel &&
         driver->securityDriver->domainSetSecurityHostdevLabel(vm, hostdev) < 0)
@@ -7041,11 +7106,22 @@ static int qemudDomainDetachHostUsbDevice(struct qemud_driver *driver,
 
         unsigned bus = vm->def->hostdevs[i]->source.subsys.u.usb.bus;
         unsigned device = vm->def->hostdevs[i]->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;
+        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;
+            }
         }
     }
 
index f281b96179b0be5b6328eb6ebcfc28044a9f7428..6911f4874aa3d900c9c7086109dd53d3d637dccf 100644 (file)
@@ -206,9 +206,7 @@ qemuSecurityDACSetSecurityHostdevLabel(virDomainObjPtr vm,
     switch (dev->source.subsys.type) {
     case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB: {
         usbDevice *usb = usbGetDevice(dev->source.subsys.u.usb.bus,
-                                      dev->source.subsys.u.usb.device,
-                                      dev->source.subsys.u.usb.vendor,
-                                      dev->source.subsys.u.usb.product);
+                                      dev->source.subsys.u.usb.device);
 
         if (!usb)
             goto done;
@@ -277,9 +275,7 @@ qemuSecurityDACRestoreSecurityHostdevLabel(virDomainObjPtr vm ATTRIBUTE_UNUSED,
     switch (dev->source.subsys.type) {
     case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB: {
         usbDevice *usb = usbGetDevice(dev->source.subsys.u.usb.bus,
-                                      dev->source.subsys.u.usb.device,
-                                      dev->source.subsys.u.usb.vendor,
-                                      dev->source.subsys.u.usb.product);
+                                      dev->source.subsys.u.usb.device);
 
         if (!usb)
             goto done;
index 06a2479025fa070f91893d8e58b0767f20a75830..b2c85815c31e7d466c09fabf29cbc78c34d9de32 100644 (file)
@@ -491,9 +491,7 @@ SELinuxSetSecurityHostdevLabel(virDomainObjPtr vm,
     switch (dev->source.subsys.type) {
     case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB: {
         usbDevice *usb = usbGetDevice(dev->source.subsys.u.usb.bus,
-                                      dev->source.subsys.u.usb.device,
-                                      dev->source.subsys.u.usb.vendor,
-                                      dev->source.subsys.u.usb.product);
+                                      dev->source.subsys.u.usb.device);
 
         if (!usb)
             goto done;
@@ -561,9 +559,7 @@ SELinuxRestoreSecurityHostdevLabel(virDomainObjPtr vm,
     switch (dev->source.subsys.type) {
     case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB: {
         usbDevice *usb = usbGetDevice(dev->source.subsys.u.usb.bus,
-                                      dev->source.subsys.u.usb.device,
-                                      dev->source.subsys.u.usb.vendor,
-                                      dev->source.subsys.u.usb.product);
+                                      dev->source.subsys.u.usb.device);
 
         if (!usb)
             goto done;
index 066e18b3f3113ca04d09c14a8d3e98917ec134ac..78bef41ae8a30d12cccd9a7c4260b697217e1fe5 100644 (file)
@@ -836,9 +836,7 @@ get_files(vahControl * ctl)
             switch (dev->source.subsys.type) {
             case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB: {
                 usbDevice *usb = usbGetDevice(dev->source.subsys.u.usb.bus,
-                                              dev->source.subsys.u.usb.device,
-                                              dev->source.subsys.u.usb.vendor,
-                                              dev->source.subsys.u.usb.product);
+                                              dev->source.subsys.u.usb.device);
 
                 if (usb == NULL)
                     continue;
index bf9653936ca39ad7b16c5d08786d387be86de6a8..afba325951e3981cf8b543db0420ba3fba20ee36 100644 (file)
@@ -159,9 +159,7 @@ cleanup:
 
 usbDevice *
 usbGetDevice(unsigned bus,
-             unsigned devno,
-             unsigned vendor,
-             unsigned product)
+             unsigned devno)
 {
     usbDevice *dev;
 
@@ -170,14 +168,6 @@ usbGetDevice(unsigned bus,
         return NULL;
     }
 
-    if (vendor) {
-        /* Look up bus.dev by vendor:product */
-        if (usbFindBusByVendor(vendor, product, &bus, &devno) < 0) {
-            VIR_FREE(dev);
-            return NULL;
-        }
-    }
-
     dev->bus     = bus;
     dev->dev     = devno;
 
@@ -194,6 +184,21 @@ 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)
 {
@@ -202,6 +207,18 @@ usbFreeDevice(usbDevice *dev)
 }
 
 
+unsigned usbDeviceGetBus(usbDevice *dev)
+{
+    return dev->bus;
+}
+
+
+unsigned usbDeviceGetDevno(usbDevice *dev)
+{
+    return dev->dev;
+}
+
+
 int usbDeviceFileIterate(usbDevice *dev,
                          usbDeviceFileActor actor,
                          void *opaque)
index bc22671783ca26128f73976c9ab868e64deb7321..9a1b1b763ca94d14f695b60ac451a0707eb075cc 100644 (file)
 
 typedef struct _usbDevice usbDevice;
 
-usbDevice *usbGetDevice      (unsigned       bus,
-                              unsigned       devno,
-                              unsigned       vendor,
-                              unsigned       product);
-void       usbFreeDevice     (usbDevice     *dev);
+usbDevice *usbGetDevice(unsigned bus,
+                        unsigned devno);
+usbDevice *usbFindDevice(unsigned vendor,
+                         unsigned product);
+void       usbFreeDevice (usbDevice *dev);
+
+unsigned usbDeviceGetBus(usbDevice *dev);
+unsigned usbDeviceGetDevno(usbDevice *dev);
 
 /*
  * Callback that will be invoked once for each file