diff mbox series

[net-next,3/5] net: track dst refcnt with obj_cnt

Message ID 9dc7efe678baaafb5203da0c1f2b1127e88e81c5.1638849511.git.lucien.xin@gmail.com (mailing list archive)
State RFC
Delegated to: Netdev Maintainers
Headers show
Series net: add refcnt tracking for some common objects | expand

Checks

Context Check Description
netdev/tree_selection success Clearly marked for net-next
netdev/fixes_present success Fixes tag not required for -next series
netdev/subject_prefix success Link
netdev/cover_letter success Series has a cover letter
netdev/patch_count success Link
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit success Errors and warnings before: 4757 this patch: 4757
netdev/cc_maintainers warning 1 maintainers not CCed: daniel@iogearbox.net
netdev/build_clang success Errors and warnings before: 852 this patch: 852
netdev/module_param success Was 0 now: 0
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/verify_fixes success No Fixes tag
netdev/build_allmodconfig_warn success Errors and warnings before: 4911 this patch: 4911
netdev/checkpatch success total: 0 errors, 0 warnings, 0 checks, 62 lines checked
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/source_inline success Was 0 now: 0

Commit Message

Xin Long Dec. 7, 2021, 4:02 a.m. UTC
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 mbox series

Patch

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",