All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] usb: core: sysfs: show product, manufacturer and serial without the device lock
@ 2026-10-10 23:15 ` Joe Finzel
  0 siblings, 0 replies; 4+ messages in thread
From: Joe Finzel via B4 Relay @ 2026-10-10 23:15 UTC (permalink / raw)
  To: Greg Kroah-Hartman; +Cc: linux-usb, linux-kernel, Joe Finzel

From: Joe Finzel <joe@sudmix.de>

Reading the product, manufacturer or serial attribute of a USB device
takes the device lock. A hub holds its lock in hub_event() while it
enumerates all of its ports, including the debounce and reset delays of
every child, so a reader of the hub's strings waits until the last port
is done -- seconds on a hub with several devices.

udev reads these strings for every USB device (the usb_id builtin, run
from 50-udev-default.rules). Its worker blocks SIGTERM, so when systemd
stops udevd in the initrd before switching root, it waits for that
worker. On a desktop with a few hubs this delays every boot:

  i7-13700K, ASUS ROG STRIX Z790-F, four hubs with HID devices behind
  them: udevd took 1.7 s to stop, while the hubs were still enumerating.

  QEMU, qemu-xhci with 8 usb-hubs of 8 HID devices each, second boot,
  three runs: udevd stops in 2.55-2.58 s (switch-root at 5.56-5.59 s);
  with this patch in 11-12 ms (switch-root at 3.02 s). Without usb_id in
  the udev rules, it stops in 9 ms as well.

  -device qemu-xhci,id=xhci,p2=8,p3=8
  -device usb-hub,bus=xhci.0,port=N       (N = 1..8)
  -device usb-kbd,bus=xhci.0,port=N.M   (M = 1..8; also mouse, tablet)

The lock is not needed: usb_enumerate_device() sets the strings once,
before device_add() makes the attributes visible, and usb_release_dev()
frees them only after the attributes are gone. Nothing changes them in
between: authorizing or deauthorizing a device no longer touches them
since Wireless USB, for which they could appear and disappear, was
removed. dev_string_attrs_are_visible() already reads them unlocked.

Andy Whitcroft reported the same boot stall in 2010 ("khubd -- switch
USB product/manufacturer/serial handling to RCU"); back then the strings
could still change under Wireless USB.

Signed-off-by: Joe Finzel <joe@sudmix.de>
---
Found while looking into a 1.7 s stall at the end of the initrd on a
desktop with several USB hubs; reproducible in QEMU (see the commit
message). Tested on 7.2.9 with the QEMU reproduction; applies to
usb-next.
---
 drivers/usb/core/sysfs.c | 19 +++++++++----------
 1 file changed, 9 insertions(+), 10 deletions(-)

diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c
index d22dc7845..52e0a227c 100644
--- a/drivers/usb/core/sysfs.c
+++ b/drivers/usb/core/sysfs.c
@@ -120,21 +120,20 @@ static ssize_t devspec_show(struct device *dev, struct device_attribute *attr,
 static DEVICE_ATTR_RO(devspec);
 #endif
 
-/* String fields */
+/*
+ * String fields. usb_enumerate_device() reads them once, before the device
+ * is added, and they are freed only when it is released, so showing them
+ * needs no lock -- dev_string_attrs_are_visible() reads them unlocked, too.
+ * The device lock would make readers wait while a hub holds it to enumerate
+ * all of its ports.
+ */
 #define usb_string_attr(name)						\
 static ssize_t  name##_show(struct device *dev,				\
 		struct device_attribute *attr, char *buf)		\
 {									\
-	struct usb_device *udev;					\
-	int retval;							\
+	struct usb_device *udev = to_usb_device(dev);			\
 									\
-	udev = to_usb_device(dev);					\
-	retval = usb_lock_device_interruptible(udev);			\
-	if (retval < 0)							\
-		return -EINTR;						\
-	retval = sysfs_emit(buf, "%s\n", udev->name);			\
-	usb_unlock_device(udev);					\
-	return retval;							\
+	return sysfs_emit(buf, "%s\n", udev->name);			\
 }									\
 static DEVICE_ATTR_RO(name)
 

---
base-commit: 42bcac323cc3b16566fed8c5b250318ad02a0de0
change-id: 20261011-usb-string-attrs-74abcc8b0195

Best regards,
-- 
Joe Finzel <joe@sudmix.de>



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

* [PATCH] usb: core: sysfs: show product, manufacturer and serial without the device lock
@ 2026-10-10 23:15 ` Joe Finzel
  0 siblings, 0 replies; 4+ messages in thread
From: Joe Finzel @ 2026-10-10 23:15 UTC (permalink / raw)
  To: Greg Kroah-Hartman; +Cc: linux-usb, linux-kernel, Joe Finzel

Reading the product, manufacturer or serial attribute of a USB device
takes the device lock. A hub holds its lock in hub_event() while it
enumerates all of its ports, including the debounce and reset delays of
every child, so a reader of the hub's strings waits until the last port
is done -- seconds on a hub with several devices.

udev reads these strings for every USB device (the usb_id builtin, run
from 50-udev-default.rules). Its worker blocks SIGTERM, so when systemd
stops udevd in the initrd before switching root, it waits for that
worker. On a desktop with a few hubs this delays every boot:

  i7-13700K, ASUS ROG STRIX Z790-F, four hubs with HID devices behind
  them: udevd took 1.7 s to stop, while the hubs were still enumerating.

  QEMU, qemu-xhci with 8 usb-hubs of 8 HID devices each, second boot,
  three runs: udevd stops in 2.55-2.58 s (switch-root at 5.56-5.59 s);
  with this patch in 11-12 ms (switch-root at 3.02 s). Without usb_id in
  the udev rules, it stops in 9 ms as well.

  -device qemu-xhci,id=xhci,p2=8,p3=8
  -device usb-hub,bus=xhci.0,port=N       (N = 1..8)
  -device usb-kbd,bus=xhci.0,port=N.M   (M = 1..8; also mouse, tablet)

The lock is not needed: usb_enumerate_device() sets the strings once,
before device_add() makes the attributes visible, and usb_release_dev()
frees them only after the attributes are gone. Nothing changes them in
between: authorizing or deauthorizing a device no longer touches them
since Wireless USB, for which they could appear and disappear, was
removed. dev_string_attrs_are_visible() already reads them unlocked.

Andy Whitcroft reported the same boot stall in 2010 ("khubd -- switch
USB product/manufacturer/serial handling to RCU"); back then the strings
could still change under Wireless USB.

Signed-off-by: Joe Finzel <joe@sudmix.de>
---
Found while looking into a 1.7 s stall at the end of the initrd on a
desktop with several USB hubs; reproducible in QEMU (see the commit
message). Tested on 7.2.9 with the QEMU reproduction; applies to
usb-next.
---
 drivers/usb/core/sysfs.c | 19 +++++++++----------
 1 file changed, 9 insertions(+), 10 deletions(-)

diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c
index d22dc7845..52e0a227c 100644
--- a/drivers/usb/core/sysfs.c
+++ b/drivers/usb/core/sysfs.c
@@ -120,21 +120,20 @@ static ssize_t devspec_show(struct device *dev, struct device_attribute *attr,
 static DEVICE_ATTR_RO(devspec);
 #endif
 
-/* String fields */
+/*
+ * String fields. usb_enumerate_device() reads them once, before the device
+ * is added, and they are freed only when it is released, so showing them
+ * needs no lock -- dev_string_attrs_are_visible() reads them unlocked, too.
+ * The device lock would make readers wait while a hub holds it to enumerate
+ * all of its ports.
+ */
 #define usb_string_attr(name)						\
 static ssize_t  name##_show(struct device *dev,				\
 		struct device_attribute *attr, char *buf)		\
 {									\
-	struct usb_device *udev;					\
-	int retval;							\
+	struct usb_device *udev = to_usb_device(dev);			\
 									\
-	udev = to_usb_device(dev);					\
-	retval = usb_lock_device_interruptible(udev);			\
-	if (retval < 0)							\
-		return -EINTR;						\
-	retval = sysfs_emit(buf, "%s\n", udev->name);			\
-	usb_unlock_device(udev);					\
-	return retval;							\
+	return sysfs_emit(buf, "%s\n", udev->name);			\
 }									\
 static DEVICE_ATTR_RO(name)
 

---
base-commit: 42bcac323cc3b16566fed8c5b250318ad02a0de0
change-id: 20261011-usb-string-attrs-74abcc8b0195

Best regards,
-- 
Joe Finzel <joe@sudmix.de>


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

* Re: [PATCH] usb: core: sysfs: show product, manufacturer and serial without the device lock
  2026-10-10 23:15 ` Joe Finzel
  (?)
@ 2026-10-10 23:23 ` sashiko-bot
  -1 siblings, 0 replies; 4+ messages in thread
From: sashiko-bot @ 2026-10-10 23:23 UTC (permalink / raw)
  To: Joe Finzel; +Cc: linux-usb

> From: Joe Finzel <joe@sudmix.de>
> 
> Reading the product, manufacturer or serial attribute of a USB device
> takes the device lock. A hub holds its lock in hub_event() while it
> enumerates all of its ports, including the debounce and reset delays of
> every child, so a reader of the hub's strings waits until the last port
> is done -- seconds on a hub with several devices.
> 
> udev reads these strings for every USB device (the usb_id builtin, run
> from 50-udev-default.rules). Its worker blocks SIGTERM, so when systemd
> stops udevd in the initrd before switching root, it waits for that
> worker. On a desktop with a few hubs this delays every boot:
> 
>   i7-13700K, ASUS ROG STRIX Z790-F, four hubs with HID devices behind
>   them: udevd took 1.7 s to stop, while the hubs were still enumerating.
> [ ... ]
> Andy Whitcroft reported the same boot stall in 2010 ("khubd -- switch
> USB product/manufacturer/serial handling to RCU"); back then the strings
> could still change under Wireless USB.
> 
> Signed-off-by: Joe Finzel <joe@sudmix.de>

Sashiko has reviewed this patch and found no issues. It looks great!

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261011-usb-string-attrs-v1-1-81c01b035237@sudmix.de?part=1


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

* Re: [PATCH] usb: core: sysfs: show product, manufacturer and serial without the device lock
  2026-10-10 23:15 ` Joe Finzel
  (?)
  (?)
@ 2026-10-11  2:11 ` Alan Stern
  -1 siblings, 0 replies; 4+ messages in thread
From: Alan Stern @ 2026-10-11  2:11 UTC (permalink / raw)
  To: joe; +Cc: Greg Kroah-Hartman, linux-usb, linux-kernel

On Sun, Oct 11, 2026 at 01:15:38AM +0200, Joe Finzel via B4 Relay wrote:
> From: Joe Finzel <joe@sudmix.de>
> 
> Reading the product, manufacturer or serial attribute of a USB device
> takes the device lock. A hub holds its lock in hub_event() while it
> enumerates all of its ports, including the debounce and reset delays of
> every child, so a reader of the hub's strings waits until the last port
> is done -- seconds on a hub with several devices.
> 
> udev reads these strings for every USB device (the usb_id builtin, run
> from 50-udev-default.rules). Its worker blocks SIGTERM, so when systemd
> stops udevd in the initrd before switching root, it waits for that
> worker. On a desktop with a few hubs this delays every boot:
> 
>   i7-13700K, ASUS ROG STRIX Z790-F, four hubs with HID devices behind
>   them: udevd took 1.7 s to stop, while the hubs were still enumerating.
> 
>   QEMU, qemu-xhci with 8 usb-hubs of 8 HID devices each, second boot,
>   three runs: udevd stops in 2.55-2.58 s (switch-root at 5.56-5.59 s);
>   with this patch in 11-12 ms (switch-root at 3.02 s). Without usb_id in
>   the udev rules, it stops in 9 ms as well.
> 
>   -device qemu-xhci,id=xhci,p2=8,p3=8
>   -device usb-hub,bus=xhci.0,port=N       (N = 1..8)
>   -device usb-kbd,bus=xhci.0,port=N.M   (M = 1..8; also mouse, tablet)
> 
> The lock is not needed: usb_enumerate_device() sets the strings once,
> before device_add() makes the attributes visible, and usb_release_dev()
> frees them only after the attributes are gone. Nothing changes them in
> between: authorizing or deauthorizing a device no longer touches them
> since Wireless USB, for which they could appear and disappear, was
> removed. dev_string_attrs_are_visible() already reads them unlocked.

No; it reads the pointers to but not the contents of the strings.  
However, this is a minor point.

> Andy Whitcroft reported the same boot stall in 2010 ("khubd -- switch
> USB product/manufacturer/serial handling to RCU"); back then the strings
> could still change under Wireless USB.
> 
> Signed-off-by: Joe Finzel <joe@sudmix.de>
> ---
> Found while looking into a 1.7 s stall at the end of the initrd on a
> desktop with several USB hubs; reproducible in QEMU (see the commit
> message). Tested on 7.2.9 with the QEMU reproduction; applies to
> usb-next.
> ---

You could submit v2 of this patch with the claim above removed (and also 
removed from the comment below).  When you do, you may add:

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

Alan Stern

>  drivers/usb/core/sysfs.c | 19 +++++++++----------
>  1 file changed, 9 insertions(+), 10 deletions(-)
> 
> diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c
> index d22dc7845..52e0a227c 100644
> --- a/drivers/usb/core/sysfs.c
> +++ b/drivers/usb/core/sysfs.c
> @@ -120,21 +120,20 @@ static ssize_t devspec_show(struct device *dev, struct device_attribute *attr,
>  static DEVICE_ATTR_RO(devspec);
>  #endif
>  
> -/* String fields */
> +/*
> + * String fields. usb_enumerate_device() reads them once, before the device
> + * is added, and they are freed only when it is released, so showing them
> + * needs no lock -- dev_string_attrs_are_visible() reads them unlocked, too.
> + * The device lock would make readers wait while a hub holds it to enumerate
> + * all of its ports.
> + */
>  #define usb_string_attr(name)						\
>  static ssize_t  name##_show(struct device *dev,				\
>  		struct device_attribute *attr, char *buf)		\
>  {									\
> -	struct usb_device *udev;					\
> -	int retval;							\
> +	struct usb_device *udev = to_usb_device(dev);			\
>  									\
> -	udev = to_usb_device(dev);					\
> -	retval = usb_lock_device_interruptible(udev);			\
> -	if (retval < 0)							\
> -		return -EINTR;						\
> -	retval = sysfs_emit(buf, "%s\n", udev->name);			\
> -	usb_unlock_device(udev);					\
> -	return retval;							\
> +	return sysfs_emit(buf, "%s\n", udev->name);			\
>  }									\
>  static DEVICE_ATTR_RO(name)
>  
> 
> ---
> base-commit: 42bcac323cc3b16566fed8c5b250318ad02a0de0
> change-id: 20261011-usb-string-attrs-74abcc8b0195
> 
> Best regards,
> -- 
> Joe Finzel <joe@sudmix.de>

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

end of thread, other threads:[~2026-10-11  2:11 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-10 23:15 [PATCH] usb: core: sysfs: show product, manufacturer and serial without the device lock Joe Finzel via B4 Relay
2026-10-10 23:15 ` Joe Finzel
2026-10-10 23:23 ` sashiko-bot
2026-10-11  2:11 ` Alan Stern

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.