[PATCH] usb: gadget: udc-core: Race between disconnect/unbind and setup

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

 



On Mon, Jul 9, 2012 at 7:15 AM, Alan Stern <stern@xxxxxxxxxxxxxxxxxxx> wrote:
> > What I see is that usb_gadget_disconnect() does tell the UDC driver to
> > stop activity on the port, but that only happens after
> > composite_disconnect() was called.  Can you confirm that the order of
> > the calls in usb_gadget_remove_driver() is correct?
> 
> They might need to be changed.  It does seems like a bad idea to tell 
> the gadget driver that a disconnect occurred before the host knows 
> about it.
> 
> If you change the order of those two calls, does that make your posted 
> patch unnecessary?

Yes, that works too.  Here is the change:

-- 8< --

From: Kevin Cernekee <cernekee@xxxxxxxxx>

usb_gadget_remove_driver() runs through a four-step sequence to shut down
the gadget driver.  For the case of a composite gadget + at91 UDC, this
would look like:

    udc->driver->disconnect(udc->gadget);          // composite_disconnect()
    usb_gadget_disconnect(udc->gadget);            // at91_pullup(gadget, 0)
    udc->driver->unbind(udc->gadget);              // composite_unbind()
    usb_gadget_udc_stop(udc->gadget, udc->driver); // at91_stop()

The UDC driver can receive SETUP packets from the host up until the
point when usb_gadget_disconnect() returns.  On rare occasions, the
gadget driver may see this sequence:

    udc->driver->disconnect(udc->gadget);          // composite_disconnect()
    udc->driver->setup(udc->gadget, &ctrl);        // composite_setup()
    udc->driver->unbind(udc->gadget);              // composite_unbind()

Some gadget drivers, such as composite, assume this will never happen
and crash as a result.

The fix is to quiesce the UDC hardware (via usb_gadget_disconnect)
before running the gadget driver through the disconnect/unbind sequence.

Signed-off-by: Kevin Cernekee <cernekee@xxxxxxxxx>
---
 drivers/usb/gadget/udc-core.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/usb/gadget/udc-core.c b/drivers/usb/gadget/udc-core.c
index e5e44f8..bae243c 100644
--- a/drivers/usb/gadget/udc-core.c
+++ b/drivers/usb/gadget/udc-core.c
@@ -262,8 +262,8 @@ static void usb_gadget_remove_driver(struct usb_udc *udc)
 	kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE);
 
 	if (udc_is_newstyle(udc)) {
-		udc->driver->disconnect(udc->gadget);
 		usb_gadget_disconnect(udc->gadget);
+		udc->driver->disconnect(udc->gadget);
 		udc->driver->unbind(udc->gadget);
 		usb_gadget_udc_stop(udc->gadget, udc->driver);
 	} else {
-- 
1.7.11.1

--
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