diff options
| author | Mark Brown <broonie@kernel.org> | 2026-07-03 16:21:11 +0100 |
|---|---|---|
| committer | Mark Brown <broonie@kernel.org> | 2026-07-03 16:21:11 +0100 |
| commit | e1c68a43919d23be3c16bd28e080b381f769eadf (patch) | |
| tree | bc927a25506f73d9d3cb4d0cf6c20c55a4cd8533 /include | |
| parent | 586fdefdc281411252ac7266aa4aeb69dd300dd9 (diff) | |
| parent | 110ef9f94f84d425ab55d09b2d70ed12ceffdf08 (diff) | |
| download | linux-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.h | 15 | ||||
| -rw-r--r-- | include/net/dst.h | 22 | ||||
| -rw-r--r-- | include/net/sock.h | 8 |
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; } |
