Re: unbalanced calls to post_reset() from usb_reset_device()

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

 



Am Mittwoch, 11. November 2009 21:49:59 schrieb Alan Stern:
> On Wed, 11 Nov 2009, Oliver Neukum wrote:
> > Hi,
> >
> > it seems to me that we have a subtle bug in usb_reset_device().
> > If we reset a device we may reprobe an interface. If that causes
> > another interface to be claimed we may call post_reset() for that
> > interface without having called pre_reset().
> >
> > I think it is necessary to do the rebinding in a second pass after
> > doing the notifications. But this is subtle. Alan, what do you think?
> 
> You are right.  But I would make the code a little cleaner...
> 
> > @@ -3696,13 +3696,15 @@ int usb_reset_device(struct usb_device *udev)
> 
> A few lines above this, it would be good to change
> 
> 	if (config) {
> 
> to
> 
> 	if (ret != -ENODEV && config) {
> 
> There's no point sending post_reset notifications if the reset caused
> the device to go away.

IIRC the reasoning was that many drivers implement pre_reset() as mutex_lock()
of a mutex also needed in disconnect(), so that pre/post_reset are always
supposed to be strictly balanced.

> >  			if (!rebind && cintf->dev.driver) {
> >  				drv = to_usb_driver(cintf->dev.driver);
> > -				if (drv->post_reset)
> > -					rebind = (drv->post_reset)(cintf);
> > -				else if (cintf->condition ==
> > -						USB_INTERFACE_BOUND)
> > -					rebind = 1;
> > +				rebind = (drv->post_reset)(cintf);
> >  			}
> > -			if (ret == 0 && rebind)
> > +			cintf->needs_binding = rebind;
> 
> You don't need the "rebind" variable here.  Directly set
> cintf->needs_binding to the result of the method call.  Or rather, if
> the method call returns nonzero, set cintf->needs_binding to 1 (since
> it is a bitflag, not an int).

Roger

> 
> > +		}
> > +
> > +		/* second pass to not call post_reset on new drivers */
> 
> Rephrase the comment to make it more clear:
> 
> 		/* Don't rebind until after all the post_reset calls */
> 
> > +		for (i = config->desc.bNumInterfaces - 1; i >= 0; --i){
> > +			struct usb_interface *cintf = config->interface[i];
> 
> Missing blank line.
> 
> > +			if (ret == 0 && cintf->needs_binding)
> 
> If ret is tested above then it doesn't need to be tested here.  And in
> fact the existing test is wrong; it should be against -ENODEV rather
> than 0.  A reset can fail for reasons that don't cause the device to go
> away.

But in that case the reason for resetting is likely to persist and the device
won't work. Do we really want to rebind under such conditions?

	Regards
		Oliver
--
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