]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/usb/misc/ldusb.c
USB: fix usbled disconnect read race #2
[linux-2.6-omap-h63xx.git] / drivers / usb / misc / ldusb.c
index 7bad494047621a38f61bd8cf90057f2d40870ea7..8208496dfc638410ade09db081d0c7c729571d32 100644 (file)
@@ -176,9 +176,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;
 
 /**
@@ -222,16 +219,17 @@ static void ld_usb_interrupt_in_callback(struct urb *urb)
        struct ld_usb *dev = urb->context;
        size_t *actual_buffer;
        unsigned int next_ring_head;
+       int status = urb->status;
        int retval;
 
-       if (urb->status) {
-               if (urb->status == -ENOENT ||
-                   urb->status == -ECONNRESET ||
-                   urb->status == -ESHUTDOWN) {
+       if (status) {
+               if (status == -ENOENT ||
+                   status == -ECONNRESET ||
+                   status == -ESHUTDOWN) {
                        goto exit;
                } else {
                        dbg_info(&dev->intf->dev, "%s: nonzero status received: %d\n",
-                                __FUNCTION__, urb->status);
+                                __FUNCTION__, status);
                        spin_lock(&dev->rbsl);
                        goto resubmit; /* maybe we can recover */
                }
@@ -278,14 +276,15 @@ exit:
 static void ld_usb_interrupt_out_callback(struct urb *urb)
 {
        struct ld_usb *dev = urb->context;
+       int status = urb->status;
 
        /* sync/async unlink faults aren't errors */
-       if (urb->status && !(urb->status == -ENOENT ||
-                            urb->status == -ECONNRESET ||
-                            urb->status == -ESHUTDOWN))
+       if (status && !(status == -ENOENT ||
+                       status == -ECONNRESET ||
+                       status == -ESHUTDOWN))
                dbg_info(&dev->intf->dev,
                         "%s - nonzero write interrupt status received: %d\n",
-                        __FUNCTION__, urb->status);
+                        __FUNCTION__, status);
 
        dev->interrupt_out_busy = 0;
        wake_up_interruptible(&dev->write_wait);
@@ -298,35 +297,28 @@ static int ld_usb_open(struct inode *inode, struct file *file)
 {
        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) {
@@ -366,9 +358,6 @@ static int ld_usb_open(struct inode *inode, struct file *file)
 unlock_exit:
        up(&dev->sem);
 
-unlock_disconnect_exit:
-       mutex_unlock(&disconnect_mutex);
-
        return retval;
 }
 
@@ -766,18 +755,16 @@ static void ld_usb_disconnect(struct usb_interface *intf)
        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);
@@ -787,8 +774,6 @@ static void ld_usb_disconnect(struct usb_interface *intf)
                up(&dev->sem);
        }
 
-       mutex_unlock(&disconnect_mutex);
-
        dev_info(&intf->dev, "LD USB Device #%d now disconnected\n",
                 (minor - USB_LD_MINOR_BASE));
 }