Fishwaldo opened a new pull request, #19742:
URL: https://github.com/apache/nuttx/pull/19742
## Summary
`usbhost_registerclass()` links a caller-supplied `struct
usbhost_registry_s` into a singly linked list. Those structures are static, so
registering the same one twice does not add a second entry — it sets that
entry's `flink` to itself:
```c
usbclass->flink = g_classregistry; /* g_classregistry is already usbclass
*/
g_classregistry = usbclass;
```
The list now has no end. Nothing notices while every device that appears
matches something, because `usbhost_findclass()` returns before it reaches the
self-link. The first device that matches *nothing* — anything whose class
driver is not built in — walks the list looking for it and never comes back,
holding `g_classregistry_lock`. On an SMP system every other CPU that touches
the registry then spins behind it.
The fix is to walk the list before linking and treat a repeat registration
as the no-op the caller expected.
**This is a guardrail rather than a fix for a failure anyone is hitting
in-tree today.** No in-tree configuration registers a class twice, so nothing
upstream is currently broken. But the mistake is easy to make:
`drivers_initialize()` calls `usbhost_drivers_initialize()` whenever
`CONFIG_USBHOST_WAITER` is set, which registers every class the configuration
selected, and around 70 in-tree boards also call a class initialiser directly
from board bring-up. A board that does both gets the second registration for
free, and the symptom it produces — a silent wedge, no crash, no message —
gives almost nothing to debug from.
## Impact
- **User visible:** on an affected build, a board with an unsupported USB
device attached boots and then stops responding, with no crash and no message.
On SMP the console can go with it.
- **Configurations affected:** any with `CONFIG_USBHOST` where a class ends
up registered twice. Unaffected otherwise — the added loop runs once per
registration, at init, over a list of at most a handful of entries.
- **Compatibility:** none. A duplicate call previously corrupted the list;
it now returns `OK` without doing anything.
- **Hardware, build, documentation, security:** unaffected.
## Testing
**Host:** macOS 15.5 (Apple Silicon). **Board:** EIC7700 EVB, RISC-V
EIC7700X, 4 cores SMP.
The trigger is a real device with no driver in NuttX: a Realtek RTL8153 USB
Ethernet adapter (`0bda:8153`), attached through a hub alongside devices that
do have drivers.
Since no in-tree configuration registers twice, I reproduced it by adding a
second `usbhost_drivers_initialize()` call to board bring-up, standing in for
board code that also registers. Both runs are otherwise the same tree, board
and configuration.
**Before (without this patch)** — NSH is reached, then the board stops
answering and the watchdog resets it:
```
=== [ 52.52s] NSH reached ===
##### CMD 1: uname -a
##### END 1 (REBOOTED (firmware banner seen mid-command), 14.68s)
```
The last USB line before it stops is the mass storage device:
```
usb 0-1.1: mass storage, driver attached
usb 0-1.1: Product: USB Flash Disk
```
Enumeration halts there — immediately before `0-1.4`, the Realtek adapter.
That is the first device to match nothing, and the search for it is where the
loop is entered.
**After (with this patch)** — same double registration, same devices:
```
##### CMD 1: uname -a
NuttX 13.0.0 risc-v starpro64
##### END 1 (ok, 1.52s)
##### CMD 2: ls /dev
kbda kbdb sda ttyACM0
```
and the device that used to be fatal is enumerated and reported:
```
usb 0-1.4: new device, idVendor=0bda, idProduct=8153
usb 0-1.4: vendor specific, no driver
usb 0-1.4: Product: USB 10/100/1000 LAN
```
**Build:** `qemu-intel64:jumbo`, the in-tree configuration with an xHCI host
controller, builds clean.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]