rtnl deadlock after hv_netvsc sub-channel ring allocation fails (ENOMEM) when a VPN adapter is hot-added in mirrored networking - follow-up to #41474
- Dominant language
- C++
- Stars
- 33.7k
- Forks
- 1.8k
- Avg merge
- 3d 17h
- Merged PRs (30d)
- 116
Description
[logs.etl.txt](https://github.com/user-attachments/files/32282419/logs.etl.txt)
[logs.etl.txt](https://github.com/user-attachments/files/32282371/logs.etl.txt)
### Windows Version
10.0.26200.9168
### WSL Version
2.7.13.0
### Are you using WSL 1 or WSL 2?
- [x] WSL 2
- [ ] WSL 1
### Kernel Version
6.18.33.2-2 (uname -r: 6.18.33.2-microsoft-standard-WSL2)
### Distro Version
Ubuntu 24.04.4 LTS
### Other Software
- Cisco AnyConnect / Secure Client VPN (adapter "Cisco AnyConnect Virtual Miniport Adapter for Windows x64").
- `.wslconfig`: `memory=10GB`, `swap=4GB`, `processors=11`, `networkingMode=mirrored`, `dnsTunneling=true`, `autoProxy=false`, `[experimental] autoMemoryReclaim=gradual`, `sparseVhd=true`.
- Normal developer load inside the VM (Node.js tooling, several SSH sessions).
### Repro Steps
Same kernel failure as #41474, which was closed because only post-recovery logs were attached. This report is captured **while the VM is still deadlocked**, and it has a different, common trigger: no small memory cap, just a VPN connecting on the Windows host.
1. WSL2 running for about 1.5 days with `networkingMode=mirrored` and `autoMemoryReclaim=gradual`, 10 GB memory limit.
2. On Windows, connect Cisco AnyConnect. Mirrored networking hot-adds the VPN adapter into the VM as `eth1`.
3. `vmbus_add_channel_work` on the `hv_sub_chan` workqueue tries to allocate the sub-channel ring buffer (order 8, about 1 MiB contiguous, `GFP_KERNEL|__GFP_ZERO`) and fails, although about 6.5 GB is available: memory is fragmented (see buddyinfo).
4. `netvsc_sc_open` logs `sub channel open failed: -12` seven times.
5. From that moment every rtnetlink dump blocks forever in `rtnl_dumpit`, in state D. Anything that calls `getifaddrs()` or lists interfaces hangs and cannot be killed: `ip addr`, `ss`, `sshd` connection children (before the SSH banner), `npm` / Node.js, `sudo`. Load average climbs with each new stuck process (41 at capture time, 36 processes in D state).
It is not reproducible on demand, because it needs fragmented kernel memory at the moment the adapter is hot-added. The host had **40 earlier order-7 ring allocation failures on the `hv_pri_chan` workqueue** (`vmbus_probe` / `vmbus_device_register` path) over the previous day, and **none of them hung anything**. The single failure on the **sub-channel** path (`netvsc_sc_open`) is the one that left rtnl blocked.
### Expected Behavior
A failed sub-channel open should unwind and release rtnl, so the interface keeps working with fewer channels, or is removed cleanly. Netlink queries should never block permanently.
### Actual Behavior
rtnl stays blocked indefinitely. The only recovery is `wsl --shutdown`. All networking-related process creation in the distro is wedged (SSH server unusable, Node.js tools hang at startup, `sudo` hangs).
Allocation failure (sanitized; `dmesg -T` wall-clock times drift in WSL, the order of events is reliable):
```
kworker/0:1: page allocation failure: order:8, mode:0xdc0(GFP_KERNEL|__GFP_ZERO), nodemask=(null),cpuset=/,mems_allowed=0
CPU: 0 UID: 0 PID: 18457 Comm: kworker/0:1 Not tainted 6.18.33.2-microsoft-standard-WSL2 #1 PREEMPT(none)
Workqueue: hv_sub_chan vmbus_add_channel_work
Call Trace:
dump_stack_lvl+0x70/0x90
dump_stack+0x14/0x20
warn_alloc+0x10a/0x180
? __alloc_pages_direct_compact+0x1a6/0x250
__alloc_pages_slowpath.constprop.0+0x2a3/0xe30
__alloc_frozen_pages_noprof+0x31c/0x330
__alloc_pages_noprof+0x12/0x30
vmbus_alloc_ring+0x78/0xd0
? __pfx_netvsc_channel_cb+0x10/0x10
vmbus_open+0x29/0x80
? rtnl_is_locked+0x19/0x30
netvsc_sc_open+0x11a/0x1a0
vmbus_add_channel_work+0x101/0x1d0
process_one_work+0x19b/0x3c0
worker_thread+0x1a3/0x320
kthread+0x111/0x240
ret_from_fork+0x13c/0x1a0
ret_from_fork_asm+0x1a/0x30
...
hv_netvsc eth1: sub channel open failed: -12 (x7)
```
Every blocked process has the same stack (read as root from `/proc//stack`):
```
=== comm ip state D (disk sleep)
[<0>] rtnl_dumpit+0x7f/0xb0
[<0>] netlink_dump+0x188/0x3c0
[<0>] __netlink_dump_start+0x1fc/0x330
[<0>] rtnetlink_rcv_msg+0x2a6/0x3f0
[<0>] netlink_rcv_skb+0x60/0x110
[<0>] rtnetlink_rcv+0x19/0x20
[<0>] netlink_unicast+0x282/0x3d0
[<0>] netlink_sendmsg+0x20c/0x440
[<0>] __sys_sendto+0x1ee/0x200
[<0>] __x64_sys_sendto+0x28/0x30
[<0>] x64_sys_call+0x15e7/0x20f0
[<0>] do_syscall_64+0x73/0x990
[<0>] entry_SYSCALL_64_after_hwframe+0x76/0x7e
```
Fragmentation at capture time (`/proc/buddyinfo`, orders 0-10), MemAvailable 6,533,488 kB of 10,183,560 kB:
```
Node 0, zone DMA32 11829 7332 5518 4144 2494 1426 866 463 172 39 4
Node 0, zone Normal 6096 3637 3034 1638 914 182 137 61 29 35 8
```
A possible code path, for the maintainers to confirm: the sub-channel setup in `netvsc` waits under rtnl for all requested sub-channels to report open (`open_chn == num_chn`). If one `netvsc_sc_open` fails with ENOMEM, that count may never be reached, so the waiter keeps rtnl held. We could not see the holder directly: the distro PID namespace hides kernel threads, and the `echo w > /proc/sysrq-trigger` dump in the kernel log was truncated after 9 of 36 blocked tasks.
### Diagnostic Logs
I cannot run `collect-wsl-logs.ps1`: this is a managed corporate laptop without Windows administrator rights, so no `logs.etl` can be produced. Please do not auto-close for the missing ETL; everything below was collected **during** the deadlock from inside the VM (root through `wsl -u root`), plus non-admin Windows output:
- `dmesg-subchannel-failure.txt` - the failing allocation, Mem-Info and buddy lists at failure time, and the `sub channel open failed` lines
- `dmesg-primary-channel-failure-example.txt` - one of the 40 earlier order-7 `hv_pri_chan` failures that did not hang
- `waiter-stacks.txt` - kernel stacks of blocked `ip`, `sshd` and `npm` processes
- `dstate-processes.txt` - all 36 blocked processes with their wait channels
- `sysrq-w-blocked-tasks.txt` - `echo w > /proc/sysrq-trigger` output (truncated by the kernel log)
- `meminfo.txt`, `buddyinfo.txt`, `wsl-version.txt`, `wslconfig.txt`, `windows-adapters.txt`
Device GUIDs, MAC and IP addresses and user names are replaced by placeholders. The full kernel log is available on request. The VM had to be restarted with `wsl --shutdown` after this capture, because every networking-related process creation was wedged. If it happens again, tell me which extra kernel-side capture you want taken before the restart.
Related: #41474 (same failure with a low `memory=` cap, closed for missing logs).
[dmesg-subchannel-failure.txt](https://github.com/user-attachments/files/32281914/dmesg-subchannel-failure.txt)
[dmesg-primary-channel-failure-example.txt](https://github.com/user-attachments/files/32281910/dmesg-primary-channel-failure-example.txt)
[waiter-stacks.txt](https://github.com/user-attachments/files/32281912/waiter-stacks.txt)
[dstate-processes.txt](https://github.com/user-attachments/files/32281915/dstate-processes.txt)
[sysrq-w-blocked-tasks.txt](https://github.com/user-attachments/files/32281917/sysrq-w-blocked-tasks.txt)
[meminfo.txt](https://github.com/user-attachments/files/32281916/meminfo.txt)
[buddyinfo.txt](https://github.com/user-attachments/files/32281913/buddyinfo.txt)
[wsl-version.txt](https://github.com/user-attachments/files/32281909/wsl-version.txt)
[wslconfig.txt](https://github.com/user-attachments/files/32281911/wslconfig.txt)
[windows-adapters.txt](https://github.com/user-attachments/files/32281908/windows-adapters.txt)
Contributor guide
Research direction
Start by tracing the mentioned netvsc_sc_open and vmbus_add_channel_work paths, then follow how rtnetlink enters rtnl_dumpit during sub-channel setup. Compare the failed sub-channel case with the earlier primary-channel allocation failures and inspect the wait for all requested channels to open. Done means an ENOMEM failure unwinds cleanly, releases rtnl, and leaves netlink queries responsive.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- c, linux
- Domain
- networking, operating-systems
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100