Re: gadgetfs w/ multithreading and blocking I/O fails USB-IF Ch9 Halt Endpoint Test

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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 majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux