]> git.hungrycats.org Git - linux/commitdiff
[PATCH] USB: race condition in open of w9968cf
authorOliver Neukum <oliver@neukum.org>
Thu, 25 Mar 2004 08:53:25 +0000 (00:53 -0800)
committerGreg Kroah-Hartman <greg@kroah.com>
Thu, 25 Mar 2004 08:53:25 +0000 (00:53 -0800)
there's a race in how open handles multiple openers.
You implement exclusive opening and wait for close
in case of further openers. However if there are more than one
waiter, only one of them must be allowed to proceed.

drivers/usb/media/w9968cf.c

index 4dd52530b2d62649c47ad27784522575e2e11a20..b69de96c6196dd98cbccafa66fbc3271fbc59c90 100644 (file)
@@ -905,8 +905,7 @@ static void w9968cf_urb_complete(struct urb *urb, struct pt_regs *regs)
        spin_unlock(&cam->urb_lock);
 
        /* Wake up the user process */
-       if (waitqueue_active(&cam->wait_queue))
-               wake_up_interruptible(&cam->wait_queue);
+       wake_up_interruptible(&cam->wait_queue);
 }
 
 
@@ -2690,6 +2689,7 @@ static int w9968cf_open(struct inode* inode, struct file* filp)
                        up(&cam->dev_sem);
                        return -EWOULDBLOCK;
                }
+retry:
                up(&cam->dev_sem);
                err = wait_event_interruptible(cam->open, cam->disconnected ||
                                               (cam->users == 0));
@@ -2698,6 +2698,9 @@ static int w9968cf_open(struct inode* inode, struct file* filp)
                if (cam->disconnected)
                        return -ENODEV;
                down(&cam->dev_sem);
+               /*recheck - there may be several waiters */
+               if (cam->users)
+                       goto retry;
        }
 
        DBG(5, "Opening '%s', /dev/video%d ...",
@@ -2758,8 +2761,7 @@ static int w9968cf_release(struct inode* inode, struct file* filp)
        cam->users--;
        w9968cf_deallocate_memory(cam);
 
-       if (waitqueue_active(&cam->open))
-               wake_up_interruptible(&cam->open);
+       wake_up_interruptible(&cam->open);
 
        DBG(5, "Video device closed.")
        up(&cam->dev_sem);