diff -rup libvirt-0.7.1/src/hostusb.c new/src/hostusb.c --- libvirt-0.7.1/src/hostusb.c 2010-05-17 16:53:48.740748000 -0400 +++ new/src/hostusb.c 2010-05-17 16:57:19.294731000 -0400 @@ -37,9 +37,10 @@ #include "util.h" #include "virterror_internal.h" +#define USB_SYSFS "/sys/bus/usb" #define USB_DEVFS "/dev/bus/usb/" -#define USB_ID_LEN 10 /* "XXXX XXXX" */ -#define USB_ADDR_LEN 8 /* "XXX:XXX" */ +#define USB_ID_LEN 10 /* "1234 5678" */ +#define USB_ADDR_LEN 8 /* "123:456" */ struct _usbDevice { unsigned bus; @@ -57,6 +58,101 @@ struct _usbDevice { virReportErrorHelper(conn, VIR_FROM_NONE, code, __FILE__, \ __FUNCTION__, __LINE__, fmt) +static int usbSysReadFile(virConnectPtr conn, + const char *f_name, const char *d_name, + int base, unsigned *value) +{ + int ret = -1, tmp; + char *buf = NULL; + char *filename = NULL; + char *ignore = NULL; + + tmp = virAsprintf(&filename, USB_SYSFS "/devices/%s/%s", d_name, f_name); + if (tmp < 0) { + virReportOOMError(conn); + goto error; + } + + if (virFileReadAll(filename, 1024, &buf) < 0) + goto error; + + if (virStrToLong_ui(buf, &ignore, base, value) < 0) { + usbReportError(conn, VIR_ERR_INTERNAL_ERROR, + _("Could not parse usb file %s"), filename); + goto error; + } + + ret = 0; +error: + VIR_FREE(filename); + VIR_FREE(buf); + return ret; +} + +static int usbFindBusByVendor(virConnectPtr conn, + unsigned vendor, unsigned product, + unsigned *bus, unsigned *devno) +{ + DIR *dir = NULL; + int ret = -1, found = 0; + char *ignore = NULL; + struct dirent *de; + + dir = opendir(USB_SYSFS "/devices"); + if (!dir) { + virReportSystemError(conn, errno, + _("Could not open directory %s"), + USB_SYSFS "/devices"); + goto error; + } + + while ((de = readdir(dir))) { + unsigned found_prod, found_vend; + if (de->d_name[0] == '.' || strchr(de->d_name, ':')) + continue; + + if (usbSysReadFile(conn, "idVendor", de->d_name, + 16, &found_vend) < 0) + goto error; + if (usbSysReadFile(conn, "idProduct", de->d_name, + 16, &found_prod) < 0) + goto error; + + if (found_prod == product && found_vend == vendor) { + /* Lookup bus.addr info */ + char *tmpstr = de->d_name; + unsigned found_bus, found_addr; + + if (STREQ(de->d_name, "usb")) + tmpstr += 3; + + if (virStrToLong_ui(tmpstr, &ignore, 10, &found_bus) < 0) { + usbReportError(conn, VIR_ERR_INTERNAL_ERROR, + _("Failed to parse dir name '%s'"), + de->d_name); + goto error; + } + + if (usbSysReadFile(conn, "devnum", de->d_name, + 10, &found_addr) < 0) + goto error; + + *bus = found_bus; + *devno = found_addr; + found = 1; + break; + } + } + + if (!found) + usbReportError(conn, VIR_ERR_INTERNAL_ERROR, + _("Did not find USB device %x:%x"), vendor, product); + else + ret = 0; + +error: + return ret; +} usbDevice * usbGetDevice(virConnectPtr conn, @@ -86,6 +182,21 @@ usbGetDevice(virConnectPtr conn, 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(virConnectPtr conn ATTRIBUTE_UNUSED, usbDevice *dev) { @@ -93,6 +204,18 @@ usbFreeDevice(virConnectPtr conn ATTRIBU VIR_FREE(dev); } +unsigned usbDeviceGetBus(usbDevice *dev) +{ + return dev->bus; +} + + +unsigned usbDeviceGetDevno(usbDevice *dev) +{ + return dev->dev; +} + + int usbDeviceFileIterate(virConnectPtr conn, usbDevice *dev, diff -rup libvirt-0.7.1/src/hostusb.h new/src/hostusb.h --- libvirt-0.7.1/src/hostusb.h 2009-09-10 09:45:00.000000000 -0400 +++ new/src/hostusb.h 2010-05-17 16:58:06.553924000 -0400 @@ -27,11 +27,16 @@ typedef struct _usbDevice usbDevice; -usbDevice *usbGetDevice (virConnectPtr conn, - unsigned bus, - unsigned devno); -void usbFreeDevice (virConnectPtr conn, - usbDevice *dev); +usbDevice *usbGetDevice(virConnectPtr conn, + unsigned bus, + unsigned devno); +usbDevice *usbFindDevice(virConnectPtr conn, + unsigned vendor, + unsigned product); +void usbFreeDevice (virConnectPtr conn, usbDevice *dev); + +unsigned usbDeviceGetBus(usbDevice *dev); +unsigned usbDeviceGetDevno(usbDevice *dev); /* * Callback that will be invoked once for each file diff -rup libvirt-0.7.1/src/libvirt_private.syms new/src/libvirt_private.syms --- libvirt-0.7.1/src/libvirt_private.syms 2010-05-17 16:53:48.401831000 -0400 +++ new/src/libvirt_private.syms 2010-05-17 16:55:03.001748000 -0400 @@ -441,7 +441,10 @@ virFileMatchesNameSuffix; # usb.h usbGetDevice; +usbFindDevice; usbFreeDevice; +usbDeviceGetBus; +usbDeviceGetDevno; usbDeviceFileIterate; # uuid.h diff -rup libvirt-0.7.1/src/qemu_driver.c new/src/qemu_driver.c --- libvirt-0.7.1/src/qemu_driver.c 2010-05-17 16:53:48.785743000 -0400 +++ new/src/qemu_driver.c 2010-05-17 17:06:40.575145000 -0400 @@ -1493,16 +1493,13 @@ qemuUpdateActivePciHostdevs(struct qemud } static int -qemuPrepareHostDevices(virConnectPtr conn, - struct qemud_driver *driver, - virDomainDefPtr def) +qemuPrepareHostPCIDevices(virConnectPtr conn, + struct qemud_driver *driver, + virDomainDefPtr def) { pciDeviceList *pcidevs; int i; - if (!def->nhostdevs) - return 0; - if (!(pcidevs = qemuGetPciHostDeviceList(conn, def))) return -1; @@ -1792,14 +1789,11 @@ static int qemuDomainSetHostdevUSBOwners struct qemuFileOwner owner = { uid, gid }; int ret = -1; - /* XXX what todo for USB devs assigned based on product/vendor ? Doom :-( */ - if (!def->source.subsys.u.usb.bus || - !def->source.subsys.u.usb.device) - return 0; - usbDevice *dev = usbGetDevice(conn, def->source.subsys.u.usb.bus, - def->source.subsys.u.usb.device); + def->source.subsys.u.usb.device, + def->source.subsys.u.usb.vendor, + def->source.subsys.u.usb.product); if (!dev) goto cleanup; @@ -2065,13 +2059,17 @@ static int qemudStartVMDaemon(virConnect return -1; } + DEBUG0("Preparing host devices"); + if (qemuPrepareHostDevices(conn, driver, vm->def) < 0) + goto cleanup; + /* If you are using a SecurityDriver with dynamic labelling, then generate a security label for isolation */ if (vm->def->seclabel.type == VIR_DOMAIN_SECLABEL_DYNAMIC && driver->securityDriver && driver->securityDriver->domainGenSecurityLabel && driver->securityDriver->domainGenSecurityLabel(conn, vm) < 0) - return -1; + return cleanup; /* Ensure no historical cgroup for this VM is lieing around bogus settings */ qemuRemoveCgroup(conn, driver, vm); @@ -2119,9 +2117,6 @@ static int qemudStartVMDaemon(virConnect if (qemuSetupCgroup(conn, driver, vm) < 0) goto cleanup; - if (qemuPrepareHostDevices(conn, driver, vm->def) < 0) - goto cleanup; - if (VIR_ALLOC(vm->monitor_chr) < 0) { virReportOOMError(conn); goto cleanup; @@ -2348,6 +2343,56 @@ retry: } + +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_USB) + 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 qemudDispatchVMEvent(int watch, int fd, int events, void *opaque) { struct qemud_driver *driver = opaque; @@ -6294,6 +6339,23 @@ static int qemudDomainDetachHostDevice(v 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(conn, vm, dev->data.hostdev) < 0) VIR_WARN0("Failed to restore device labelling"); diff -rup libvirt-0.7.1/src/security_selinux.c new/src/security_selinux.c --- libvirt-0.7.1/src/security_selinux.c 2010-05-17 16:53:48.775745000 -0400 +++ new/src/security_selinux.c 2010-05-17 16:58:47.442604000 -0400 @@ -482,20 +482,15 @@ SELinuxSetSecurityHostdevLabel(virConnec switch (dev->source.subsys.type) { case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB: { - if (dev->source.subsys.u.usb.bus && dev->source.subsys.u.usb.device) { - usbDevice *usb = usbGetDevice(conn, - dev->source.subsys.u.usb.bus, - dev->source.subsys.u.usb.device); - - if (!usb) - goto done; - - ret = usbDeviceFileIterate(conn, usb, SELinuxSetSecurityUSBLabel, vm); - usbFreeDevice(conn, usb); - } else { - /* XXX deal with product/vendor better */ - ret = 0; - } + usbDevice *usb = usbGetDevice(conn, + dev->source.subsys.u.usb.bus, + dev->source.subsys.u.usb.device); + + if (!usb) + goto done; + + ret = usbDeviceFileIterate(conn, usb, SELinuxSetSecurityUSBLabel, vm); + usbFreeDevice(conn, usb); break; } diff -rup libvirt-0.7.1/src/hostusb.c new/src/hostusb.c --- libvirt-0.7.1/src/hostusb.c 2010-05-17 17:09:02.573638000 -0400 +++ new/src/hostusb.c 2010-05-17 17:29:49.133509000 -0400 @@ -184,16 +184,17 @@ usbGetDevice(virConnectPtr conn, usbDevice * -usbFindDevice(unsigned vendor, +usbFindDevice(virConnectPtr conn, + unsigned vendor, unsigned product) { unsigned bus = 0, devno = 0; - if (usbFindBusByVendor(vendor, product, &bus, &devno) < 0) { + if (usbFindBusByVendor(conn, vendor, product, &bus, &devno) < 0) { return NULL; } - return usbGetDevice(bus, devno); + return usbGetDevice(conn, bus, devno); } diff -rup libvirt-0.7.1/src/qemu_driver.c new/src/qemu_driver.c --- libvirt-0.7.1/src/qemu_driver.c 2010-05-17 17:09:02.602638000 -0400 +++ new/src/qemu_driver.c 2010-05-17 17:36:10.066214000 -0400 @@ -1791,9 +1791,7 @@ static int qemuDomainSetHostdevUSBOwners usbDevice *dev = usbGetDevice(conn, def->source.subsys.u.usb.bus, - def->source.subsys.u.usb.device, - def->source.subsys.u.usb.vendor, - def->source.subsys.u.usb.product); + def->source.subsys.u.usb.device); if (!dev) goto cleanup; @@ -2026,6 +2024,10 @@ qemuPrepareMonitorChr(virConnectPtr conn return 0; } +static int +qemuPrepareHostDevices(struct qemud_driver *driver, + virDomainDefPtr def); + static int qemudStartVMDaemon(virConnectPtr conn, struct qemud_driver *driver, virDomainObjPtr vm, @@ -2060,7 +2062,7 @@ static int qemudStartVMDaemon(virConnect } DEBUG0("Preparing host devices"); - if (qemuPrepareHostDevices(conn, driver, vm->def) < 0) + if (qemuPrepareHostDevices(driver, vm->def) < 0) goto cleanup; /* If you are using a SecurityDriver with dynamic labelling, @@ -2069,7 +2071,7 @@ static int qemudStartVMDaemon(virConnect driver->securityDriver && driver->securityDriver->domainGenSecurityLabel && driver->securityDriver->domainGenSecurityLabel(conn, vm) < 0) - return cleanup; + goto cleanup; /* Ensure no historical cgroup for this VM is lieing around bogus settings */ qemuRemoveCgroup(conn, driver, vm); @@ -2360,7 +2362,8 @@ qemuPrepareHostUSBDevices(struct qemud_d /* Resolve a vendor/product to bus/device */ if (hostdev->source.subsys.u.usb.vendor) { usbDevice *usb - = usbFindDevice(hostdev->source.subsys.u.usb.vendor, + = usbFindDevice(NULL, + hostdev->source.subsys.u.usb.vendor, hostdev->source.subsys.u.usb.product); if (!usb) @@ -2369,7 +2372,7 @@ qemuPrepareHostUSBDevices(struct qemud_d hostdev->source.subsys.u.usb.bus = usbDeviceGetBus(usb); hostdev->source.subsys.u.usb.device = usbDeviceGetDevno(usb); - usbFreeDevice(usb); + usbFreeDevice(NULL, usb); } } @@ -2383,7 +2386,7 @@ qemuPrepareHostDevices(struct qemud_driv if (!def->nhostdevs) return 0; - if (qemuPrepareHostPCIDevices(driver, def) < 0) + if (qemuPrepareHostPCIDevices(NULL, driver, def) < 0) return -1; if (qemuPrepareHostUSBDevices(driver, def) < 0) @@ -6343,7 +6346,8 @@ static int qemudDomainDetachHostDevice(v 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, + = usbFindDevice(NULL, + hostdev->source.subsys.u.usb.vendor, hostdev->source.subsys.u.usb.product); if (!usb) @@ -6352,7 +6356,7 @@ static int qemudDomainDetachHostDevice(v hostdev->source.subsys.u.usb.bus = usbDeviceGetBus(usb); hostdev->source.subsys.u.usb.device = usbDeviceGetDevno(usb); - usbFreeDevice(usb); + usbFreeDevice(NULL, usb); }