This patch (as908) adds central protection in usbcore for the
prototypical race between opening and unregistering a char device.
The spinlock used to protect the minor-numbers array is replaced with
an rwsem, which can remain locked across a call to a driver's open()
method.  This guarantees that open() and deregister() will be mutually
exclusive.

The private locks currently used in several individual drivers for
this purpose are no longer necessary, and the patch removes them.  The
following USB drivers are affected: usblcd, idmouse, auerswald,
legousbtower, sisusbvga/sisusb, ldusb, adutux, iowarrior, and
usb-skeleton.

As a side effect of this change, usb_deregister_dev() must not be
called while holding a lock that is acquired by open().  Unfortunately
a number of drivers do this, but luckily the solution is simple: call
usb_deregister_dev() before acquiring the lock.

In addition to these changes (and their consequent code
simplifications), the patch fixes a use-after-free bug in adutux and a
race between open() and release() in iowarrior.

Signed-off-by: Alan Stern <[EMAIL PROTECTED]>

---

Index: usb-2.6/drivers/usb/core/file.c
===================================================================
--- usb-2.6.orig/drivers/usb/core/file.c
+++ usb-2.6/drivers/usb/core/file.c
@@ -16,15 +16,15 @@
  */
 
 #include <linux/module.h>
-#include <linux/spinlock.h>
 #include <linux/errno.h>
+#include <linux/rwsem.h>
 #include <linux/usb.h>
 
 #include "usb.h"
 
 #define MAX_USB_MINORS 256
 static const struct file_operations *usb_minors[MAX_USB_MINORS];
-static DEFINE_SPINLOCK(minor_lock);
+static DECLARE_RWSEM(minor_rwsem);
 
 static int usb_open(struct inode * inode, struct file * file)
 {
@@ -33,14 +33,11 @@ static int usb_open(struct inode * inode
        int err = -ENODEV;
        const struct file_operations *old_fops, *new_fops = NULL;
 
-       spin_lock (&minor_lock);
+       down_read(&minor_rwsem);
        c = usb_minors[minor];
 
-       if (!c || !(new_fops = fops_get(c))) {
-               spin_unlock(&minor_lock);
-               return err;
-       }
-       spin_unlock(&minor_lock);
+       if (!c || !(new_fops = fops_get(c)))
+               goto done;
 
        old_fops = file->f_op;
        file->f_op = new_fops;
@@ -52,6 +49,8 @@ static int usb_open(struct inode * inode
                file->f_op = fops_get(old_fops);
        }
        fops_put(old_fops);
+ done:
+       up_read(&minor_rwsem);
        return err;
 }
 
@@ -166,7 +165,7 @@ int usb_register_dev(struct usb_interfac
        if (class_driver->fops == NULL)
                goto exit;
 
-       spin_lock (&minor_lock);
+       down_write(&minor_rwsem);
        for (minor = minor_base; minor < MAX_USB_MINORS; ++minor) {
                if (usb_minors[minor])
                        continue;
@@ -176,7 +175,7 @@ int usb_register_dev(struct usb_interfac
                retval = 0;
                break;
        }
-       spin_unlock (&minor_lock);
+       up_write(&minor_rwsem);
 
        if (retval)
                goto exit;
@@ -197,9 +196,9 @@ int usb_register_dev(struct usb_interfac
        intf->usb_dev = device_create(usb_class->class, &intf->dev,
                                      MKDEV(USB_MAJOR, minor), "%s", temp);
        if (IS_ERR(intf->usb_dev)) {
-               spin_lock (&minor_lock);
+               down_write(&minor_rwsem);
                usb_minors[intf->minor] = NULL;
-               spin_unlock (&minor_lock);
+               up_write(&minor_rwsem);
                retval = PTR_ERR(intf->usb_dev);
        }
 exit:
@@ -236,9 +235,9 @@ void usb_deregister_dev(struct usb_inter
 
        dbg ("removing %d minor", intf->minor);
 
-       spin_lock (&minor_lock);
+       down_write(&minor_rwsem);
        usb_minors[intf->minor] = NULL;
-       spin_unlock (&minor_lock);
+       up_write(&minor_rwsem);
 
        snprintf(name, BUS_ID_SIZE, class_driver->name, intf->minor - 
minor_base);
        device_destroy(usb_class->class, MKDEV(USB_MAJOR, intf->minor));
@@ -247,5 +246,3 @@ void usb_deregister_dev(struct usb_inter
        destroy_usb_class();
 }
 EXPORT_SYMBOL(usb_deregister_dev);
-
-
Index: usb-2.6/drivers/usb/misc/auerswald.c
===================================================================
--- usb-2.6.orig/drivers/usb/misc/auerswald.c
+++ usb-2.6/drivers/usb/misc/auerswald.c
@@ -2040,12 +2040,12 @@ static void auerswald_disconnect (struct
        if (!cp)
                return;
 
-       down (&cp->mutex);
-       info ("device /dev/%s now disconnecting", cp->name);
-
        /* give back our USB minor number */
        usb_deregister_dev(intf, &auerswald_class);
 
+       down (&cp->mutex);
+       info ("device /dev/%s now disconnecting", cp->name);
+
        /* Stop the interrupt endpoint */
        auerswald_int_release (cp);
 
Index: usb-2.6/drivers/usb/misc/idmouse.c
===================================================================
--- usb-2.6.orig/drivers/usb/misc/idmouse.c
+++ usb-2.6/drivers/usb/misc/idmouse.c
@@ -119,9 +119,6 @@ static struct usb_driver idmouse_driver 
        .id_table = idmouse_table,
 };
 
-/* prevent races between open() and disconnect() */
-static DEFINE_MUTEX(disconnect_mutex);
-
 static int idmouse_create_image(struct usb_idmouse *dev)
 {
        int bytes_read;
@@ -211,21 +208,15 @@ static int idmouse_open(struct inode *in
        struct usb_interface *interface;
        int result;
 
-       /* prevent disconnects */
-       mutex_lock(&disconnect_mutex);
-
        /* get the interface from minor number and driver information */
        interface = usb_find_interface (&idmouse_driver, iminor (inode));
-       if (!interface) {
-               mutex_unlock(&disconnect_mutex);
+       if (!interface)
                return -ENODEV;
-       }
+
        /* get the device information block from the interface */
        dev = usb_get_intfdata(interface);
-       if (!dev) {
-               mutex_unlock(&disconnect_mutex);
+       if (!dev)
                return -ENODEV;
-       }
 
        /* lock this device */
        down(&dev->sem);
@@ -255,9 +246,6 @@ error:
 
        /* unlock this device */
        up(&dev->sem);
-
-       /* unlock the disconnect semaphore */
-       mutex_unlock(&disconnect_mutex);
        return result;
 }
 
@@ -265,15 +253,10 @@ static int idmouse_release(struct inode 
 {
        struct usb_idmouse *dev;
 
-       /* prevent a race condition with open() */
-       mutex_lock(&disconnect_mutex);
-
        dev = file->private_data;
 
-       if (dev == NULL) {
-               mutex_unlock(&disconnect_mutex);
+       if (dev == NULL)
                return -ENODEV;
-       }
 
        /* lock our device */
        down(&dev->sem);
@@ -281,7 +264,6 @@ static int idmouse_release(struct inode 
        /* are we really open? */
        if (dev->open <= 0) {
                up(&dev->sem);
-               mutex_unlock(&disconnect_mutex);
                return -ENODEV;
        }
 
@@ -291,12 +273,9 @@ static int idmouse_release(struct inode 
                /* the device was unplugged before the file was released */
                up(&dev->sem);
                idmouse_delete(dev);
-               mutex_unlock(&disconnect_mutex);
-               return 0;
+       } else {
+               up(&dev->sem);
        }
-
-       up(&dev->sem);
-       mutex_unlock(&disconnect_mutex);
        return 0;
 }
 
@@ -391,30 +370,27 @@ static void idmouse_disconnect(struct us
 {
        struct usb_idmouse *dev;
 
-       /* prevent races with open() */
-       mutex_lock(&disconnect_mutex);
-
        /* get device structure */
        dev = usb_get_intfdata(interface);
        usb_set_intfdata(interface, NULL);
 
-       /* lock it */
-       down(&dev->sem);
-
        /* give back our minor */
        usb_deregister_dev(interface, &idmouse_class);
 
+       /* lock it */
+       down(&dev->sem);
+
        /* prevent device read, write and ioctl */
        dev->present = 0;
 
-       /* unlock */
-       up(&dev->sem);
-
        /* if the device is opened, idmouse_release will clean this up */
-       if (!dev->open)
+       if (!dev->open) {
+               up(&dev->sem);
                idmouse_delete(dev);
-
-       mutex_unlock(&disconnect_mutex);
+       } else {
+               /* unlock */
+               up(&dev->sem);
+       }
 
        info("%s disconnected", DRIVER_DESC);
 }
Index: usb-2.6/drivers/usb/misc/usblcd.c
===================================================================
--- usb-2.6.orig/drivers/usb/misc/usblcd.c
+++ usb-2.6/drivers/usb/misc/usblcd.c
@@ -47,7 +47,6 @@ struct usb_lcd {
 #define to_lcd_dev(d) container_of(d, struct usb_lcd, kref)
 
 static struct usb_driver lcd_driver;
-static DEFINE_MUTEX(usb_lcd_open_mutex);
 
 
 static void lcd_delete(struct kref *kref)
@@ -65,24 +64,19 @@ static int lcd_open(struct inode *inode,
        struct usb_lcd *dev;
        struct usb_interface *interface;
        int subminor;
-       int retval = 0;
 
        subminor = iminor(inode);
 
-       mutex_lock(&usb_lcd_open_mutex);
        interface = usb_find_interface(&lcd_driver, subminor);
        if (!interface) {
                err ("USBLCD: %s - error, can't find device for minor %d",
                     __FUNCTION__, subminor);
-               retval = -ENODEV;
-               goto exit;
+               return -ENODEV;
        }
 
        dev = usb_get_intfdata(interface);
-       if (!dev) {
-               retval = -ENODEV;
-               goto exit;
-       }
+       if (!dev)
+               return -ENODEV;
 
        /* increment our usage count for the device */
        kref_get(&dev->kref);
@@ -90,9 +84,7 @@ static int lcd_open(struct inode *inode,
        /* save our object in the file's private structure */
        file->private_data = dev;
 
-exit:
-       mutex_unlock(&usb_lcd_open_mutex);
-       return retval;
+       return 0;
 }
 
 static int lcd_release(struct inode *inode, struct file *file)
@@ -349,17 +341,12 @@ static void lcd_disconnect(struct usb_in
        struct usb_lcd *dev;
         int minor = interface->minor;
 
-        /* prevent skel_open() from racing skel_disconnect() */
-        mutex_lock(&usb_lcd_open_mutex);
-
         dev = usb_get_intfdata(interface);
         usb_set_intfdata(interface, NULL);
 
         /* give back our minor */
         usb_deregister_dev(interface, &lcd_class);
  
-       mutex_unlock(&usb_lcd_open_mutex);
-
        /* decrement our usage count */
        kref_put(&dev->kref, lcd_delete);
 
Index: usb-2.6/drivers/usb/misc/adutux.c
===================================================================
--- usb-2.6.orig/drivers/usb/misc/adutux.c
+++ usb-2.6/drivers/usb/misc/adutux.c
@@ -108,8 +108,6 @@ struct adu_device {
        struct urb*             interrupt_out_urb;
 };
 
-/* prevent races between open() and disconnect */
-static DEFINE_MUTEX(disconnect_mutex);
 static struct usb_driver adu_driver;
 
 static void adu_debug_data(int level, const char *function, int size,
@@ -256,8 +254,6 @@ static int adu_open(struct inode *inode,
 
        subminor = iminor(inode);
 
-       mutex_lock(&disconnect_mutex);
-
        interface = usb_find_interface(&adu_driver, subminor);
        if (!interface) {
                err("%s - error, can't find device for minor %d",
@@ -306,7 +302,6 @@ static int adu_open(struct inode *inode,
        up(&dev->sem);
 
 exit_no_device:
-       mutex_unlock(&disconnect_mutex);
        dbg(2,"%s : leave, return value %d ", __FUNCTION__, retval);
 
        return retval;
@@ -318,12 +313,6 @@ static int adu_release_internal(struct a
 
        dbg(2," %s : enter", __FUNCTION__);
 
-       if (dev->udev == NULL) {
-               /* the device was unplugged before the file was released */
-               adu_delete(dev);
-               goto exit;
-       }
-
        /* decrement our usage count for the device */
        --dev->open_count;
        dbg(2," %s : open count %d", __FUNCTION__, dev->open_count);
@@ -332,7 +321,6 @@ static int adu_release_internal(struct a
                dev->open_count = 0;
        }
 
-exit:
        dbg(2," %s : leave", __FUNCTION__);
        return retval;
 }
@@ -367,8 +355,15 @@ static int adu_release(struct inode *ino
                goto exit;
        }
 
-       /* do the work */
-       retval = adu_release_internal(dev);
+       if (dev->udev == NULL) {
+               /* the device was unplugged before the file was released */
+               up(&dev->sem);
+               adu_delete(dev);
+               dev = NULL;
+       } else {
+               /* do the work */
+               retval = adu_release_internal(dev);
+       }
 
 exit:
        if (dev)
@@ -831,19 +826,17 @@ static void adu_disconnect(struct usb_in
 
        dbg(2," %s : enter", __FUNCTION__);
 
-       mutex_lock(&disconnect_mutex); /* not interruptible */
-
        dev = usb_get_intfdata(interface);
        usb_set_intfdata(interface, NULL);
 
-       down(&dev->sem); /* not interruptible */
-
        minor = dev->minor;
 
        /* give back our minor */
        usb_deregister_dev(interface, &adu_class);
        dev->minor = 0;
 
+       down(&dev->sem); /* not interruptible */
+
        /* if the device is not opened, then we clean up right now */
        dbg(2," %s : open count %d", __FUNCTION__, dev->open_count);
        if (!dev->open_count) {
@@ -854,8 +847,6 @@ static void adu_disconnect(struct usb_in
                up(&dev->sem);
        }
 
-       mutex_unlock(&disconnect_mutex);
-
        dev_info(&interface->dev, "ADU device adutux%d now disconnected",
                 (minor - ADU_MINOR_BASE));
 
Index: usb-2.6/drivers/usb/misc/iowarrior.c
===================================================================
--- usb-2.6.orig/drivers/usb/misc/iowarrior.c
+++ usb-2.6/drivers/usb/misc/iowarrior.c
@@ -100,8 +100,6 @@ struct iowarrior {
 /*--------------*/
 /*    globals   */
 /*--------------*/
-/* prevent races between open() and disconnect() */
-static DECLARE_MUTEX(disconnect_sem);
 
 /*
  *  USB spec identifies 5 second timeouts.
@@ -599,22 +597,18 @@ static int iowarrior_open(struct inode *
 
        subminor = iminor(inode);
 
-       /* prevent disconnects */
-       down(&disconnect_sem);
-
        interface = usb_find_interface(&iowarrior_driver, subminor);
        if (!interface) {
                err("%s - error, can't find device for minor %d", __FUNCTION__,
                    subminor);
-               retval = -ENODEV;
-               goto out;
+               return -ENODEV;
        }
 
        dev = usb_get_intfdata(interface);
-       if (!dev) {
-               retval = -ENODEV;
-               goto out;
-       }
+       if (!dev)
+               return -ENODEV;
+
+       mutex_lock(&dev->mutex);
 
        /* Only one process can open each device, no sharing. */
        if (dev->opened) {
@@ -635,7 +629,7 @@ static int iowarrior_open(struct inode *
        retval = 0;
 
 out:
-       up(&disconnect_sem);
+       mutex_unlock(&dev->mutex);
        return retval;
 }
 
@@ -867,19 +861,16 @@ static void iowarrior_disconnect(struct 
        struct iowarrior *dev;
        int minor;
 
-       /* prevent races with open() */
-       down(&disconnect_sem);
-
        dev = usb_get_intfdata(interface);
        usb_set_intfdata(interface, NULL);
 
-       mutex_lock(&dev->mutex);
-
        minor = dev->minor;
 
        /* give back our minor */
        usb_deregister_dev(interface, &iowarrior_class);
 
+       mutex_lock(&dev->mutex);
+
        /* prevent device read, write and ioctl */
        dev->present = 0;
 
@@ -897,7 +888,6 @@ static void iowarrior_disconnect(struct 
                /* no process is using the device, cleanup now */
                iowarrior_delete(dev);
        }
-       up(&disconnect_sem);
 
        dev_info(&interface->dev, "I/O-Warror #%d now disconnected\n",
                 minor - IOWARRIOR_MINOR_BASE);
Index: usb-2.6/drivers/usb/misc/ldusb.c
===================================================================
--- usb-2.6.orig/drivers/usb/misc/ldusb.c
+++ usb-2.6/drivers/usb/misc/ldusb.c
@@ -174,9 +174,6 @@ struct ld_usb {
        int                     interrupt_out_busy;
 };
 
-/* prevent races between open() and disconnect() */
-static DEFINE_MUTEX(disconnect_mutex);
-
 static struct usb_driver ld_usb_driver;
 
 /**
@@ -290,35 +287,28 @@ static int ld_usb_open(struct inode *ino
 {
        struct ld_usb *dev;
        int subminor;
-       int retval = 0;
+       int retval;
        struct usb_interface *interface;
 
        nonseekable_open(inode, file);
        subminor = iminor(inode);
 
-       mutex_lock(&disconnect_mutex);
-
        interface = usb_find_interface(&ld_usb_driver, subminor);
 
        if (!interface) {
                err("%s - error, can't find device for minor %d\n",
                     __FUNCTION__, subminor);
-               retval = -ENODEV;
-               goto unlock_disconnect_exit;
+               return -ENODEV;
        }
 
        dev = usb_get_intfdata(interface);
 
-       if (!dev) {
-               retval = -ENODEV;
-               goto unlock_disconnect_exit;
-       }
+       if (!dev)
+               return -ENODEV;
 
        /* lock this device */
-       if (down_interruptible(&dev->sem)) {
-               retval = -ERESTARTSYS;
-               goto unlock_disconnect_exit;
-       }
+       if (down_interruptible(&dev->sem))
+               return -ERESTARTSYS;
 
        /* allow opening only once */
        if (dev->open_count) {
@@ -357,9 +347,6 @@ static int ld_usb_open(struct inode *ino
 unlock_exit:
        up(&dev->sem);
 
-unlock_disconnect_exit:
-       mutex_unlock(&disconnect_mutex);
-
        return retval;
 }
 
@@ -739,18 +726,16 @@ static void ld_usb_disconnect(struct usb
        struct ld_usb *dev;
        int minor;
 
-       mutex_lock(&disconnect_mutex);
-
        dev = usb_get_intfdata(intf);
        usb_set_intfdata(intf, NULL);
 
-       down(&dev->sem);
-
        minor = intf->minor;
 
        /* give back our minor */
        usb_deregister_dev(intf, &ld_usb_class);
 
+       down(&dev->sem);
+
        /* if the device is not opened, then we clean up right now */
        if (!dev->open_count) {
                up(&dev->sem);
@@ -760,8 +745,6 @@ static void ld_usb_disconnect(struct usb
                up(&dev->sem);
        }
 
-       mutex_unlock(&disconnect_mutex);
-
        dev_info(&intf->dev, "LD USB Device #%d now disconnected\n",
                 (minor - USB_LD_MINOR_BASE));
 }
Index: usb-2.6/drivers/usb/misc/legousbtower.c
===================================================================
--- usb-2.6.orig/drivers/usb/misc/legousbtower.c
+++ usb-2.6/drivers/usb/misc/legousbtower.c
@@ -254,9 +254,6 @@ static int  tower_probe     (struct usb_inte
 static void tower_disconnect   (struct usb_interface *interface);
 
 
-/* prevent races between open() and disconnect */
-static DEFINE_MUTEX (disconnect_mutex);
-
 /* file operations needed when we register this driver */
 static const struct file_operations tower_fops = {
        .owner =        THIS_MODULE,
@@ -344,28 +341,26 @@ static int tower_open (struct inode *ino
        nonseekable_open(inode, file);
        subminor = iminor(inode);
 
-       mutex_lock (&disconnect_mutex);
-
        interface = usb_find_interface (&tower_driver, subminor);
 
        if (!interface) {
                err ("%s - error, can't find device for minor %d",
                     __FUNCTION__, subminor);
                retval = -ENODEV;
-               goto unlock_disconnect_exit;
+               goto exit;
        }
 
        dev = usb_get_intfdata(interface);
 
        if (!dev) {
                retval = -ENODEV;
-               goto unlock_disconnect_exit;
+               goto exit;
        }
 
        /* lock this device */
        if (down_interruptible (&dev->sem)) {
                retval = -ERESTARTSYS;
-               goto unlock_disconnect_exit;
+               goto exit;
        }
 
        /* allow opening only once */
@@ -421,9 +416,7 @@ static int tower_open (struct inode *ino
 unlock_exit:
        up (&dev->sem);
 
-unlock_disconnect_exit:
-       mutex_unlock (&disconnect_mutex);
-
+exit:
        dbg(2, "%s: leave, return value %d ", __FUNCTION__, retval);
 
        return retval;
@@ -993,19 +986,16 @@ static void tower_disconnect (struct usb
 
        dbg(2, "%s: enter", __FUNCTION__);
 
-       mutex_lock (&disconnect_mutex);
-
        dev = usb_get_intfdata (interface);
        usb_set_intfdata (interface, NULL);
 
-
-       down (&dev->sem);
-
        minor = dev->minor;
 
        /* give back our minor */
        usb_deregister_dev (interface, &tower_class);
 
+       down (&dev->sem);
+
        /* if the device is not opened, then we clean up right now */
        if (!dev->open_count) {
                up (&dev->sem);
@@ -1015,8 +1005,6 @@ static void tower_disconnect (struct usb
                up (&dev->sem);
        }
 
-       mutex_unlock (&disconnect_mutex);
-
        info("LEGO USB Tower #%d now disconnected", (minor - 
LEGO_USB_TOWER_MINOR_BASE));
 
        dbg(2, "%s: leave", __FUNCTION__);
Index: usb-2.6/drivers/usb/misc/sisusbvga/sisusb.c
===================================================================
--- usb-2.6.orig/drivers/usb/misc/sisusbvga/sisusb.c
+++ usb-2.6/drivers/usb/misc/sisusbvga/sisusb.c
@@ -72,8 +72,6 @@ MODULE_PARM_DESC(last, "Number of last c
 
 static struct usb_driver sisusb_driver;
 
-DEFINE_MUTEX(disconnect_mutex);
-
 static void
 sisusb_free_buffers(struct sisusb_usb_data *sisusb)
 {
@@ -2511,31 +2509,24 @@ sisusb_open(struct inode *inode, struct 
        struct usb_interface *interface;
        int subminor = iminor(inode);
 
-       mutex_lock(&disconnect_mutex);
-
        if (!(interface = usb_find_interface(&sisusb_driver, subminor))) {
                printk(KERN_ERR "sisusb[%d]: Failed to find interface\n",
                                subminor);
-               mutex_unlock(&disconnect_mutex);
                return -ENODEV;
        }
 
-       if (!(sisusb = usb_get_intfdata(interface))) {
-               mutex_unlock(&disconnect_mutex);
+       if (!(sisusb = usb_get_intfdata(interface)))
                return -ENODEV;
-       }
 
        mutex_lock(&sisusb->lock);
 
        if (!sisusb->present || !sisusb->ready) {
                mutex_unlock(&sisusb->lock);
-               mutex_unlock(&disconnect_mutex);
                return -ENODEV;
        }
 
        if (sisusb->isopen) {
                mutex_unlock(&sisusb->lock);
-               mutex_unlock(&disconnect_mutex);
                return -EBUSY;
        }
 
@@ -2543,7 +2534,6 @@ sisusb_open(struct inode *inode, struct 
                if (sisusb->sisusb_dev->speed == USB_SPEED_HIGH) {
                        if (sisusb_init_gfxdevice(sisusb, 0)) {
                                mutex_unlock(&sisusb->lock);
-                               mutex_unlock(&disconnect_mutex);
                                printk(KERN_ERR
                                        "sisusbvga[%d]: Failed to initialize "
                                        "device\n",
@@ -2552,7 +2542,6 @@ sisusb_open(struct inode *inode, struct 
                        }
                } else {
                        mutex_unlock(&sisusb->lock);
-                       mutex_unlock(&disconnect_mutex);
                        printk(KERN_ERR
                                "sisusbvga[%d]: Device not attached to "
                                "USB 2.0 hub\n",
@@ -2570,8 +2559,6 @@ sisusb_open(struct inode *inode, struct 
 
        mutex_unlock(&sisusb->lock);
 
-       mutex_unlock(&disconnect_mutex);
-
        return 0;
 }
 
@@ -2601,12 +2588,8 @@ sisusb_release(struct inode *inode, stru
        struct sisusb_usb_data *sisusb;
        int myminor;
 
-       mutex_lock(&disconnect_mutex);
-
-       if (!(sisusb = (struct sisusb_usb_data *)file->private_data)) {
-               mutex_unlock(&disconnect_mutex);
+       if (!(sisusb = (struct sisusb_usb_data *)file->private_data))
                return -ENODEV;
-       }
 
        mutex_lock(&sisusb->lock);
 
@@ -2626,8 +2609,6 @@ sisusb_release(struct inode *inode, stru
        /* decrement the usage count on our device */
        kref_put(&sisusb->kref, sisusb_delete);
 
-       mutex_unlock(&disconnect_mutex);
-
        return 0;
 }
 
@@ -3383,12 +3364,9 @@ static void sisusb_disconnect(struct usb
        sisusb_console_exit(sisusb);
 #endif
 
-       /* The above code doesn't need the disconnect
-        * semaphore to be down; its meaning is to
-        * protect all other routines from the disconnect
-        * case, not the other way round.
-        */
-       mutex_lock(&disconnect_mutex);
+       minor = sisusb->minor;
+
+       usb_deregister_dev(intf, &usb_sisusb_class);
 
        mutex_lock(&sisusb->lock);
 
@@ -3396,12 +3374,8 @@ static void sisusb_disconnect(struct usb
        if (!sisusb_wait_all_out_complete(sisusb))
                sisusb_kill_all_busy(sisusb);
 
-       minor = sisusb->minor;
-
        usb_set_intfdata(intf, NULL);
 
-       usb_deregister_dev(intf, &usb_sisusb_class);
-
 #ifdef SISUSB_OLD_CONFIG_COMPAT
        if (sisusb->ioctl32registered) {
                int ret;
@@ -3426,8 +3400,6 @@ static void sisusb_disconnect(struct usb
        /* decrement our usage count */
        kref_put(&sisusb->kref, sisusb_delete);
 
-       mutex_unlock(&disconnect_mutex);
-
        printk(KERN_INFO "sisusbvga[%d]: Disconnected\n", minor);
 }
 
Index: usb-2.6/drivers/usb/usb-skeleton.c
===================================================================
--- usb-2.6.orig/drivers/usb/usb-skeleton.c
+++ usb-2.6/drivers/usb/usb-skeleton.c
@@ -34,9 +34,6 @@ static struct usb_device_id skel_table [
 };
 MODULE_DEVICE_TABLE(usb, skel_table);
 
-/* to prevent a race between open and disconnect */
-static DEFINE_MUTEX(skel_open_lock);
-
 
 /* Get a minor range for your devices from the usb maintainer */
 #define USB_SKEL_MINOR_BASE    192
@@ -83,10 +80,8 @@ static int skel_open(struct inode *inode
 
        subminor = iminor(inode);
 
-       mutex_lock(&skel_open_lock);
        interface = usb_find_interface(&skel_driver, subminor);
        if (!interface) {
-               mutex_unlock(&skel_open_lock);
                err ("%s - error, can't find device for minor %d",
                     __FUNCTION__, subminor);
                retval = -ENODEV;
@@ -95,15 +90,12 @@ static int skel_open(struct inode *inode
 
        dev = usb_get_intfdata(interface);
        if (!dev) {
-               mutex_unlock(&skel_open_lock);
                retval = -ENODEV;
                goto exit;
        }
 
        /* increment our usage count for the device */
        kref_get(&dev->kref);
-       /* now we can drop the lock */
-       mutex_unlock(&skel_open_lock);
 
        /* prevent the device from being autosuspended */
        retval = usb_autopm_get_interface(interface);
@@ -368,23 +360,17 @@ static void skel_disconnect(struct usb_i
        struct usb_skel *dev;
        int minor = interface->minor;
 
-       /* prevent skel_open() from racing skel_disconnect() */
-       mutex_lock(&skel_open_lock);
-
        dev = usb_get_intfdata(interface);
        usb_set_intfdata(interface, NULL);
 
        /* give back our minor */
        usb_deregister_dev(interface, &skel_class);
-       mutex_unlock(&skel_open_lock);
 
        /* prevent more I/O from starting */
        mutex_lock(&dev->io_mutex);
        dev->interface = NULL;
        mutex_unlock(&dev->io_mutex);
 
-
-
        /* decrement our usage count */
        kref_put(&dev->kref, skel_delete);
 


-------------------------------------------------------------------------
This SF.net email is sponsored by DB2 Express
Download DB2 Express C - the FREE version of DB2 express and take
control of your XML. No limits. Just data. Click to get it now.
http://sourceforge.net/powerbar/db2/
_______________________________________________
linux-usb-devel@lists.sourceforge.net
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to