diff -urN linux-2.4.27/drivers/usb/devices.c linux-2.4.28/drivers/usb/devices.c --- linux-2.4.27/drivers/usb/devices.c 2002-11-28 15:53:14.000000000 -0800 +++ linux-2.4.28/drivers/usb/devices.c 2004-11-17 03:54:21.802406282 -0800 @@ -387,22 +387,31 @@ if (start > end) return start; - + + /* + * Grab device's exclusive_access mutex to prevent its driver or + * devio from using this device while we are accessing it. + */ + down (&dev->exclusive_access); + start = usb_dump_device_descriptor(start, end, &dev->descriptor); if (start > end) - return start; - + goto out; + start = usb_dump_device_strings (start, end, dev); for (i = 0; i < dev->descriptor.bNumConfigurations; i++) { if (start > end) - return start; + goto out; start = usb_dump_config(dev->speed, start, end, dev->config + i, /* active ? */ (dev->config + i) == dev->actconfig); } + +out: + up (&dev->exclusive_access); return start; } @@ -543,9 +552,13 @@ /* Now look at all of this device's children. */ for (chix = 0; chix < usbdev->maxchild; chix++) { - if (usbdev->children[chix]) { - ret = usb_device_dump(buffer, nbytes, skip_bytes, file_offset, usbdev->children[chix], + struct usb_device *childdev = usbdev->children[chix]; + if (childdev) { + usb_inc_dev_use(childdev); + ret = usb_device_dump(buffer, nbytes, skip_bytes, + file_offset, childdev, bus, level + 1, chix, ++cnt); + usb_dec_dev_use(childdev); if (ret == -EFAULT) return total_written; total_written += ret; diff -urN linux-2.4.27/drivers/usb/devio.c linux-2.4.28/drivers/usb/devio.c --- linux-2.4.27/drivers/usb/devio.c 2004-08-07 16:26:05.000000000 -0700 +++ linux-2.4.28/drivers/usb/devio.c 2004-11-17 03:54:21.803406323 -0800 @@ -1158,6 +1158,13 @@ up_read(&ps->devsem); return -ENODEV; } + + /* + * grab device's exclusive_access mutex to prevent its driver from + * using this device while it is being accessed by us. + */ + down(&ps->dev->exclusive_access); + switch (cmd) { case USBDEVFS_CONTROL: ret = proc_control(ps, (void *)arg); @@ -1237,6 +1244,7 @@ ret = proc_ioctl(ps, (void *) arg); break; } + up(&ps->dev->exclusive_access); up_read(&ps->devsem); if (ret >= 0) inode->i_atime = CURRENT_TIME; diff -urN linux-2.4.27/drivers/usb/storage/transport.c linux-2.4.28/drivers/usb/storage/transport.c --- linux-2.4.27/drivers/usb/storage/transport.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.28/drivers/usb/storage/transport.c 2004-11-17 03:54:21.854408420 -0800 @@ -627,8 +627,17 @@ int need_auto_sense; int result; + /* + * Grab device's exclusive_access mutex to prevent libusb/usbfs from + * sending out a command in the middle of ours (if libusb sends a + * get_descriptor or something on pipe 0 after our CBW and before + * our CSW, and then we get a stall, we have trouble). + */ + down(&(us->pusb_dev->exclusive_access)); + /* send the command to the transport layer */ result = us->transport(srb, us); + up(&(us->pusb_dev->exclusive_access)); /* if the command gets aborted by the higher layers, we need to * short-circuit all other processing @@ -748,7 +757,9 @@ srb->use_sg = 0; /* issue the auto-sense command */ + down(&(us->pusb_dev->exclusive_access)); temp_result = us->transport(us->srb, us); + up(&(us->pusb_dev->exclusive_access)); /* let's clean up right away */ srb->request_buffer = old_request_buffer; diff -urN linux-2.4.27/drivers/usb/usb.c linux-2.4.28/drivers/usb/usb.c --- linux-2.4.27/drivers/usb/usb.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.28/drivers/usb/usb.c 2004-11-17 03:54:21.917411010 -0800 @@ -989,6 +989,7 @@ INIT_LIST_HEAD(&dev->filelist); init_MUTEX(&dev->serialize); + init_MUTEX(&dev->exclusive_access); dev->bus->op->allocate(dev);