Commit 59c2deed authored by Alan Stern's avatar Alan Stern Committed by Greg Kroah-Hartman

[PATCH] USB: Lock devices during tree traversal

On Tue, 27 Apr 2004, Greg KH wrote:

> So, what's next in this patch series?  :)

Funny you should ask...

While writing those patches I noted a problem, that the USB device tree
can change while a process reading /proc/bus/usb/devices is traversing it,
leading to an oops when a pointer to a no-longer-existing child device is
dereferenced.  The ensuing discussion led to the conclusion that the
devices' ->serialize locks should be acquired, top-down, while going
through the tree.

That means changing the code that populates the devices file and changing
the code that adds and removes USB device structures.  This patch takes
care of the first part.  I'm delaying the second part because that section
of usbcore is still under change -- David Brownell's revisions have not
yet been fully integrated.

A similar change should be made to usb_find_device() and match_device() in
usb.c.  You may want to add that yourself.
parent df6ed992
...@@ -452,6 +452,7 @@ static char *usb_dump_string(char *start, char *end, const struct usb_device *de ...@@ -452,6 +452,7 @@ static char *usb_dump_string(char *start, char *end, const struct usb_device *de
* nbytes - the maximum number of bytes to write * nbytes - the maximum number of bytes to write
* skip_bytes - the number of bytes to skip before writing anything * skip_bytes - the number of bytes to skip before writing anything
* file_offset - the offset into the devices file on completion * file_offset - the offset into the devices file on completion
* The caller must own the usbdev->serialize semaphore.
*/ */
static ssize_t usb_device_dump(char __user **buffer, size_t *nbytes, loff_t *skip_bytes, loff_t *file_offset, static ssize_t usb_device_dump(char __user **buffer, size_t *nbytes, loff_t *skip_bytes, loff_t *file_offset,
struct usb_device *usbdev, struct usb_bus *bus, int level, int index, int count) struct usb_device *usbdev, struct usb_bus *bus, int level, int index, int count)
...@@ -552,9 +553,13 @@ static ssize_t usb_device_dump(char __user **buffer, size_t *nbytes, loff_t *ski ...@@ -552,9 +553,13 @@ static ssize_t usb_device_dump(char __user **buffer, size_t *nbytes, loff_t *ski
/* Now look at all of this device's children. */ /* Now look at all of this device's children. */
for (chix = 0; chix < usbdev->maxchild; chix++) { for (chix = 0; chix < usbdev->maxchild; chix++) {
if (usbdev->children[chix]) { struct usb_device *childdev = usbdev->children[chix];
ret = usb_device_dump(buffer, nbytes, skip_bytes, file_offset, usbdev->children[chix],
if (childdev) {
down(&childdev->serialize);
ret = usb_device_dump(buffer, nbytes, skip_bytes, file_offset, childdev,
bus, level + 1, chix, ++cnt); bus, level + 1, chix, ++cnt);
up(&childdev->serialize);
if (ret == -EFAULT) if (ret == -EFAULT)
return total_written; return total_written;
total_written += ret; total_written += ret;
...@@ -582,8 +587,11 @@ static ssize_t usb_device_read(struct file *file, char __user *buf, size_t nbyte ...@@ -582,8 +587,11 @@ static ssize_t usb_device_read(struct file *file, char __user *buf, size_t nbyte
for (buslist = usb_bus_list.next; buslist != &usb_bus_list; buslist = buslist->next) { for (buslist = usb_bus_list.next; buslist != &usb_bus_list; buslist = buslist->next) {
/* print devices for this bus */ /* print devices for this bus */
bus = list_entry(buslist, struct usb_bus, bus_list); bus = list_entry(buslist, struct usb_bus, bus_list);
/* recurse through all children of the root hub */ /* recurse through all children of the root hub */
down(&bus->root_hub->serialize);
ret = usb_device_dump(&buf, &nbytes, &skip_bytes, ppos, bus->root_hub, bus, 0, 0, 0); ret = usb_device_dump(&buf, &nbytes, &skip_bytes, ppos, bus->root_hub, bus, 0, 0, 0);
up(&bus->root_hub->serialize);
if (ret < 0) { if (ret < 0) {
up(&usb_bus_list_lock); up(&usb_bus_list_lock);
return ret; return ret;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment