I won't go through all the stuff about the PL(n), SL(n), and LL locks
because I think it's getting a bit confusing.  Instead, let's consider
what operations can occur on a usb_device and which need to be mutually
exclusive.

Here's a list of operations that can apply to any device:

        (1) Disconnect
        (2) Change configuration
        (3) Change a binding
        (4) Suspend/resume
        (5) Reset

It's clear that each of these has to be mutually exclusive with itself;  
we don't want two different processes making a configuration change
simultaneously!  (Incidentally, (1) means the work carried out by
usb_disconnect().  Changing the device's state to USB_STATE_NOTATTACHED
would be a separate action -- we would like that to happen as soon as
possible regardless of anything else.)

For hubs we have some additional per-port operations:

        (6) Attach/detach a child device
        (7) Do a port suspend/resume/reset

Note that (6) on port(n) implies (1) on children[n], just as (7) implies
(4) or (5).  There are other redundancies as well, since (1) and (2)
imply (3) for any device, and (3) implies (6) for all ports on a hub.

I was going to go through each pair of these, considering which actions
could be allowed at the same time.  But there's no need; you can easily
see that for any device (including hubs) (1)-(5) should all be mutually
exclusive, except that in principle (3) could take place for different
interfaces at the same time (although that's probably not such a good 
idea).

It's also quite clear that for a hub, neither (6) nor (7) should be
allowed on a port while any of (1)-(5) are going on.  Also (6) and (7)  
on a single port should be mutually exclusive, although they can coexist
with (6) or (7) on a different port.  Notice that (7) can never happen for
a port unless a device is already attached to that port.  Since (7)
implies (4) or (5) on the child device, (7) must be mutually exclusive
with (1)-(7) on the child.  In the same way, (6) must be mutually 
exclusive with (1)-(7) on the child, if there is a child (i.e., detach -- 
with attach there's no child until the attach finishes).

This means that (6)-(7) on a port can be treated as though they belong to 
the child device.  In other words, for any device we can imagine the 
possible actions are (1)-(5) plus (6) & (7) on the upstream port.  When 
viewed this way, it turns out for any device all the actions must be 
mutually exclusive.


Now there can be times when, even though you're not doing any of these
actions, you still want to prevent some of them.  I won't go into this
because it will probably be okay to prevent all the actions, even though
that's more than you need.  (Tree traversal needs to prevent (6) on all
ports of a hub -- it doesn't hurt much to prevent (1)-(5) as well.  If the
lock could be shared then multiple traversals could occur at once, but I
suspect it's not worth the trouble.)

There are some other considerations too.  Like, while suspending the
entire subtree below a hub you don't want some other process to start
resuming the devices you've just suspended.  To prevent this sort of thing 
both usb_suspend_device() and usb_resume_device() should use the locktree 
algorithm.  I don't think it's needed for reset or disconnect, though.

There's also the problem of detecting when a device has been unplugged as 
soon as possible.  This detection occurs when khubd makes a 
GET_PORT_STATUS request for the port, and it shouldn't do that while (7)
is taking place on that port.  So sometimes the detection will be 
unavoidably delayed.  Fortunately that shouldn't happen very often.


Now maybe I've overlooked something here or oversimplified in some way.  
But altogether I think this makes a good case that using a single lock is
the way to go.

Alan Stern



-------------------------------------------------------
This SF.Net email is sponsored by Sleepycat Software
Learn developer strategies Cisco, Motorola, Ericsson & Lucent use to 
deliver higher performing products faster, at low TCO.
http://www.sleepycat.com/telcomwpreg.php?From=osdnemail3
_______________________________________________
[EMAIL PROTECTED]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to