Gadgetfs's use of spinlocks

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

 



Dave:

A bug in gadgetfs has persisted for quite a while: nested spin_locks
when used with net2280.  This is because inode.c calls usb_ep_queue()
for ep0 while holding the device lock, and ep0_complete() tries to
acquire the lock.  Since net2280 will call the completion routine
directly during submission if the request is small enough to fit
entirely in a FIFO, we end up in deadlock.  (Dummy_hcd may behave the
same way; I haven't checked.)

The patch below attempts to fix the problem by dropping the lock around 
the calls to usb_ep_queue() for ep0, but I don't know whether doing 
this might lead to other problems.  I suppose the places inside 
gadgetfs_setup() are probably okay, but what about the call inside 
ep0_read()?  There's a possibility that the host might send a new 
SETUP packet while waiting for the userspace program to get around to 
reading the OUT data from the previous transfer.

Can you look this over and figure out what more (if anything) needs to 
be done?

Thanks,

Alan Stern



Index: usb-2.6/drivers/usb/gadget/inode.c
===================================================================
--- usb-2.6.orig/drivers/usb/gadget/inode.c
+++ usb-2.6/drivers/usb/gadget/inode.c
@@ -1000,8 +1000,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 */
@@ -1535,8 +1538,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;
@@ -1559,7 +1564,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