On Thu, 2 Aug 2012, Dan Rittersdorf wrote:

> > It looks like the lesson is not to have one thread accessing an
> > endpoint at the same time as another thread issues a CLEAR_HALT.
> 
> Thank you -- that spawned a couple thoughts on a potential solution.
> 
> And I appreciate you refraining from simply saying "doh!"   :-)
> I should have seen the problem as an application level issue, but was 
> blind to it because I presumed that "usb.c" was known to "work".

If you have any bug fixes for usb.c, please send them in.

> > There are some known problems related to locking in gadgetfs (it 
> > submits requests while holding a lock that the completion routine will 
> > take). So far nobody has cared about it enough to do a careful audit 
> > and fix. 
> 
> Yes, I ran into that issue quickly on this project.   I addressed one 
> case in ep0_read() by unlocking around the usb_ep_queue() call.
> I have not yet discovered any other instances.  ep0_write() doesn't make 
> the same mistake.

I have had this patch hanging around for a long time.  I don't know if 
it's entirely right (I don't use gadgetfs much), but see what you 
think.

Alan Stern



Index: usb-3.3/drivers/usb/gadget/inode.c
===================================================================
--- usb-3.3.orig/drivers/usb/gadget/inode.c
+++ usb-3.3/drivers/usb/gadget/inode.c
@@ -998,8 +998,11 @@ ep0_read (struct file *fd, char __user *
                        struct usb_ep           *ep = dev->gadget->ep0;
                        struct usb_request      *req = dev->req;
 
-                       if ((retval = setup_req (ep, req, 0)) == 0)
+                       if ((retval = setup_req (ep, req, 0)) == 0) {
+                               spin_unlock(&dev->lock);
                                retval = usb_ep_queue (ep, req, GFP_ATOMIC);
+                               spin_lock(&dev->lock);
+                       }
                        dev->state = STATE_DEV_CONNECTED;
 
                        /* assume that was SET_CONFIGURATION */
@@ -1533,8 +1536,10 @@ delegate:
                                                        w_length);
                                if (value < 0)
                                        break;
+                               spin_unlock(&dev->lock);
                                value = usb_ep_queue (gadget->ep0, dev->req,
                                                        GFP_ATOMIC);
+                               spin_lock(&dev->lock);
                                if (value < 0) {
                                        clean_req (gadget->ep0, dev->req);
                                        break;
@@ -1557,7 +1562,9 @@ delegate:
        if (value >= 0 && dev->state != STATE_DEV_SETUP) {
                req->length = value;
                req->zero = value < w_length;
+               spin_unlock(&dev->lock);
                value = usb_ep_queue (gadget->ep0, req, GFP_ATOMIC);
+               spin_lock(&dev->lock);
                if (value < 0) {
                        DBG (dev, "ep_queue --> %d\n", value);
                        req->status = 0;

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to