ChangeSet 1.1255, 2003/06/18 16:55:30-07:00, [EMAIL PROTECTED]

[PATCH] USB: fix 2.4 usbdevfs race

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.


 drivers/usb/hub.c |    7 +++----
 1 files changed, 3 insertions(+), 4 deletions(-)


diff -Nru a/drivers/usb/hub.c b/drivers/usb/hub.c
--- a/drivers/usb/hub.c Wed Jun 18 17:34:56 2003
+++ b/drivers/usb/hub.c Wed Jun 18 17:34:56 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: INetU
Attention Web Developers & Consultants: Become An INetU Hosting Partner.
Refer Dedicated Servers. We Manage Them. You Get 10% Monthly Commission!
INetU Dedicated Managed Hosting http://www.inetu.net/partner/index.php
_______________________________________________
[EMAIL PROTECTED]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to