This resolves a race in gadgetfs associated with changing device/ep0
when processing control requests.  The fix is to change that state
earlier, when the control response is issued, so there's no window
in which userspace could see the wrong state; and enlarge the scope
of the spinlock during the ep0 request completion handler.

Signed-off-by: David Brownell <[EMAIL PROTECTED]>

Index: at91/drivers/usb/gadget/inode.c
===================================================================
--- at91.orig/drivers/usb/gadget/inode.c        2007-01-16 21:42:15.000000000 
-0800
+++ at91/drivers/usb/gadget/inode.c     2007-01-16 21:42:18.000000000 -0800
@@ -933,28 +933,24 @@ static void clean_req (struct usb_ep *ep
 static void ep0_complete (struct usb_ep *ep, struct usb_request *req)
 {
        struct dev_data         *dev = ep->driver_data;
+       unsigned long           flags;
        int                     free = 1;
 
        /* for control OUT, data must still get to userspace */
+       spin_lock_irqsave(&dev->lock, flags);
        if (!dev->setup_in) {
                dev->setup_out_error = (req->status != 0);
                if (!dev->setup_out_error)
                        free = 0;
                dev->setup_out_ready = 1;
                ep0_readable (dev);
-       } else {
-               unsigned long   flags;
-
-               spin_lock_irqsave(&dev->lock, flags);
-               if (dev->state == STATE_DEV_SETUP)
-                       dev->state = STATE_DEV_CONNECTED;
-               spin_unlock_irqrestore(&dev->lock, flags);
        }
 
        /* clean up as appropriate */
        if (free && req->buf != &dev->rbuf)
                clean_req (ep, req);
        req->complete = epio_complete;
+       spin_unlock_irqrestore(&dev->lock, flags);
 }
 
 static int setup_req (struct usb_ep *ep, struct usb_request *req, u16 len)
@@ -1036,6 +1032,13 @@ ep0_read (struct file *fd, char __user *
                        spin_lock_irq (&dev->lock);
                        if (retval)
                                goto done;
+
+                       if (dev->state != STATE_DEV_SETUP) {
+                               retval = -ECANCELED;
+                               goto done;
+                       }
+                       dev->state = STATE_DEV_CONNECTED;
+
                        if (dev->setup_out_error)
                                retval = -EIO;
                        else {
@@ -1187,6 +1190,7 @@ ep0_write (struct file *fd, const char _
                if (dev->setup_in) {
                        retval = setup_req (dev->gadget->ep0, dev->req, len);
                        if (retval == 0) {
+                               dev->state = STATE_DEV_CONNECTED;
                                spin_unlock_irq (&dev->lock);
                                if (copy_from_user (dev->req->buf, buf, len))
                                        retval = -EFAULT;

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys - and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
_______________________________________________
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