aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2016-09-17 05:49:14 -0400
committerDavid Howells <dhowells@redhat.com>2016-09-17 06:24:04 -0400
commit71f3ca408fd43b586c02480768a503af075b247e (patch)
tree9fcca5ef4f931aa9836e5f92b78abfb5c2d68a55
parentba39f3a0ed756ccd882adf4a77916ec863db3ce4 (diff)
rxrpc: Improve skb tracing
Improve sk_buff tracing within AF_RXRPC by the following means: (1) Use an enum to note the event type rather than plain integers and use an array of event names rather than a big multi ?: list. (2) Distinguish Rx from Tx packets and account them separately. This requires the call phase to be tracked so that we know what we might find in rxtx_buffer[]. (3) Add a parameter to rxrpc_{new,see,get,free}_skb() to indicate the event type. (4) A pair of 'rotate' events are added to indicate packets that are about to be rotated out of the Rx and Tx windows. (5) A pair of 'lost' events are added, along with rxrpc_lose_skb() for packet loss injection recording. Signed-off-by: David Howells <dhowells@redhat.com>
-rw-r--r--include/trace/events/rxrpc.h12
-rw-r--r--net/rxrpc/af_rxrpc.c5
-rw-r--r--net/rxrpc/ar-internal.h33
-rw-r--r--net/rxrpc/call_event.c8
-rw-r--r--net/rxrpc/call_object.c11
-rw-r--r--net/rxrpc/conn_event.c6
-rw-r--r--net/rxrpc/input.c13
-rw-r--r--net/rxrpc/local_event.c4
-rw-r--r--net/rxrpc/misc.c18
-rw-r--r--net/rxrpc/output.c4
-rw-r--r--net/rxrpc/peer_event.c10
-rw-r--r--net/rxrpc/recvmsg.c7
-rw-r--r--net/rxrpc/sendmsg.c10
-rw-r--r--net/rxrpc/skbuff.c53
14 files changed, 131 insertions, 63 deletions
diff --git a/include/trace/events/rxrpc.h b/include/trace/events/rxrpc.h
index 58732202e9f0..75a5d8bf50e1 100644
--- a/include/trace/events/rxrpc.h
+++ b/include/trace/events/rxrpc.h
@@ -107,14 +107,14 @@ TRACE_EVENT(rxrpc_call,
107 ); 107 );
108 108
109TRACE_EVENT(rxrpc_skb, 109TRACE_EVENT(rxrpc_skb,
110 TP_PROTO(struct sk_buff *skb, int op, int usage, int mod_count, 110 TP_PROTO(struct sk_buff *skb, enum rxrpc_skb_trace op,
111 const void *where), 111 int usage, int mod_count, const void *where),
112 112
113 TP_ARGS(skb, op, usage, mod_count, where), 113 TP_ARGS(skb, op, usage, mod_count, where),
114 114
115 TP_STRUCT__entry( 115 TP_STRUCT__entry(
116 __field(struct sk_buff *, skb ) 116 __field(struct sk_buff *, skb )
117 __field(int, op ) 117 __field(enum rxrpc_skb_trace, op )
118 __field(int, usage ) 118 __field(int, usage )
119 __field(int, mod_count ) 119 __field(int, mod_count )
120 __field(const void *, where ) 120 __field(const void *, where )
@@ -130,11 +130,7 @@ TRACE_EVENT(rxrpc_skb,
130 130
131 TP_printk("s=%p %s u=%d m=%d p=%pSR", 131 TP_printk("s=%p %s u=%d m=%d p=%pSR",
132 __entry->skb, 132 __entry->skb,
133 (__entry->op == 0 ? "NEW" : 133 rxrpc_skb_traces[__entry->op],
134 __entry->op == 1 ? "SEE" :
135 __entry->op == 2 ? "GET" :
136 __entry->op == 3 ? "FRE" :
137 "PUR"),
138 __entry->usage, 134 __entry->usage,
139 __entry->mod_count, 135 __entry->mod_count,
140 __entry->where) 136 __entry->where)
diff --git a/net/rxrpc/af_rxrpc.c b/net/rxrpc/af_rxrpc.c
index 09f81befc705..8dbf7bed2cc4 100644
--- a/net/rxrpc/af_rxrpc.c
+++ b/net/rxrpc/af_rxrpc.c
@@ -45,7 +45,7 @@ u32 rxrpc_epoch;
45atomic_t rxrpc_debug_id; 45atomic_t rxrpc_debug_id;
46 46
47/* count of skbs currently in use */ 47/* count of skbs currently in use */
48atomic_t rxrpc_n_skbs; 48atomic_t rxrpc_n_tx_skbs, rxrpc_n_rx_skbs;
49 49
50struct workqueue_struct *rxrpc_workqueue; 50struct workqueue_struct *rxrpc_workqueue;
51 51
@@ -867,7 +867,8 @@ static void __exit af_rxrpc_exit(void)
867 proto_unregister(&rxrpc_proto); 867 proto_unregister(&rxrpc_proto);
868 rxrpc_destroy_all_calls(); 868 rxrpc_destroy_all_calls();
869 rxrpc_destroy_all_connections(); 869 rxrpc_destroy_all_connections();
870 ASSERTCMP(atomic_read(&rxrpc_n_skbs), ==, 0); 870 ASSERTCMP(atomic_read(&rxrpc_n_tx_skbs), ==, 0);
871 ASSERTCMP(atomic_read(&rxrpc_n_rx_skbs), ==, 0);
871 rxrpc_destroy_all_locals(); 872 rxrpc_destroy_all_locals();
872 873
873 remove_proc_entry("rxrpc_conns", init_net.proc_net); 874 remove_proc_entry("rxrpc_conns", init_net.proc_net);
diff --git a/net/rxrpc/ar-internal.h b/net/rxrpc/ar-internal.h
index a17341d2df3d..034f525f2235 100644
--- a/net/rxrpc/ar-internal.h
+++ b/net/rxrpc/ar-internal.h
@@ -520,6 +520,7 @@ struct rxrpc_call {
520 rxrpc_seq_t rx_expect_next; /* Expected next packet sequence number */ 520 rxrpc_seq_t rx_expect_next; /* Expected next packet sequence number */
521 u8 rx_winsize; /* Size of Rx window */ 521 u8 rx_winsize; /* Size of Rx window */
522 u8 tx_winsize; /* Maximum size of Tx window */ 522 u8 tx_winsize; /* Maximum size of Tx window */
523 bool tx_phase; /* T if transmission phase, F if receive phase */
523 u8 nr_jumbo_bad; /* Number of jumbo dups/exceeds-windows */ 524 u8 nr_jumbo_bad; /* Number of jumbo dups/exceeds-windows */
524 525
525 /* receive-phase ACK management */ 526 /* receive-phase ACK management */
@@ -534,6 +535,27 @@ struct rxrpc_call {
534 rxrpc_serial_t acks_latest; /* serial number of latest ACK received */ 535 rxrpc_serial_t acks_latest; /* serial number of latest ACK received */
535}; 536};
536 537
538enum rxrpc_skb_trace {
539 rxrpc_skb_rx_cleaned,
540 rxrpc_skb_rx_freed,
541 rxrpc_skb_rx_got,
542 rxrpc_skb_rx_lost,
543 rxrpc_skb_rx_received,
544 rxrpc_skb_rx_rotated,
545 rxrpc_skb_rx_purged,
546 rxrpc_skb_rx_seen,
547 rxrpc_skb_tx_cleaned,
548 rxrpc_skb_tx_freed,
549 rxrpc_skb_tx_got,
550 rxrpc_skb_tx_lost,
551 rxrpc_skb_tx_new,
552 rxrpc_skb_tx_rotated,
553 rxrpc_skb_tx_seen,
554 rxrpc_skb__nr_trace
555};
556
557extern const char rxrpc_skb_traces[rxrpc_skb__nr_trace][7];
558
537enum rxrpc_conn_trace { 559enum rxrpc_conn_trace {
538 rxrpc_conn_new_client, 560 rxrpc_conn_new_client,
539 rxrpc_conn_new_service, 561 rxrpc_conn_new_service,
@@ -642,7 +664,7 @@ extern const char *rxrpc_acks(u8 reason);
642/* 664/*
643 * af_rxrpc.c 665 * af_rxrpc.c
644 */ 666 */
645extern atomic_t rxrpc_n_skbs; 667extern atomic_t rxrpc_n_tx_skbs, rxrpc_n_rx_skbs;
646extern u32 rxrpc_epoch; 668extern u32 rxrpc_epoch;
647extern atomic_t rxrpc_debug_id; 669extern atomic_t rxrpc_debug_id;
648extern struct workqueue_struct *rxrpc_workqueue; 670extern struct workqueue_struct *rxrpc_workqueue;
@@ -1000,10 +1022,11 @@ int rxrpc_do_sendmsg(struct rxrpc_sock *, struct msghdr *, size_t);
1000 */ 1022 */
1001void rxrpc_kernel_data_consumed(struct rxrpc_call *, struct sk_buff *); 1023void rxrpc_kernel_data_consumed(struct rxrpc_call *, struct sk_buff *);
1002void rxrpc_packet_destructor(struct sk_buff *); 1024void rxrpc_packet_destructor(struct sk_buff *);
1003void rxrpc_new_skb(struct sk_buff *); 1025void rxrpc_new_skb(struct sk_buff *, enum rxrpc_skb_trace);
1004void rxrpc_see_skb(struct sk_buff *); 1026void rxrpc_see_skb(struct sk_buff *, enum rxrpc_skb_trace);
1005void rxrpc_get_skb(struct sk_buff *); 1027void rxrpc_get_skb(struct sk_buff *, enum rxrpc_skb_trace);
1006void rxrpc_free_skb(struct sk_buff *); 1028void rxrpc_free_skb(struct sk_buff *, enum rxrpc_skb_trace);
1029void rxrpc_lose_skb(struct sk_buff *, enum rxrpc_skb_trace);
1007void rxrpc_purge_queue(struct sk_buff_head *); 1030void rxrpc_purge_queue(struct sk_buff_head *);
1008 1031
1009/* 1032/*
diff --git a/net/rxrpc/call_event.c b/net/rxrpc/call_event.c
index f0cabc48a1b7..7d1b99824ed9 100644
--- a/net/rxrpc/call_event.c
+++ b/net/rxrpc/call_event.c
@@ -170,7 +170,7 @@ static void rxrpc_resend(struct rxrpc_call *call)
170 continue; 170 continue;
171 171
172 skb = call->rxtx_buffer[ix]; 172 skb = call->rxtx_buffer[ix];
173 rxrpc_see_skb(skb); 173 rxrpc_see_skb(skb, rxrpc_skb_tx_seen);
174 sp = rxrpc_skb(skb); 174 sp = rxrpc_skb(skb);
175 175
176 if (annotation == RXRPC_TX_ANNO_UNACK) { 176 if (annotation == RXRPC_TX_ANNO_UNACK) {
@@ -199,7 +199,7 @@ static void rxrpc_resend(struct rxrpc_call *call)
199 continue; 199 continue;
200 200
201 skb = call->rxtx_buffer[ix]; 201 skb = call->rxtx_buffer[ix];
202 rxrpc_get_skb(skb); 202 rxrpc_get_skb(skb, rxrpc_skb_tx_got);
203 spin_unlock_bh(&call->lock); 203 spin_unlock_bh(&call->lock);
204 sp = rxrpc_skb(skb); 204 sp = rxrpc_skb(skb);
205 205
@@ -211,7 +211,7 @@ static void rxrpc_resend(struct rxrpc_call *call)
211 211
212 if (rxrpc_send_data_packet(call->conn, skb) < 0) { 212 if (rxrpc_send_data_packet(call->conn, skb) < 0) {
213 call->resend_at = now + 2; 213 call->resend_at = now + 2;
214 rxrpc_free_skb(skb); 214 rxrpc_free_skb(skb, rxrpc_skb_tx_freed);
215 return; 215 return;
216 } 216 }
217 217
@@ -219,7 +219,7 @@ static void rxrpc_resend(struct rxrpc_call *call)
219 rxrpc_expose_client_call(call); 219 rxrpc_expose_client_call(call);
220 sp->resend_at = now + rxrpc_resend_timeout; 220 sp->resend_at = now + rxrpc_resend_timeout;
221 221
222 rxrpc_free_skb(skb); 222 rxrpc_free_skb(skb, rxrpc_skb_tx_freed);
223 spin_lock_bh(&call->lock); 223 spin_lock_bh(&call->lock);
224 224
225 /* We need to clear the retransmit state, but there are two 225 /* We need to clear the retransmit state, but there are two
diff --git a/net/rxrpc/call_object.c b/net/rxrpc/call_object.c
index 54f30482a7fd..f50a6094e198 100644
--- a/net/rxrpc/call_object.c
+++ b/net/rxrpc/call_object.c
@@ -182,6 +182,7 @@ static struct rxrpc_call *rxrpc_alloc_client_call(struct sockaddr_rxrpc *srx,
182 return ERR_PTR(-ENOMEM); 182 return ERR_PTR(-ENOMEM);
183 call->state = RXRPC_CALL_CLIENT_AWAIT_CONN; 183 call->state = RXRPC_CALL_CLIENT_AWAIT_CONN;
184 call->service_id = srx->srx_service; 184 call->service_id = srx->srx_service;
185 call->tx_phase = true;
185 186
186 _leave(" = %p", call); 187 _leave(" = %p", call);
187 return call; 188 return call;
@@ -458,7 +459,9 @@ void rxrpc_release_call(struct rxrpc_sock *rx, struct rxrpc_call *call)
458 rxrpc_disconnect_call(call); 459 rxrpc_disconnect_call(call);
459 460
460 for (i = 0; i < RXRPC_RXTX_BUFF_SIZE; i++) { 461 for (i = 0; i < RXRPC_RXTX_BUFF_SIZE; i++) {
461 rxrpc_free_skb(call->rxtx_buffer[i]); 462 rxrpc_free_skb(call->rxtx_buffer[i],
463 (call->tx_phase ? rxrpc_skb_tx_cleaned :
464 rxrpc_skb_rx_cleaned));
462 call->rxtx_buffer[i] = NULL; 465 call->rxtx_buffer[i] = NULL;
463 } 466 }
464 467
@@ -552,9 +555,11 @@ void rxrpc_cleanup_call(struct rxrpc_call *call)
552 555
553 /* Clean up the Rx/Tx buffer */ 556 /* Clean up the Rx/Tx buffer */
554 for (i = 0; i < RXRPC_RXTX_BUFF_SIZE; i++) 557 for (i = 0; i < RXRPC_RXTX_BUFF_SIZE; i++)
555 rxrpc_free_skb(call->rxtx_buffer[i]); 558 rxrpc_free_skb(call->rxtx_buffer[i],
559 (call->tx_phase ? rxrpc_skb_tx_cleaned :
560 rxrpc_skb_rx_cleaned));
556 561
557 rxrpc_free_skb(call->tx_pending); 562 rxrpc_free_skb(call->tx_pending, rxrpc_skb_tx_cleaned);
558 563
559 call_rcu(&call->rcu, rxrpc_rcu_destroy_call); 564 call_rcu(&call->rcu, rxrpc_rcu_destroy_call);
560} 565}
diff --git a/net/rxrpc/conn_event.c b/net/rxrpc/conn_event.c
index 9b19c51831aa..75a15a4c74c3 100644
--- a/net/rxrpc/conn_event.c
+++ b/net/rxrpc/conn_event.c
@@ -388,7 +388,7 @@ void rxrpc_process_connection(struct work_struct *work)
388 /* go through the conn-level event packets, releasing the ref on this 388 /* go through the conn-level event packets, releasing the ref on this
389 * connection that each one has when we've finished with it */ 389 * connection that each one has when we've finished with it */
390 while ((skb = skb_dequeue(&conn->rx_queue))) { 390 while ((skb = skb_dequeue(&conn->rx_queue))) {
391 rxrpc_see_skb(skb); 391 rxrpc_see_skb(skb, rxrpc_skb_rx_seen);
392 ret = rxrpc_process_event(conn, skb, &abort_code); 392 ret = rxrpc_process_event(conn, skb, &abort_code);
393 switch (ret) { 393 switch (ret) {
394 case -EPROTO: 394 case -EPROTO:
@@ -399,7 +399,7 @@ void rxrpc_process_connection(struct work_struct *work)
399 goto requeue_and_leave; 399 goto requeue_and_leave;
400 case -ECONNABORTED: 400 case -ECONNABORTED:
401 default: 401 default:
402 rxrpc_free_skb(skb); 402 rxrpc_free_skb(skb, rxrpc_skb_rx_freed);
403 break; 403 break;
404 } 404 }
405 } 405 }
@@ -416,7 +416,7 @@ requeue_and_leave:
416protocol_error: 416protocol_error:
417 if (rxrpc_abort_connection(conn, -ret, abort_code) < 0) 417 if (rxrpc_abort_connection(conn, -ret, abort_code) < 0)
418 goto requeue_and_leave; 418 goto requeue_and_leave;
419 rxrpc_free_skb(skb); 419 rxrpc_free_skb(skb, rxrpc_skb_rx_freed);
420 _leave(" [EPROTO]"); 420 _leave(" [EPROTO]");
421 goto out; 421 goto out;
422} 422}
diff --git a/net/rxrpc/input.c b/net/rxrpc/input.c
index b690220533c6..84bb16d47b85 100644
--- a/net/rxrpc/input.c
+++ b/net/rxrpc/input.c
@@ -50,7 +50,7 @@ static void rxrpc_rotate_tx_window(struct rxrpc_call *call, rxrpc_seq_t to)
50 call->tx_hard_ack++; 50 call->tx_hard_ack++;
51 ix = call->tx_hard_ack & RXRPC_RXTX_BUFF_MASK; 51 ix = call->tx_hard_ack & RXRPC_RXTX_BUFF_MASK;
52 skb = call->rxtx_buffer[ix]; 52 skb = call->rxtx_buffer[ix];
53 rxrpc_see_skb(skb); 53 rxrpc_see_skb(skb, rxrpc_skb_tx_rotated);
54 call->rxtx_buffer[ix] = NULL; 54 call->rxtx_buffer[ix] = NULL;
55 call->rxtx_annotations[ix] = 0; 55 call->rxtx_annotations[ix] = 0;
56 skb->next = list; 56 skb->next = list;
@@ -66,7 +66,7 @@ static void rxrpc_rotate_tx_window(struct rxrpc_call *call, rxrpc_seq_t to)
66 skb = list; 66 skb = list;
67 list = skb->next; 67 list = skb->next;
68 skb->next = NULL; 68 skb->next = NULL;
69 rxrpc_free_skb(skb); 69 rxrpc_free_skb(skb, rxrpc_skb_tx_freed);
70 } 70 }
71} 71}
72 72
@@ -99,6 +99,7 @@ static bool rxrpc_end_tx_phase(struct rxrpc_call *call, const char *abort_why)
99 default: 99 default:
100 break; 100 break;
101 case RXRPC_CALL_CLIENT_AWAIT_REPLY: 101 case RXRPC_CALL_CLIENT_AWAIT_REPLY:
102 call->tx_phase = false;
102 call->state = RXRPC_CALL_CLIENT_RECV_REPLY; 103 call->state = RXRPC_CALL_CLIENT_RECV_REPLY;
103 break; 104 break;
104 case RXRPC_CALL_SERVER_AWAIT_ACK: 105 case RXRPC_CALL_SERVER_AWAIT_ACK:
@@ -278,7 +279,7 @@ next_subpacket:
278 * Barriers against rxrpc_recvmsg_data() and rxrpc_rotate_rx_window() 279 * Barriers against rxrpc_recvmsg_data() and rxrpc_rotate_rx_window()
279 * and also rxrpc_fill_out_ack(). 280 * and also rxrpc_fill_out_ack().
280 */ 281 */
281 rxrpc_get_skb(skb); 282 rxrpc_get_skb(skb, rxrpc_skb_rx_got);
282 call->rxtx_annotations[ix] = annotation; 283 call->rxtx_annotations[ix] = annotation;
283 smp_wmb(); 284 smp_wmb();
284 call->rxtx_buffer[ix] = skb; 285 call->rxtx_buffer[ix] = skb;
@@ -691,13 +692,13 @@ void rxrpc_data_ready(struct sock *udp_sk)
691 return; 692 return;
692 } 693 }
693 694
694 rxrpc_new_skb(skb); 695 rxrpc_new_skb(skb, rxrpc_skb_rx_received);
695 696
696 _net("recv skb %p", skb); 697 _net("recv skb %p", skb);
697 698
698 /* we'll probably need to checksum it (didn't call sock_recvmsg) */ 699 /* we'll probably need to checksum it (didn't call sock_recvmsg) */
699 if (skb_checksum_complete(skb)) { 700 if (skb_checksum_complete(skb)) {
700 rxrpc_free_skb(skb); 701 rxrpc_free_skb(skb, rxrpc_skb_rx_freed);
701 __UDP_INC_STATS(&init_net, UDP_MIB_INERRORS, 0); 702 __UDP_INC_STATS(&init_net, UDP_MIB_INERRORS, 0);
702 _leave(" [CSUM failed]"); 703 _leave(" [CSUM failed]");
703 return; 704 return;
@@ -821,7 +822,7 @@ void rxrpc_data_ready(struct sock *udp_sk)
821discard_unlock: 822discard_unlock:
822 rcu_read_unlock(); 823 rcu_read_unlock();
823discard: 824discard:
824 rxrpc_free_skb(skb); 825 rxrpc_free_skb(skb, rxrpc_skb_rx_freed);
825out: 826out:
826 trace_rxrpc_rx_done(0, 0); 827 trace_rxrpc_rx_done(0, 0);
827 return; 828 return;
diff --git a/net/rxrpc/local_event.c b/net/rxrpc/local_event.c
index f073e932500e..190f68bd9e27 100644
--- a/net/rxrpc/local_event.c
+++ b/net/rxrpc/local_event.c
@@ -90,7 +90,7 @@ void rxrpc_process_local_events(struct rxrpc_local *local)
90 if (skb) { 90 if (skb) {
91 struct rxrpc_skb_priv *sp = rxrpc_skb(skb); 91 struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
92 92
93 rxrpc_see_skb(skb); 93 rxrpc_see_skb(skb, rxrpc_skb_rx_seen);
94 _debug("{%d},{%u}", local->debug_id, sp->hdr.type); 94 _debug("{%d},{%u}", local->debug_id, sp->hdr.type);
95 95
96 switch (sp->hdr.type) { 96 switch (sp->hdr.type) {
@@ -107,7 +107,7 @@ void rxrpc_process_local_events(struct rxrpc_local *local)
107 break; 107 break;
108 } 108 }
109 109
110 rxrpc_free_skb(skb); 110 rxrpc_free_skb(skb, rxrpc_skb_rx_freed);
111 } 111 }
112 112
113 _leave(""); 113 _leave("");
diff --git a/net/rxrpc/misc.c b/net/rxrpc/misc.c
index c7065d893d1e..026e1f2e83ff 100644
--- a/net/rxrpc/misc.c
+++ b/net/rxrpc/misc.c
@@ -102,6 +102,24 @@ const char *rxrpc_acks(u8 reason)
102 return str[reason]; 102 return str[reason];
103} 103}
104 104
105const char rxrpc_skb_traces[rxrpc_skb__nr_trace][7] = {
106 [rxrpc_skb_rx_cleaned] = "Rx CLN",
107 [rxrpc_skb_rx_freed] = "Rx FRE",
108 [rxrpc_skb_rx_got] = "Rx GOT",
109 [rxrpc_skb_rx_lost] = "Rx *L*",
110 [rxrpc_skb_rx_received] = "Rx RCV",
111 [rxrpc_skb_rx_purged] = "Rx PUR",
112 [rxrpc_skb_rx_rotated] = "Rx ROT",
113 [rxrpc_skb_rx_seen] = "Rx SEE",
114 [rxrpc_skb_tx_cleaned] = "Tx CLN",
115 [rxrpc_skb_tx_freed] = "Tx FRE",
116 [rxrpc_skb_tx_got] = "Tx GOT",
117 [rxrpc_skb_tx_lost] = "Tx *L*",
118 [rxrpc_skb_tx_new] = "Tx NEW",
119 [rxrpc_skb_tx_rotated] = "Tx ROT",
120 [rxrpc_skb_tx_seen] = "Tx SEE",
121};
122
105const char rxrpc_conn_traces[rxrpc_conn__nr_trace][4] = { 123const char rxrpc_conn_traces[rxrpc_conn__nr_trace][4] = {
106 [rxrpc_conn_new_client] = "NWc", 124 [rxrpc_conn_new_client] = "NWc",
107 [rxrpc_conn_new_service] = "NWs", 125 [rxrpc_conn_new_service] = "NWs",
diff --git a/net/rxrpc/output.c b/net/rxrpc/output.c
index 2c9daeadce87..a2cad5ce7416 100644
--- a/net/rxrpc/output.c
+++ b/net/rxrpc/output.c
@@ -324,7 +324,7 @@ void rxrpc_reject_packets(struct rxrpc_local *local)
324 whdr.type = RXRPC_PACKET_TYPE_ABORT; 324 whdr.type = RXRPC_PACKET_TYPE_ABORT;
325 325
326 while ((skb = skb_dequeue(&local->reject_queue))) { 326 while ((skb = skb_dequeue(&local->reject_queue))) {
327 rxrpc_see_skb(skb); 327 rxrpc_see_skb(skb, rxrpc_skb_rx_seen);
328 sp = rxrpc_skb(skb); 328 sp = rxrpc_skb(skb);
329 329
330 if (rxrpc_extract_addr_from_skb(&srx, skb) == 0) { 330 if (rxrpc_extract_addr_from_skb(&srx, skb) == 0) {
@@ -343,7 +343,7 @@ void rxrpc_reject_packets(struct rxrpc_local *local)
343 kernel_sendmsg(local->socket, &msg, iov, 2, size); 343 kernel_sendmsg(local->socket, &msg, iov, 2, size);
344 } 344 }
345 345
346 rxrpc_free_skb(skb); 346 rxrpc_free_skb(skb, rxrpc_skb_rx_freed);
347 } 347 }
348 348
349 _leave(""); 349 _leave("");
diff --git a/net/rxrpc/peer_event.c b/net/rxrpc/peer_event.c
index 9e0725f5652b..18276e7cb9e0 100644
--- a/net/rxrpc/peer_event.c
+++ b/net/rxrpc/peer_event.c
@@ -155,11 +155,11 @@ void rxrpc_error_report(struct sock *sk)
155 _leave("UDP socket errqueue empty"); 155 _leave("UDP socket errqueue empty");
156 return; 156 return;
157 } 157 }
158 rxrpc_new_skb(skb); 158 rxrpc_new_skb(skb, rxrpc_skb_rx_received);
159 serr = SKB_EXT_ERR(skb); 159 serr = SKB_EXT_ERR(skb);
160 if (!skb->len && serr->ee.ee_origin == SO_EE_ORIGIN_TIMESTAMPING) { 160 if (!skb->len && serr->ee.ee_origin == SO_EE_ORIGIN_TIMESTAMPING) {
161 _leave("UDP empty message"); 161 _leave("UDP empty message");
162 rxrpc_free_skb(skb); 162 rxrpc_free_skb(skb, rxrpc_skb_rx_freed);
163 return; 163 return;
164 } 164 }
165 165
@@ -169,7 +169,7 @@ void rxrpc_error_report(struct sock *sk)
169 peer = NULL; 169 peer = NULL;
170 if (!peer) { 170 if (!peer) {
171 rcu_read_unlock(); 171 rcu_read_unlock();
172 rxrpc_free_skb(skb); 172 rxrpc_free_skb(skb, rxrpc_skb_rx_freed);
173 _leave(" [no peer]"); 173 _leave(" [no peer]");
174 return; 174 return;
175 } 175 }
@@ -179,7 +179,7 @@ void rxrpc_error_report(struct sock *sk)
179 serr->ee.ee_code == ICMP_FRAG_NEEDED)) { 179 serr->ee.ee_code == ICMP_FRAG_NEEDED)) {
180 rxrpc_adjust_mtu(peer, serr); 180 rxrpc_adjust_mtu(peer, serr);
181 rcu_read_unlock(); 181 rcu_read_unlock();
182 rxrpc_free_skb(skb); 182 rxrpc_free_skb(skb, rxrpc_skb_rx_freed);
183 rxrpc_put_peer(peer); 183 rxrpc_put_peer(peer);
184 _leave(" [MTU update]"); 184 _leave(" [MTU update]");
185 return; 185 return;
@@ -187,7 +187,7 @@ void rxrpc_error_report(struct sock *sk)
187 187
188 rxrpc_store_error(peer, serr); 188 rxrpc_store_error(peer, serr);
189 rcu_read_unlock(); 189 rcu_read_unlock();
190 rxrpc_free_skb(skb); 190 rxrpc_free_skb(skb, rxrpc_skb_rx_freed);
191 191
192 /* The ref we obtained is passed off to the work item */ 192 /* The ref we obtained is passed off to the work item */
193 rxrpc_queue_work(&peer->error_distributor); 193 rxrpc_queue_work(&peer->error_distributor);
diff --git a/net/rxrpc/recvmsg.c b/net/rxrpc/recvmsg.c
index 79e65668bc58..6ba4af5a8d95 100644
--- a/net/rxrpc/recvmsg.c
+++ b/net/rxrpc/recvmsg.c
@@ -155,6 +155,7 @@ static void rxrpc_end_rx_phase(struct rxrpc_call *call)
155 break; 155 break;
156 156
157 case RXRPC_CALL_SERVER_RECV_REQUEST: 157 case RXRPC_CALL_SERVER_RECV_REQUEST:
158 call->tx_phase = true;
158 call->state = RXRPC_CALL_SERVER_ACK_REQUEST; 159 call->state = RXRPC_CALL_SERVER_ACK_REQUEST;
159 break; 160 break;
160 default: 161 default:
@@ -185,7 +186,7 @@ static void rxrpc_rotate_rx_window(struct rxrpc_call *call)
185 hard_ack++; 186 hard_ack++;
186 ix = hard_ack & RXRPC_RXTX_BUFF_MASK; 187 ix = hard_ack & RXRPC_RXTX_BUFF_MASK;
187 skb = call->rxtx_buffer[ix]; 188 skb = call->rxtx_buffer[ix];
188 rxrpc_see_skb(skb); 189 rxrpc_see_skb(skb, rxrpc_skb_rx_rotated);
189 sp = rxrpc_skb(skb); 190 sp = rxrpc_skb(skb);
190 flags = sp->hdr.flags; 191 flags = sp->hdr.flags;
191 serial = sp->hdr.serial; 192 serial = sp->hdr.serial;
@@ -197,7 +198,7 @@ static void rxrpc_rotate_rx_window(struct rxrpc_call *call)
197 /* Barrier against rxrpc_input_data(). */ 198 /* Barrier against rxrpc_input_data(). */
198 smp_store_release(&call->rx_hard_ack, hard_ack); 199 smp_store_release(&call->rx_hard_ack, hard_ack);
199 200
200 rxrpc_free_skb(skb); 201 rxrpc_free_skb(skb, rxrpc_skb_rx_freed);
201 202
202 _debug("%u,%u,%02x", hard_ack, top, flags); 203 _debug("%u,%u,%02x", hard_ack, top, flags);
203 trace_rxrpc_receive(call, rxrpc_receive_rotate, serial, hard_ack); 204 trace_rxrpc_receive(call, rxrpc_receive_rotate, serial, hard_ack);
@@ -317,7 +318,7 @@ static int rxrpc_recvmsg_data(struct socket *sock, struct rxrpc_call *call,
317 break; 318 break;
318 } 319 }
319 smp_rmb(); 320 smp_rmb();
320 rxrpc_see_skb(skb); 321 rxrpc_see_skb(skb, rxrpc_skb_rx_seen);
321 sp = rxrpc_skb(skb); 322 sp = rxrpc_skb(skb);
322 323
323 if (!(flags & MSG_PEEK)) 324 if (!(flags & MSG_PEEK))
diff --git a/net/rxrpc/sendmsg.c b/net/rxrpc/sendmsg.c
index 28d8f73cf11d..6a39ee97a0b7 100644
--- a/net/rxrpc/sendmsg.c
+++ b/net/rxrpc/sendmsg.c
@@ -100,7 +100,7 @@ static void rxrpc_queue_packet(struct rxrpc_call *call, struct sk_buff *skb,
100 ASSERTCMP(seq, ==, call->tx_top + 1); 100 ASSERTCMP(seq, ==, call->tx_top + 1);
101 101
102 ix = seq & RXRPC_RXTX_BUFF_MASK; 102 ix = seq & RXRPC_RXTX_BUFF_MASK;
103 rxrpc_get_skb(skb); 103 rxrpc_get_skb(skb, rxrpc_skb_tx_got);
104 call->rxtx_annotations[ix] = RXRPC_TX_ANNO_UNACK; 104 call->rxtx_annotations[ix] = RXRPC_TX_ANNO_UNACK;
105 smp_wmb(); 105 smp_wmb();
106 call->rxtx_buffer[ix] = skb; 106 call->rxtx_buffer[ix] = skb;
@@ -146,7 +146,7 @@ static void rxrpc_queue_packet(struct rxrpc_call *call, struct sk_buff *skb,
146 rxrpc_instant_resend(call, ix); 146 rxrpc_instant_resend(call, ix);
147 } 147 }
148 148
149 rxrpc_free_skb(skb); 149 rxrpc_free_skb(skb, rxrpc_skb_tx_freed);
150 _leave(""); 150 _leave("");
151} 151}
152 152
@@ -201,7 +201,7 @@ static int rxrpc_send_data(struct rxrpc_sock *rx,
201 201
202 skb = call->tx_pending; 202 skb = call->tx_pending;
203 call->tx_pending = NULL; 203 call->tx_pending = NULL;
204 rxrpc_see_skb(skb); 204 rxrpc_see_skb(skb, rxrpc_skb_tx_seen);
205 205
206 copied = 0; 206 copied = 0;
207 do { 207 do {
@@ -242,7 +242,7 @@ static int rxrpc_send_data(struct rxrpc_sock *rx,
242 if (!skb) 242 if (!skb)
243 goto maybe_error; 243 goto maybe_error;
244 244
245 rxrpc_new_skb(skb); 245 rxrpc_new_skb(skb, rxrpc_skb_tx_new);
246 246
247 _debug("ALLOC SEND %p", skb); 247 _debug("ALLOC SEND %p", skb);
248 248
@@ -352,7 +352,7 @@ out:
352 return ret; 352 return ret;
353 353
354call_terminated: 354call_terminated:
355 rxrpc_free_skb(skb); 355 rxrpc_free_skb(skb, rxrpc_skb_tx_freed);
356 _leave(" = %d", -call->error); 356 _leave(" = %d", -call->error);
357 return -call->error; 357 return -call->error;
358 358
diff --git a/net/rxrpc/skbuff.c b/net/rxrpc/skbuff.c
index 620d9ccaf3c1..5154cbf7e540 100644
--- a/net/rxrpc/skbuff.c
+++ b/net/rxrpc/skbuff.c
@@ -18,55 +18,77 @@
18#include <net/af_rxrpc.h> 18#include <net/af_rxrpc.h>
19#include "ar-internal.h" 19#include "ar-internal.h"
20 20
21#define select_skb_count(op) (op >= rxrpc_skb_tx_cleaned ? &rxrpc_n_tx_skbs : &rxrpc_n_rx_skbs)
22
21/* 23/*
22 * Note the existence of a new-to-us socket buffer (allocated or dequeued). 24 * Note the allocation or reception of a socket buffer.
23 */ 25 */
24void rxrpc_new_skb(struct sk_buff *skb) 26void rxrpc_new_skb(struct sk_buff *skb, enum rxrpc_skb_trace op)
25{ 27{
26 const void *here = __builtin_return_address(0); 28 const void *here = __builtin_return_address(0);
27 int n = atomic_inc_return(&rxrpc_n_skbs); 29 int n = atomic_inc_return(select_skb_count(op));
28 trace_rxrpc_skb(skb, 0, atomic_read(&skb->users), n, here); 30 trace_rxrpc_skb(skb, op, atomic_read(&skb->users), n, here);
29} 31}
30 32
31/* 33/*
32 * Note the re-emergence of a socket buffer from a queue or buffer. 34 * Note the re-emergence of a socket buffer from a queue or buffer.
33 */ 35 */
34void rxrpc_see_skb(struct sk_buff *skb) 36void rxrpc_see_skb(struct sk_buff *skb, enum rxrpc_skb_trace op)
35{ 37{
36 const void *here = __builtin_return_address(0); 38 const void *here = __builtin_return_address(0);
37 if (skb) { 39 if (skb) {
38 int n = atomic_read(&rxrpc_n_skbs); 40 int n = atomic_read(select_skb_count(op));
39 trace_rxrpc_skb(skb, 1, atomic_read(&skb->users), n, here); 41 trace_rxrpc_skb(skb, op, atomic_read(&skb->users), n, here);
40 } 42 }
41} 43}
42 44
43/* 45/*
44 * Note the addition of a ref on a socket buffer. 46 * Note the addition of a ref on a socket buffer.
45 */ 47 */
46void rxrpc_get_skb(struct sk_buff *skb) 48void rxrpc_get_skb(struct sk_buff *skb, enum rxrpc_skb_trace op)
47{ 49{
48 const void *here = __builtin_return_address(0); 50 const void *here = __builtin_return_address(0);
49 int n = atomic_inc_return(&rxrpc_n_skbs); 51 int n = atomic_inc_return(select_skb_count(op));
50 trace_rxrpc_skb(skb, 2, atomic_read(&skb->users), n, here); 52 trace_rxrpc_skb(skb, op, atomic_read(&skb->users), n, here);
51 skb_get(skb); 53 skb_get(skb);
52} 54}
53 55
54/* 56/*
55 * Note the destruction of a socket buffer. 57 * Note the destruction of a socket buffer.
56 */ 58 */
57void rxrpc_free_skb(struct sk_buff *skb) 59void rxrpc_free_skb(struct sk_buff *skb, enum rxrpc_skb_trace op)
58{ 60{
59 const void *here = __builtin_return_address(0); 61 const void *here = __builtin_return_address(0);
60 if (skb) { 62 if (skb) {
61 int n; 63 int n;
62 CHECK_SLAB_OKAY(&skb->users); 64 CHECK_SLAB_OKAY(&skb->users);
63 n = atomic_dec_return(&rxrpc_n_skbs); 65 n = atomic_dec_return(select_skb_count(op));
64 trace_rxrpc_skb(skb, 3, atomic_read(&skb->users), n, here); 66 trace_rxrpc_skb(skb, op, atomic_read(&skb->users), n, here);
65 kfree_skb(skb); 67 kfree_skb(skb);
66 } 68 }
67} 69}
68 70
69/* 71/*
72 * Note the injected loss of a socket buffer.
73 */
74void rxrpc_lose_skb(struct sk_buff *skb, enum rxrpc_skb_trace op)
75{
76 const void *here = __builtin_return_address(0);
77 if (skb) {
78 int n;
79 CHECK_SLAB_OKAY(&skb->users);
80 if (op == rxrpc_skb_tx_lost) {
81 n = atomic_read(select_skb_count(op));
82 trace_rxrpc_skb(skb, op, atomic_read(&skb->users), n, here);
83 } else {
84 n = atomic_dec_return(select_skb_count(op));
85 trace_rxrpc_skb(skb, op, atomic_read(&skb->users), n, here);
86 kfree_skb(skb);
87 }
88 }
89}
90
91/*
70 * Clear a queue of socket buffers. 92 * Clear a queue of socket buffers.
71 */ 93 */
72void rxrpc_purge_queue(struct sk_buff_head *list) 94void rxrpc_purge_queue(struct sk_buff_head *list)
@@ -74,8 +96,9 @@ void rxrpc_purge_queue(struct sk_buff_head *list)
74 const void *here = __builtin_return_address(0); 96 const void *here = __builtin_return_address(0);
75 struct sk_buff *skb; 97 struct sk_buff *skb;
76 while ((skb = skb_dequeue((list))) != NULL) { 98 while ((skb = skb_dequeue((list))) != NULL) {
77 int n = atomic_dec_return(&rxrpc_n_skbs); 99 int n = atomic_dec_return(select_skb_count(rxrpc_skb_rx_purged));
78 trace_rxrpc_skb(skb, 4, atomic_read(&skb->users), n, here); 100 trace_rxrpc_skb(skb, rxrpc_skb_rx_purged,
101 atomic_read(&skb->users), n, here);
79 kfree_skb(skb); 102 kfree_skb(skb);
80 } 103 }
81} 104}