linux-usb.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 3/3 v5] USB: Fix device driver race
@ 2020-07-25  9:16 Bastien Nocera
  2020-07-25 14:59 ` Alan Stern
  0 siblings, 1 reply; 7+ messages in thread
From: Bastien Nocera @ 2020-07-25  9:16 UTC (permalink / raw)
  To: linux-usb; +Cc: Greg Kroah-Hartman, Alan Stern

When a new device with a specialised device driver is plugged in, the
new driver will be modprobe()'d but the driver core will attach the
"generic" driver to the device.

After that, nothing will trigger a reprobe when the modprobe()'d device
driver has finished initialising, as the device has the "generic"
driver attached to it.

Trigger a reprobe ourselves when new specialised drivers get registered.

Fixes: 88b7381a939d ("USB: Select better matching USB drivers when available")
Signed-off-by: Bastien Nocera <hadess@hadess.net>
---
Changes since v4:
- Add commit subject to "fixes" section
- Clarify conditional that checks for generic driver
- Remove check duplicated inside the loop

Changes since v3:
- Only reprobe devices that could use the new driver
- Many code fixes

Changes since v2:
- Fix formatting

Changes since v1:
- Simplified after Alan Stern's comments and some clarifications from
Benjamin Tissoires.


 drivers/usb/core/driver.c | 37 +++++++++++++++++++++++++++++++++++--
 1 file changed, 35 insertions(+), 2 deletions(-)

diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index f81606c6a35b..7d3878aa8090 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -905,6 +905,32 @@ static int usb_uevent(struct device *dev, struct kobj_uevent_env *env)
 	return 0;
 }
 
+static bool is_dev_usb_generic_driver(struct device *dev)
+{
+	struct usb_device_driver *udd = dev->driver ?
+		to_usb_device_driver(dev->driver) : NULL;
+
+	return udd == &usb_generic_driver;
+}
+
+static int __usb_bus_reprobe_drivers(struct device *dev, void *data)
+{
+	struct usb_device_driver *new_udriver = data;
+	struct usb_device *udev;
+
+	if (!is_dev_usb_generic_driver(dev))
+		return 0;
+
+	udev = to_usb_device(dev);
+	if (usb_device_match_id(udev, new_udriver->id_table) == NULL &&
+	    (!new_udriver->match || new_udriver->match(udev) != 0))
+		return 0;
+
+	(void)!device_reprobe(dev);
+
+	return 0;
+}
+
 /**
  * usb_register_device_driver - register a USB device (not interface) driver
  * @new_udriver: USB operations for the device driver
@@ -934,13 +960,20 @@ int usb_register_device_driver(struct usb_device_driver *new_udriver,
 
 	retval = driver_register(&new_udriver->drvwrap.driver);
 
-	if (!retval)
+	if (!retval) {
 		pr_info("%s: registered new device driver %s\n",
 			usbcore_name, new_udriver->name);
-	else
+		/*
+		 * Check whether any device could be better served with
+		 * this new driver
+		 */
+		bus_for_each_dev(&usb_bus_type, NULL, new_udriver,
+				 __usb_bus_reprobe_drivers);
+	} else {
 		printk(KERN_ERR "%s: error %d registering device "
 			"	driver %s\n",
 			usbcore_name, retval, new_udriver->name);
+	}
 
 	return retval;
 }


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH 3/3 v5] USB: Fix device driver race
  2020-07-25  9:16 [PATCH 3/3 v5] USB: Fix device driver race Bastien Nocera
@ 2020-07-25 14:59 ` Alan Stern
  2020-07-25 15:24   ` Bastien Nocera
  0 siblings, 1 reply; 7+ messages in thread
From: Alan Stern @ 2020-07-25 14:59 UTC (permalink / raw)
  To: Bastien Nocera; +Cc: linux-usb, Greg Kroah-Hartman

On Sat, Jul 25, 2020 at 11:16:47AM +0200, Bastien Nocera wrote:
> When a new device with a specialised device driver is plugged in, the
> new driver will be modprobe()'d but the driver core will attach the
> "generic" driver to the device.
> 
> After that, nothing will trigger a reprobe when the modprobe()'d device
> driver has finished initialising, as the device has the "generic"
> driver attached to it.
> 
> Trigger a reprobe ourselves when new specialised drivers get registered.
> 
> Fixes: 88b7381a939d ("USB: Select better matching USB drivers when available")
> Signed-off-by: Bastien Nocera <hadess@hadess.net>
> ---
> Changes since v4:
> - Add commit subject to "fixes" section
> - Clarify conditional that checks for generic driver
> - Remove check duplicated inside the loop
> 
> Changes since v3:
> - Only reprobe devices that could use the new driver
> - Many code fixes
> 
> Changes since v2:
> - Fix formatting
> 
> Changes since v1:
> - Simplified after Alan Stern's comments and some clarifications from
> Benjamin Tissoires.
> 
> 
>  drivers/usb/core/driver.c | 37 +++++++++++++++++++++++++++++++++++--
>  1 file changed, 35 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
> index f81606c6a35b..7d3878aa8090 100644
> --- a/drivers/usb/core/driver.c
> +++ b/drivers/usb/core/driver.c
> @@ -905,6 +905,32 @@ static int usb_uevent(struct device *dev, struct kobj_uevent_env *env)
>  	return 0;
>  }
>  
> +static bool is_dev_usb_generic_driver(struct device *dev)
> +{
> +	struct usb_device_driver *udd = dev->driver ?
> +		to_usb_device_driver(dev->driver) : NULL;
> +
> +	return udd == &usb_generic_driver;
> +}

Heh...  I don't recommend this optimization because it's a little 
unclear, but the function can be shortened to:

	return dev->driver == &usb_generic_driver.drvwrap.driver;

> +
> +static int __usb_bus_reprobe_drivers(struct device *dev, void *data)
> +{
> +	struct usb_device_driver *new_udriver = data;
> +	struct usb_device *udev;
> +
> +	if (!is_dev_usb_generic_driver(dev))
> +		return 0;
> +
> +	udev = to_usb_device(dev);
> +	if (usb_device_match_id(udev, new_udriver->id_table) == NULL &&
> +	    (!new_udriver->match || new_udriver->match(udev) != 0))
> +		return 0;
> +
> +	(void)!device_reprobe(dev);

What's that '!' doing hiding in there?  It doesn't affect the final 
outcome, but it sure looks weird -- if people notice it at all.

Aside from that,

Acked-by: Alan Stern <stern@rowland.harvard.edu>

Alan Stern

> +
> +	return 0;
> +}
> +
>  /**
>   * usb_register_device_driver - register a USB device (not interface) driver
>   * @new_udriver: USB operations for the device driver
> @@ -934,13 +960,20 @@ int usb_register_device_driver(struct usb_device_driver *new_udriver,
>  
>  	retval = driver_register(&new_udriver->drvwrap.driver);
>  
> -	if (!retval)
> +	if (!retval) {
>  		pr_info("%s: registered new device driver %s\n",
>  			usbcore_name, new_udriver->name);
> -	else
> +		/*
> +		 * Check whether any device could be better served with
> +		 * this new driver
> +		 */
> +		bus_for_each_dev(&usb_bus_type, NULL, new_udriver,
> +				 __usb_bus_reprobe_drivers);
> +	} else {
>  		printk(KERN_ERR "%s: error %d registering device "
>  			"	driver %s\n",
>  			usbcore_name, retval, new_udriver->name);
> +	}
>  
>  	return retval;
>  }
> 

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 3/3 v5] USB: Fix device driver race
  2020-07-25 14:59 ` Alan Stern
@ 2020-07-25 15:24   ` Bastien Nocera
  2020-07-25 19:57     ` Alan Stern
  0 siblings, 1 reply; 7+ messages in thread
From: Bastien Nocera @ 2020-07-25 15:24 UTC (permalink / raw)
  To: Alan Stern; +Cc: linux-usb, Greg Kroah-Hartman

On Sat, 2020-07-25 at 10:59 -0400, Alan Stern wrote:
<snip>
> > +	udev = to_usb_device(dev);
> > +	if (usb_device_match_id(udev, new_udriver->id_table) == NULL &&
> > +	    (!new_udriver->match || new_udriver->match(udev) != 0))
> > +		return 0;
> > +
> > +	(void)!device_reprobe(dev);
> 
> What's that '!' doing hiding in there?  It doesn't affect the final 
> outcome, but it sure looks weird -- if people notice it at all.

It's how we stop gcc from complaining about the warn_unused_result
attribute on device_reprobe()... (void) is enough with clang, but not
with gcc.

> Aside from that,
> 
> Acked-by: Alan Stern <stern@rowland.harvard.edu>

Thanks!



^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 3/3 v5] USB: Fix device driver race
  2020-07-25 15:24   ` Bastien Nocera
@ 2020-07-25 19:57     ` Alan Stern
  2020-07-26  8:36       ` Greg Kroah-Hartman
  0 siblings, 1 reply; 7+ messages in thread
From: Alan Stern @ 2020-07-25 19:57 UTC (permalink / raw)
  To: Bastien Nocera; +Cc: linux-usb, Greg Kroah-Hartman

On Sat, Jul 25, 2020 at 05:24:20PM +0200, Bastien Nocera wrote:
> On Sat, 2020-07-25 at 10:59 -0400, Alan Stern wrote:
> <snip>
> > > +	udev = to_usb_device(dev);
> > > +	if (usb_device_match_id(udev, new_udriver->id_table) == NULL &&
> > > +	    (!new_udriver->match || new_udriver->match(udev) != 0))
> > > +		return 0;
> > > +
> > > +	(void)!device_reprobe(dev);
> > 
> > What's that '!' doing hiding in there?  It doesn't affect the final 
> > outcome, but it sure looks weird -- if people notice it at all.
> 
> It's how we stop gcc from complaining about the warn_unused_result
> attribute on device_reprobe()... (void) is enough with clang, but not
> with gcc.

Hmmm.  Maybe this is an indication that device_reprobe() doesn't really 
need to be __must_check.

Greg, do you know why it's annotated this way?

Alan Stern

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 3/3 v5] USB: Fix device driver race
  2020-07-25 19:57     ` Alan Stern
@ 2020-07-26  8:36       ` Greg Kroah-Hartman
  2020-07-26 14:17         ` Alan Stern
  0 siblings, 1 reply; 7+ messages in thread
From: Greg Kroah-Hartman @ 2020-07-26  8:36 UTC (permalink / raw)
  To: Alan Stern; +Cc: Bastien Nocera, linux-usb

On Sat, Jul 25, 2020 at 03:57:07PM -0400, Alan Stern wrote:
> On Sat, Jul 25, 2020 at 05:24:20PM +0200, Bastien Nocera wrote:
> > On Sat, 2020-07-25 at 10:59 -0400, Alan Stern wrote:
> > <snip>
> > > > +	udev = to_usb_device(dev);
> > > > +	if (usb_device_match_id(udev, new_udriver->id_table) == NULL &&
> > > > +	    (!new_udriver->match || new_udriver->match(udev) != 0))
> > > > +		return 0;
> > > > +
> > > > +	(void)!device_reprobe(dev);
> > > 
> > > What's that '!' doing hiding in there?  It doesn't affect the final 
> > > outcome, but it sure looks weird -- if people notice it at all.
> > 
> > It's how we stop gcc from complaining about the warn_unused_result
> > attribute on device_reprobe()... (void) is enough with clang, but not
> > with gcc.
> 
> Hmmm.  Maybe this is an indication that device_reprobe() doesn't really 
> need to be __must_check.
> 
> Greg, do you know why it's annotated this way?

Because you really should pass up the return value if an error happens
here.  Why do we think it is safe to ignore?

And that "(void)!" is not ok, if the annotation is safe to ignore, then
we need to remove the annotation, don't work around stuff like this
without at the very least, a comment saying why it is ok.

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 3/3 v5] USB: Fix device driver race
  2020-07-26  8:36       ` Greg Kroah-Hartman
@ 2020-07-26 14:17         ` Alan Stern
  2020-07-26 15:01           ` Greg Kroah-Hartman
  0 siblings, 1 reply; 7+ messages in thread
From: Alan Stern @ 2020-07-26 14:17 UTC (permalink / raw)
  To: Greg Kroah-Hartman; +Cc: Bastien Nocera, linux-usb

On Sun, Jul 26, 2020 at 10:36:55AM +0200, Greg Kroah-Hartman wrote:
> On Sat, Jul 25, 2020 at 03:57:07PM -0400, Alan Stern wrote:
> > On Sat, Jul 25, 2020 at 05:24:20PM +0200, Bastien Nocera wrote:
> > > On Sat, 2020-07-25 at 10:59 -0400, Alan Stern wrote:
> > > <snip>
> > > > > +	udev = to_usb_device(dev);
> > > > > +	if (usb_device_match_id(udev, new_udriver->id_table) == NULL &&
> > > > > +	    (!new_udriver->match || new_udriver->match(udev) != 0))
> > > > > +		return 0;
> > > > > +
> > > > > +	(void)!device_reprobe(dev);
> > > > 
> > > > What's that '!' doing hiding in there?  It doesn't affect the final 
> > > > outcome, but it sure looks weird -- if people notice it at all.
> > > 
> > > It's how we stop gcc from complaining about the warn_unused_result
> > > attribute on device_reprobe()... (void) is enough with clang, but not
> > > with gcc.
> > 
> > Hmmm.  Maybe this is an indication that device_reprobe() doesn't really 
> > need to be __must_check.
> > 
> > Greg, do you know why it's annotated this way?
> 
> Because you really should pass up the return value if an error happens
> here.  Why do we think it is safe to ignore?
> 
> And that "(void)!" is not ok, if the annotation is safe to ignore, then
> we need to remove the annotation, don't work around stuff like this
> without at the very least, a comment saying why it is ok.

I suppose Bastien could log an error message at that point.  There isn't 
much else to do.

Alan Stern

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 3/3 v5] USB: Fix device driver race
  2020-07-26 14:17         ` Alan Stern
@ 2020-07-26 15:01           ` Greg Kroah-Hartman
  0 siblings, 0 replies; 7+ messages in thread
From: Greg Kroah-Hartman @ 2020-07-26 15:01 UTC (permalink / raw)
  To: Alan Stern; +Cc: Bastien Nocera, linux-usb

On Sun, Jul 26, 2020 at 10:17:08AM -0400, Alan Stern wrote:
> On Sun, Jul 26, 2020 at 10:36:55AM +0200, Greg Kroah-Hartman wrote:
> > On Sat, Jul 25, 2020 at 03:57:07PM -0400, Alan Stern wrote:
> > > On Sat, Jul 25, 2020 at 05:24:20PM +0200, Bastien Nocera wrote:
> > > > On Sat, 2020-07-25 at 10:59 -0400, Alan Stern wrote:
> > > > <snip>
> > > > > > +	udev = to_usb_device(dev);
> > > > > > +	if (usb_device_match_id(udev, new_udriver->id_table) == NULL &&
> > > > > > +	    (!new_udriver->match || new_udriver->match(udev) != 0))
> > > > > > +		return 0;
> > > > > > +
> > > > > > +	(void)!device_reprobe(dev);
> > > > > 
> > > > > What's that '!' doing hiding in there?  It doesn't affect the final 
> > > > > outcome, but it sure looks weird -- if people notice it at all.
> > > > 
> > > > It's how we stop gcc from complaining about the warn_unused_result
> > > > attribute on device_reprobe()... (void) is enough with clang, but not
> > > > with gcc.
> > > 
> > > Hmmm.  Maybe this is an indication that device_reprobe() doesn't really 
> > > need to be __must_check.
> > > 
> > > Greg, do you know why it's annotated this way?
> > 
> > Because you really should pass up the return value if an error happens
> > here.  Why do we think it is safe to ignore?
> > 
> > And that "(void)!" is not ok, if the annotation is safe to ignore, then
> > we need to remove the annotation, don't work around stuff like this
> > without at the very least, a comment saying why it is ok.
> 
> I suppose Bastien could log an error message at that point.  There isn't 
> much else to do.

It looks like no one does anything with the return value of that
function, so we should just change it to void and stop checking it
entirely :(

greg k-h

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2020-07-26 15:01 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-07-25  9:16 [PATCH 3/3 v5] USB: Fix device driver race Bastien Nocera
2020-07-25 14:59 ` Alan Stern
2020-07-25 15:24   ` Bastien Nocera
2020-07-25 19:57     ` Alan Stern
2020-07-26  8:36       ` Greg Kroah-Hartman
2020-07-26 14:17         ` Alan Stern
2020-07-26 15:01           ` Greg Kroah-Hartman

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).