diff options
Diffstat (limited to 'kernel/trace')
-rw-r--r-- | kernel/trace/ftrace.c | 25 | ||||
-rw-r--r-- | kernel/trace/trace.c | 38 | ||||
-rw-r--r-- | kernel/trace/trace.h | 8 | ||||
-rw-r--r-- | kernel/trace/trace_events.c | 110 | ||||
-rw-r--r-- | kernel/trace/trace_functions.c | 79 |
5 files changed, 153 insertions, 107 deletions
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 8fdc18500c61..774e9108e5dc 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c @@ -1106,6 +1106,7 @@ struct ftrace_func_probe { struct ftrace_ops ops; struct trace_array *tr; struct list_head list; + void *data; int ref; }; @@ -3187,7 +3188,7 @@ t_probe_show(struct seq_file *m, struct ftrace_iterator *iter) probe_ops = probe->probe_ops; if (probe_ops->print) - return probe_ops->print(m, probe_entry->ip, probe_ops, NULL); + return probe_ops->print(m, probe_entry->ip, probe_ops, probe->data); seq_printf(m, "%ps:%ps\n", (void *)probe_entry->ip, (void *)probe_ops->func); @@ -3814,7 +3815,7 @@ static void function_trace_probe_call(unsigned long ip, unsigned long parent_ip, * on the hash. rcu_read_lock is too dangerous here. */ preempt_disable_notrace(); - probe_ops->func(ip, parent_ip, probe->tr, probe_ops, NULL); + probe_ops->func(ip, parent_ip, probe->tr, probe_ops, probe->data); preempt_enable_notrace(); } @@ -3972,6 +3973,12 @@ static void release_probe(struct ftrace_func_probe *probe) if (!probe->ref) { probe_ops = probe->probe_ops; + /* + * Sending zero as ip tells probe_ops to free + * the probe->data itself + */ + if (probe_ops->free) + probe_ops->free(probe_ops, probe->tr, 0, probe->data); list_del(&probe->list); kfree(probe); } @@ -4060,9 +4067,15 @@ register_ftrace_function_probe(char *glob, struct trace_array *tr, */ if (probe_ops->init) { ret = probe_ops->init(probe_ops, tr, - entry->ip, data); - if (ret < 0) + entry->ip, data, + &probe->data); + if (ret < 0) { + if (probe_ops->free && count) + probe_ops->free(probe_ops, tr, + 0, probe->data); + probe->data = NULL; goto out; + } } count++; } @@ -4109,7 +4122,7 @@ register_ftrace_function_probe(char *glob, struct trace_array *tr, hlist_for_each_entry(entry, &hash->buckets[i], hlist) { if (ftrace_lookup_ip(old_hash, entry->ip)) continue; - probe_ops->free(probe_ops, tr, entry->ip, NULL); + probe_ops->free(probe_ops, tr, entry->ip, probe->data); } } goto out_unlock; @@ -4227,7 +4240,7 @@ unregister_ftrace_function_probe_func(char *glob, struct trace_array *tr, hlist_for_each_entry_safe(entry, tmp, &hhd, hlist) { hlist_del(&entry->hlist); if (probe_ops->free) - probe_ops->free(probe_ops, tr, entry->ip, NULL); + probe_ops->free(probe_ops, tr, entry->ip, probe->data); kfree(entry); } mutex_unlock(&ftrace_lock); diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index e61610e5e6e3..18256cd7ad2c 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -6737,7 +6737,7 @@ static const struct file_operations tracing_dyn_info_fops = { static void ftrace_snapshot(unsigned long ip, unsigned long parent_ip, struct trace_array *tr, struct ftrace_probe_ops *ops, - void **data) + void *data) { tracing_snapshot(); } @@ -6745,9 +6745,9 @@ ftrace_snapshot(unsigned long ip, unsigned long parent_ip, static void ftrace_count_snapshot(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 ftrace_func_mapper *mapper = data; long *count = NULL; if (mapper) @@ -6768,7 +6768,7 @@ static int ftrace_snapshot_print(struct seq_file *m, unsigned long ip, struct ftrace_probe_ops *ops, void *data) { - struct ftrace_func_mapper *mapper = ops->private_data; + struct ftrace_func_mapper *mapper = data; long *count = NULL; seq_printf(m, "%ps:", (void *)ip); @@ -6788,18 +6788,32 @@ ftrace_snapshot_print(struct seq_file *m, unsigned long ip, static int ftrace_snapshot_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 ftrace_func_mapper *mapper = *data; + + if (!mapper) { + mapper = allocate_ftrace_func_mapper(); + if (!mapper) + return -ENOMEM; + *data = mapper; + } - return ftrace_func_mapper_add_ip(mapper, ip, data); + return ftrace_func_mapper_add_ip(mapper, ip, init_data); } static void ftrace_snapshot_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 ftrace_func_mapper *mapper = data; + + if (!ip) { + if (!mapper) + return; + free_ftrace_func_mapper(mapper, NULL); + return; + } ftrace_func_mapper_remove_ip(mapper, ip); } @@ -6842,12 +6856,6 @@ ftrace_trace_snapshot_callback(struct trace_array *tr, struct ftrace_hash *hash, if (!strlen(number)) goto out_reg; - if (!ops->private_data) { - ops->private_data = allocate_ftrace_func_mapper(); - if (!ops->private_data) - return -ENOMEM; - } - /* * We use the callback data field (which is a pointer) * as our counter. diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h index e978ecd257b8..8f6754fba778 100644 --- a/kernel/trace/trace.h +++ b/kernel/trace/trace.h @@ -943,18 +943,18 @@ struct ftrace_probe_ops { unsigned long parent_ip, struct trace_array *tr, struct ftrace_probe_ops *ops, - void **data); + void *data); int (*init)(struct ftrace_probe_ops *ops, struct trace_array *tr, - unsigned long ip, void *data); + unsigned long ip, void *init_data, + void **data); void (*free)(struct ftrace_probe_ops *ops, struct trace_array *tr, - unsigned long ip, void **data); + unsigned long ip, void *data); int (*print)(struct seq_file *m, unsigned long ip, struct ftrace_probe_ops *ops, void *data); - void *private_data; }; struct ftrace_func_mapper; 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; diff --git a/kernel/trace/trace_functions.c b/kernel/trace/trace_functions.c index b95f56ba9744..7775e1ca5bad 100644 --- a/kernel/trace/trace_functions.c +++ b/kernel/trace/trace_functions.c @@ -268,9 +268,10 @@ static struct tracer function_trace __tracer_data = #ifdef CONFIG_DYNAMIC_FTRACE static void update_traceon_count(struct ftrace_probe_ops *ops, - unsigned long ip, bool on) + unsigned long ip, bool on, + void *data) { - struct ftrace_func_mapper *mapper = ops->private_data; + struct ftrace_func_mapper *mapper = data; long *count; long old_count; @@ -329,23 +330,23 @@ static void update_traceon_count(struct ftrace_probe_ops *ops, static void ftrace_traceon_count(unsigned long ip, unsigned long parent_ip, struct trace_array *tr, struct ftrace_probe_ops *ops, - void **data) + void *data) { - update_traceon_count(ops, ip, 1); + update_traceon_count(ops, ip, 1, data); } static void ftrace_traceoff_count(unsigned long ip, unsigned long parent_ip, struct trace_array *tr, struct ftrace_probe_ops *ops, - void **data) + void *data) { - update_traceon_count(ops, ip, 0); + update_traceon_count(ops, ip, 0, data); } static void ftrace_traceon(unsigned long ip, unsigned long parent_ip, struct trace_array *tr, struct ftrace_probe_ops *ops, - void **data) + void *data) { if (tracing_is_on()) return; @@ -356,7 +357,7 @@ ftrace_traceon(unsigned long ip, unsigned long parent_ip, static void ftrace_traceoff(unsigned long ip, unsigned long parent_ip, struct trace_array *tr, struct ftrace_probe_ops *ops, - void **data) + void *data) { if (!tracing_is_on()) return; @@ -376,7 +377,7 @@ ftrace_traceoff(unsigned long ip, unsigned long parent_ip, static void ftrace_stacktrace(unsigned long ip, unsigned long parent_ip, struct trace_array *tr, struct ftrace_probe_ops *ops, - void **data) + void *data) { trace_dump_stack(STACK_SKIP); } @@ -384,9 +385,9 @@ ftrace_stacktrace(unsigned long ip, unsigned long parent_ip, static void ftrace_stacktrace_count(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 ftrace_func_mapper *mapper = data; long *count; long old_count; long new_count; @@ -423,9 +424,10 @@ ftrace_stacktrace_count(unsigned long ip, unsigned long parent_ip, } while (new_count != old_count); } -static int update_count(struct ftrace_probe_ops *ops, unsigned long ip) +static int update_count(struct ftrace_probe_ops *ops, unsigned long ip, + void *data) { - struct ftrace_func_mapper *mapper = ops->private_data; + struct ftrace_func_mapper *mapper = data; long *count = NULL; if (mapper) @@ -443,9 +445,9 @@ static int update_count(struct ftrace_probe_ops *ops, unsigned long ip) static void ftrace_dump_probe(unsigned long ip, unsigned long parent_ip, struct trace_array *tr, struct ftrace_probe_ops *ops, - void **data) + void *data) { - if (update_count(ops, ip)) + if (update_count(ops, ip, data)) ftrace_dump(DUMP_ALL); } @@ -453,17 +455,18 @@ ftrace_dump_probe(unsigned long ip, unsigned long parent_ip, static void ftrace_cpudump_probe(unsigned long ip, unsigned long parent_ip, struct trace_array *tr, struct ftrace_probe_ops *ops, - void **data) + void *data) { - if (update_count(ops, ip)) + if (update_count(ops, ip, data)) ftrace_dump(DUMP_ORIG); } static int ftrace_probe_print(const char *name, struct seq_file *m, - unsigned long ip, struct ftrace_probe_ops *ops) + unsigned long ip, struct ftrace_probe_ops *ops, + void *data) { - struct ftrace_func_mapper *mapper = ops->private_data; + struct ftrace_func_mapper *mapper = data; long *count = NULL; seq_printf(m, "%ps:%s", (void *)ip, name); @@ -484,52 +487,64 @@ ftrace_traceon_print(struct seq_file *m, unsigned long ip, struct ftrace_probe_ops *ops, void *data) { - return ftrace_probe_print("traceon", m, ip, ops); + return ftrace_probe_print("traceon", m, ip, ops, data); } static int ftrace_traceoff_print(struct seq_file *m, unsigned long ip, struct ftrace_probe_ops *ops, void *data) { - return ftrace_probe_print("traceoff", m, ip, ops); + return ftrace_probe_print("traceoff", m, ip, ops, data); } static int ftrace_stacktrace_print(struct seq_file *m, unsigned long ip, struct ftrace_probe_ops *ops, void *data) { - return ftrace_probe_print("stacktrace", m, ip, ops); + return ftrace_probe_print("stacktrace", m, ip, ops, data); } static int ftrace_dump_print(struct seq_file *m, unsigned long ip, struct ftrace_probe_ops *ops, void *data) { - return ftrace_probe_print("dump", m, ip, ops); + return ftrace_probe_print("dump", m, ip, ops, data); } static int ftrace_cpudump_print(struct seq_file *m, unsigned long ip, struct ftrace_probe_ops *ops, void *data) { - return ftrace_probe_print("cpudump", m, ip, ops); + return ftrace_probe_print("cpudump", m, ip, ops, data); } static int ftrace_count_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 ftrace_func_mapper *mapper = *data; + + if (!mapper) { + mapper = allocate_ftrace_func_mapper(); + if (!mapper) + return -ENOMEM; + *data = mapper; + } - return ftrace_func_mapper_add_ip(mapper, ip, data); + return ftrace_func_mapper_add_ip(mapper, ip, init_data); } static void ftrace_count_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 ftrace_func_mapper *mapper = data; + + if (!ip) { + free_ftrace_func_mapper(mapper, NULL); + return; + } ftrace_func_mapper_remove_ip(mapper, ip); } @@ -607,12 +622,6 @@ ftrace_trace_probe_callback(struct trace_array *tr, if (!strlen(number)) goto out_reg; - if (!ops->private_data) { - ops->private_data = allocate_ftrace_func_mapper(); - if (!ops->private_data) - return -ENOMEM; - } - /* * We use the callback data field (which is a pointer) * as our counter. |