[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20130516114900.13508.29247.stgit@mhiramat-M0-7522>
Date: Thu, 16 May 2013 20:49:00 +0900
From: Masami Hiramatsu <masami.hiramatsu.pt@...achi.com>
To: linux-kernel@...r.kernel.org, Steven Rostedt <rostedt@...dmis.org>
Cc: Srikar Dronamraju <srikar@...ux.vnet.ibm.com>,
Frederic Weisbecker <fweisbec@...il.com>,
yrl.pp-manager.tt@...achi.com, Oleg Nesterov <oleg@...hat.com>,
Ingo Molnar <mingo@...hat.com>,
Tom Zanussi <tom.zanussi@...el.com>
Subject: [PATCH 5/5] tracing: Support enable/disable multiple events trigger
by wild cards
Support enable/disable multiple events trigger on ftrace
by using wild cards. This makes enabling multiple events
at once easy.
e.g.)
# echo vfs_symlink:enable_event:\*:\*rq\* > set_ftrace_filter
# cat set_ftrace_filter
#### all functions enabled ####
vfs_symlink:enable_event:*:*rq*:unlimited
# grep 0\\* -r events/*/*/enable
events/block/block_getrq/enable:0*
events/block/block_rq_abort/enable:0*
events/block/block_rq_complete/enable:0*
events/block/block_rq_insert/enable:0*
events/block/block_rq_issue/enable:0*
events/block/block_rq_remap/enable:0*
events/block/block_rq_requeue/enable:0*
events/block/block_sleeprq/enable:0*
events/irq/irq_handler_entry/enable:0*
events/irq/irq_handler_exit/enable:0*
events/irq/softirq_entry/enable:0*
events/irq/softirq_exit/enable:0*
events/irq/softirq_raise/enable:0*
Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@...achi.com>
Cc: Steven Rostedt <rostedt@...dmis.org>
Cc: Frederic Weisbecker <fweisbec@...il.com>
Cc: Ingo Molnar <mingo@...hat.com>
---
Documentation/trace/ftrace.txt | 12 ++--
kernel/trace/trace_events.c | 123 +++++++++++++++++++++++++++++-----------
2 files changed, 95 insertions(+), 40 deletions(-)
diff --git a/Documentation/trace/ftrace.txt b/Documentation/trace/ftrace.txt
index bfe8c29..92ca5236 100644
--- a/Documentation/trace/ftrace.txt
+++ b/Documentation/trace/ftrace.txt
@@ -2407,11 +2407,11 @@ The following commands are supported:
echo '!native_flush_tlb_others:snapshot:0' > set_ftrace_filter
- enable_event/disable_event
- These commands can enable or disable a trace event. Note, because
+ These commands can enable or disable trace events. Note, because
function tracing callbacks are very sensitive, when these commands
- are registered, the trace point is activated, but disabled in
- a "soft" mode. That is, the tracepoint will be called, but
- just will not be traced. The event tracepoint stays in this mode
+ are registered, the tracepoints are activated, but disabled in
+ a "soft" mode. That is, the tracepoints will be called, but
+ just will not be traced. The event tracepoints stay in this mode
as long as there's a command that triggers it.
echo 'try_to_wake_up:enable_event:sched:sched_switch:2' > \
@@ -2422,8 +2422,10 @@ The following commands are supported:
<function>:enable_event:<system>:<event>[:count]
<function>:disable_event:<system>:<event>[:count]
- To remove the events commands:
+ Note that the system and event accept wildcards for operating
+ multiple events at once.
+ To remove the events commands:
echo '!try_to_wake_up:enable_event:sched:sched_switch:0' > \
set_ftrace_filter
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c
index 27963e2..1376bb4 100644
--- a/kernel/trace/trace_events.c
+++ b/kernel/trace/trace_events.c
@@ -1850,17 +1850,21 @@ __trace_add_event_dirs(struct trace_array *tr)
#define DISABLE_EVENT_STR "disable_event"
struct event_probe_data {
- struct ftrace_event_file *file;
+ struct ftrace_event_file **files;
+ char *event;
+ char *system;
unsigned long count;
int ref;
bool enable;
};
-static struct ftrace_event_file *
-find_event_file(struct trace_array *tr, const char *system, const char *event)
+static int
+find_event_files(struct trace_array *tr, const char *system, const char *event,
+ struct ftrace_event_file **files, int size)
{
struct ftrace_event_file *file;
struct ftrace_event_call *call;
+ int nr = 0;
list_for_each_entry(file, &tr->events, list) {
@@ -1872,11 +1876,14 @@ find_event_file(struct trace_array *tr, const char *system, const char *event)
if (call->flags & TRACE_EVENT_FL_IGNORE_ENABLE)
continue;
- if (strcmp(event, call->name) == 0 &&
- strcmp(system, call->class->system) == 0)
- return file;
+ if (strglobmatch(event, call->name) &&
+ strglobmatch(system, call->class->system)) {
+ if (files && nr < size)
+ files[nr] = file;
+ nr++;
+ }
}
- return NULL;
+ return nr;
}
static void
@@ -1884,14 +1891,24 @@ event_enable_probe(unsigned long ip, unsigned long parent_ip, void **_data)
{
struct event_probe_data **pdata = (struct event_probe_data **)_data;
struct event_probe_data *data = *pdata;
+ struct ftrace_event_file **file;
if (!data)
return;
- if (data->enable)
- clear_bit(FTRACE_EVENT_FL_SOFT_DISABLED_BIT, &data->file->flags);
- else
- set_bit(FTRACE_EVENT_FL_SOFT_DISABLED_BIT, &data->file->flags);
+ file = data->files;
+ if (unlikely(!file))
+ return;
+
+ while (*file) {
+ if (data->enable)
+ clear_bit(FTRACE_EVENT_FL_SOFT_DISABLED_BIT,
+ &(*file)->flags);
+ else
+ set_bit(FTRACE_EVENT_FL_SOFT_DISABLED_BIT,
+ &(*file)->flags);
+ file++;
+ }
}
static void
@@ -1906,10 +1923,6 @@ event_enable_count_probe(unsigned long ip, unsigned long parent_ip, void **_data
if (!data->count)
return;
- /* Skip if the event is in a state we want to switch to */
- if (data->enable == !(data->file->flags & FTRACE_EVENT_FL_SOFT_DISABLED))
- return;
-
if (data->count != -1)
(data->count)--;
@@ -1926,8 +1939,7 @@ event_enable_print(struct seq_file *m, unsigned long ip,
seq_printf(m, "%s:%s:%s",
data->enable ? ENABLE_EVENT_STR : DISABLE_EVENT_STR,
- data->file->event_call->class->system,
- data->file->event_call->name);
+ data->system, data->event);
if (data->count == -1)
seq_printf(m, ":unlimited\n");
@@ -1948,6 +1960,40 @@ event_enable_init(struct ftrace_probe_ops *ops, unsigned long ip,
return 0;
}
+static int event_files_soft_mode(struct ftrace_event_file **files, int enable)
+{
+ struct ftrace_event_file **file = files;
+
+ if (!file)
+ return -EINVAL;
+
+ while (*file) {
+ /* Don't let event modules unload while probe registered */
+ if (enable) {
+ if (!try_module_get((*file)->event_call->mod))
+ goto rollback;
+ }
+
+ __ftrace_event_enable_disable(*file, enable, 1);
+
+ if (!enable)
+ module_put((*file)->event_call->mod);
+
+ file++;
+ }
+
+ return 0;
+
+ rollback:
+ while (file != files) {
+ file--;
+ __ftrace_event_enable_disable(*file, 0, 1);
+ module_put((*file)->event_call->mod);
+ }
+
+ return -EBUSY;
+}
+
static void
event_enable_free(struct ftrace_probe_ops *ops, unsigned long ip,
void **_data)
@@ -1960,9 +2006,11 @@ event_enable_free(struct ftrace_probe_ops *ops, unsigned long ip,
data->ref--;
if (!data->ref) {
- /* Remove the SOFT_MODE flag */
- __ftrace_event_enable_disable(data->file, 0, 1);
- module_put(data->file->event_call->mod);
+ /* We don't need wait rcu because no one refers data here */
+ event_files_soft_mode(data->files, 0);
+ kfree(data->files);
+ kfree(data->event);
+ kfree(data->system);
kfree(data);
}
*pdata = NULL;
@@ -2001,13 +2049,13 @@ event_enable_func(struct ftrace_hash *hash,
char *glob, char *cmd, char *param, int enabled)
{
struct trace_array *tr = top_trace_array();
- struct ftrace_event_file *file;
struct ftrace_probe_ops *ops;
struct event_probe_data *data;
const char *system;
const char *event;
char *number;
bool enable;
+ int nr_files;
int ret;
/* hash funcs only work with set_ftrace_filter */
@@ -2026,8 +2074,8 @@ event_enable_func(struct ftrace_hash *hash,
mutex_lock(&event_mutex);
ret = -EINVAL;
- file = find_event_file(tr, system, event);
- if (!file)
+ nr_files = find_event_files(tr, system, event, NULL, 0);
+ if (nr_files == 0)
goto out;
enable = strcmp(cmd, ENABLE_EVENT_STR) == 0;
@@ -2050,7 +2098,17 @@ event_enable_func(struct ftrace_hash *hash,
data->enable = enable;
data->count = -1;
- data->file = file;
+ data->files = kzalloc((nr_files + 1) * sizeof(*data->files),
+ GFP_KERNEL);
+ if (!data->files)
+ goto out_free;
+
+ find_event_files(tr, system, event, data->files, nr_files);
+
+ data->event = kstrdup(event, GFP_KERNEL);
+ data->system = kstrdup(system, GFP_KERNEL);
+ if (!data->event || !data->system)
+ goto out_free;
if (!param)
goto out_reg;
@@ -2070,16 +2128,10 @@ event_enable_func(struct ftrace_hash *hash,
goto out_free;
out_reg:
- /* Don't let event modules unload while probe registered */
- ret = try_module_get(file->event_call->mod);
- if (!ret) {
- ret = -EBUSY;
+ ret = event_files_soft_mode(data->files, 1);
+ if (ret < 0)
goto out_free;
- }
- ret = __ftrace_event_enable_disable(file, 1, 1);
- if (ret < 0)
- goto out_put;
ret = register_ftrace_function_probe(glob, ops, data);
/*
* The above returns on success the # of functions enabled,
@@ -2098,10 +2150,11 @@ event_enable_func(struct ftrace_hash *hash,
return ret;
out_disable:
- __ftrace_event_enable_disable(file, 0, 1);
- out_put:
- module_put(file->event_call->mod);
+ event_files_soft_mode(data->files, 0);
out_free:
+ kfree(data->files);
+ kfree(data->event);
+ kfree(data->system);
kfree(data);
goto out;
}
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
Powered by blists - more mailing lists