Here's a patch to fix a race condition in usbdevfs. The fix is in hub.c
but the race is related to usbdevfs.
The race goes like this:
Process 1 (khubd) Process 2 (mount)
usb_hub_port_connect_change()
hub->children[port] = dev
usb_new_device()
usbdevfs_read_super()
recurse_new_dev_inode()
new_dev_inode()
list_add_tail(..., &dev->inodes)
usbdevfs_add_device()
new_dev_inode()
list_add_tail(..., &dev->inodes)
The problem is that the inode gets added twice, corrupting dev->inodes.
This will cause a problems at disconnect where the same inode will be
freed twice, causing a neverending loop, or an oops. I think it will
also cause problems at unmount.
The fix is to just move setting hub->children to later in the
enumeration process. This way usbdevfs_read_super won't see the device
before it has been through the usbdevfs_add_device path.
I didn't see this on x86, but apparentely others have looking at the
RedHat 9 kernel sources. (RedHat bugzilla #81091)
Pete, could you give this patch a shot for the problem you found in that
bug? I'm pretty sure they are the same problem.
I haven't looked at the 2.5 code to see if the same problem exists.
JE
# This is a BitKeeper generated patch for the following project:
# Project Name: greg k-h's linux 2.4 USB kernel tree
# This patch format is intended for GNU patch command version 2.5 or higher.
# This patch includes the following deltas:
# ChangeSet 1.825 -> 1.826
# drivers/usb/hub.c 1.31 -> 1.32
#
# The following is the BitKeeper ChangeSet Log
# --------------------------------------------
# 03/06/04 [EMAIL PROTECTED] 1.826
# hub.c:
# Fix race between usbdevfs_read_super and usbdevfs_add_device
# --------------------------------------------
#
diff -Nru a/drivers/usb/hub.c b/drivers/usb/hub.c
--- a/drivers/usb/hub.c Wed Jun 4 21:17:38 2003
+++ b/drivers/usb/hub.c Wed Jun 4 21:17:38 2003
@@ -716,8 +716,6 @@
break;
}
- hub->children[port] = dev;
-
/* Reset the device */
if (usb_hub_port_reset(hub, port, dev, delay)) {
usb_free_dev(dev);
@@ -761,8 +759,10 @@
dev->bus->bus_name, dev->devpath, dev->devnum);
/* Run it through the hoops (find a driver, etc) */
- if (!usb_new_device(dev))
+ if (!usb_new_device(dev)) {
+ hub->children[port] = dev;
goto done;
+ }
/* Free the configuration if there was an error */
usb_free_dev(dev);
@@ -771,7 +771,6 @@
delay = HUB_LONG_RESET_TIME;
}
- hub->children[port] = NULL;
usb_hub_port_disable(hub, port);
done:
up(&usb_address0_sem);
-------------------------------------------------------
This SF.net email is sponsored by: Etnus, makers of TotalView, The best
thread debugger on the planet. Designed with thread debugging features
you've never dreamed of, try TotalView 6 free at www.etnus.com.
_______________________________________________
[EMAIL PROTECTED]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel