Skip to content

Commit 286c171

Browse files
committed
9p fid refcount: add a 9p_fid_ref tracepoint
This adds a tracepoint event for 9p fid lifecycle tracing: when a fid is created, its reference count increased/decreased, and freed. The new 9p_fid_ref tracepoint should help anyone wishing to debug any fid problem such as missing clunk (destroy) or use-after-free. Link: https://lkml.kernel.org/r/20220612085330.1451496-6-asmadeus@codewreck.org Signed-off-by: Dominique Martinet <asmadeus@codewreck.org>
1 parent b48dbb9 commit 286c171

3 files changed

Lines changed: 80 additions & 1 deletion

File tree

include/net/9p/client.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
#include <linux/utsname.h>
1313
#include <linux/idr.h>
14+
#include <linux/tracepoint-defs.h>
1415

1516
/* Number of requests per row */
1617
#define P9_ROW_MAXTAG 255
@@ -237,6 +238,12 @@ static inline int p9_req_try_get(struct p9_req_t *r)
237238

238239
int p9_req_put(struct p9_req_t *r);
239240

241+
/* We cannot have the real tracepoints in header files,
242+
* use a wrapper function */
243+
DECLARE_TRACEPOINT(9p_fid_ref);
244+
void do_trace_9p_fid_get(struct p9_fid *fid);
245+
void do_trace_9p_fid_put(struct p9_fid *fid);
246+
240247
/* fid reference counting helpers:
241248
* - fids used for any length of time should always be referenced through
242249
* p9_fid_get(), and released with p9_fid_put()
@@ -249,6 +256,9 @@ int p9_req_put(struct p9_req_t *r);
249256
*/
250257
static inline struct p9_fid *p9_fid_get(struct p9_fid *fid)
251258
{
259+
if (tracepoint_enabled(9p_fid_ref))
260+
do_trace_9p_fid_get(fid);
261+
252262
refcount_inc(&fid->count);
253263

254264
return fid;
@@ -259,6 +269,9 @@ static inline int p9_fid_put(struct p9_fid *fid)
259269
if (!fid || IS_ERR(fid))
260270
return 0;
261271

272+
if (tracepoint_enabled(9p_fid_ref))
273+
do_trace_9p_fid_put(fid);
274+
262275
if (!refcount_dec_and_test(&fid->count))
263276
return 0;
264277

include/trace/events/9p.h

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,13 +77,35 @@
7777
EM( P9_TWSTAT, "P9_TWSTAT" ) \
7878
EMe(P9_RWSTAT, "P9_RWSTAT" )
7979

80+
81+
#define P9_FID_REFTYPE \
82+
EM( P9_FID_REF_CREATE, "create " ) \
83+
EM( P9_FID_REF_GET, "get " ) \
84+
EM( P9_FID_REF_PUT, "put " ) \
85+
EMe(P9_FID_REF_DESTROY, "destroy" )
86+
8087
/* Define EM() to export the enums to userspace via TRACE_DEFINE_ENUM() */
8188
#undef EM
8289
#undef EMe
8390
#define EM(a, b) TRACE_DEFINE_ENUM(a);
8491
#define EMe(a, b) TRACE_DEFINE_ENUM(a);
8592

8693
P9_MSG_T
94+
P9_FID_REFTYPE
95+
96+
/* And also use EM/EMe to define helper enums -- once */
97+
#ifndef __9P_DECLARE_TRACE_ENUMS_ONLY_ONCE
98+
#define __9P_DECLARE_TRACE_ENUMS_ONLY_ONCE
99+
#undef EM
100+
#undef EMe
101+
#define EM(a, b) a,
102+
#define EMe(a, b) a
103+
104+
enum p9_fid_reftype {
105+
P9_FID_REFTYPE
106+
} __mode(byte);
107+
108+
#endif
87109

88110
/*
89111
* Now redefine the EM() and EMe() macros to map the enums to the strings
@@ -96,6 +118,8 @@ P9_MSG_T
96118

97119
#define show_9p_op(type) \
98120
__print_symbolic(type, P9_MSG_T)
121+
#define show_9p_fid_reftype(type) \
122+
__print_symbolic(type, P9_FID_REFTYPE)
99123

100124
TRACE_EVENT(9p_client_req,
101125
TP_PROTO(struct p9_client *clnt, int8_t type, int tag),
@@ -168,6 +192,30 @@ TRACE_EVENT(9p_protocol_dump,
168192
__entry->tag, 0, __entry->line, 16, __entry->line + 16)
169193
);
170194

195+
196+
TRACE_EVENT(9p_fid_ref,
197+
TP_PROTO(struct p9_fid *fid, __u8 type),
198+
199+
TP_ARGS(fid, type),
200+
201+
TP_STRUCT__entry(
202+
__field( int, fid )
203+
__field( int, refcount )
204+
__field( __u8, type )
205+
),
206+
207+
TP_fast_assign(
208+
__entry->fid = fid->fid;
209+
__entry->refcount = refcount_read(&fid->count);
210+
__entry->type = type;
211+
),
212+
213+
TP_printk("%s fid %d, refcount %d",
214+
show_9p_fid_reftype(__entry->type),
215+
__entry->fid, __entry->refcount)
216+
);
217+
218+
171219
#endif /* _TRACE_9P_H */
172220

173221
/* This part must be outside protection */

net/9p/client.c

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -907,8 +907,10 @@ static struct p9_fid *p9_fid_create(struct p9_client *clnt)
907907
GFP_NOWAIT);
908908
spin_unlock_irq(&clnt->lock);
909909
idr_preload_end();
910-
if (!ret)
910+
if (!ret) {
911+
trace_9p_fid_ref(fid, P9_FID_REF_CREATE);
911912
return fid;
913+
}
912914

913915
kfree(fid);
914916
return NULL;
@@ -920,6 +922,7 @@ static void p9_fid_destroy(struct p9_fid *fid)
920922
unsigned long flags;
921923

922924
p9_debug(P9_DEBUG_FID, "fid %d\n", fid->fid);
925+
trace_9p_fid_ref(fid, P9_FID_REF_DESTROY);
923926
clnt = fid->clnt;
924927
spin_lock_irqsave(&clnt->lock, flags);
925928
idr_remove(&clnt->fids, fid->fid);
@@ -928,6 +931,21 @@ static void p9_fid_destroy(struct p9_fid *fid)
928931
kfree(fid);
929932
}
930933

934+
/* We also need to export tracepoint symbols for tracepoint_enabled() */
935+
EXPORT_TRACEPOINT_SYMBOL(9p_fid_ref);
936+
937+
void do_trace_9p_fid_get(struct p9_fid *fid)
938+
{
939+
trace_9p_fid_ref(fid, P9_FID_REF_GET);
940+
}
941+
EXPORT_SYMBOL(do_trace_9p_fid_get);
942+
943+
void do_trace_9p_fid_put(struct p9_fid *fid)
944+
{
945+
trace_9p_fid_ref(fid, P9_FID_REF_PUT);
946+
}
947+
EXPORT_SYMBOL(do_trace_9p_fid_put);
948+
931949
static int p9_client_version(struct p9_client *c)
932950
{
933951
int err = 0;

0 commit comments

Comments
 (0)