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>
This commit is contained in:
parent
01a90a4598
commit
df844fd46b
|
@ -0,0 +1,56 @@
|
||||||
|
/* AF_RXRPC tracepoints
|
||||||
|
*
|
||||||
|
* Copyright (C) 2016 Red Hat, Inc. All Rights Reserved.
|
||||||
|
* Written by David Howells (dhowells@redhat.com)
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public Licence
|
||||||
|
* as published by the Free Software Foundation; either version
|
||||||
|
* 2 of the Licence, or (at your option) any later version.
|
||||||
|
*/
|
||||||
|
#undef TRACE_SYSTEM
|
||||||
|
#define TRACE_SYSTEM rxrpc
|
||||||
|
|
||||||
|
#if !defined(_TRACE_RXRPC_H) || defined(TRACE_HEADER_MULTI_READ)
|
||||||
|
#define _TRACE_RXRPC_H
|
||||||
|
|
||||||
|
#include <linux/tracepoint.h>
|
||||||
|
|
||||||
|
TRACE_EVENT(rxrpc_skb,
|
||||||
|
TP_PROTO(struct sk_buff *skb, int op, int usage, int mod_count,
|
||||||
|
const void *where),
|
||||||
|
|
||||||
|
TP_ARGS(skb, op, usage, mod_count, where),
|
||||||
|
|
||||||
|
TP_STRUCT__entry(
|
||||||
|
__field(struct sk_buff *, skb )
|
||||||
|
__field(int, op )
|
||||||
|
__field(int, usage )
|
||||||
|
__field(int, mod_count )
|
||||||
|
__field(const void *, where )
|
||||||
|
),
|
||||||
|
|
||||||
|
TP_fast_assign(
|
||||||
|
__entry->skb = skb;
|
||||||
|
__entry->op = op;
|
||||||
|
__entry->usage = usage;
|
||||||
|
__entry->mod_count = mod_count;
|
||||||
|
__entry->where = where;
|
||||||
|
),
|
||||||
|
|
||||||
|
TP_printk("s=%p %s u=%d m=%d p=%pSR",
|
||||||
|
__entry->skb,
|
||||||
|
(__entry->op == 0 ? "NEW" :
|
||||||
|
__entry->op == 1 ? "SEE" :
|
||||||
|
__entry->op == 2 ? "GET" :
|
||||||
|
__entry->op == 3 ? "FRE" :
|
||||||
|
"PUR"),
|
||||||
|
__entry->usage,
|
||||||
|
__entry->mod_count,
|
||||||
|
__entry->where)
|
||||||
|
);
|
||||||
|
|
||||||
|
#endif /* _TRACE_RXRPC_H */
|
||||||
|
|
||||||
|
/* This part must be outside protection */
|
||||||
|
#include <trace/define_trace.h>
|
|
@ -22,6 +22,7 @@
|
||||||
#include <net/net_namespace.h>
|
#include <net/net_namespace.h>
|
||||||
#include <net/sock.h>
|
#include <net/sock.h>
|
||||||
#include <net/af_rxrpc.h>
|
#include <net/af_rxrpc.h>
|
||||||
|
#define CREATE_TRACE_POINTS
|
||||||
#include "ar-internal.h"
|
#include "ar-internal.h"
|
||||||
|
|
||||||
MODULE_DESCRIPTION("RxRPC network protocol");
|
MODULE_DESCRIPTION("RxRPC network protocol");
|
||||||
|
|
|
@ -479,6 +479,8 @@ static inline void rxrpc_abort_call(struct rxrpc_call *call, u32 abort_code)
|
||||||
write_unlock_bh(&call->state_lock);
|
write_unlock_bh(&call->state_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#include <trace/events/rxrpc.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* af_rxrpc.c
|
* af_rxrpc.c
|
||||||
*/
|
*/
|
||||||
|
@ -752,6 +754,11 @@ int rxrpc_init_server_conn_security(struct rxrpc_connection *);
|
||||||
* skbuff.c
|
* skbuff.c
|
||||||
*/
|
*/
|
||||||
void rxrpc_packet_destructor(struct sk_buff *);
|
void rxrpc_packet_destructor(struct sk_buff *);
|
||||||
|
void rxrpc_new_skb(struct sk_buff *);
|
||||||
|
void rxrpc_see_skb(struct sk_buff *);
|
||||||
|
void rxrpc_get_skb(struct sk_buff *);
|
||||||
|
void rxrpc_free_skb(struct sk_buff *);
|
||||||
|
void rxrpc_purge_queue(struct sk_buff_head *);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* sysctl.c
|
* sysctl.c
|
||||||
|
@ -899,44 +906,6 @@ do { \
|
||||||
|
|
||||||
#endif /* __KDEBUGALL */
|
#endif /* __KDEBUGALL */
|
||||||
|
|
||||||
/*
|
|
||||||
* socket buffer accounting / leak finding
|
|
||||||
*/
|
|
||||||
static inline void __rxrpc_new_skb(struct sk_buff *skb, const char *fn)
|
|
||||||
{
|
|
||||||
//_net("new skb %p %s [%d]", skb, fn, atomic_read(&rxrpc_n_skbs));
|
|
||||||
//atomic_inc(&rxrpc_n_skbs);
|
|
||||||
}
|
|
||||||
|
|
||||||
#define rxrpc_new_skb(skb) __rxrpc_new_skb((skb), __func__)
|
|
||||||
|
|
||||||
static inline void __rxrpc_kill_skb(struct sk_buff *skb, const char *fn)
|
|
||||||
{
|
|
||||||
//_net("kill skb %p %s [%d]", skb, fn, atomic_read(&rxrpc_n_skbs));
|
|
||||||
//atomic_dec(&rxrpc_n_skbs);
|
|
||||||
}
|
|
||||||
|
|
||||||
#define rxrpc_kill_skb(skb) __rxrpc_kill_skb((skb), __func__)
|
|
||||||
|
|
||||||
static inline void __rxrpc_free_skb(struct sk_buff *skb, const char *fn)
|
|
||||||
{
|
|
||||||
if (skb) {
|
|
||||||
CHECK_SLAB_OKAY(&skb->users);
|
|
||||||
//_net("free skb %p %s [%d]",
|
|
||||||
// skb, fn, atomic_read(&rxrpc_n_skbs));
|
|
||||||
//atomic_dec(&rxrpc_n_skbs);
|
|
||||||
kfree_skb(skb);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#define rxrpc_free_skb(skb) __rxrpc_free_skb((skb), __func__)
|
|
||||||
|
|
||||||
static inline void rxrpc_purge_queue(struct sk_buff_head *list)
|
|
||||||
{
|
|
||||||
struct sk_buff *skb;
|
|
||||||
while ((skb = skb_dequeue((list))) != NULL)
|
|
||||||
rxrpc_free_skb(skb);
|
|
||||||
}
|
|
||||||
|
|
||||||
#define rxrpc_get_call(CALL) \
|
#define rxrpc_get_call(CALL) \
|
||||||
do { \
|
do { \
|
||||||
|
|
|
@ -203,6 +203,7 @@ void rxrpc_accept_incoming_calls(struct rxrpc_local *local)
|
||||||
|
|
||||||
_net("incoming call skb %p", skb);
|
_net("incoming call skb %p", skb);
|
||||||
|
|
||||||
|
rxrpc_see_skb(skb);
|
||||||
sp = rxrpc_skb(skb);
|
sp = rxrpc_skb(skb);
|
||||||
|
|
||||||
/* Set up a response packet header in case we need it */
|
/* Set up a response packet header in case we need it */
|
||||||
|
|
|
@ -407,6 +407,7 @@ static int rxrpc_drain_rx_oos_queue(struct rxrpc_call *call)
|
||||||
|
|
||||||
skb = skb_dequeue(&call->rx_oos_queue);
|
skb = skb_dequeue(&call->rx_oos_queue);
|
||||||
if (skb) {
|
if (skb) {
|
||||||
|
rxrpc_see_skb(skb);
|
||||||
sp = rxrpc_skb(skb);
|
sp = rxrpc_skb(skb);
|
||||||
|
|
||||||
_debug("drain OOS packet %d [%d]",
|
_debug("drain OOS packet %d [%d]",
|
||||||
|
@ -427,6 +428,7 @@ static int rxrpc_drain_rx_oos_queue(struct rxrpc_call *call)
|
||||||
|
|
||||||
/* find out what the next packet is */
|
/* find out what the next packet is */
|
||||||
skb = skb_peek(&call->rx_oos_queue);
|
skb = skb_peek(&call->rx_oos_queue);
|
||||||
|
rxrpc_see_skb(skb);
|
||||||
if (skb)
|
if (skb)
|
||||||
call->rx_first_oos = rxrpc_skb(skb)->hdr.seq;
|
call->rx_first_oos = rxrpc_skb(skb)->hdr.seq;
|
||||||
else
|
else
|
||||||
|
@ -576,6 +578,7 @@ process_further:
|
||||||
if (!skb)
|
if (!skb)
|
||||||
return -EAGAIN;
|
return -EAGAIN;
|
||||||
|
|
||||||
|
rxrpc_see_skb(skb);
|
||||||
_net("deferred skb %p", skb);
|
_net("deferred skb %p", skb);
|
||||||
|
|
||||||
sp = rxrpc_skb(skb);
|
sp = rxrpc_skb(skb);
|
||||||
|
|
|
@ -277,6 +277,7 @@ void rxrpc_process_connection(struct work_struct *work)
|
||||||
/* go through the conn-level event packets, releasing the ref on this
|
/* go through the conn-level event packets, releasing the ref on this
|
||||||
* connection that each one has when we've finished with it */
|
* connection that each one has when we've finished with it */
|
||||||
while ((skb = skb_dequeue(&conn->rx_queue))) {
|
while ((skb = skb_dequeue(&conn->rx_queue))) {
|
||||||
|
rxrpc_see_skb(skb);
|
||||||
ret = rxrpc_process_event(conn, skb, &abort_code);
|
ret = rxrpc_process_event(conn, skb, &abort_code);
|
||||||
switch (ret) {
|
switch (ret) {
|
||||||
case -EPROTO:
|
case -EPROTO:
|
||||||
|
@ -365,6 +366,7 @@ void rxrpc_reject_packets(struct rxrpc_local *local)
|
||||||
whdr.type = RXRPC_PACKET_TYPE_ABORT;
|
whdr.type = RXRPC_PACKET_TYPE_ABORT;
|
||||||
|
|
||||||
while ((skb = skb_dequeue(&local->reject_queue))) {
|
while ((skb = skb_dequeue(&local->reject_queue))) {
|
||||||
|
rxrpc_see_skb(skb);
|
||||||
sp = rxrpc_skb(skb);
|
sp = rxrpc_skb(skb);
|
||||||
switch (sa.sa.sa_family) {
|
switch (sa.sa.sa_family) {
|
||||||
case AF_INET:
|
case AF_INET:
|
||||||
|
|
|
@ -93,6 +93,7 @@ void rxrpc_process_local_events(struct rxrpc_local *local)
|
||||||
if (skb) {
|
if (skb) {
|
||||||
struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
|
struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
|
||||||
|
|
||||||
|
rxrpc_see_skb(skb);
|
||||||
_debug("{%d},{%u}", local->debug_id, sp->hdr.type);
|
_debug("{%d},{%u}", local->debug_id, sp->hdr.type);
|
||||||
|
|
||||||
switch (sp->hdr.type) {
|
switch (sp->hdr.type) {
|
||||||
|
|
|
@ -548,6 +548,7 @@ static int rxrpc_send_data(struct rxrpc_sock *rx,
|
||||||
|
|
||||||
skb = call->tx_pending;
|
skb = call->tx_pending;
|
||||||
call->tx_pending = NULL;
|
call->tx_pending = NULL;
|
||||||
|
rxrpc_see_skb(skb);
|
||||||
|
|
||||||
copied = 0;
|
copied = 0;
|
||||||
do {
|
do {
|
||||||
|
|
|
@ -111,6 +111,7 @@ int rxrpc_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
|
||||||
}
|
}
|
||||||
|
|
||||||
peek_next_packet:
|
peek_next_packet:
|
||||||
|
rxrpc_see_skb(skb);
|
||||||
sp = rxrpc_skb(skb);
|
sp = rxrpc_skb(skb);
|
||||||
call = sp->call;
|
call = sp->call;
|
||||||
ASSERT(call != NULL);
|
ASSERT(call != NULL);
|
||||||
|
|
|
@ -163,3 +163,65 @@ void rxrpc_kernel_free_skb(struct sk_buff *skb)
|
||||||
rxrpc_free_skb(skb);
|
rxrpc_free_skb(skb);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(rxrpc_kernel_free_skb);
|
EXPORT_SYMBOL(rxrpc_kernel_free_skb);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Note the existence of a new-to-us socket buffer (allocated or dequeued).
|
||||||
|
*/
|
||||||
|
void rxrpc_new_skb(struct sk_buff *skb)
|
||||||
|
{
|
||||||
|
const void *here = __builtin_return_address(0);
|
||||||
|
int n = atomic_inc_return(&rxrpc_n_skbs);
|
||||||
|
trace_rxrpc_skb(skb, 0, atomic_read(&skb->users), n, here);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Note the re-emergence of a socket buffer from a queue or buffer.
|
||||||
|
*/
|
||||||
|
void rxrpc_see_skb(struct sk_buff *skb)
|
||||||
|
{
|
||||||
|
const void *here = __builtin_return_address(0);
|
||||||
|
if (skb) {
|
||||||
|
int n = atomic_read(&rxrpc_n_skbs);
|
||||||
|
trace_rxrpc_skb(skb, 1, atomic_read(&skb->users), n, here);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Note the addition of a ref on a socket buffer.
|
||||||
|
*/
|
||||||
|
void rxrpc_get_skb(struct sk_buff *skb)
|
||||||
|
{
|
||||||
|
const void *here = __builtin_return_address(0);
|
||||||
|
int n = atomic_inc_return(&rxrpc_n_skbs);
|
||||||
|
trace_rxrpc_skb(skb, 2, atomic_read(&skb->users), n, here);
|
||||||
|
skb_get(skb);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Note the destruction of a socket buffer.
|
||||||
|
*/
|
||||||
|
void rxrpc_free_skb(struct sk_buff *skb)
|
||||||
|
{
|
||||||
|
const void *here = __builtin_return_address(0);
|
||||||
|
if (skb) {
|
||||||
|
int n;
|
||||||
|
CHECK_SLAB_OKAY(&skb->users);
|
||||||
|
n = atomic_dec_return(&rxrpc_n_skbs);
|
||||||
|
trace_rxrpc_skb(skb, 3, atomic_read(&skb->users), n, here);
|
||||||
|
kfree_skb(skb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Clear a queue of socket buffers.
|
||||||
|
*/
|
||||||
|
void rxrpc_purge_queue(struct sk_buff_head *list)
|
||||||
|
{
|
||||||
|
const void *here = __builtin_return_address(0);
|
||||||
|
struct sk_buff *skb;
|
||||||
|
while ((skb = skb_dequeue((list))) != NULL) {
|
||||||
|
int n = atomic_dec_return(&rxrpc_n_skbs);
|
||||||
|
trace_rxrpc_skb(skb, 4, atomic_read(&skb->users), n, here);
|
||||||
|
kfree_skb(skb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue