Re: [PATCH 2/2] USB: don't hold usb_bus_list_lock for usb_disconnect()

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

 



On Fri, Sep 13, 2013 at 2:14 PM, Alan Stern <stern@xxxxxxxxxxxxxxxxxxx> wrote:
> On Fri, 13 Sep 2013, Bjorn Helgaas wrote:
>
>> On Fri, Sep 13, 2013 at 12:25 PM, Alan Stern <stern@xxxxxxxxxxxxxxxxxxx> wrote:
>> > On Fri, 13 Sep 2013, Bjorn Helgaas wrote:
>> >
>> >> usb_bus_list_lock protects the usb_bus_list, and we don't touch that list
>> >> in usb_disconnect(), so there's no reason to hold the lock here.
>> >
>> > The code says:
>> >
>> > /* used when updating list of hcds */
>> > DEFINE_MUTEX(usb_bus_list_lock);        /* exported only for usbfs */
>> > EXPORT_SYMBOL_GPL (usb_bus_list_lock);
>> >
>> > Unforunately, the first comment is incomplete.  usb_bus_list_lock
>> > protects both the list of buses and also the set of root hubs.  That's
>> > why it isn't needed in hub_quiesce() and hub_port_connect_change();
>> > those routines remove only non-root devices.
>> >
>> > Removing the usages in usb_add_hcd() and usb_remove_hcd() isn't safe.
>> > You can see where this usage is important in
>> > devices.c:usb_device_read().
>>
>> I don't know how the set of root hubs is managed, so I don't see the
>> conflict between, e.g., usb_remove_hcd() and usb_device_read().  I'm
>> not looking to become a USB expert, so I'll just take your word for it
>> -- I don't want to waste more of your time on it.

Thanks.  Maybe this is more relevant than I thought.  I'd sure like to
copy your strategy rather than reinvent something.

> Very briefly, usb_device_read() dereferences bus->root_hub:
>
>         usb_lock_device(bus->root_hub);
>
> On the other hand, usb_remove_hcd() calls both
>
>         usb_disconnect(&rhdev);
>
> and
>
>         usb_put_dev(hcd->self.root_hub);
>
> (note that rhdev == hcd->self.root_hub == bus->root_hub), which
> unregisters and deallocates the root_hub structure.  Something has to
> prevent usb_device_read() from accessing the structure after it has
> been unregistered and freed; that's where usb_bus_list_lock comes in.

I hadn't paid attention to hcd->rh_registered before, but that seems
important.  When iterating over usb_bus_list, usb_device_read()
ignores buses with hcd->rh_registered == 0.

usb_remove_hcd() clears hcd->rh_registered before deallocating the
root_hub with usb_put_dev().  I think the mutex_lock/unlock between
clearing rh_registered and deallocating root_hub will ensure that
usb_device_read() cannot see rh_registered == 1 and a deallocated
root_hub structure.  But that seems more like a memory barrier issue
than a locking issue, and I don't yet see how usb_disconnect() is
related.

I guess I'm hung up because I don't know how managing the set of root
hubs is different from managing usb_bus_list.  Maybe it has something
to do with the device_add() call in register_root_hub() and the
device_del() call in usb_disconnect().  We hold usb_bus_list_lock in
both cases, but neither does anything with usb_bus_list.  Or maybe it
has something to do with the visibility of stores to
hcd->rh_registered?

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