The Linux Kernel Mailing List
 help / color / mirror / Atom feed
* [PATCH net 0/2] Fix ref_tracker warnings at boot
@ 2026-07-31  3:51 Jiangshan Yi
  2026-07-31  3:51 ` [PATCH net 1/2] net: cancel pending netdev_work on device unregistration Jiangshan Yi
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Jiangshan Yi @ 2026-07-31  3:51 UTC (permalink / raw)
  To: andrew+netdev, davem, edumazet, kuba, pabeni
  Cc: horms, netdev, linux-kernel, 13667453960, Jiangshan Yi

This series fixes two ref_tracker warnings that appear at boot on
both TCG and KVM:

  WARNING: lib/ref_tracker.c:322 at ref_tracker_free
  WARNING: lib/ref_tracker.c:246 at ref_tracker_dir_exit

Patch 1 fixes the root cause: pending netdev_work is not canceled
during device unregistration, leaving a stale work_tracker.  When
netdev_work_proc() later runs during the RTNL release window of
netdev_wait_allrefs_any(), it triggers the double-free and leak
warnings.

Patch 2 is a defensive hardening: netdev_put() unconditionally calls
__dev_put() even when ref_tracker_free() returns -EINVAL (double-free),
over-decrementing the device refcount.  While patch 1 prevents the
double-free from occurring in the netdev_work path, patch 2 ensures
that any double-free from any source does not corrupt the refcount.

Tested on KVM (16 vCPU, 8 GB RAM) with KASAN/UBSAN/KFENCE enabled:
  Before: 2 ref_tracker WARNINGs, 80 UBSAN reports
  After:  0 WARNINGs, 53 UBSAN reports (23 network-related fixed)
          0 KASAN, 0 BUG, no regressions

Jiangshan Yi (2):
  net: cancel pending netdev_work on device unregistration
  net: guard refcount against tracker double-free

 include/linux/netdevice.h | 19 ++++++++++++-------
 net/core/dev.c            |  2 +-
 net/core/dev.h            |  2 ++
 net/core/netdev_work.c    | 10 ++++++++++
 4 files changed, 25 insertions(+), 8 deletions(-)

-- 
2.25.1

^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH net 1/2] net: cancel pending netdev_work on device unregistration
  2026-07-31  3:51 [PATCH net 0/2] Fix ref_tracker warnings at boot Jiangshan Yi
@ 2026-07-31  3:51 ` Jiangshan Yi
  2026-07-31  3:51 ` [PATCH net 2/2] net: guard refcount against tracker double-free Jiangshan Yi
  2026-08-06  2:27 ` [PATCH net 0/2] Fix ref_tracker warnings at boot Jakub Kicinski
  2 siblings, 0 replies; 4+ messages in thread
From: Jiangshan Yi @ 2026-07-31  3:51 UTC (permalink / raw)
  To: andrew+netdev, davem, edumazet, kuba, pabeni
  Cc: horms, netdev, linux-kernel, 13667453960, Jiangshan Yi, stable

When a netdev is unregistered, pending netdev_work events are not
explicitly canceled.  Only events cleared by ndo_stop() (e.g.
VLAN_WORK_LINK_STATE) are handled; core events like
NETDEV_WORK_RX_MODE and driver events like VLAN_WORK_MTU /
VLAN_WORK_FEATURES remain pending, keeping a tracked reference
(dev->work_tracker) on the device.

During netdev_wait_allrefs_any(), RTNL is released to let the system
workqueue run.  netdev_work_proc() may then attempt to process the
stale work_tracker, triggering ref_tracker warnings at boot:

  WARNING: lib/ref_tracker.c:322 at ref_tracker_free
  WARNING: lib/ref_tracker.c:246 at ref_tracker_dir_exit

Add netdev_work_cancel_all() to cancel all pending core and driver
work, releasing the work_tracker before the device enters
netdev_run_todo().  Call it from unregister_netdevice_many_notify()
after rx_mode cleanup.

This is safe because netdev_work_cancel_all() runs under RTNL in
unregister_netdevice_many_notify(), and netdev_work_proc() also
requires RTNL, so the two cannot execute concurrently.  If
netdev_work_proc() has already dequeued the device, the cancel is a
no-op; otherwise it releases the tracker before the device enters
netdev_run_todo().

Fixes: 12c765be84d2 ("net: turn the rx_mode work into a generic netdev_work facility")
Cc: stable@vger.kernel.org
Signed-off-by: Jiangshan Yi <yijiangshan@kylinos.cn>
---
 net/core/dev.c         |  2 +-
 net/core/dev.h         |  2 ++
 net/core/netdev_work.c | 10 ++++++++++
 3 files changed, 13 insertions(+), 1 deletion(-)

diff --git a/net/core/dev.c b/net/core/dev.c
index 5933c5d..b461b01 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -12456,7 +12456,7 @@ void unregister_netdevice_many_notify(struct list_head *head,
 		dev_uc_flush(dev);
 		dev_mc_flush(dev);
 
-
+		netdev_work_cancel_all(dev);
 		netdev_rss_contexts_free(dev);
 
 		call_netdevice_notifiers(NETDEV_PRE_UNINIT, dev);
diff --git a/net/core/dev.h b/net/core/dev.h
index 5d0b030..d3ac3ba 100644
--- a/net/core/dev.h
+++ b/net/core/dev.h
@@ -180,6 +180,8 @@ void __netdev_work_core_sched(struct net_device *dev, unsigned long event);
 unsigned long
 __netdev_work_core_cancel(struct net_device *dev, unsigned long mask);
 
+void netdev_work_cancel_all(struct net_device *dev);
+
 void __dev_notify_flags(struct net_device *dev, unsigned int old_flags,
 			unsigned int gchanges, u32 portid,
 			const struct nlmsghdr *nlh);
diff --git a/net/core/netdev_work.c b/net/core/netdev_work.c
index 3109fae..d69363d 100644
--- a/net/core/netdev_work.c
+++ b/net/core/netdev_work.c
@@ -99,6 +99,16 @@ __netdev_work_core_cancel(struct net_device *dev, unsigned long mask)
 	return netdev_work_dequeue(dev, &dev->work_core_pending, mask);
 }
 
+/* Cancel all pending core and driver work and release the work_tracker
+ * reference.  Must be called under RTNL, which mutually excludes
+ * netdev_work_proc().
+ */
+void netdev_work_cancel_all(struct net_device *dev)
+{
+	__netdev_work_core_cancel(dev, ~0UL);
+	netdev_work_cancel(dev, ~0UL);
+}
+
 static void netdev_work_run(struct net_device *dev, unsigned long events,
 			    unsigned long core)
 {
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH net 2/2] net: guard refcount against tracker double-free
  2026-07-31  3:51 [PATCH net 0/2] Fix ref_tracker warnings at boot Jiangshan Yi
  2026-07-31  3:51 ` [PATCH net 1/2] net: cancel pending netdev_work on device unregistration Jiangshan Yi
@ 2026-07-31  3:51 ` Jiangshan Yi
  2026-08-06  2:27 ` [PATCH net 0/2] Fix ref_tracker warnings at boot Jakub Kicinski
  2 siblings, 0 replies; 4+ messages in thread
From: Jiangshan Yi @ 2026-07-31  3:51 UTC (permalink / raw)
  To: andrew+netdev, davem, edumazet, kuba, pabeni
  Cc: horms, netdev, linux-kernel, 13667453960, Jiangshan Yi, stable

As a defensive measure, guard netdev_put() and netdev_ref_replace()
against refcount corruption when ref_tracker_free() returns -EINVAL
(tracker already freed).  Currently __dev_put() is called
unconditionally, which over-decrements the device refcount on a
double-free and can cause netdev_wait_allrefs_any() to return
prematurely.

Change netdev_tracker_free() to return int so callers can detect
the -EINVAL case.  In netdev_put() and netdev_ref_replace(), skip
__dev_put() when the tracker was already freed; ref_tracker_free()
has already warned and the first successful free already decremented
the refcount.  The -EEXIST case (NULL tracker, untracked reference)
still calls __dev_put(), preserving existing behavior.

Fixes: f12bf6f3f942 ("net: watchdog: add net device refcount tracker")
Cc: stable@vger.kernel.org
Signed-off-by: Jiangshan Yi <yijiangshan@kylinos.cn>
---
 include/linux/netdevice.h | 19 ++++++++++++-------
 1 file changed, 12 insertions(+), 7 deletions(-)

diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 9981d63..5e8cf3f 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -4512,11 +4512,13 @@ static inline void netdev_tracker_alloc(struct net_device *dev,
 #endif
 }
 
-static inline void netdev_tracker_free(struct net_device *dev,
+static inline int netdev_tracker_free(struct net_device *dev,
 				       netdevice_tracker *tracker)
 {
 #ifdef CONFIG_NET_DEV_REFCNT_TRACKER
-	ref_tracker_free(&dev->refcnt_tracker, tracker);
+	return ref_tracker_free(&dev->refcnt_tracker, tracker);
+#else
+	return 0;
 #endif
 }
 
@@ -4533,8 +4535,12 @@ static inline void netdev_put(struct net_device *dev,
 			      netdevice_tracker *tracker)
 {
 	if (dev) {
-		netdev_tracker_free(dev, tracker);
-		__dev_put(dev);
+		/* Skip __dev_put() on -EINVAL: ref_tracker_free() already
+		 * warned and the refcount was decremented by the first
+		 * successful free.
+		 */
+		if (netdev_tracker_free(dev, tracker) != -EINVAL)
+			__dev_put(dev);
 	}
 }
 
@@ -4569,11 +4575,10 @@ static inline void netdev_ref_replace(struct net_device *odev,
 				      netdevice_tracker *tracker,
 				      gfp_t gfp)
 {
-	if (odev)
-		netdev_tracker_free(odev, tracker);
+	if (odev && netdev_tracker_free(odev, tracker) != -EINVAL)
+		__dev_put(odev);
 
 	__dev_hold(ndev);
-	__dev_put(odev);
 
 	if (ndev)
 		__netdev_tracker_alloc(ndev, tracker, gfp);
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [PATCH net 0/2] Fix ref_tracker warnings at boot
  2026-07-31  3:51 [PATCH net 0/2] Fix ref_tracker warnings at boot Jiangshan Yi
  2026-07-31  3:51 ` [PATCH net 1/2] net: cancel pending netdev_work on device unregistration Jiangshan Yi
  2026-07-31  3:51 ` [PATCH net 2/2] net: guard refcount against tracker double-free Jiangshan Yi
@ 2026-08-06  2:27 ` Jakub Kicinski
  2 siblings, 0 replies; 4+ messages in thread
From: Jakub Kicinski @ 2026-08-06  2:27 UTC (permalink / raw)
  To: Jiangshan Yi
  Cc: andrew+netdev, davem, edumazet, pabeni, horms, netdev,
	linux-kernel, 13667453960

On Fri, 31 Jul 2026 11:51:33 +0800 Jiangshan Yi wrote:
> This series fixes two ref_tracker warnings that appear at boot on
> both TCG and KVM:
> 
>   WARNING: lib/ref_tracker.c:322 at ref_tracker_free
>   WARNING: lib/ref_tracker.c:246 at ref_tracker_dir_exit

Thanks for the report, I've been siting on a fix for this.
Let me send mine out.

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2026-08-06  2:27 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-31  3:51 [PATCH net 0/2] Fix ref_tracker warnings at boot Jiangshan Yi
2026-07-31  3:51 ` [PATCH net 1/2] net: cancel pending netdev_work on device unregistration Jiangshan Yi
2026-07-31  3:51 ` [PATCH net 2/2] net: guard refcount against tracker double-free Jiangshan Yi
2026-08-06  2:27 ` [PATCH net 0/2] Fix ref_tracker warnings at boot Jakub Kicinski

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox