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
Windows Version
10.0.26200.9168
WSL Version
2.7.13.0
Are you using WSL 1 or WSL 2?
- 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.
- WSL2 running for about 1.5 days with
networkingMode=mirroredandautoMemoryReclaim=gradual, 10 GB memory limit. - On Windows, connect Cisco AnyConnect. Mirrored networking hot-adds the VPN adapter into the VM as
eth1. vmbus_add_channel_workon thehv_sub_chanworkqueue 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).netvsc_sc_openlogssub channel open failed: -12seven times.- From that moment every rtnetlink dump blocks forever in
rtnl_dumpit, in state D. Anything that callsgetifaddrs()or lists interfaces hangs and cannot be killed:ip addr,ss,sshdconnection 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:
<TASK>
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
</TASK>
...
hv_netvsc <device-guid> eth1: sub channel open failed: -12 (x7)
Every blocked process has the same stack (read as root from /proc/<pid>/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 thesub channel open failedlinesdmesg-primary-channel-failure-example.txt- one of the 40 earlier order-7hv_pri_chanfailures that did not hangwaiter-stacks.txt- kernel stacks of blockedip,sshdandnpmprocessesdstate-processes.txt- all 36 blocked processes with their wait channelssysrq-w-blocked-tasks.txt-echo w > /proc/sysrq-triggeroutput (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 dmesg-primary-channel-failure-example.txt waiter-stacks.txt dstate-processes.txt sysrq-w-blocked-tasks.txt meminfo.txt buddyinfo.txt wsl-version.txt wslconfig.txt windows-adapters.txt
Source: microsoft/WSL