tracing: Ftrace dynamic ftrace_event_call support
Add dynamic ftrace_event_call support to ftrace. Trace engines can add
new ftrace_event_call to ftrace on the fly. Each operator function of
the call takes an ftrace_event_call data structure as an argument,
because these functions may be shared among several ftrace_event_calls.
Changes from v13:
- Define remove_subsystem_dir() always (revirt a2ca5e03
), because
trace_remove_event_call() uses it.
- Modify syscall tracer because of ftrace_event_call change.
[fweisbec@gmail.com: Fixed conflict against latest tracing/core]
Signed-off-by: Masami Hiramatsu <mhiramat@redhat.com>
Cc: Ananth N Mavinakayanahalli <ananth@in.ibm.com>
Cc: Avi Kivity <avi@redhat.com>
Cc: Andi Kleen <ak@linux.intel.com>
Cc: Christoph Hellwig <hch@infradead.org>
Cc: Frank Ch. Eigler <fche@redhat.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Jason Baron <jbaron@redhat.com>
Cc: Jim Keniston <jkenisto@us.ibm.com>
Cc: K.Prasad <prasad@linux.vnet.ibm.com>
Cc: Lai Jiangshan <laijs@cn.fujitsu.com>
Cc: Li Zefan <lizf@cn.fujitsu.com>
Cc: Przemysław Pawełczyk <przemyslaw@pawelczyk.it>
Cc: Roland McGrath <roland@redhat.com>
Cc: Sam Ravnborg <sam@ravnborg.org>
Cc: Srikar Dronamraju <srikar@linux.vnet.ibm.com>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Tom Zanussi <tzanussi@gmail.com>
Cc: Vegard Nossum <vegard.nossum@gmail.com>
LKML-Reference: <20090813203453.31965.71901.stgit@localhost.localdomain>
Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com>
This commit is contained in:
committed by
Frederic Weisbecker
parent
b1cf540f0e
commit
bd1a5c849b
@@ -27,8 +27,8 @@ DEFINE_MUTEX(event_mutex);
|
||||
|
||||
LIST_HEAD(ftrace_events);
|
||||
|
||||
int trace_define_field(struct ftrace_event_call *call, const char *type,
|
||||
const char *name, int offset, int size, int is_signed,
|
||||
int trace_define_field(struct ftrace_event_call *call, char *type,
|
||||
char *name, int offset, int size, int is_signed,
|
||||
int filter_type)
|
||||
{
|
||||
struct ftrace_event_field *field;
|
||||
@@ -92,9 +92,7 @@ int trace_define_common_fields(struct ftrace_event_call *call)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(trace_define_common_fields);
|
||||
|
||||
#ifdef CONFIG_MODULES
|
||||
|
||||
static void trace_destroy_fields(struct ftrace_event_call *call)
|
||||
void trace_destroy_fields(struct ftrace_event_call *call)
|
||||
{
|
||||
struct ftrace_event_field *field, *next;
|
||||
|
||||
@@ -106,8 +104,6 @@ static void trace_destroy_fields(struct ftrace_event_call *call)
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* CONFIG_MODULES */
|
||||
|
||||
static void ftrace_event_enable_disable(struct ftrace_event_call *call,
|
||||
int enable)
|
||||
{
|
||||
@@ -116,14 +112,14 @@ static void ftrace_event_enable_disable(struct ftrace_event_call *call,
|
||||
if (call->enabled) {
|
||||
call->enabled = 0;
|
||||
tracing_stop_cmdline_record();
|
||||
call->unregfunc(call->data);
|
||||
call->unregfunc(call);
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
if (!call->enabled) {
|
||||
call->enabled = 1;
|
||||
tracing_start_cmdline_record();
|
||||
call->regfunc(call->data);
|
||||
call->regfunc(call);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -991,27 +987,43 @@ event_create_dir(struct ftrace_event_call *call, struct dentry *d_events,
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define for_each_event(event, start, end) \
|
||||
for (event = start; \
|
||||
(unsigned long)event < (unsigned long)end; \
|
||||
event++)
|
||||
static int __trace_add_event_call(struct ftrace_event_call *call)
|
||||
{
|
||||
struct dentry *d_events;
|
||||
int ret;
|
||||
|
||||
#ifdef CONFIG_MODULES
|
||||
if (!call->name)
|
||||
return -EINVAL;
|
||||
|
||||
static LIST_HEAD(ftrace_module_file_list);
|
||||
if (call->raw_init) {
|
||||
ret = call->raw_init(call);
|
||||
if (ret < 0) {
|
||||
if (ret != -ENOSYS)
|
||||
pr_warning("Could not initialize trace "
|
||||
"events/%s\n", call->name);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Modules must own their file_operations to keep up with
|
||||
* reference counting.
|
||||
*/
|
||||
struct ftrace_module_file_ops {
|
||||
struct list_head list;
|
||||
struct module *mod;
|
||||
struct file_operations id;
|
||||
struct file_operations enable;
|
||||
struct file_operations format;
|
||||
struct file_operations filter;
|
||||
};
|
||||
d_events = event_trace_events_dir();
|
||||
if (!d_events)
|
||||
return -ENOENT;
|
||||
|
||||
list_add(&call->list, &ftrace_events);
|
||||
return event_create_dir(call, d_events, &ftrace_event_id_fops,
|
||||
&ftrace_enable_fops, &ftrace_event_filter_fops,
|
||||
&ftrace_event_format_fops);
|
||||
}
|
||||
|
||||
/* Add an additional event_call dynamically */
|
||||
int trace_add_event_call(struct ftrace_event_call *call)
|
||||
{
|
||||
int ret;
|
||||
mutex_lock(&event_mutex);
|
||||
ret = __trace_add_event_call(call);
|
||||
mutex_unlock(&event_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void remove_subsystem_dir(const char *name)
|
||||
{
|
||||
@@ -1039,6 +1051,48 @@ static void remove_subsystem_dir(const char *name)
|
||||
}
|
||||
}
|
||||
|
||||
static void __trace_remove_event_call(struct ftrace_event_call *call)
|
||||
{
|
||||
ftrace_event_enable_disable(call, 0);
|
||||
if (call->event)
|
||||
__unregister_ftrace_event(call->event);
|
||||
debugfs_remove_recursive(call->dir);
|
||||
list_del(&call->list);
|
||||
trace_destroy_fields(call);
|
||||
destroy_preds(call);
|
||||
remove_subsystem_dir(call->system);
|
||||
}
|
||||
|
||||
/* Remove an event_call */
|
||||
void trace_remove_event_call(struct ftrace_event_call *call)
|
||||
{
|
||||
mutex_lock(&event_mutex);
|
||||
__trace_remove_event_call(call);
|
||||
mutex_unlock(&event_mutex);
|
||||
}
|
||||
|
||||
#define for_each_event(event, start, end) \
|
||||
for (event = start; \
|
||||
(unsigned long)event < (unsigned long)end; \
|
||||
event++)
|
||||
|
||||
#ifdef CONFIG_MODULES
|
||||
|
||||
static LIST_HEAD(ftrace_module_file_list);
|
||||
|
||||
/*
|
||||
* Modules must own their file_operations to keep up with
|
||||
* reference counting.
|
||||
*/
|
||||
struct ftrace_module_file_ops {
|
||||
struct list_head list;
|
||||
struct module *mod;
|
||||
struct file_operations id;
|
||||
struct file_operations enable;
|
||||
struct file_operations format;
|
||||
struct file_operations filter;
|
||||
};
|
||||
|
||||
static struct ftrace_module_file_ops *
|
||||
trace_create_file_ops(struct module *mod)
|
||||
{
|
||||
@@ -1096,7 +1150,7 @@ static void trace_module_add_events(struct module *mod)
|
||||
if (!call->name)
|
||||
continue;
|
||||
if (call->raw_init) {
|
||||
ret = call->raw_init();
|
||||
ret = call->raw_init(call);
|
||||
if (ret < 0) {
|
||||
if (ret != -ENOSYS)
|
||||
pr_warning("Could not initialize trace "
|
||||
@@ -1131,14 +1185,7 @@ static void trace_module_remove_events(struct module *mod)
|
||||
list_for_each_entry_safe(call, p, &ftrace_events, list) {
|
||||
if (call->mod == mod) {
|
||||
found = true;
|
||||
ftrace_event_enable_disable(call, 0);
|
||||
if (call->event)
|
||||
__unregister_ftrace_event(call->event);
|
||||
debugfs_remove_recursive(call->dir);
|
||||
list_del(&call->list);
|
||||
trace_destroy_fields(call);
|
||||
destroy_preds(call);
|
||||
remove_subsystem_dir(call->system);
|
||||
__trace_remove_event_call(call);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1256,7 +1303,7 @@ static __init int event_trace_init(void)
|
||||
if (!call->name)
|
||||
continue;
|
||||
if (call->raw_init) {
|
||||
ret = call->raw_init();
|
||||
ret = call->raw_init(call);
|
||||
if (ret < 0) {
|
||||
if (ret != -ENOSYS)
|
||||
pr_warning("Could not initialize trace "
|
||||
|
Reference in New Issue
Block a user