Greg:

Linus has said that waiting for a device's release() method to be called
is evil, with a possible exception for unloadable kernel modules.  He 
feels that rmmod is generally unnecessary -- it's mostly an aid for 
developers and not very important for users.  My feeling is that as long 
as rmmod is there, it should work safely.

This patch helps USB host driver modules to unload by waiting for the
bus's release() method.  Rather than duplicate the functionality in each 
HCD, it is centralized in usbcore.  It's basically just a home-brewed 
version of the defunct device_unregister_wait().

The usual arguments against waiting for release apply, of course.  Here's
how I see it:

        If we do wait for release, then we provide a way for the superuser
        to cause a deadlock by deliberately doing something foolish like
        "rmmod uhci_hcd </sys/devices/pci/0000:07.2/usb1/serial".

        If we don't wait for release, then we provide a way for any old
        user to cause an oops by getting a reference to a device on the
        USB bus and not releasing the reference until rmmod finishes.

If you don't believe that, try it yourself.  Sysfs provides a great way to 
obtain references to devices.  Find a sysfs attribute file for the root 
hub in the bus you want to remove, and as a regular user do:

        sleep 10 <sysfs_file

While that's waiting, in another window as root rmmod the bus's HCD.  When 
the sleep command finishes you'll get a dandy oops.

I think the choice of which alternative to prefer is clear.  This patch 
implements it.

Alan Stern


===== include/linux/usb.h 1.175 vs edited =====
--- 1.175/include/linux/usb.h   Mon Mar  8 12:27:12 2004
+++ edited/include/linux/usb.h  Mon Mar 15 11:32:52 2004
@@ -240,6 +240,7 @@
 
        struct class_device class_dev;  /* class device for this bus */
        void (*release)(struct usb_bus *bus);   /* function to destroy this bus's 
memory */
+       struct completion *released;    /* wait for release */
 };
 #define        to_usb_bus(d) container_of(d, struct usb_bus, class_dev)
 
===== drivers/usb/core/hcd.c 1.131 vs edited =====
--- 1.131/drivers/usb/core/hcd.c        Sun Mar  7 14:29:08 2004
+++ edited/drivers/usb/core/hcd.c       Mon Mar 15 11:32:52 2004
@@ -588,9 +588,11 @@
 static void usb_host_release(struct class_device *class_dev)
 {
        struct usb_bus *bus = to_usb_bus(class_dev);
+       struct completion *released = bus->released;
 
        if (bus->release)
                bus->release(bus);
+       complete(released);
 }
 
 static struct class usb_host_class = {
@@ -712,6 +714,8 @@
  */
 void usb_deregister_bus (struct usb_bus *bus)
 {
+       struct completion released;
+
        dev_info (bus->controller, "USB bus %d deregistered\n", bus->busnum);
 
        /*
@@ -727,7 +731,10 @@
 
        clear_bit (bus->busnum, busmap.busmap);
 
+       init_completion(&released);
+       bus->released = &released;
        class_device_unregister(&bus->class_dev);
+       wait_for_completion(&released);
 }
 EXPORT_SYMBOL (usb_deregister_bus);
 



-------------------------------------------------------
This SF.Net email is sponsored by: IBM Linux Tutorials
Free Linux tutorial presented by Daniel Robbins, President and CEO of
GenToo technologies. Learn everything from fundamentals to system
administration.http://ads.osdn.com/?ad_id=1470&alloc_id=3638&op=click
_______________________________________________
[EMAIL PROTECTED]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to