Re: [PATCH] tracing/events: Add module tracepoints

Steven Rostedt
2009-07-21T13:32:26Z

On Tue, 21 Jul 2009, Li Zefan wrote:

> Add trace points to trace module_load, module_free, module_get,
> module_put and module_request, and use trace_event facility
> to get the trace output.
>
> Here's the sample output:
>
> TASK-PID CPU# TIMESTAMP FUNCTION
> | | | | |
> <...>-42 [000] 1.758380: module_request: fb0 wait=1 call_site=fb_open
> ...
> <...>-60 [000] 3.269403: module_load: scsi_wait_scan
> <...>-60 [000] 3.269432: module_put: scsi_wait_scan call_site=sys_init_module refcnt=0
> <...>-61 [001] 3.273168: module_free: scsi_wait_scan
> ...
> <...>-1021 [000] 13.836081: module_load: sunrpc
> <...>-1021 [000] 13.840589: module_put: sunrpc call_site=sys_init_module refcnt=-1
> <...>-1027 [000] 13.848098: module_get: sunrpc call_site=try_module_get refcnt=0
> <...>-1027 [000] 13.848308: module_get: sunrpc call_site=get_filesystem refcnt=1
> <...>-1027 [000] 13.848692: module_put: sunrpc call_site=put_filesystem refcnt=0
> ...
> modprobe-2587 [001] 1088.437213: module_load: trace_events_sample F
> modprobe-2587 [001] 1088.437786: module_put: trace_events_sample call_site=sys_init_module refcnt=0
>
>
> Note:
>
> - the taints flag can be 'F', 'C' and/or 'P' if mod->taints != 0
>
> - the module refcnt is percpu, so it can be negative in a specific cpu
>
> Signed-off-by: Li Zefan <lizf@cn.fujitsu.com>

I'm fine with this, but I would like an Acked-by from Rusty before pulling
it in.

-- Steve

> ---
> include/linux/module.h | 14 ++++-
> include/trace/events/module.h | 126 +++++++++++++++++++++++++++++++++++++++++
> kernel/kmod.c | 4 +
> kernel/module.c | 11 ++++
> 4 files changed, 152 insertions(+), 3 deletions(-)
> create mode 100644 include/trace/events/module.h
>
> diff --git a/include/linux/module.h b/include/linux/module.h
> index 7a5c82c..86863cd 100644
> --- a/include/linux/module.h
> +++ b/include/linux/module.h
> @@ -17,10 +17,12 @@
> #include <linux/moduleparam.h>
> #include <linux/marker.h>
> #include <linux/tracepoint.h>
> -#include <asm/local.h>
>
> +#include <asm/local.h>
> #include <asm/module.h>
>
> +#include <trace/events/module.h>
> +
> /* Not Yet Implemented */
> #define MODULE_SUPPORTED_DEVICE(name)
>
> @@ -480,7 +482,10 @@ static inline local_t *__module_ref_addr(struct module *mod, int cpu)
> static inline void __module_get(struct module *module)
> {
> if (module) {
> - local_inc(__module_ref_addr(module, get_cpu()));
> + unsigned int cpu = get_cpu();
> + local_inc(__module_ref_addr(module, cpu));
> + trace_module_get(module, _THIS_IP_,
> + local_read(__module_ref_addr(module, cpu)));
> put_cpu();
> }
> }
> @@ -491,8 +496,11 @@ static inline int try_module_get(struct module *module)
>
> if (module) {
> unsigned int cpu = get_cpu();
> - if (likely(module_is_live(module)))
> + if (likely(module_is_live(module))) {
> local_inc(__module_ref_addr(module, cpu));
> + trace_module_get(module, _THIS_IP_,
> + local_read(__module_ref_addr(module, cpu)));
> + }
> else
> ret = 0;
> put_cpu();
> diff --git a/include/trace/events/module.h b/include/trace/events/module.h
> new file mode 100644
> index 0000000..84160fb
> --- /dev/null
> +++ b/include/trace/events/module.h
> @@ -0,0 +1,126 @@
> +#undef TRACE_SYSTEM
> +#define TRACE_SYSTEM module
> +
> +#if !defined(_TRACE_MODULE_H) || defined(TRACE_HEADER_MULTI_READ)
> +#define _TRACE_MODULE_H
> +
> +#include <linux/tracepoint.h>
> +
> +#ifdef CONFIG_MODULES
> +
> +struct module;
> +
> +#define show_module_flags(flags) __print_flags(flags, "", \
> + { (1UL << TAINT_PROPRIETARY_MODULE), "P" }, \
> + { (1UL << TAINT_FORCED_MODULE), "F" }, \
> + { (1UL << TAINT_CRAP), "C" })
> +
> +TRACE_EVENT(module_load,
> +
> + TP_PROTO(struct module *mod),
> +
> + TP_ARGS(mod),
> +
> + TP_STRUCT__entry(
> + __field( unsigned int, taints )
> + __string( name, mod->name )
> + ),
> +
> + TP_fast_assign(
> + __entry->taints = mod->taints;
> + __assign_str(name, mod->name);
> + ),
> +
> + TP_printk("%s %s", __get_str(name), show_module_flags(__entry->taints))
> +);
> +
> +TRACE_EVENT(module_free,
> +
> + TP_PROTO(struct module *mod),
> +
> + TP_ARGS(mod),
> +
> + TP_STRUCT__entry(
> + __string( name, mod->name )
> + ),
> +
> + TP_fast_assign(
> + __assign_str(name, mod->name);
> + ),
> +
> + TP_printk("%s", __get_str(name))
> +);
> +
> +TRACE_EVENT(module_get,
> +
> + TP_PROTO(struct module *mod, unsigned long ip, int refcnt),
> +
> + TP_ARGS(mod, ip, refcnt),
> +
> + TP_STRUCT__entry(
> + __field( unsigned long, ip )
> + __field( int, refcnt )
> + __string( name, mod->name )
> + ),
> +
> + TP_fast_assign(
> + __entry->ip = ip;
> + __entry->refcnt = refcnt;
> + __assign_str(name, mod->name);
> + ),
> +
> + TP_printk("%s call_site=%pf refcnt=%d",
> + __get_str(name), (void *)__entry->ip, __entry->refcnt)
> +);
> +
> +TRACE_EVENT(module_put,
> +
> + TP_PROTO(struct module *mod, unsigned long ip, int refcnt),
> +
> + TP_ARGS(mod, ip, refcnt),
> +
> + TP_STRUCT__entry(
> + __field( unsigned long, ip )
> + __field( int, refcnt )
> + __string( name, mod->name )
> + ),
> +
> + TP_fast_assign(
> + __entry->ip = ip;
> + __entry->refcnt = refcnt;
> + __assign_str(name, mod->name);
> + ),
> +
> + TP_printk("%s call_site=%pf refcnt=%d",
> + __get_str(name), (void *)__entry->ip, __entry->refcnt)
> +);
> +
> +TRACE_EVENT(module_request,
> +
> + TP_PROTO(char *name, bool wait, unsigned long ip),
> +
> + TP_ARGS(name, wait, ip),
> +
> + TP_STRUCT__entry(
> + __field( bool, wait )
> + __field( unsigned long, ip )
> + __string( name, name )
> + ),
> +
> + TP_fast_assign(
> + __entry->wait = wait;
> + __entry->ip = ip;
> + __assign_str(name, name);
> + ),
> +
> + TP_printk("%s wait=%d call_site=%pf",
> + __get_str(name), (int)__entry->wait, (void *)__entry->ip)
> +);
> +
> +#endif /* CONFIG_MODULES */
> +
> +#endif /* _TRACE_MODULE_H */
> +
> +/* This part must be outside protection */
> +#include <trace/define_trace.h>
> +
> diff --git a/kernel/kmod.c b/kernel/kmod.c
> index 385c31a..a922808 100644
> --- a/kernel/kmod.c
> +++ b/kernel/kmod.c
> @@ -37,6 +37,8 @@
> #include <linux/suspend.h>
> #include <asm/uaccess.h>
>
> +#include <trace/events/module.h>
> +
> extern int max_threads;
>
> static struct workqueue_struct *khelper_wq;
> @@ -108,6 +110,8 @@ int __request_module(bool wait, const char *fmt, ...)
> return -ENOMEM;
> }
>
> + trace_module_request(module_name, wait, _RET_IP_);
> +
> ret = call_usermodehelper(modprobe_path, argv, envp,
> wait ? UMH_WAIT_PROC : UMH_WAIT_EXEC);
> atomic_dec(&kmod_concurrent);
> diff --git a/kernel/module.c b/kernel/module.c
> index 0a04983..38bf87a 100644
> --- a/kernel/module.c
> +++ b/kernel/module.c
> @@ -55,6 +55,11 @@
> #include <linux/percpu.h>
> #include <linux/kmemleak.h>
>
> +#define CREATE_TRACE_POINTS
> +#include <trace/events/module.h>
> +
> +EXPORT_TRACEPOINT_SYMBOL(module_get);
> +
> #if 0
> #define DEBUGP printk
> #else
> @@ -940,6 +945,8 @@ void module_put(struct module *module)
> if (module) {
> unsigned int cpu = get_cpu();
> local_dec(__module_ref_addr(module, cpu));
> + trace_module_put(module, _RET_IP_,
> + local_read(__module_ref_addr(module, cpu)));
> /* Maybe they're waiting for us to drop reference? */
> if (unlikely(!module_is_live(module)))
> wake_up_process(module->waiter);
> @@ -1490,6 +1497,8 @@ static int __unlink_module(void *_mod)
> /* Free a module, remove from lists, etc (must hold module_mutex). */
> static void free_module(struct module *mod)
> {
> + trace_module_free(mod);
> +
> /* Delete from various lists */
> stop_machine(__unlink_module, mod, NULL);
> remove_notes_attrs(mod);
> @@ -2357,6 +2366,8 @@ static noinline struct module *load_module(void __user *umod,
> /* Get rid of temporary copy */
> vfree(hdr);
>
> + trace_module_load(mod);
> +
> /* Done! */
> return mod;
>
> --
> 1.6.3
>
>