[PATCH net-next 3/5] net: track dst refcnt with obj_cnt
flat view
STALE1772d
From: Xin Long <lucien.xin@gmail.com>
Date: 2021-12-07 04:02:20
Subsystem:
library code, networking [general], networking [sockets], the rest · Maintainers:
Andrew Morton, "David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, Kuniyuki Iwashima, Willem de Bruijn, Linus Torvalds
Two types are added into obj_cnt to count dst_hold* and dst_release*,
and all it does is put obj_cnt_track_by_dev() into these two
functions.
Here is an example to track the refcnt of a dst whose dev is dummy0:
# sysctl -w obj_cnt.control="clear" # clear the old result
# sysctl -w obj_cnt.type=0xc # enable dst_hold/put track
# sysctl -w obj_cnt.name=dummy0 # count dst_hold/put(dst)
# sysctl -w obj_cnt.nr_entries=4 # save 4 frames' call trace
#
# ip link add dummy0 type dummy
# ip link set dummy0 up
# ip addr add 1.1.1.1/24 dev dummy0
# ping 1.1.1.2 -c 2
# ip link set dummy0 down
# ip link del dummy0
# sysctl -w obj_cnt.control="scan" # print the new result
# dmesg
OBJ_CNT: obj_cnt_dump: obj: ffff9e45d7e8b780, type: dst_hold, cnt: 1,:
rt_cache_route+0x45/0xc0
rt_set_nexthop.constprop.63+0x143/0x3c0
ip_route_output_key_hash_rcu+0x256/0x9a0
ip_route_output_key_hash+0x72/0xa0
OBJ_CNT: obj_cnt_dump: obj: ffff9e45cbef9100, type: dst_put, cnt: 1,:
dst_release+0x2a/0x90
__dev_queue_xmit+0x72c/0xc90
ip6_finish_output2+0x2d2/0x660
ip6_output+0x6e/0x130
...
OBJ_CNT: obj_cnt_dump: obj: ffff9e45ca463d00, type: dst_put, cnt: 1,:
dst_release+0x2a/0x90
__dev_queue_xmit+0x72c/0xc90
ip6_finish_output2+0x1e8/0x660
ip6_output+0x6e/0x130
OBJ_CNT: obj_cnt_dump: obj: ffff9e45d7e8b780, type: dst_hold, cnt: 2,:
ip_route_output_key_hash_rcu+0x88e/0x9a0
ip_route_output_key_hash+0x72/0xa0
ip_route_output_flow+0x19/0x50
raw_sendmsg+0x32b/0xe40
...
Signed-off-by: Xin Long <lucien.xin@gmail.com>
---
include/linux/obj_cnt.h | 2 ++
include/net/dst.h | 8 +++++++-
include/net/sock.h | 3 ++-
lib/obj_cnt.c | 4 +++-
net/core/dst.c | 2 ++
5 files changed, 16 insertions(+), 3 deletions(-)
diff --git a/include/linux/obj_cnt.h b/include/linux/obj_cnt.h
index bb2d37484a32..ae4c12beb876 100644
--- a/include/linux/obj_cnt.h
+++ b/include/linux/obj_cnt.h@@ -5,6 +5,8 @@ enum { OBJ_CNT_DEV_HOLD, OBJ_CNT_DEV_PUT, + OBJ_CNT_DST_HOLD, + OBJ_CNT_DST_PUT, OBJ_CNT_TYPE_MAX };
diff --git a/include/net/dst.h b/include/net/dst.h
index 6aa252c3fc55..e2704495d32f 100644
--- a/include/net/dst.h
+++ b/include/net/dst.h@@ -227,6 +227,7 @@ static inline void dst_hold(struct dst_entry *dst) * If your kernel compilation stops here, please check * the placement of __refcnt in struct dst_entry */ + obj_cnt_track_by_dev(dst, dst->dev, OBJ_CNT_DST_HOLD); BUILD_BUG_ON(offsetof(struct dst_entry, __refcnt) & 63); WARN_ON(atomic_inc_not_zero(&dst->__refcnt) == 0); }
@@ -298,7 +299,12 @@ 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 atomic_inc_not_zero(&dst->__refcnt); + if (atomic_inc_not_zero(&dst->__refcnt)) { + obj_cnt_track_by_dev(dst, dst->dev, OBJ_CNT_DST_HOLD); + return true; + } + + return false; } /**
diff --git a/include/net/sock.h b/include/net/sock.h
index ae61cd0b650d..07d59c27ac11 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h@@ -2071,8 +2071,9 @@ sk_dst_get(struct sock *sk) rcu_read_lock(); dst = rcu_dereference(sk->sk_dst_cache); - if (dst && !atomic_inc_not_zero(&dst->__refcnt)) + if (dst && !dst_hold_safe(dst)) dst = NULL; + rcu_read_unlock(); return dst; }
diff --git a/lib/obj_cnt.c b/lib/obj_cnt.c
index 12a1fdafd632..648adc135080 100644
--- a/lib/obj_cnt.c
+++ b/lib/obj_cnt.c@@ -16,7 +16,9 @@ static spinlock_t obj_cnt_lock; static char *obj_cnt_str[OBJ_CNT_TYPE_MAX] = { "dev_hold", - "dev_put" + "dev_put", + "dst_hold", + "dst_put" }; struct obj_cnt {
diff --git a/net/core/dst.c b/net/core/dst.c
index d16c2c9bfebd..94ff1fe0fc09 100644
--- a/net/core/dst.c
+++ b/net/core/dst.c@@ -169,6 +169,7 @@ void dst_release(struct dst_entry *dst) if (dst) { int newrefcnt; + obj_cnt_track_by_dev(dst, dst->dev, OBJ_CNT_DST_PUT); newrefcnt = atomic_dec_return(&dst->__refcnt); if (WARN_ONCE(newrefcnt < 0, "dst_release underflow")) net_warn_ratelimited("%s: dst:%p refcnt:%d\n",
@@ -184,6 +185,7 @@ void dst_release_immediate(struct dst_entry *dst) if (dst) { int newrefcnt; + obj_cnt_track_by_dev(dst, dst->dev, OBJ_CNT_DST_PUT); newrefcnt = atomic_dec_return(&dst->__refcnt); if (WARN_ONCE(newrefcnt < 0, "dst_release_immediate underflow")) net_warn_ratelimited("%s: dst:%p refcnt:%d\n",
--
2.27.0