Jesse:
Could you please try out the patch below in place of the controversial one
I sent you back on July 7? You're the only person I know who has run up
against the problem these two patches address.
Oh, yes -- this patch also needs that one-line correction from July 6
applied.
Thanks,
Alan Stern
===== drivers/usb/core/devices.c 1.38 vs edited =====
--- 1.38/drivers/usb/core/devices.c Thu Jun 24 12:44:16 2004
+++ edited/drivers/usb/core/devices.c Mon Jul 12 14:01:04 2004
@@ -555,10 +555,10 @@
struct usb_device *childdev = usbdev->children[chix];
if (childdev) {
- usb_lock_device(childdev);
+ down(&childdev->serialize);
ret = usb_device_dump(buffer, nbytes, skip_bytes, file_offset,
childdev,
bus, level + 1, chix, ++cnt);
- usb_unlock_device(childdev);
+ up(&childdev->serialize);
if (ret == -EFAULT)
return total_written;
total_written += ret;
===== drivers/usb/core/hub.c 1.182 vs edited =====
--- 1.182/drivers/usb/core/hub.c Thu Jul 1 10:53:20 2004
+++ edited/drivers/usb/core/hub.c Mon Jul 12 14:10:07 2004
@@ -965,9 +965,11 @@
usb_set_device_state(udev, USB_STATE_NOTATTACHED);
/* lock the bus list on behalf of HCDs unregistering their root hubs */
- if (!udev->parent)
+ if (!udev->parent) {
down(&usb_bus_list_lock);
- usb_lock_device(udev);
+ usb_lock_device(udev);
+ } else
+ down(&udev->serialize);
dev_info (&udev->dev, "USB disconnect, address %d\n", udev->devnum);
@@ -996,9 +998,11 @@
*pdev = NULL;
spin_unlock_irq(&device_state_lock);
- usb_unlock_device(udev);
- if (!udev->parent)
+ if (!udev->parent) {
+ usb_unlock_device(udev);
up(&usb_bus_list_lock);
+ } else
+ up(&udev->serialize);
device_unregister(&udev->dev);
}
@@ -1693,7 +1697,7 @@
* udev becomes globally accessible, although presumably
* no one will look at it until hdev is unlocked.
*/
- usb_lock_device (udev);
+ down(&udev->serialize);
status = 0;
/* We mustn't add new devices if the parent hub has
@@ -1717,7 +1721,7 @@
}
}
- usb_unlock_device (udev);
+ up(&udev->serialize);
if (status)
goto loop;
===== drivers/usb/core/usb.c 1.282 vs edited =====
--- 1.282/drivers/usb/core/usb.c Tue Jul 6 08:00:32 2004
+++ edited/drivers/usb/core/usb.c Mon Jul 12 14:00:12 2004
@@ -845,6 +845,43 @@
put_device(&intf->dev);
}
+
+/* USB device locking
+ *
+ * Although locking USB devices should be straightforward, it is
+ * complicated by the way the driver-model core works. When a new USB
+ * driver is registered or unregistered, the core will automatically
+ * probe or disconnect all matching interfaces on all USB devices while
+ * holding the USB subsystem writelock. There's no good way for us to
+ * tell which devices will be used or to lock them beforehand. Our only
+ * option is to effectively lock all the USB devices.
+ *
+ * We do that by using a private rw-semaphore, usb_all_devices_rwsem.
+ * When locking an individual device you must first acquire the rwsem's
+ * readlock. When a driver is registered or unregistered the writelock
+ * must be held. These actions are encapsulated in the subroutines
+ * below, so all a driver needs to do is call usb_lock_device() and
+ * usb_unlock_device().
+ *
+ * Complications arise when several devices are to be locked at the
+ * same time. Only hub-aware drivers that are part of usbcore ever have
+ * to do this; nobody else needs to worry about it. The problem is that
+ * usb_lock_device() must not be called to lock a second device since it
+ * would acquire the rwsem's readlock reentrantly, leading to deadlock if
+ * another thread was waiting for the writelock. The solution is simple:
+ *
+ * When locking more than one device, call usb_lock_device()
+ * to lock the first one. Lock the others by calling
+ * down(&udev->serialize) directly.
+ *
+ * When unlocking multiple devices, use up(&udev->serialize)
+ * to unlock all but the last one. Unlock the last one by
+ * calling usb_unlock_device().
+ *
+ * When locking more than one device, always lock the parent
+ * before locking the child.
+ */
+
/**
* usb_lock_device - acquire the lock for a usb device structure
* @udev: device that's being locked
@@ -976,10 +1013,10 @@
/* look through all of the children of this device */
for (child = 0; child < dev->maxchild; ++child) {
if (dev->children[child]) {
- usb_lock_device(dev->children[child]);
+ down(&dev->children[child]->serialize);
ret_dev = match_device(dev->children[child],
vendor_id, product_id);
- usb_unlock_device(dev->children[child]);
+ up(&dev->children[child]->serialize);
if (ret_dev)
goto exit;
}
-------------------------------------------------------
This SF.Net email sponsored by Black Hat Briefings & Training.
Attend Black Hat Briefings & Training, Las Vegas July 24-29 -
digital self defense, top technical experts, no vendor pitches,
unmatched networking opportunities. Visit www.blackhat.com
_______________________________________________
[EMAIL PROTECTED]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel