Skip to content

rose: purge rose_neigh->queue on final teardown - #9

Open
f6bvp wants to merge 1 commit into
linux-netdev:mainfrom
f6bvp:rose-neigh-queue-purge
Open

f6bvp wants to merge 1 commit into
linux-netdev:mainfrom
f6bvp:rose-neigh-queue-purge

Conversation

@f6bvp

@f6bvp f6bvp commented Sep 18, 2026

Copy link
Copy Markdown
Contributor

rose_transmit_link() queues an outgoing frame on rose_neigh->queue
instead of sending it immediately whenever the neighbour isn't
"restarted" yet (link not up) -- notably the CLEAR_REQUEST built by
rose_write_internal() when a socket is released (e.g. its owning
process is killed) while the underlying AX.25 link to that neighbour
is still coming up.

rose_neigh_put() already tears down both timers and drops the ax25/
digipeat references before freeing the neighbour, but never empties
this queue. kfree(rose_neigh) only frees the rose_neigh struct itself
(the sk_buff_head embedded in it is just three next/prev/len words),
not the skbs still linked into it -- every frame still queued here at
that point leaks for good.

rose_remove_neigh() (rose_route.c) already purges this same queue, but
it is only one of about two dozen call sites that can drop the last
reference and trigger the real kfree() in rose_neigh_put() -- every
socket releasing its own rose->neighbour reference (af_rose.c,
rose_in.c, rose_timer.c) can just as well be the one that does. Doing
the purge once, centrally, in rose_neigh_put() itself covers all of
them regardless of which call site happens to be last, rather than
relying on whichever caller happened to remember it.

Matches a leak pattern observed and documented back in May 2026
(mailbbs killed -> rose_release() -> rose_write_internal() ->
rose_transmit_link() queues the CLEAR_REQUEST -> skb never freed),
never root-caused until now.

Testing: deployed on three independent nodes since 2026-09-13/15
(three different kernel bases -- 6.12.94, 6.18.46, 6.18.34), running
live production ROSE traffic since, no regression observed.

rose_transmit_link() queues an outgoing frame on rose_neigh->queue
instead of sending it immediately whenever the neighbour isn't
"restarted" yet (link not up) -- notably the CLEAR_REQUEST built by
rose_write_internal() when a socket is released (e.g. its owning
process is killed) while the underlying AX.25 link to that neighbour
is still coming up.

rose_neigh_put() already tears down both timers and drops the ax25/
digipeat references before freeing the neighbour, but never empties
this queue. kfree(rose_neigh) only frees the rose_neigh struct itself
(the sk_buff_head embedded in it is just three next/prev/len words),
not the skbs still linked into it -- every frame still queued here at
that point leaks for good.

rose_remove_neigh() (rose_route.c) already purges this same queue, but
it is only one of about two dozen call sites that can drop the last
reference and trigger the real kfree() in rose_neigh_put() -- every
socket releasing its own rose->neighbour reference (af_rose.c,
rose_in.c, rose_timer.c) can just as well be the one that does. Doing
the purge once, centrally, in rose_neigh_put() itself covers all of
them regardless of which call site happens to be last, rather than
relying on whichever caller happened to remember it.

Matches a leak pattern observed and documented back in May 2026
(mailbbs killed -> rose_release() -> rose_write_internal() ->
rose_transmit_link() queues the CLEAR_REQUEST -> skb never freed),
never root-caused until now.

Deployed and running since 2026-09-13/15 on three independent nodes
(f6bvp-12, f6bvp-8, f6bvp-10 -- three different kernel bases,
6.12.94/6.18.46/6.18.34), no regression observed.

Signed-off-by: F6BVP <bernard.f6bvp@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant