Re: iw scan hangs in netlink ENOBUFS loop with kernel 6.6.99+
Peter Astrand <[email protected]> Sun, 26 Jul 2026 20:39:06 +0200 (CEST)
| Newsgroups | dev.linux.lists.regressions,org.kernel.vger.linux-wireless,org.kernel.vger.stable |
|---|---|
| Message-ID | <[email protected]> |
On Wed, 22 Jul 2026, Peter Astrand wrote:
>
> On Tue, 21 Jul 2026, Thorsten Leemhuis wrote:
>
> > On 7/14/26 00:37, Peter Astrand wrote:
> > >
> > > kernel 6.6.y
> > > iw 6.7
> > > libnl-genl-3-200 3.9.0
> > > mac80211_hwsim
> > >
> > > With kernel 6.6.99 and later, "iw dev <device> scan" sometimes hangs in
> > > busy loop:
> >
> > Thanks for the report. We need to rule out if this is a 6.6.y specific
> > problem (like a broken or incomplete backport) or something general.
> > Could you please check if 7.2-rc is affected as well? Testing 6.18.y
> > might help, too, if it's easy for you to try. Maybe switching to that
> > might be the easies way to resolve the problem and a good idea in
> > general, as explained here:
> > http://www.kroah.com/log/blog/2018/08/24/what-stable-kernel-should-i-use/
>
> Platform is NXP imx6ull. Forgot to mention that we are actually running
> https://github.com/Freescale/linux-fslc/tree/6.6-2.2.x-imx rather than
> upstream kernel. No changes to net/netlink though.
>
> We cannot easily test with 7.X, but I have tested
> https://github.com/Freescale/linux-fslc/tree/6.18-2.0.x-imx and can
> reproduce the same problem; this is 6.18.20. strace output is similar:
>
> recvmsg(3, {msg_namelen=12}, 0) = -1 ENOBUFS (No buffer space available)
> recvmsg(3, {msg_name={sa_family=AF_NETLINK, nl_pid=0, nl_groups=00000000}, msg_namelen=12, msg_iov=[{iov_base=[{nlmsg_len=48, nlmsg_type=NLMSG_ERROR, nlmsg_flags=0, nlmsg_seq=2510255223, nlmsg_pid=1468011032}, {error=-ENOBUFS, msg=[{nlmsg_len=28, nlmsg_type=0x1b /* NLMSG_??? */, nlmsg_flags=NLM_F_REQUEST|NLM_F_ACK|0x300, nlmsg_seq=2510255223, nlmsg_pid=1468011032}, "\x20\x00\x00\x00\x08\x00\x03\x00\x0d\x00\x00\x00"]}], iov_len=16384}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, MSG_PEEK|MSG_TRUNC) = 48
Claude created a patch (against 6.6.y, but applies to master as well):
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -1219,7 +1219,7 @@ int netlink_attachskb(struct sock *sk, struct
sk_buff *skb,
nlk = nlk_sk(sk);
rmem = atomic_add_return(skb->truesize, &sk->sk_rmem_alloc);
- if ((rmem == skb->truesize || rmem <= READ_ONCE(sk->sk_rcvbuf)) &&
+ if (rmem - skb->truesize <= READ_ONCE(sk->sk_rcvbuf) &&
!test_bit(NETLINK_S_CONGESTED, &nlk->state)) {
netlink_skb_set_owner_r(skb, sk);
return 0;
@@ -1395,7 +1395,7 @@ static int netlink_broadcast_deliver(struct sock
*sk, struct sk_buff *skb)
rmem = atomic_add_return(skb->truesize, &sk->sk_rmem_alloc);
rcvbuf = READ_ONCE(sk->sk_rcvbuf);
- if ((rmem == skb->truesize || rmem <= rcvbuf) &&
+ if (rmem - skb->truesize <= rcvbuf &&
!test_bit(NETLINK_S_CONGESTED, &nlk->state)) {
netlink_skb_set_owner_r(skb, sk);
__netlink_sendskb(sk, skb);
@@ -2232,7 +2232,7 @@ static int netlink_dump(struct sock *sk, bool
lock_taken)
rcvbuf = READ_ONCE(sk->sk_rcvbuf);
rmem = atomic_add_return(skb->truesize, &sk->sk_rmem_alloc);
- if (rmem != skb->truesize && rmem >= rcvbuf) {
+ if (rmem - skb->truesize >= rcvbuf) {
atomic_sub(skb->truesize, &sk->sk_rmem_alloc);
goto errout_skb;
}
It also created this commit message:
netlink: restore pre-add admission-control boundary
Commit 55baecb9eb90 ("netlink: Fix wraparounds of sk->sk_rmem_alloc.")
moved the sk_rmem_alloc admission check in netlink_attachskb(),
netlink_broadcast_deliver() and netlink_dump() from "queue was already
under budget before this skb" (checked BEFORE adding truesize) to
"queue is still under budget after this skb" (checked AFTER adding
truesize). That's a strictly stricter boundary: a message that would
push the queue from just-under to just-over sk_rcvbuf is now rejected
outright, where before it was admitted.
For slow-draining or MSG_PEEK-based readers (e.g. iw/libnl doing
netlink dumps), a message can hit this new, stricter ceiling every
time it's retried, turning what used to be a transient ENOBUFS into
a permanent one for that message size -- causing indefinite retry
loops in userspace (iw scan hanging).
Fix by keeping atomic_add_return()-based accounting (needed for the
actual wraparound fix), but comparing against the pre-add value:
rmem is guaranteed >= skb->truesize since it's the value just
returned by adding truesize, so `rmem - skb->truesize` can't
underflow and stays unsigned throughout, preserving the wraparound
fix while restoring the original admission boundary.
The patch seems to solve my issues. However, since I don't understand this
code well, I cannot really say if the patch is correct.
Br,
Peter