mirror of
https://github.com/lkl/linux.git
synced 2025-12-19 16:13:19 +09:00
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>
This commit is contained in:
committed by
Dominique Martinet
parent
b48dbb998d
commit
286c171b86
@@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
#include <linux/utsname.h>
|
#include <linux/utsname.h>
|
||||||
#include <linux/idr.h>
|
#include <linux/idr.h>
|
||||||
|
#include <linux/tracepoint-defs.h>
|
||||||
|
|
||||||
/* Number of requests per row */
|
/* Number of requests per row */
|
||||||
#define P9_ROW_MAXTAG 255
|
#define P9_ROW_MAXTAG 255
|
||||||
@@ -237,6 +238,12 @@ static inline int p9_req_try_get(struct p9_req_t *r)
|
|||||||
|
|
||||||
int p9_req_put(struct p9_req_t *r);
|
int p9_req_put(struct p9_req_t *r);
|
||||||
|
|
||||||
|
/* We cannot have the real tracepoints in header files,
|
||||||
|
* use a wrapper function */
|
||||||
|
DECLARE_TRACEPOINT(9p_fid_ref);
|
||||||
|
void do_trace_9p_fid_get(struct p9_fid *fid);
|
||||||
|
void do_trace_9p_fid_put(struct p9_fid *fid);
|
||||||
|
|
||||||
/* fid reference counting helpers:
|
/* fid reference counting helpers:
|
||||||
* - fids used for any length of time should always be referenced through
|
* - fids used for any length of time should always be referenced through
|
||||||
* p9_fid_get(), and released with p9_fid_put()
|
* p9_fid_get(), and released with p9_fid_put()
|
||||||
@@ -249,6 +256,9 @@ int p9_req_put(struct p9_req_t *r);
|
|||||||
*/
|
*/
|
||||||
static inline struct p9_fid *p9_fid_get(struct p9_fid *fid)
|
static inline struct p9_fid *p9_fid_get(struct p9_fid *fid)
|
||||||
{
|
{
|
||||||
|
if (tracepoint_enabled(9p_fid_ref))
|
||||||
|
do_trace_9p_fid_get(fid);
|
||||||
|
|
||||||
refcount_inc(&fid->count);
|
refcount_inc(&fid->count);
|
||||||
|
|
||||||
return fid;
|
return fid;
|
||||||
@@ -259,6 +269,9 @@ static inline int p9_fid_put(struct p9_fid *fid)
|
|||||||
if (!fid || IS_ERR(fid))
|
if (!fid || IS_ERR(fid))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
if (tracepoint_enabled(9p_fid_ref))
|
||||||
|
do_trace_9p_fid_put(fid);
|
||||||
|
|
||||||
if (!refcount_dec_and_test(&fid->count))
|
if (!refcount_dec_and_test(&fid->count))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
|||||||
@@ -77,6 +77,13 @@
|
|||||||
EM( P9_TWSTAT, "P9_TWSTAT" ) \
|
EM( P9_TWSTAT, "P9_TWSTAT" ) \
|
||||||
EMe(P9_RWSTAT, "P9_RWSTAT" )
|
EMe(P9_RWSTAT, "P9_RWSTAT" )
|
||||||
|
|
||||||
|
|
||||||
|
#define P9_FID_REFTYPE \
|
||||||
|
EM( P9_FID_REF_CREATE, "create " ) \
|
||||||
|
EM( P9_FID_REF_GET, "get " ) \
|
||||||
|
EM( P9_FID_REF_PUT, "put " ) \
|
||||||
|
EMe(P9_FID_REF_DESTROY, "destroy" )
|
||||||
|
|
||||||
/* Define EM() to export the enums to userspace via TRACE_DEFINE_ENUM() */
|
/* Define EM() to export the enums to userspace via TRACE_DEFINE_ENUM() */
|
||||||
#undef EM
|
#undef EM
|
||||||
#undef EMe
|
#undef EMe
|
||||||
@@ -84,6 +91,21 @@
|
|||||||
#define EMe(a, b) TRACE_DEFINE_ENUM(a);
|
#define EMe(a, b) TRACE_DEFINE_ENUM(a);
|
||||||
|
|
||||||
P9_MSG_T
|
P9_MSG_T
|
||||||
|
P9_FID_REFTYPE
|
||||||
|
|
||||||
|
/* And also use EM/EMe to define helper enums -- once */
|
||||||
|
#ifndef __9P_DECLARE_TRACE_ENUMS_ONLY_ONCE
|
||||||
|
#define __9P_DECLARE_TRACE_ENUMS_ONLY_ONCE
|
||||||
|
#undef EM
|
||||||
|
#undef EMe
|
||||||
|
#define EM(a, b) a,
|
||||||
|
#define EMe(a, b) a
|
||||||
|
|
||||||
|
enum p9_fid_reftype {
|
||||||
|
P9_FID_REFTYPE
|
||||||
|
} __mode(byte);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Now redefine the EM() and EMe() macros to map the enums to the strings
|
* Now redefine the EM() and EMe() macros to map the enums to the strings
|
||||||
@@ -96,6 +118,8 @@ P9_MSG_T
|
|||||||
|
|
||||||
#define show_9p_op(type) \
|
#define show_9p_op(type) \
|
||||||
__print_symbolic(type, P9_MSG_T)
|
__print_symbolic(type, P9_MSG_T)
|
||||||
|
#define show_9p_fid_reftype(type) \
|
||||||
|
__print_symbolic(type, P9_FID_REFTYPE)
|
||||||
|
|
||||||
TRACE_EVENT(9p_client_req,
|
TRACE_EVENT(9p_client_req,
|
||||||
TP_PROTO(struct p9_client *clnt, int8_t type, int tag),
|
TP_PROTO(struct p9_client *clnt, int8_t type, int tag),
|
||||||
@@ -168,6 +192,30 @@ TRACE_EVENT(9p_protocol_dump,
|
|||||||
__entry->tag, 0, __entry->line, 16, __entry->line + 16)
|
__entry->tag, 0, __entry->line, 16, __entry->line + 16)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
TRACE_EVENT(9p_fid_ref,
|
||||||
|
TP_PROTO(struct p9_fid *fid, __u8 type),
|
||||||
|
|
||||||
|
TP_ARGS(fid, type),
|
||||||
|
|
||||||
|
TP_STRUCT__entry(
|
||||||
|
__field( int, fid )
|
||||||
|
__field( int, refcount )
|
||||||
|
__field( __u8, type )
|
||||||
|
),
|
||||||
|
|
||||||
|
TP_fast_assign(
|
||||||
|
__entry->fid = fid->fid;
|
||||||
|
__entry->refcount = refcount_read(&fid->count);
|
||||||
|
__entry->type = type;
|
||||||
|
),
|
||||||
|
|
||||||
|
TP_printk("%s fid %d, refcount %d",
|
||||||
|
show_9p_fid_reftype(__entry->type),
|
||||||
|
__entry->fid, __entry->refcount)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
#endif /* _TRACE_9P_H */
|
#endif /* _TRACE_9P_H */
|
||||||
|
|
||||||
/* This part must be outside protection */
|
/* This part must be outside protection */
|
||||||
|
|||||||
@@ -907,8 +907,10 @@ static struct p9_fid *p9_fid_create(struct p9_client *clnt)
|
|||||||
GFP_NOWAIT);
|
GFP_NOWAIT);
|
||||||
spin_unlock_irq(&clnt->lock);
|
spin_unlock_irq(&clnt->lock);
|
||||||
idr_preload_end();
|
idr_preload_end();
|
||||||
if (!ret)
|
if (!ret) {
|
||||||
|
trace_9p_fid_ref(fid, P9_FID_REF_CREATE);
|
||||||
return fid;
|
return fid;
|
||||||
|
}
|
||||||
|
|
||||||
kfree(fid);
|
kfree(fid);
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -920,6 +922,7 @@ static void p9_fid_destroy(struct p9_fid *fid)
|
|||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
p9_debug(P9_DEBUG_FID, "fid %d\n", fid->fid);
|
p9_debug(P9_DEBUG_FID, "fid %d\n", fid->fid);
|
||||||
|
trace_9p_fid_ref(fid, P9_FID_REF_DESTROY);
|
||||||
clnt = fid->clnt;
|
clnt = fid->clnt;
|
||||||
spin_lock_irqsave(&clnt->lock, flags);
|
spin_lock_irqsave(&clnt->lock, flags);
|
||||||
idr_remove(&clnt->fids, fid->fid);
|
idr_remove(&clnt->fids, fid->fid);
|
||||||
@@ -928,6 +931,21 @@ static void p9_fid_destroy(struct p9_fid *fid)
|
|||||||
kfree(fid);
|
kfree(fid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* We also need to export tracepoint symbols for tracepoint_enabled() */
|
||||||
|
EXPORT_TRACEPOINT_SYMBOL(9p_fid_ref);
|
||||||
|
|
||||||
|
void do_trace_9p_fid_get(struct p9_fid *fid)
|
||||||
|
{
|
||||||
|
trace_9p_fid_ref(fid, P9_FID_REF_GET);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(do_trace_9p_fid_get);
|
||||||
|
|
||||||
|
void do_trace_9p_fid_put(struct p9_fid *fid)
|
||||||
|
{
|
||||||
|
trace_9p_fid_ref(fid, P9_FID_REF_PUT);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(do_trace_9p_fid_put);
|
||||||
|
|
||||||
static int p9_client_version(struct p9_client *c)
|
static int p9_client_version(struct p9_client *c)
|
||||||
{
|
{
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
|||||||
Reference in New Issue
Block a user