FAILED: patch "[PATCH] net: netpoll: fix incorrect refcount handling causing" failed to apply to 6.6-stable tree
Subsystems (2)
[email protected]
maintainerThe patch below does not apply to the 6.6-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-6.6.y
git checkout FETCH_HEAD
git cherry-pick -x 49c8d2c1f94cc2f4d1a108530d7ba52614b874c2
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2025112006-author-harmony-d5f7@gregkh' --subject-prefix 'PATCH 6.6.y' HEAD^..
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From 49c8d2c1f94cc2f4d1a108530d7ba52614b874c2 Mon Sep 17 00:00:00 2001
From: Breno Leitao <[email protected]>
Date: Fri, 7 Nov 2025 06:03:37 -0800
Subject: [PATCH] net: netpoll: fix incorrect refcount handling causing
incorrect cleanup
commit efa95b01da18 ("netpoll: fix use after free") incorrectly ignored the refcount and prematurely set dev->npinfo to NULL during netpoll cleanup, leading to improper behavior and memory leaks.
Scenario causing lack of proper cleanup:
1) A netpoll is associated with a NIC (e.g., eth0) and netdev->npinfo is allocated, and refcnt = 1
- Keep in mind that npinfo is shared among all netpoll instances. In this case, there is just one.
2) Another netpoll is also associated with the same NIC and npinfo->refcnt += 1.
- Now dev->npinfo->refcnt = 2;
- There is just one npinfo associated to the netdev.
3) When the first netpolls goes to clean up:
- The first cleanup succeeds and clears np->dev->npinfo, ignoring refcnt.
- It basically calls RCU_INIT_POINTER(np->dev->npinfo, NULL);
- Set dev->npinfo = NULL, without proper cleanup
- No ->ndo_netpoll_cleanup() is either called
4) Now the second target tries to clean up
- The second cleanup fails because np->dev->npinfo is already NULL.
* In this case, ops->ndo_netpoll_cleanup() was never called, and the skb pool is not cleaned as well (for the second netpoll instance)
- This leaks npinfo and skbpool skbs, which is clearly reported by kmemleak.
Revert commit efa95b01da18 ("netpoll: fix use after free") and adds clarifying comments emphasizing that npinfo cleanup should only happen once the refcount reaches zero, ensuring stable and correct netpoll behavior.
net/core/netpoll.c +5 -2
@@ -811,6 +811,10 @@ static void __netpoll_cleanup(struct netpoll *np)if (!npinfo)return ; +/* At this point, there is a single npinfo instance per netdevice, and +* its refcnt tracks how many netpoll structures are linked to it. We +* only perform npinfo cleanup when the refcnt decrements to zero. +*/ if (refcount_dec_and_test (&npinfo->refcnt)) {const struct net_device_ops *ops;
@@ -820,8 +824,7 @@ static void __netpoll_cleanup(struct netpoll *np)RCU_INIT_POINTER (np->dev->npinfo,NULL );call_rcu (&npinfo->rcu, rcu_cleanup_netpoll_info); - }else -RCU_INIT_POINTER (np->dev->npinfo,NULL ); + }skb_pool_flush (np); }
Sasha Levin
maintainerPATCH 1/4 netpoll: remove netpoll_srcu
From: Eric Dumazet <[email protected]>
[ Upstream commit 9a95eedc81deb86af1ac56f2c2bfe8306b27b82a ]
netpoll_srcu is currently used from netpoll_poll_disable() and __netpoll_cleanup()
Both functions run under RTNL, using netpoll_srcu adds confusion and no additional protection.
Moreover the synchronize_srcu() call in __netpoll_cleanup() is performed before clearing np->dev->npinfo, which violates RCU rules.
After this patch, netpoll_poll_disable() and netpoll_poll_enable() simply use rtnl_dereference().
This saves a big chunk of memory (more than 192KB on platforms with 512 cpus)
Stable-dep-of: 49c8d2c1f94c ("net: netpoll: fix incorrect refcount handling causing incorrect cleanup")
--- net/core/netpoll.c | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-)
net/core/netpoll.c +4 -11
@@ -48,8 +48,6 @@static struct sk_buff_head skb_pool; -DEFINE_STATIC_SRCU (netpoll_srcu); -#define USEC_PER_POLL 50#define MAX_SKB_SIZE \
@@ -220,24 +218,21 @@ EXPORT_SYMBOL(netpoll_poll_dev);void netpoll_poll_disable (struct net_device *dev) {struct netpoll_info *ni; -int idx; +might_sleep (); - idx =srcu_read_lock (&netpoll_srcu); - ni =srcu_dereference (dev->npinfo, &netpoll_srcu); + ni =rtnl_dereference (dev->npinfo);if (ni)down (&ni->dev_lock); -srcu_read_unlock (&netpoll_srcu, idx); }EXPORT_SYMBOL (netpoll_poll_disable);void netpoll_poll_enable (struct net_device *dev) {struct netpoll_info *ni; -rcu_read_lock (); - ni =rcu_dereference (dev->npinfo); + + ni =rtnl_dereference (dev->npinfo);if (ni)up (&ni->dev_lock); -rcu_read_unlock (); }EXPORT_SYMBOL (netpoll_poll_enable);
@@ -843,8 +838,6 @@ void __netpoll_cleanup(struct netpoll *np)if (!npinfo)return ; -synchronize_srcu (&netpoll_srcu); -if (refcount_dec_and_test (&npinfo->refcnt)) {const struct net_device_ops *ops;
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 2/4 net: netpoll: Individualize the skb pool
From: Breno Leitao <[email protected]>
[ Upstream commit 221a9c1df790fa711d65daf5ba05d0addc279153 ]
The current implementation of the netpoll system uses a global skb pool, which can lead to inefficient memory usage and waste when targets are disabled or no longer in use.
This can result in a significant amount of memory being unnecessarily allocated and retained, potentially causing performance issues and limiting the availability of resources for other system components.
Modify the netpoll system to assign a skb pool to each target instead of using a global one.
This approach allows for more fine-grained control over memory allocation and deallocation, ensuring that resources are only allocated and retained as needed.
Stable-dep-of: 49c8d2c1f94c ("net: netpoll: fix incorrect refcount handling causing incorrect cleanup")
--- include/linux/netpoll.h | 1 + net/core/netpoll.c | 31 +++++++++++++------------------ 2 files changed, 14 insertions(+), 18 deletions(-)
include/linux/netpoll.h +1 -0
@@ -32,6 +32,7 @@ struct netpoll {bool ipv6;u16 local_port, remote_port;u8 remote_mac[ETH_ALEN ]; +struct sk_buff_head skb_pool; };struct netpoll_info {
net/core/netpoll.c +13 -18
@@ -45,9 +45,6 @@#define MAX_UDP_CHUNK 1460#define MAX_SKBS 32 - -static struct sk_buff_head skb_pool; -#define USEC_PER_POLL 50#define MAX_SKB_SIZE \
@@ -236,20 +233,23 @@ void netpoll_poll_enable(struct net_device *dev) }EXPORT_SYMBOL (netpoll_poll_enable); -static void refill_skbs (void ) +static void refill_skbs (struct netpoll *np) { +struct sk_buff_head *skb_pool;struct sk_buff *skb;unsigned long flags; -spin_lock_irqsave (&skb_pool.lock, flags); -while (skb_pool.qlen <MAX_SKBS ) { + skb_pool = &np->skb_pool; + +spin_lock_irqsave (&skb_pool->lock, flags); +while (skb_pool->qlen <MAX_SKBS ) { skb =alloc_skb (MAX_SKB_SIZE ,GFP_ATOMIC );if (!skb)break ; -__skb_queue_tail (&skb_pool, skb); +__skb_queue_tail (skb_pool, skb); } -spin_unlock_irqrestore (&skb_pool.lock, flags); +spin_unlock_irqrestore (&skb_pool->lock, flags); }static void zap_completion_queue (void )
@@ -286,12 +286,12 @@ static struct sk_buff *find_skb(struct netpoll *np, int len, int reserve)struct sk_buff *skb;zap_completion_queue (); -refill_skbs (); +refill_skbs (np); repeat: skb =alloc_skb (len,GFP_ATOMIC );if (!skb) - skb =skb_dequeue (&skb_pool); + skb =skb_dequeue (&np->skb_pool);if (!skb) {if (++count <10 ) {
@@ -680,6 +680,8 @@ int netpoll_setup(struct netpoll *np)struct in_device *in_dev;int err; +skb_queue_head_init (&np->skb_pool); +rtnl_lock ();if (np->dev_name[0 ]) {struct net *net = current->nsproxy->net_ns;
@@ -780,7 +782,7 @@ int netpoll_setup(struct netpoll *np) }/* fill up the skb queue */ -refill_skbs (); +refill_skbs (np); err =__netpoll_setup (np, ndev);if (err)
@@ -806,13 +808,6 @@ int netpoll_setup(struct netpoll *np) }EXPORT_SYMBOL (netpoll_setup); -static int __init netpoll_init (void ) -{ -skb_queue_head_init (&skb_pool); -return 0 ; -} -core_initcall (netpoll_init); -static void rcu_cleanup_netpoll_info (struct rcu_head *rcu_head) { struct netpoll_info *npinfo =
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 3/4 net: netpoll: flush skb pool during cleanup
In reply to Sasha LevinFrom: Breno Leitao <[email protected]>
[ Upstream commit 6c59f16f1770481a6ee684720ec55b1e38b3a4b2 ]
The netpoll subsystem maintains a pool of 32 pre-allocated SKBs per instance, but these SKBs are not freed when the netpoll user is brought down. This leads to memory waste as these buffers remain allocated but unused.
Add skb_pool_flush() to properly clean up these SKBs when netconsole is terminated, improving memory efficiency.
Stable-dep-of: 49c8d2c1f94c ("net: netpoll: fix incorrect refcount handling causing incorrect cleanup")
--- net/core/netpoll.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-)
net/core/netpoll.c +13 -1
@@ -538,6 +538,14 @@ static int netpoll_parse_ip_addr(const char *str, union inet_addr *addr)return -1 ; } +static void skb_pool_flush (struct netpoll *np) +{ +struct sk_buff_head *skb_pool; + + skb_pool = &np->skb_pool; +skb_queue_purge_reason (skb_pool,SKB_CONSUMED ); +} +int netpoll_parse_options (struct netpoll *np,char *opt) {char *cur=opt, *delim;
@@ -786,7 +794,7 @@ int netpoll_setup(struct netpoll *np) err =__netpoll_setup (np, ndev);if (err) - goto put; + goto flush;rtnl_unlock ();/* Make sure all NAPI polls which started before dev->npinfo
@@ -797,6 +805,8 @@ int netpoll_setup(struct netpoll *np)return 0 ; +flush: +skb_pool_flush (np); put:DEBUG_NET_WARN_ON_ONCE (np->dev);if (ip_overwritten)
@@ -844,6 +854,8 @@ void __netpoll_cleanup(struct netpoll *np)call_rcu (&npinfo->rcu, rcu_cleanup_netpoll_info); }else RCU_INIT_POINTER (np->dev->npinfo,NULL ); + +skb_pool_flush (np); }EXPORT_SYMBOL_GPL (__netpoll_cleanup);
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 4/4 net: netpoll: fix incorrect refcount handling causing incorrect cleanup
In reply to Sasha LevinFrom: Breno Leitao <[email protected]>
[ Upstream commit 49c8d2c1f94cc2f4d1a108530d7ba52614b874c2 ]
commit efa95b01da18 ("netpoll: fix use after free") incorrectly ignored the refcount and prematurely set dev->npinfo to NULL during netpoll cleanup, leading to improper behavior and memory leaks.
Scenario causing lack of proper cleanup:
1) A netpoll is associated with a NIC (e.g., eth0) and netdev->npinfo is allocated, and refcnt = 1
- Keep in mind that npinfo is shared among all netpoll instances. In this case, there is just one.
2) Another netpoll is also associated with the same NIC and npinfo->refcnt += 1.
- Now dev->npinfo->refcnt = 2;
- There is just one npinfo associated to the netdev.
3) When the first netpolls goes to clean up:
- The first cleanup succeeds and clears np->dev->npinfo, ignoring refcnt.
- It basically calls RCU_INIT_POINTER(np->dev->npinfo, NULL);
- Set dev->npinfo = NULL, without proper cleanup
- No ->ndo_netpoll_cleanup() is either called
4) Now the second target tries to clean up
- The second cleanup fails because np->dev->npinfo is already NULL.
* In this case, ops->ndo_netpoll_cleanup() was never called, and the skb pool is not cleaned as well (for the second netpoll instance)
- This leaks npinfo and skbpool skbs, which is clearly reported by kmemleak.
Revert commit efa95b01da18 ("netpoll: fix use after free") and adds clarifying comments emphasizing that npinfo cleanup should only happen once the refcount reaches zero, ensuring stable and correct netpoll behavior.
--- net/core/netpoll.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-)
net/core/netpoll.c +5 -2
@@ -843,6 +843,10 @@ void __netpoll_cleanup(struct netpoll *np)if (!npinfo)return ; +/* At this point, there is a single npinfo instance per netdevice, and +* its refcnt tracks how many netpoll structures are linked to it. We +* only perform npinfo cleanup when the refcnt decrements to zero. +*/ if (refcount_dec_and_test (&npinfo->refcnt)) {const struct net_device_ops *ops;
@@ -852,8 +856,7 @@ void __netpoll_cleanup(struct netpoll *np)RCU_INIT_POINTER (np->dev->npinfo,NULL );call_rcu (&npinfo->rcu, rcu_cleanup_netpoll_info); - }else -RCU_INIT_POINTER (np->dev->npinfo,NULL ); + }skb_pool_flush (np); }
Signature · 1 line
2.51.0