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]

Reply via email to