summaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
authorMark Brown <broonie@kernel.org>2026-07-03 16:21:11 +0100
committerMark Brown <broonie@kernel.org>2026-07-03 16:21:11 +0100
commite1c68a43919d23be3c16bd28e080b381f769eadf (patch)
treebc927a25506f73d9d3cb4d0cf6c20c55a4cd8533 /include
parent586fdefdc281411252ac7266aa4aeb69dd300dd9 (diff)
parent110ef9f94f84d425ab55d09b2d70ed12ceffdf08 (diff)
downloadlinux-next-e1c68a43919d23be3c16bd28e080b381f769eadf.tar.gz
linux-next-e1c68a43919d23be3c16bd28e080b381f769eadf.zip
Merge branch 'master' of git://git.code.sf.net/p/tomoyo/tomoyo.git
Diffstat (limited to 'include')
-rw-r--r--include/linux/netdevice.h15
-rw-r--r--include/net/dst.h22
-rw-r--r--include/net/sock.h8
3 files changed, 41 insertions, 4 deletions
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 9981d637f8b5..987c3c87f14f 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -2142,6 +2142,8 @@ enum netdev_reg_state {
*
* FIXME: cleanup struct net_device such that network protocol info
* moves out.
+ *
+ * @netdev_trace_buffer_list: Linked list for debugging refcount leak.
*/
struct net_device {
@@ -2298,6 +2300,9 @@ struct net_device {
#if IS_ENABLED(CONFIG_TLS_DEVICE)
const struct tlsdev_ops *tlsdev_ops;
#endif
+#ifdef CONFIG_NET_DEV_REFCNT_TRACKER
+ struct list_head netdev_trace_buffer_list;
+#endif
unsigned int operstate;
unsigned char link_mode;
@@ -3248,6 +3253,7 @@ enum netdev_cmd {
NETDEV_OFFLOAD_XSTATS_REPORT_USED,
NETDEV_OFFLOAD_XSTATS_REPORT_DELTA,
NETDEV_XDP_FEAT_CHANGE,
+ NETDEV_DEBUG_UNREGISTER,
};
const char *netdev_cmd_to_name(enum netdev_cmd cmd);
@@ -4469,9 +4475,15 @@ static inline bool dev_nit_active(const struct net_device *dev)
void dev_queue_xmit_nit(struct sk_buff *skb, struct net_device *dev);
+void save_netdev_trace_buffer(struct net_device *dev, int delta);
+int trim_netdev_trace(unsigned long *entries, int nr_entries);
+
static inline void __dev_put(struct net_device *dev)
{
if (dev) {
+#ifdef CONFIG_NET_DEV_REFCNT_TRACKER
+ save_netdev_trace_buffer(dev, -1);
+#endif
#ifdef CONFIG_PCPU_DEV_REFCNT
this_cpu_dec(*dev->pcpu_refcnt);
#else
@@ -4483,6 +4495,9 @@ static inline void __dev_put(struct net_device *dev)
static inline void __dev_hold(struct net_device *dev)
{
if (dev) {
+#ifdef CONFIG_NET_DEV_REFCNT_TRACKER
+ save_netdev_trace_buffer(dev, 1);
+#endif
#ifdef CONFIG_PCPU_DEV_REFCNT
this_cpu_inc(*dev->pcpu_refcnt);
#else
diff --git a/include/net/dst.h b/include/net/dst.h
index 307073eae7f8..10b73fb45117 100644
--- a/include/net/dst.h
+++ b/include/net/dst.h
@@ -95,8 +95,19 @@ struct dst_entry {
#ifdef CONFIG_64BIT
struct lwtunnel_state *lwtstate;
#endif
+#ifdef CONFIG_NET_DEV_REFCNT_TRACKER
+ atomic_t dst_trace_seq;
+#endif
};
+#ifdef CONFIG_NET_DEV_REFCNT_TRACKER
+void save_dst_trace_buffer(struct dst_entry *dst, int delta);
+void dump_dst_trace_buffer(const struct net_device *dev);
+#else
+static inline void save_dst_trace_buffer(struct dst_entry *dst, int delta) { };
+static inline void dump_dst_trace_buffer(const struct net_device *dev) { };
+#endif
+
struct dst_metrics {
u32 metrics[RTAX_MAX];
refcount_t refcnt;
@@ -244,7 +255,10 @@ static inline void dst_hold(struct dst_entry *dst)
* the placement of __rcuref in struct dst_entry
*/
BUILD_BUG_ON(offsetof(struct dst_entry, __rcuref) & 63);
- WARN_ON(!rcuref_get(&dst->__rcuref));
+ if (!rcuref_get(&dst->__rcuref))
+ WARN_ON(1);
+ else
+ save_dst_trace_buffer(dst, 1);
}
static inline void dst_use_noref(struct dst_entry *dst, unsigned long time)
@@ -308,7 +322,11 @@ static inline void skb_dst_copy(struct sk_buff *nskb, const struct sk_buff *oskb
*/
static inline bool dst_hold_safe(struct dst_entry *dst)
{
- return rcuref_get(&dst->__rcuref);
+ const bool ret = rcuref_get(&dst->__rcuref);
+
+ if (ret)
+ save_dst_trace_buffer(dst, 1);
+ return ret;
}
/**
diff --git a/include/net/sock.h b/include/net/sock.h
index 51185222aac2..a043fd422089 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -2206,8 +2206,12 @@ sk_dst_get(const struct sock *sk)
rcu_read_lock();
dst = rcu_dereference(sk->sk_dst_cache);
- if (dst && !rcuref_get(&dst->__rcuref))
- dst = NULL;
+ if (dst) {
+ if (!rcuref_get(&dst->__rcuref))
+ dst = NULL;
+ else
+ save_dst_trace_buffer(dst, 1);
+ }
rcu_read_unlock();
return dst;
}