--- /dev/null
+/* 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>
#include <net/net_namespace.h>
#include <net/sock.h>
#include <net/af_rxrpc.h>
+#define CREATE_TRACE_POINTS
#include "ar-internal.h"
MODULE_DESCRIPTION("RxRPC network protocol");
write_unlock_bh(&call->state_lock);
}
+#include <trace/events/rxrpc.h>
+
/*
* af_rxrpc.c
*/
* skbuff.c
*/
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
#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) \
do { \
_net("incoming call skb %p", skb);
+ rxrpc_see_skb(skb);
sp = rxrpc_skb(skb);
/* Set up a response packet header in case we need it */
skb = skb_dequeue(&call->rx_oos_queue);
if (skb) {
+ rxrpc_see_skb(skb);
sp = rxrpc_skb(skb);
_debug("drain OOS packet %d [%d]",
/* find out what the next packet is */
skb = skb_peek(&call->rx_oos_queue);
+ rxrpc_see_skb(skb);
if (skb)
call->rx_first_oos = rxrpc_skb(skb)->hdr.seq;
else
if (!skb)
return -EAGAIN;
+ rxrpc_see_skb(skb);
_net("deferred skb %p", skb);
sp = rxrpc_skb(skb);
/* go through the conn-level event packets, releasing the ref on this
* connection that each one has when we've finished with it */
while ((skb = skb_dequeue(&conn->rx_queue))) {
+ rxrpc_see_skb(skb);
ret = rxrpc_process_event(conn, skb, &abort_code);
switch (ret) {
case -EPROTO:
whdr.type = RXRPC_PACKET_TYPE_ABORT;
while ((skb = skb_dequeue(&local->reject_queue))) {
+ rxrpc_see_skb(skb);
sp = rxrpc_skb(skb);
switch (sa.sa.sa_family) {
case AF_INET:
if (skb) {
struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
+ rxrpc_see_skb(skb);
_debug("{%d},{%u}", local->debug_id, sp->hdr.type);
switch (sp->hdr.type) {
skb = call->tx_pending;
call->tx_pending = NULL;
+ rxrpc_see_skb(skb);
copied = 0;
do {
}
peek_next_packet:
+ rxrpc_see_skb(skb);
sp = rxrpc_skb(skb);
call = sp->call;
ASSERT(call != NULL);
rxrpc_free_skb(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);
+ }
+}