diff options
author | David Howells <dhowells@redhat.com> | 2016-08-23 10:27:24 -0400 |
---|---|---|
committer | David Howells <dhowells@redhat.com> | 2016-08-23 10:27:24 -0400 |
commit | df844fd46b98c2efde8f4ac2d50d59bc90c4c679 (patch) | |
tree | 0a067071fa1bf6fe2fc41de100d822e9585289a0 | |
parent | 01a90a459850ed1f1573f06f00f7b9d466339df0 (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.h | 56 | ||||
-rw-r--r-- | net/rxrpc/af_rxrpc.c | 1 | ||||
-rw-r--r-- | net/rxrpc/ar-internal.h | 45 | ||||
-rw-r--r-- | net/rxrpc/call_accept.c | 1 | ||||
-rw-r--r-- | net/rxrpc/call_event.c | 3 | ||||
-rw-r--r-- | net/rxrpc/conn_event.c | 2 | ||||
-rw-r--r-- | net/rxrpc/local_event.c | 1 | ||||
-rw-r--r-- | net/rxrpc/output.c | 1 | ||||
-rw-r--r-- | net/rxrpc/recvmsg.c | 1 | ||||
-rw-r--r-- | net/rxrpc/skbuff.c | 62 |
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 | |||
19 | TRACE_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 | ||
27 | MODULE_DESCRIPTION("RxRPC network protocol"); | 28 | MODULE_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 | */ |
754 | void rxrpc_packet_destructor(struct sk_buff *); | 756 | void rxrpc_packet_destructor(struct sk_buff *); |
757 | void rxrpc_new_skb(struct sk_buff *); | ||
758 | void rxrpc_see_skb(struct sk_buff *); | ||
759 | void rxrpc_get_skb(struct sk_buff *); | ||
760 | void rxrpc_free_skb(struct sk_buff *); | ||
761 | void 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 | */ | ||
905 | static 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 | |||
913 | static 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 | |||
921 | static 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 | |||
934 | static 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) \ |
942 | do { \ | 911 | do { \ |
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 | } |
165 | EXPORT_SYMBOL(rxrpc_kernel_free_skb); | 165 | EXPORT_SYMBOL(rxrpc_kernel_free_skb); |
166 | |||
167 | /* | ||
168 | * Note the existence of a new-to-us socket buffer (allocated or dequeued). | ||
169 | */ | ||
170 | void 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 | */ | ||
180 | void 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 | */ | ||
192 | void 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 | */ | ||
203 | void 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 | */ | ||
218 | void 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 | } | ||