aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2016-08-23 10:27:24 -0400
committerDavid Howells <dhowells@redhat.com>2016-08-23 10:27:24 -0400
commitdf844fd46b98c2efde8f4ac2d50d59bc90c4c679 (patch)
tree0a067071fa1bf6fe2fc41de100d822e9585289a0
parent01a90a459850ed1f1573f06f00f7b9d466339df0 (diff)
rxrpc: Use a tracepoint for skb accounting debugging
Use a tracepoint to log various skb accounting points to help in debugging refcounting errors. Signed-off-by: David Howells <dhowells@redhat.com>
-rw-r--r--include/trace/events/rxrpc.h56
-rw-r--r--net/rxrpc/af_rxrpc.c1
-rw-r--r--net/rxrpc/ar-internal.h45
-rw-r--r--net/rxrpc/call_accept.c1
-rw-r--r--net/rxrpc/call_event.c3
-rw-r--r--net/rxrpc/conn_event.c2
-rw-r--r--net/rxrpc/local_event.c1
-rw-r--r--net/rxrpc/output.c1
-rw-r--r--net/rxrpc/recvmsg.c1
-rw-r--r--net/rxrpc/skbuff.c62
10 files changed, 135 insertions, 38 deletions
diff --git a/include/trace/events/rxrpc.h b/include/trace/events/rxrpc.h
new file mode 100644
index 000000000000..15283ee3e41a
--- /dev/null
+++ b/include/trace/events/rxrpc.h
@@ -0,0 +1,56 @@
1/* AF_RXRPC tracepoints
2 *
3 * Copyright (C) 2016 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public Licence
8 * as published by the Free Software Foundation; either version
9 * 2 of the Licence, or (at your option) any later version.
10 */
11#undef TRACE_SYSTEM
12#define TRACE_SYSTEM rxrpc
13
14#if !defined(_TRACE_RXRPC_H) || defined(TRACE_HEADER_MULTI_READ)
15#define _TRACE_RXRPC_H
16
17#include <linux/tracepoint.h>
18
19TRACE_EVENT(rxrpc_skb,
20 TP_PROTO(struct sk_buff *skb, int op, int usage, int mod_count,
21 const void *where),
22
23 TP_ARGS(skb, op, usage, mod_count, where),
24
25 TP_STRUCT__entry(
26 __field(struct sk_buff *, skb )
27 __field(int, op )
28 __field(int, usage )
29 __field(int, mod_count )
30 __field(const void *, where )
31 ),
32
33 TP_fast_assign(
34 __entry->skb = skb;
35 __entry->op = op;
36 __entry->usage = usage;
37 __entry->mod_count = mod_count;
38 __entry->where = where;
39 ),
40
41 TP_printk("s=%p %s u=%d m=%d p=%pSR",
42 __entry->skb,
43 (__entry->op == 0 ? "NEW" :
44 __entry->op == 1 ? "SEE" :
45 __entry->op == 2 ? "GET" :
46 __entry->op == 3 ? "FRE" :
47 "PUR"),
48 __entry->usage,
49 __entry->mod_count,
50 __entry->where)
51 );
52
53#endif /* _TRACE_RXRPC_H */
54
55/* This part must be outside protection */
56#include <trace/define_trace.h>
diff --git a/net/rxrpc/af_rxrpc.c b/net/rxrpc/af_rxrpc.c
index 88effadd4b16..c7cf356b42b8 100644
--- a/net/rxrpc/af_rxrpc.c
+++ b/net/rxrpc/af_rxrpc.c
@@ -22,6 +22,7 @@
22#include <net/net_namespace.h> 22#include <net/net_namespace.h>
23#include <net/sock.h> 23#include <net/sock.h>
24#include <net/af_rxrpc.h> 24#include <net/af_rxrpc.h>
25#define CREATE_TRACE_POINTS
25#include "ar-internal.h" 26#include "ar-internal.h"
26 27
27MODULE_DESCRIPTION("RxRPC network protocol"); 28MODULE_DESCRIPTION("RxRPC network protocol");
diff --git a/net/rxrpc/ar-internal.h b/net/rxrpc/ar-internal.h
index 648060a5df35..8cb517fbbd23 100644
--- a/net/rxrpc/ar-internal.h
+++ b/net/rxrpc/ar-internal.h
@@ -479,6 +479,8 @@ static inline void rxrpc_abort_call(struct rxrpc_call *call, u32 abort_code)
479 write_unlock_bh(&call->state_lock); 479 write_unlock_bh(&call->state_lock);
480} 480}
481 481
482#include <trace/events/rxrpc.h>
483
482/* 484/*
483 * af_rxrpc.c 485 * af_rxrpc.c
484 */ 486 */
@@ -752,6 +754,11 @@ int rxrpc_init_server_conn_security(struct rxrpc_connection *);
752 * skbuff.c 754 * skbuff.c
753 */ 755 */
754void rxrpc_packet_destructor(struct sk_buff *); 756void rxrpc_packet_destructor(struct sk_buff *);
757void rxrpc_new_skb(struct sk_buff *);
758void rxrpc_see_skb(struct sk_buff *);
759void rxrpc_get_skb(struct sk_buff *);
760void rxrpc_free_skb(struct sk_buff *);
761void rxrpc_purge_queue(struct sk_buff_head *);
755 762
756/* 763/*
757 * sysctl.c 764 * sysctl.c
@@ -899,44 +906,6 @@ do { \
899 906
900#endif /* __KDEBUGALL */ 907#endif /* __KDEBUGALL */
901 908
902/*
903 * socket buffer accounting / leak finding
904 */
905static inline void __rxrpc_new_skb(struct sk_buff *skb, const char *fn)
906{
907 //_net("new skb %p %s [%d]", skb, fn, atomic_read(&rxrpc_n_skbs));
908 //atomic_inc(&rxrpc_n_skbs);
909}
910
911#define rxrpc_new_skb(skb) __rxrpc_new_skb((skb), __func__)
912
913static inline void __rxrpc_kill_skb(struct sk_buff *skb, const char *fn)
914{
915 //_net("kill skb %p %s [%d]", skb, fn, atomic_read(&rxrpc_n_skbs));
916 //atomic_dec(&rxrpc_n_skbs);
917}
918
919#define rxrpc_kill_skb(skb) __rxrpc_kill_skb((skb), __func__)
920
921static inline void __rxrpc_free_skb(struct sk_buff *skb, const char *fn)
922{
923 if (skb) {
924 CHECK_SLAB_OKAY(&skb->users);
925 //_net("free skb %p %s [%d]",
926 // skb, fn, atomic_read(&rxrpc_n_skbs));
927 //atomic_dec(&rxrpc_n_skbs);
928 kfree_skb(skb);
929 }
930}
931
932#define rxrpc_free_skb(skb) __rxrpc_free_skb((skb), __func__)
933
934static inline void rxrpc_purge_queue(struct sk_buff_head *list)
935{
936 struct sk_buff *skb;
937 while ((skb = skb_dequeue((list))) != NULL)
938 rxrpc_free_skb(skb);
939}
940 909
941#define rxrpc_get_call(CALL) \ 910#define rxrpc_get_call(CALL) \
942do { \ 911do { \
diff --git a/net/rxrpc/call_accept.c b/net/rxrpc/call_accept.c
index 9bae21e66d65..669ac79d3b44 100644
--- a/net/rxrpc/call_accept.c
+++ b/net/rxrpc/call_accept.c
@@ -203,6 +203,7 @@ void rxrpc_accept_incoming_calls(struct rxrpc_local *local)
203 203
204 _net("incoming call skb %p", skb); 204 _net("incoming call skb %p", skb);
205 205
206 rxrpc_see_skb(skb);
206 sp = rxrpc_skb(skb); 207 sp = rxrpc_skb(skb);
207 208
208 /* Set up a response packet header in case we need it */ 209 /* Set up a response packet header in case we need it */
diff --git a/net/rxrpc/call_event.c b/net/rxrpc/call_event.c
index eaa8035dcb71..3d1267cea9ea 100644
--- a/net/rxrpc/call_event.c
+++ b/net/rxrpc/call_event.c
@@ -407,6 +407,7 @@ static int rxrpc_drain_rx_oos_queue(struct rxrpc_call *call)
407 407
408 skb = skb_dequeue(&call->rx_oos_queue); 408 skb = skb_dequeue(&call->rx_oos_queue);
409 if (skb) { 409 if (skb) {
410 rxrpc_see_skb(skb);
410 sp = rxrpc_skb(skb); 411 sp = rxrpc_skb(skb);
411 412
412 _debug("drain OOS packet %d [%d]", 413 _debug("drain OOS packet %d [%d]",
@@ -427,6 +428,7 @@ static int rxrpc_drain_rx_oos_queue(struct rxrpc_call *call)
427 428
428 /* find out what the next packet is */ 429 /* find out what the next packet is */
429 skb = skb_peek(&call->rx_oos_queue); 430 skb = skb_peek(&call->rx_oos_queue);
431 rxrpc_see_skb(skb);
430 if (skb) 432 if (skb)
431 call->rx_first_oos = rxrpc_skb(skb)->hdr.seq; 433 call->rx_first_oos = rxrpc_skb(skb)->hdr.seq;
432 else 434 else
@@ -576,6 +578,7 @@ process_further:
576 if (!skb) 578 if (!skb)
577 return -EAGAIN; 579 return -EAGAIN;
578 580
581 rxrpc_see_skb(skb);
579 _net("deferred skb %p", skb); 582 _net("deferred skb %p", skb);
580 583
581 sp = rxrpc_skb(skb); 584 sp = rxrpc_skb(skb);
diff --git a/net/rxrpc/conn_event.c b/net/rxrpc/conn_event.c
index cee0f35bc1cf..c631d926f4db 100644
--- a/net/rxrpc/conn_event.c
+++ b/net/rxrpc/conn_event.c
@@ -277,6 +277,7 @@ void rxrpc_process_connection(struct work_struct *work)
277 /* go through the conn-level event packets, releasing the ref on this 277 /* go through the conn-level event packets, releasing the ref on this
278 * connection that each one has when we've finished with it */ 278 * connection that each one has when we've finished with it */
279 while ((skb = skb_dequeue(&conn->rx_queue))) { 279 while ((skb = skb_dequeue(&conn->rx_queue))) {
280 rxrpc_see_skb(skb);
280 ret = rxrpc_process_event(conn, skb, &abort_code); 281 ret = rxrpc_process_event(conn, skb, &abort_code);
281 switch (ret) { 282 switch (ret) {
282 case -EPROTO: 283 case -EPROTO:
@@ -365,6 +366,7 @@ void rxrpc_reject_packets(struct rxrpc_local *local)
365 whdr.type = RXRPC_PACKET_TYPE_ABORT; 366 whdr.type = RXRPC_PACKET_TYPE_ABORT;
366 367
367 while ((skb = skb_dequeue(&local->reject_queue))) { 368 while ((skb = skb_dequeue(&local->reject_queue))) {
369 rxrpc_see_skb(skb);
368 sp = rxrpc_skb(skb); 370 sp = rxrpc_skb(skb);
369 switch (sa.sa.sa_family) { 371 switch (sa.sa.sa_family) {
370 case AF_INET: 372 case AF_INET:
diff --git a/net/rxrpc/local_event.c b/net/rxrpc/local_event.c
index 31a3f86ef2f6..bcc6593b4cdb 100644
--- a/net/rxrpc/local_event.c
+++ b/net/rxrpc/local_event.c
@@ -93,6 +93,7 @@ void rxrpc_process_local_events(struct rxrpc_local *local)
93 if (skb) { 93 if (skb) {
94 struct rxrpc_skb_priv *sp = rxrpc_skb(skb); 94 struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
95 95
96 rxrpc_see_skb(skb);
96 _debug("{%d},{%u}", local->debug_id, sp->hdr.type); 97 _debug("{%d},{%u}", local->debug_id, sp->hdr.type);
97 98
98 switch (sp->hdr.type) { 99 switch (sp->hdr.type) {
diff --git a/net/rxrpc/output.c b/net/rxrpc/output.c
index 9e626f1e2668..e3a08d542fb7 100644
--- a/net/rxrpc/output.c
+++ b/net/rxrpc/output.c
@@ -548,6 +548,7 @@ static int rxrpc_send_data(struct rxrpc_sock *rx,
548 548
549 skb = call->tx_pending; 549 skb = call->tx_pending;
550 call->tx_pending = NULL; 550 call->tx_pending = NULL;
551 rxrpc_see_skb(skb);
551 552
552 copied = 0; 553 copied = 0;
553 do { 554 do {
diff --git a/net/rxrpc/recvmsg.c b/net/rxrpc/recvmsg.c
index 9ed66d533002..b964c2d49a88 100644
--- a/net/rxrpc/recvmsg.c
+++ b/net/rxrpc/recvmsg.c
@@ -111,6 +111,7 @@ int rxrpc_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
111 } 111 }
112 112
113 peek_next_packet: 113 peek_next_packet:
114 rxrpc_see_skb(skb);
114 sp = rxrpc_skb(skb); 115 sp = rxrpc_skb(skb);
115 call = sp->call; 116 call = sp->call;
116 ASSERT(call != NULL); 117 ASSERT(call != NULL);
diff --git a/net/rxrpc/skbuff.c b/net/rxrpc/skbuff.c
index 06c51d4b622d..d28058a97bc1 100644
--- a/net/rxrpc/skbuff.c
+++ b/net/rxrpc/skbuff.c
@@ -163,3 +163,65 @@ void rxrpc_kernel_free_skb(struct sk_buff *skb)
163 rxrpc_free_skb(skb); 163 rxrpc_free_skb(skb);
164} 164}
165EXPORT_SYMBOL(rxrpc_kernel_free_skb); 165EXPORT_SYMBOL(rxrpc_kernel_free_skb);
166
167/*
168 * Note the existence of a new-to-us socket buffer (allocated or dequeued).
169 */
170void rxrpc_new_skb(struct sk_buff *skb)
171{
172 const void *here = __builtin_return_address(0);
173 int n = atomic_inc_return(&rxrpc_n_skbs);
174 trace_rxrpc_skb(skb, 0, atomic_read(&skb->users), n, here);
175}
176
177/*
178 * Note the re-emergence of a socket buffer from a queue or buffer.
179 */
180void rxrpc_see_skb(struct sk_buff *skb)
181{
182 const void *here = __builtin_return_address(0);
183 if (skb) {
184 int n = atomic_read(&rxrpc_n_skbs);
185 trace_rxrpc_skb(skb, 1, atomic_read(&skb->users), n, here);
186 }
187}
188
189/*
190 * Note the addition of a ref on a socket buffer.
191 */
192void rxrpc_get_skb(struct sk_buff *skb)
193{
194 const void *here = __builtin_return_address(0);
195 int n = atomic_inc_return(&rxrpc_n_skbs);
196 trace_rxrpc_skb(skb, 2, atomic_read(&skb->users), n, here);
197 skb_get(skb);
198}
199
200/*
201 * Note the destruction of a socket buffer.
202 */
203void rxrpc_free_skb(struct sk_buff *skb)
204{
205 const void *here = __builtin_return_address(0);
206 if (skb) {
207 int n;
208 CHECK_SLAB_OKAY(&skb->users);
209 n = atomic_dec_return(&rxrpc_n_skbs);
210 trace_rxrpc_skb(skb, 3, atomic_read(&skb->users), n, here);
211 kfree_skb(skb);
212 }
213}
214
215/*
216 * Clear a queue of socket buffers.
217 */
218void rxrpc_purge_queue(struct sk_buff_head *list)
219{
220 const void *here = __builtin_return_address(0);
221 struct sk_buff *skb;
222 while ((skb = skb_dequeue((list))) != NULL) {
223 int n = atomic_dec_return(&rxrpc_n_skbs);
224 trace_rxrpc_skb(skb, 4, atomic_read(&skb->users), n, here);
225 kfree_skb(skb);
226 }
227}