ChangeSet 1.1673.8.17, 2004/03/25 16:53:25-08:00, oliver@neukum.org

[PATCH] USB: race condition in open of w9968cf

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 |   10 ++++++----
 1 files changed, 6 insertions(+), 4 deletions(-)


diff -Nru a/drivers/usb/media/w9968cf.c b/drivers/usb/media/w9968cf.c
--- a/drivers/usb/media/w9968cf.c	Wed Apr 14 14:38:58 2004
+++ b/drivers/usb/media/w9968cf.c	Wed Apr 14 14:38:58 2004
@@ -905,8 +905,7 @@
 	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 @@
 			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 @@
 		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 @@
 	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);