summaryrefslogtreecommitdiffstats
path: root/include/trace/events/afs.h
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2017-01-05 10:38:36 +0000
committerDavid Howells <dhowells@redhat.com>2017-01-09 11:10:02 +0000
commit341f741f04beceebcb30daa12ae2e5e52e64e532 (patch)
tree4c49b19c44fd13d26a2a84264aa062b07b911498 /include/trace/events/afs.h
parent210f035316f545e6f507e7d61e191495ba983e27 (diff)
downloadlinux-341f741f04beceebcb30daa12ae2e5e52e64e532.tar.gz
linux-341f741f04beceebcb30daa12ae2e5e52e64e532.tar.xz
afs: Refcount the afs_call struct
A static checker warning occurs in the AFS filesystem: fs/afs/cmservice.c:155 SRXAFSCB_CallBack() error: dereferencing freed memory 'call' due to the reply being sent before we access the server it points to. The act of sending the reply causes the call to be freed if an error occurs (but not if it doesn't). On top of this, the lifetime handling of afs_call structs is fragile because they get passed around through workqueues without any sort of refcounting. Deal with the issues by: (1) Fix the maybe/maybe not nature of the reply sending functions with regards to whether they release the call struct. (2) Refcount the afs_call struct and sort out places that need to get/put references. (3) Pass a ref through the work queue and release (or pass on) that ref in the work function. Care has to be taken because a work queue may already own a ref to the call. (4) Do the cleaning up in the put function only. (5) Simplify module cleanup by always incrementing afs_outstanding_calls whenever a call is allocated. (6) Set the backlog to 0 with kernel_listen() at the beginning of the process of closing the socket to prevent new incoming calls from occurring and to remove the contribution of preallocated calls from afs_outstanding_calls before we wait on it. A tracepoint is also added to monitor the afs_call refcount and lifetime. Reported-by: Dan Carpenter <dan.carpenter@oracle.com> Signed-off-by: David Howells <dhowells@redhat.com> Fixes: 08e0e7c82eea: "[AF_RXRPC]: Make the in-kernel AFS filesystem use AF_RXRPC."
Diffstat (limited to 'include/trace/events/afs.h')
-rw-r--r--include/trace/events/afs.h75
1 files changed, 75 insertions, 0 deletions
diff --git a/include/trace/events/afs.h b/include/trace/events/afs.h
index 845907b04ff4..8b95c16b7045 100644
--- a/include/trace/events/afs.h
+++ b/include/trace/events/afs.h
@@ -16,6 +16,51 @@
#include <linux/tracepoint.h>
+/*
+ * Define enums for tracing information.
+ */
+#ifndef __AFS_DECLARE_TRACE_ENUMS_ONCE_ONLY
+#define __AFS_DECLARE_TRACE_ENUMS_ONCE_ONLY
+
+enum afs_call_trace {
+ afs_call_trace_alloc,
+ afs_call_trace_free,
+ afs_call_trace_put,
+ afs_call_trace_wake,
+ afs_call_trace_work,
+};
+
+#endif /* end __AFS_DECLARE_TRACE_ENUMS_ONCE_ONLY */
+
+/*
+ * Declare tracing information enums and their string mappings for display.
+ */
+#define afs_call_traces \
+ EM(afs_call_trace_alloc, "ALLOC") \
+ EM(afs_call_trace_free, "FREE ") \
+ EM(afs_call_trace_put, "PUT ") \
+ EM(afs_call_trace_wake, "WAKE ") \
+ E_(afs_call_trace_work, "WORK ")
+
+/*
+ * Export enum symbols via userspace.
+ */
+#undef EM
+#undef E_
+#define EM(a, b) TRACE_DEFINE_ENUM(a);
+#define E_(a, b) TRACE_DEFINE_ENUM(a);
+
+afs_call_traces;
+
+/*
+ * Now redefine the EM() and E_() macros to map the enums to the strings that
+ * will be printed in the output.
+ */
+#undef EM
+#undef E_
+#define EM(a, b) { a, b },
+#define E_(a, b) { a, b }
+
TRACE_EVENT(afs_recv_data,
TP_PROTO(struct afs_call *call, unsigned count, unsigned offset,
bool want_more, int ret),
@@ -103,6 +148,36 @@ TRACE_EVENT(afs_cb_call,
__entry->op)
);
+TRACE_EVENT(afs_call,
+ TP_PROTO(struct afs_call *call, enum afs_call_trace op,
+ int usage, int outstanding, const void *where),
+
+ TP_ARGS(call, op, usage, outstanding, where),
+
+ TP_STRUCT__entry(
+ __field(struct afs_call *, call )
+ __field(int, op )
+ __field(int, usage )
+ __field(int, outstanding )
+ __field(const void *, where )
+ ),
+
+ TP_fast_assign(
+ __entry->call = call;
+ __entry->op = op;
+ __entry->usage = usage;
+ __entry->outstanding = outstanding;
+ __entry->where = where;
+ ),
+
+ TP_printk("c=%p %s u=%d o=%d sp=%pSR",
+ __entry->call,
+ __print_symbolic(__entry->op, afs_call_traces),
+ __entry->usage,
+ __entry->outstanding,
+ __entry->where)
+ );
+
#endif /* _TRACE_AFS_H */
/* This part must be outside protection */