On Thu, 8 Apr 2004, Marcel Holtmann wrote:

> Hi Alan,
> 
> > I think this patch for the USB Bluetooth driver will prevent the problems
> > you've been seeing.  Let me know what happens.
> 
> why do we need a modification of the USB Bluetooth driver? In the case
> of using an OHCI based card I don't see any oopses at URB unlink.

It really is an error in the Bluetooth driver.  There's a difference
between the OHCI and UHCI drivers that has the effect of making the error 
much less likely when using OHCI.

In more detail:

The code in hci_usb_unlink_urbs() calls usb_unlink_urb() to perform a
synchronous unlink of each pending URB.  It then moves each URB to the
completed list, and then frees everything on the completed list.  By doing
this, the code implicitly assumes that when usb_unlink_urb() returns the
URB will have completed and be ready to be deallocated.  That's not always
true.

(David, are you reading this?  It's a perfect example of the sort of error
the current API encourages.)

You can get more information from the kerneldoc for usb_unlink_urb(), but
basically it only guarantees that the URB will have completed if the
return value is 0 -- if there's an error then all bets are off.  The code
in hci_usb_unlink_urbs() doesn't even look at the return value -- although
doing so wouldn't help much, since you have to wait for the URB to 
complete in any case.

Normally, of course, there is no error and the code works fine.  But there
is one particular situation where an error is bound to occur:  If the URB
has _already_ been unlinked asynchronously, then usb_unlink_urb() will
return immediately without waiting for the earlier unlink to complete.  
As it happens, the USB core performs exactly this kind of asynchronous
unlink for every active URB when a device is unplugged.  The consequence
is that the Bluetooth driver was deallocating URBs while the UHCI driver
was still using them, and that led to the oopses.

They didn't show up with the OHCI driver because that driver implements a 
disable_endpoint() method.  The method waits until all URBS for a given 
endpoint are completely finished, thereby preventing the Bluetooth driver 
from deallocating the storage too early.  UHCI doesn't yet implement 
disable_endpoint(), which accounts for the difference you see.

However, just because the driver works with OHCI doesn't mean it's right.  
Other events can cause usb_unlink_urb() to return an error, and this can
happen during any device close, not just during disconnect (which is when
disable_endpoint() is normally called).  The patch I wrote really is
needed, to guarantee that the URB is not still in use when it is freed.

By the way, I noticed a couple of other little things in the driver that
could be improved.  The first is _urb_alloc() -- it should call
usb_init_urb() rather than initializing the URB by hand.  The second was
the test of the HCI_RUNNING flags bit in the hci_usb_{t,r}x_complete()  
functions.  Those tests should be made while holding hci->completion_lock
for proper synchronization.  Otherwise you can have a race on an SMP
system in which hci_usb_rx_complete() finds the bit is set; then on
another processor hci_usb_close() clears the bit, grabs & releases the
lock, and unlinks all the active URBs; then the first processor acquires
the lock and resubmits the URB.

Alan Stern



-------------------------------------------------------
This SF.Net email is sponsored by: IBM Linux Tutorials
Free Linux tutorial presented by Daniel Robbins, President and CEO of
GenToo technologies. Learn everything from fundamentals to system
administration.http://ads.osdn.com/?ad_id=1470&alloc_id=3638&op=click
_______________________________________________
[EMAIL PROTECTED]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to