Hi,

On Thursday 17 May 2007 06:38, David Brownell wrote:
> On Wednesday 16 May 2007, Hans Petter Selasky wrote:
> > Hi,
> >
> > On Wednesday 16 May 2007 20:20, David Brownell wrote:
> > > > > > > URB submission has other failure possibilities than lack of
> > > > > > > memory. Those other things have to be checked for regardless.
> > > > > >
> > > > > > Yes, but that is because you allow too many parameters in the URB
> > > > > > to be changed between USB transfers.
> > > > >
> > > > > No; it's because unforeseen events can occur.  For example, the
> > > > > device may have been unplugged or suspended.
> > > >
> > > > On FreeBSD it will never happen that you call the equivalent
> > > > of "usb_submit_urb()" after that the device has detached! It must be
> > > > something terribly wrong in the Linux USB stack if the callbacks are
> > > > alive after that you have detached a USB device.
> > >
> > > How does that work then ... driver must grab a lock, check
> > > whether the device has disconnected, then submit the request
> > > and drop the lock?  Sounds like needless slowdowns.
> >
> > Each USB device has its own lock. There are some tricks there.
> >
> > 1) usbd_transfer_start() is always called like this:
> >    usbd_transfer_start(sc->sc_xfer[x]);
> >
> > 2) sc->sc_xfer[x] is set to zero at detach holding the private lock of
> > the USB device driver. All subsequent calls to usbd_transfer_start(), if
> > any, will fail.
>
> So there's a race on SMP, where sc->sc_xfer[x] may be referenced
> on one CPU while another is nulling it.
>
> The lock you showed is inside usbd_transfer_start(), where it
> can't do any good.

It is an assert statement. The "priv_mtx" lock must be locked before you call 
usbd_transfer_start(). There is no race on SMP.

>
> > 3) usbd_transfer_start() is always non-blocking. In other words a single
> > lock is held across the call.
>
> Like usb_submit_urb() then, except that the disconnect race
> is handled by being buggy rather than by reporting a fault
> at submit time...

Ok.

>
> > ...
> >
> > > Because if there's no lock against async disconnect events,
> > > then it's trivial to have the disconnect logic underway on
> > > one CPU while another CPU does real work, submitting an I/O
> > > request.
> >
> > We solve this in one of two ways:
> >
> > 1) Using a mutex. At detach we lock the mutex stopping all transfers.
> >
> > 2) Using a thread. At detach we teardown and wait for the thread to exit.
>
> But there's that race above, so it's not "solved".
>

If you need to do Async stuff, then you have to do it in a separate thread or 
in a so-called task-queue. Else you are in for great trouble! That was the 
big "sin" in the old USB stack on FreeBSD: Calling synchronous USB callbacks 
from everywhere, like ioctl/read/write - callbacks.

Is that a problem on Linux also?

On Linux I see no locks used in the USB drivers, so they are solely protected 
by interrupt-level mechanisms.

My rule is that: Synchronous or blocking calls _must_ happen in a config 
thread that you can wait for. Else asynchronous calls on pre-allocated 
transfers can happen anywhere.

The problem clearly appears on Linux SMP because:

a) No locks are in the USB drivers (then they must be all so-called "Giant" 
locked)

b) You don't pre-allocate transfers, resulting in synchronous/blocking calls 
everywhere, and no-one thinks about what can happen then :-)

--HPS

-------------------------------------------------------------------------
This SF.net email is sponsored by DB2 Express
Download DB2 Express C - the FREE version of DB2 express and take
control of your XML. No limits. Just data. Click to get it now.
http://sourceforge.net/powerbar/db2/
_______________________________________________
linux-usb-devel@lists.sourceforge.net
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to