On Mon, 12 Apr 2004, David Brownell wrote:

> >>Hmm, could you elaborate?  The bus rwsem is only to protect
> 
> Capsule summary:  you're assuming a "topology change lock".

Isn't that one of the major functions of the bus rwsem?

> OK, you're strictly correct from the driver model perspective,
> but that doesn't contradict what I said either.

Sure it does -- you said the rwsem protects _only_ against changes in 
binding.  :-)

>   The bus rwsem
> is grabbed when devices or drivers are created, which is also
> the time driver bindings are changed (which is why we care),
> but there are several kinds of entity:
> 
>    - USB Interfaces.  Created only by holders of dev->serialize.
>    - USB Devices.  Created by khubd.
>    - USB Hubs.  Special devices, managed by usbcore/khubd.
>    - USB Drivers.  Created by module's init code.
> 
> So what I said is true:  dev->serialize protects against add/remove
> of the devices that drivers care about ("interfaces"), and anyone
> caring about a stable set of interface-to-driver bindings must hold
> the bus readlock instead.  That's the lock hierarchy of today.
> 
> The current code is logically "for each device, dump its descriptors
> and their bindings" ... so I described per-device locking.

That's the natural approach.  I question whether it provides adequate 
protection of the "for each device" part.

> It's a question of lock scope.  Grabbing the bus rwsem locks every
> USB device in the whole system.  I described a less global scheme.
> 
> One example of where a global scheme would have issues:  when fetching
> the string descriptors takes a long time.  Then "cat devices" could
> block most of the USB subsystem, not just the one device which was
> actually misbehaving.

Certainly we want to avoid doing that.


> > It's not entirely clear (to me anyway) that holding ->serialize will
> > provide sufficient protection against disconnection.  That is, when a
> > device is disconnected, the core doesn't acquire the parent hub's
> 
> At any given instant, the usbcore data records for a given device
> will be consistent if dev->serialize is used to lock it.  Plus of
> course it must have been consistent when "dev" was located -- yes?
> Doesn't matter if it was disconnected later; it was OK to start.
> (And next time, it won't be there.)

I agree with that.

> > ->serialize.  So when traversing the device tree below that hub we run the
> > risk of trying to access a nonexistent device structure.  It seems that
> > the _only_ way to protect against these changes in the bus topology is by 
> > using the bus rwsem.
> 
> I'm not sure why you'd want to protect against topology changes.
> That's global state, so of course my "synchronize locally" reflex
> kicks right in ... creating central synch points, to be held
> during I/O and state changes, can cause trouble.  Why care if a
> device you already printed (or haven't yet printed) is unplugged?
> 
> If you didn't have such a "global synch" model, what problems would
> arise?  I don't think the current code is guaranteed to provide
> a globally consistent snapshot of the device tree.

Here's a problem that can arise.  The usb_device_dump() function in 
devices.c contains this code:

        /* Now look at all of this device's children. */
        for (chix = 0; chix < usbdev->maxchild; chix++) {
                if (usbdev->children[chix]) {
                        ret = usb_device_dump(buffer, nbytes, skip_bytes, 
                                        file_offset, usbdev->children[chix],
                                        bus, level + 1, chix, ++cnt);

What happens if the child on port chix is disconnected between the time of 
the test and the time of the recursive function call?  I don't care if we
don't give a globally consistent snapshot, but causing an oops isn't 
acceptable.

> > Then of course we end up running into problems about trying to acquire the 
> > two locks in the correct order...
> 
> Given that the physical hierarchy is (root) hub down, the logical
> one for such a case should do the same thing ... I'd say, going
> just by rules of thumb!  One could hold hub->dev->serialize while
> scanning its children.

In addition the code that removes children (usb_disconnect) must be
changed to hold the parent hub's ->serialize.  It wouldn't hurt to do that
while adding children as well, although it's not necessary.

Like I said originally, the locking here needs to be fixed.  I wasn't sure 
what was the best way to do it; looks like you've identified the necessary 
changes.

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