summaryrefslogtreecommitdiffstats
path: root/kernel/trace/trace_events.c
diff options
context:
space:
mode:
authorSteven Rostedt (VMware) <rostedt@goodmis.org>2017-04-20 04:39:44 +0200
committerSteven Rostedt (VMware) <rostedt@goodmis.org>2017-04-21 04:06:46 +0200
commit6e4443199e5354255e8a4c1e8e5cfc8ef064c3ce (patch)
treeb0e7181d739a1207606bce8f60be5f305e27ea6b /kernel/trace/trace_events.c
parentftrace: Dynamically create the probe ftrace_ops for the trace_array (diff)
downloadlinux-6e4443199e5354255e8a4c1e8e5cfc8ef064c3ce.tar.xz
linux-6e4443199e5354255e8a4c1e8e5cfc8ef064c3ce.zip
tracing/ftrace: Add a better way to pass data via the probe functions
With the redesign of the registration and execution of the function probes (triggers), data can now be passed from the setup of the probe to the probe callers that are specific to the trace_array it is on. Although, all probes still only affect the toplevel trace array, this change will allow for instances to have their own probes separated from other instances and the top array. That is, something like the stacktrace probe can be set to trace only in an instance and not the toplevel trace array. This isn't implement yet, but this change sets the ground work for the change. When a probe callback is triggered (someone writes the probe format into set_ftrace_filter), it calls register_ftrace_function_probe() passing in init_data that will be used to initialize the probe. Then for every matching function, register_ftrace_function_probe() will call the probe_ops->init() function with the init data that was passed to it, as well as an address to a place holder that is associated with the probe and the instance. The first occurrence will have a NULL in the pointer. The init() function will then initialize it. If other probes are added, or more functions are part of the probe, the place holder will be passed to the init() function with the place holder data that it was initialized to the last time. Then this place_holder is passed to each of the other probe_ops functions, where it can be used in the function callback. When the probe_ops free() function is called, it can be called either with the rip of the function that is being removed from the probe, or zero, indicating that there are no more functions attached to the probe, and the place holder is about to be freed. This gives the probe_ops a way to free the data it assigned to the place holder if it was allocade during the first init call. Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
Diffstat (limited to 'kernel/trace/trace_events.c')
-rw-r--r--kernel/trace/trace_events.c110
1 files changed, 63 insertions, 47 deletions
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c
index 48c7f70cbac7..e7973e10398c 100644
--- a/kernel/trace/trace_events.c
+++ b/kernel/trace/trace_events.c
@@ -2471,54 +2471,54 @@ static void update_event_probe(struct event_probe_data *data)
static void
event_enable_probe(unsigned long ip, unsigned long parent_ip,
struct trace_array *tr, struct ftrace_probe_ops *ops,
- void **_data)
+ void *data)
{
- struct ftrace_func_mapper *mapper = ops->private_data;
- struct event_probe_data *data;
+ struct ftrace_func_mapper *mapper = data;
+ struct event_probe_data *edata;
void **pdata;
pdata = ftrace_func_mapper_find_ip(mapper, ip);
if (!pdata || !*pdata)
return;
- data = *pdata;
- update_event_probe(data);
+ edata = *pdata;
+ update_event_probe(edata);
}
static void
event_enable_count_probe(unsigned long ip, unsigned long parent_ip,
struct trace_array *tr, struct ftrace_probe_ops *ops,
- void **_data)
+ void *data)
{
- struct ftrace_func_mapper *mapper = ops->private_data;
- struct event_probe_data *data;
+ struct ftrace_func_mapper *mapper = data;
+ struct event_probe_data *edata;
void **pdata;
pdata = ftrace_func_mapper_find_ip(mapper, ip);
if (!pdata || !*pdata)
return;
- data = *pdata;
+ edata = *pdata;
- if (!data->count)
+ if (!edata->count)
return;
/* Skip if the event is in a state we want to switch to */
- if (data->enable == !(data->file->flags & EVENT_FILE_FL_SOFT_DISABLED))
+ if (edata->enable == !(edata->file->flags & EVENT_FILE_FL_SOFT_DISABLED))
return;
- if (data->count != -1)
- (data->count)--;
+ if (edata->count != -1)
+ (edata->count)--;
- update_event_probe(data);
+ update_event_probe(edata);
}
static int
event_enable_print(struct seq_file *m, unsigned long ip,
- struct ftrace_probe_ops *ops, void *_data)
+ struct ftrace_probe_ops *ops, void *data)
{
- struct ftrace_func_mapper *mapper = ops->private_data;
- struct event_probe_data *data;
+ struct ftrace_func_mapper *mapper = data;
+ struct event_probe_data *edata;
void **pdata;
pdata = ftrace_func_mapper_find_ip(mapper, ip);
@@ -2526,62 +2526,84 @@ event_enable_print(struct seq_file *m, unsigned long ip,
if (WARN_ON_ONCE(!pdata || !*pdata))
return 0;
- data = *pdata;
+ edata = *pdata;
seq_printf(m, "%ps:", (void *)ip);
seq_printf(m, "%s:%s:%s",
- data->enable ? ENABLE_EVENT_STR : DISABLE_EVENT_STR,
- data->file->event_call->class->system,
- trace_event_name(data->file->event_call));
+ edata->enable ? ENABLE_EVENT_STR : DISABLE_EVENT_STR,
+ edata->file->event_call->class->system,
+ trace_event_name(edata->file->event_call));
- if (data->count == -1)
+ if (edata->count == -1)
seq_puts(m, ":unlimited\n");
else
- seq_printf(m, ":count=%ld\n", data->count);
+ seq_printf(m, ":count=%ld\n", edata->count);
return 0;
}
static int
event_enable_init(struct ftrace_probe_ops *ops, struct trace_array *tr,
- unsigned long ip, void *_data)
+ unsigned long ip, void *init_data, void **data)
{
- struct ftrace_func_mapper *mapper = ops->private_data;
- struct event_probe_data *data = _data;
+ struct ftrace_func_mapper *mapper = *data;
+ struct event_probe_data *edata = init_data;
int ret;
- ret = ftrace_func_mapper_add_ip(mapper, ip, data);
+ if (!mapper) {
+ mapper = allocate_ftrace_func_mapper();
+ if (!mapper)
+ return -ENODEV;
+ *data = mapper;
+ }
+
+ ret = ftrace_func_mapper_add_ip(mapper, ip, edata);
if (ret < 0)
return ret;
- data->ref++;
+ edata->ref++;
+
+ return 0;
+}
+
+static int free_probe_data(void *data)
+{
+ struct event_probe_data *edata = data;
+ edata->ref--;
+ if (!edata->ref) {
+ /* Remove the SOFT_MODE flag */
+ __ftrace_event_enable_disable(edata->file, 0, 1);
+ module_put(edata->file->event_call->mod);
+ kfree(edata);
+ }
return 0;
}
static void
event_enable_free(struct ftrace_probe_ops *ops, struct trace_array *tr,
- unsigned long ip, void **_data)
+ unsigned long ip, void *data)
{
- struct ftrace_func_mapper *mapper = ops->private_data;
- struct event_probe_data *data;
+ struct ftrace_func_mapper *mapper = data;
+ struct event_probe_data *edata;
+
+ if (!ip) {
+ if (!mapper)
+ return;
+ free_ftrace_func_mapper(mapper, free_probe_data);
+ return;
+ }
- data = ftrace_func_mapper_remove_ip(mapper, ip);
+ edata = ftrace_func_mapper_remove_ip(mapper, ip);
- if (WARN_ON_ONCE(!data))
+ if (WARN_ON_ONCE(!edata))
return;
- if (WARN_ON_ONCE(data->ref <= 0))
+ if (WARN_ON_ONCE(edata->ref <= 0))
return;
- 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);
- kfree(data);
- }
+ free_probe_data(edata);
}
static struct ftrace_probe_ops event_enable_probe_ops = {
@@ -2659,12 +2681,6 @@ event_enable_func(struct trace_array *tr, struct ftrace_hash *hash,
ret = -ENOMEM;
- if (!ops->private_data) {
- ops->private_data = allocate_ftrace_func_mapper();
- if (!ops->private_data)
- goto out;
- }
-
data = kzalloc(sizeof(*data), GFP_KERNEL);
if (!data)
goto out;