Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1628603 > unrolled thread
| Started by | Steven Rostedt <rostedt@goodmis.org> |
|---|---|
| First post | 2017-04-21 23:40 +0200 |
| Last post | 2017-04-21 23:50 +0200 |
| Articles | 17 — 1 participant |
Back to article view | Back to linux.kernel
[for-next][PATCH 00/33] tracing: More updates for 4.12 Steven Rostedt <rostedt@goodmis.org> - 2017-04-21 23:40 +0200
[for-next][PATCH 15/33] tracing: Have the snapshot trigger use the mapping helper functions Steven Rostedt <rostedt@goodmis.org> - 2017-04-21 23:40 +0200
[for-next][PATCH 29/33] tracing/ftrace: Add a better way to pass data via the probe functions Steven Rostedt <rostedt@goodmis.org> - 2017-04-21 23:40 +0200
[for-next][PATCH 19/33] ftrace: Remove printing of data in showing of a function probe Steven Rostedt <rostedt@goodmis.org> - 2017-04-21 23:40 +0200
[for-next][PATCH 08/33] selftests: ftrace: Add a test to test function triggers to start and stop tracing Steven Rostedt <rostedt@goodmis.org> - 2017-04-21 23:40 +0200
[for-next][PATCH 14/33] ftrace: Added ftrace_func_mapper for function probe triggers Steven Rostedt <rostedt@goodmis.org> - 2017-04-21 23:40 +0200
[for-next][PATCH 20/33] ftrace: Remove data field from ftrace_func_probe structure Steven Rostedt <rostedt@goodmis.org> - 2017-04-21 23:40 +0200
[for-next][PATCH 28/33] ftrace: Dynamically create the probe ftrace_ops for the trace_array Steven Rostedt <rostedt@goodmis.org> - 2017-04-21 23:40 +0200
[for-next][PATCH 25/33] ftrace: If the hash for a probe fails to update then free what was initialized Steven Rostedt <rostedt@goodmis.org> - 2017-04-21 23:40 +0200
[for-next][PATCH 16/33] ftrace: Convert the rest of the function trigger over to the mapping functions Steven Rostedt <rostedt@goodmis.org> - 2017-04-21 23:40 +0200
[for-next][PATCH 01/33] ftrace: Fix removing of second function probe Steven Rostedt <rostedt@goodmis.org> - 2017-04-21 23:50 +0200
[for-next][PATCH 09/33] selftests: ftrace: Add test to test reading of set_ftrace_file Steven Rostedt <rostedt@goodmis.org> - 2017-04-21 23:50 +0200
[for-next][PATCH 13/33] ftrace: Pass probe ops to probe function Steven Rostedt <rostedt@goodmis.org> - 2017-04-21 23:50 +0200
[for-next][PATCH 07/33] selftests: ftrace: Add a selftest to test event enable/disable func trigger Steven Rostedt <rostedt@goodmis.org> - 2017-04-21 23:50 +0200
[for-next][PATCH 05/33] selftests: ftrace: Add -l/--logdir option Steven Rostedt <rostedt@goodmis.org> - 2017-04-21 23:50 +0200
[for-next][PATCH 02/33] ftrace: Fix indexing of t_hash_start() from t_next() Steven Rostedt <rostedt@goodmis.org> - 2017-04-21 23:50 +0200
[for-next][PATCH 11/33] ftrace: Move the function commands into the tracing directory Steven Rostedt <rostedt@goodmis.org> - 2017-04-21 23:50 +0200
| From | Steven Rostedt <rostedt@goodmis.org> |
|---|---|
| Date | 2017-04-21 23:40 +0200 |
| Subject | [for-next][PATCH 00/33] tracing: More updates for 4.12 |
| Message-ID | <tyOrv-2qL-3@gated-at.bofh.it> |
The biggest change is the rewrite of the function probe trigger code.
I need to make a few enhancements on that code and it was basically
created with a hack on top of an hack, and I didn't want to add more
hacks. Instead, I gutted it and rewrote it in a way that the patch series
is still bisectable. Now the probe triggers can be unique to a tracing
instance. You can add stacktrace to a function within a tracing instance,
or just stop a tracing instance from tracing.
git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-trace.git
for-next
Head SHA1: dcc19d28091a86d5baf78e3fbb32e3fc3de524be
Namhyung Kim (2):
ftrace: Add 'function-fork' trace option
selftests: ftrace: Add -l/--logdir option
Steven Rostedt (VMware) (31):
ftrace: Fix removing of second function probe
ftrace: Fix indexing of t_hash_start() from t_next()
tracing: Have the trace_event benchmark thread call cond_resched_rcu_qs()
selftests: ftrace: Add a way to reset triggers in the set_ftrace_filter file
selftests: ftrace: Add a selftest to test event enable/disable func trigger
selftests: ftrace: Add a test to test function triggers to start and stop tracing
selftests: ftrace: Add test to test reading of set_ftrace_file
ftrace: Move the probe function into the tracing directory
ftrace: Move the function commands into the tracing directory
ftrace: Remove unused "flags" field from struct ftrace_func_probe
ftrace: Pass probe ops to probe function
ftrace: Added ftrace_func_mapper for function probe triggers
tracing: Have the snapshot trigger use the mapping helper functions
ftrace: Convert the rest of the function trigger over to the mapping functions
ftrace: Remove unused unregister_ftrace_function_probe() function
ftrace: Remove unused unregister_ftrace_function_probe_all() function
ftrace: Remove printing of data in showing of a function probe
ftrace: Remove data field from ftrace_func_probe structure
ftrace: Add helper function ftrace_hash_move_and_update_ops()
ftrace: Have unregister_ftrace_function_probe_func() return a value
ftrace: Have each function probe use its own ftrace_ops
ftrace: Have the function probes call their own function
ftrace: If the hash for a probe fails to update then free what was initialized
tracing: Have the trace_array hold the list of registered func probes
tracing: Pass the trace_array into ftrace_probe_ops functions
ftrace: Dynamically create the probe ftrace_ops for the trace_array
tracing/ftrace: Add a better way to pass data via the probe functions
tracing/ftrace: Allow instances to have their own function probes
tracing/ftrace: Enable snapshot function trigger to work with instances
tracing/ftrace: Allow for the traceonoff probe be unique to instances
tracing/ftrace: Allow for instances to trigger their own stacktrace probes
----
include/linux/ftrace.h | 47 +-
kernel/trace/ftrace.c | 832 +++++++++++++--------
kernel/trace/trace.c | 133 +++-
kernel/trace/trace.h | 75 +-
kernel/trace/trace_benchmark.c | 14 +-
kernel/trace/trace_events.c | 151 ++--
kernel/trace/trace_functions.c | 224 ++++--
tools/testing/selftests/ftrace/ftracetest | 5 +
.../ftrace/test.d/ftrace/func_event_triggers.tc | 113 +++
.../ftrace/test.d/ftrace/func_set_ftrace_file.tc | 132 ++++
.../test.d/ftrace/func_traceonoff_triggers.tc | 171 +++++
tools/testing/selftests/ftrace/test.d/functions | 21 +
12 files changed, 1410 insertions(+), 508 deletions(-)
create mode 100644 tools/testing/selftests/ftrace/test.d/ftrace/func_event_triggers.tc
create mode 100644 tools/testing/selftests/ftrace/test.d/ftrace/func_set_ftrace_file.tc
create mode 100644 tools/testing/selftests/ftrace/test.d/ftrace/func_traceonoff_triggers.tc
[toc] | [next] | [standalone]
| From | Steven Rostedt <rostedt@goodmis.org> |
|---|---|
| Date | 2017-04-21 23:40 +0200 |
| Subject | [for-next][PATCH 15/33] tracing: Have the snapshot trigger use the mapping helper functions |
| Message-ID | <tyOrx-2qL-47@gated-at.bofh.it> |
| In reply to | #1628603 |
From: "Steven Rostedt (VMware)" <rostedt@goodmis.org>
As the data pointer for individual ips will soon be removed and no longer
passed to the callback function probe handlers, convert the snapshot
trigger counter over to the new ftrace_func_mapper helper functions.
Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
---
kernel/trace/trace.c | 52 ++++++++++++++++++++++++++++++++++++++++++++--------
1 file changed, 44 insertions(+), 8 deletions(-)
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 41e9a20f91f0..7febeb823c62 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -6745,13 +6745,19 @@ static void
ftrace_count_snapshot(unsigned long ip, unsigned long parent_ip,
struct ftrace_probe_ops *ops, void **data)
{
- unsigned long *count = (long *)data;
+ struct ftrace_func_mapper *mapper = ops->private_data;
+ long *count = NULL;
- if (!*count)
- return;
+ if (mapper)
+ count = (long *)ftrace_func_mapper_find_ip(mapper, ip);
+
+ if (count) {
+
+ if (*count <= 0)
+ return;
- if (*count != -1)
(*count)--;
+ }
tracing_snapshot();
}
@@ -6760,20 +6766,42 @@ static int
ftrace_snapshot_print(struct seq_file *m, unsigned long ip,
struct ftrace_probe_ops *ops, void *data)
{
- long count = (long)data;
+ struct ftrace_func_mapper *mapper = ops->private_data;
+ long *count = NULL;
seq_printf(m, "%ps:", (void *)ip);
seq_puts(m, "snapshot");
- if (count == -1)
- seq_puts(m, ":unlimited\n");
+ if (mapper)
+ count = (long *)ftrace_func_mapper_find_ip(mapper, ip);
+
+ if (count)
+ seq_printf(m, ":count=%ld\n", *count);
else
- seq_printf(m, ":count=%ld\n", count);
+ seq_puts(m, ":unlimited\n");
return 0;
}
+static int
+ftrace_snapshot_init(struct ftrace_probe_ops *ops, unsigned long ip,
+ void **data)
+{
+ struct ftrace_func_mapper *mapper = ops->private_data;
+
+ return ftrace_func_mapper_add_ip(mapper, ip, *data);
+}
+
+static void
+ftrace_snapshot_free(struct ftrace_probe_ops *ops, unsigned long ip,
+ void **_data)
+{
+ struct ftrace_func_mapper *mapper = ops->private_data;
+
+ ftrace_func_mapper_remove_ip(mapper, ip);
+}
+
static struct ftrace_probe_ops snapshot_probe_ops = {
.func = ftrace_snapshot,
.print = ftrace_snapshot_print,
@@ -6782,6 +6810,8 @@ static struct ftrace_probe_ops snapshot_probe_ops = {
static struct ftrace_probe_ops snapshot_count_probe_ops = {
.func = ftrace_count_snapshot,
.print = ftrace_snapshot_print,
+ .init = ftrace_snapshot_init,
+ .free = ftrace_snapshot_free,
};
static int
@@ -6812,6 +6842,12 @@ ftrace_trace_snapshot_callback(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.
--
2.10.2
[toc] | [prev] | [next] | [standalone]
| From | Steven Rostedt <rostedt@goodmis.org> |
|---|---|
| Date | 2017-04-21 23:40 +0200 |
| Subject | [for-next][PATCH 29/33] tracing/ftrace: Add a better way to pass data via the probe functions |
| Message-ID | <tyOrx-2qL-45@gated-at.bofh.it> |
| In reply to | #1628603 |
From: "Steven Rostedt (VMware)" <rostedt@goodmis.org>
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>
---
kernel/trace/ftrace.c | 25 +++++++---
kernel/trace/trace.c | 38 ++++++++------
kernel/trace/trace.h | 8 +--
kernel/trace/trace_events.c | 110 +++++++++++++++++++++++------------------
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.
--
2.10.2
[toc] | [prev] | [next] | [standalone]
| From | Steven Rostedt <rostedt@goodmis.org> |
|---|---|
| Date | 2017-04-21 23:40 +0200 |
| Subject | [for-next][PATCH 19/33] ftrace: Remove printing of data in showing of a function probe |
| Message-ID | <tyOrx-2qL-51@gated-at.bofh.it> |
| In reply to | #1628603 |
From: "Steven Rostedt (VMware)" <rostedt@goodmis.org> None of the probe users uses the data field anymore of the entry. They all have their own print() function. Remove showing the data field in the generic function as the data field will be going away. Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org> --- kernel/trace/ftrace.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 1c31c74d0819..15f910a03822 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c @@ -3154,11 +3154,7 @@ t_hash_show(struct seq_file *m, struct ftrace_iterator *iter) if (rec->ops->print) return rec->ops->print(m, rec->ip, rec->ops, rec->data); - seq_printf(m, "%ps:%ps", (void *)rec->ip, (void *)rec->ops->func); - - if (rec->data) - seq_printf(m, ":%p", rec->data); - seq_putc(m, '\n'); + seq_printf(m, "%ps:%ps\n", (void *)rec->ip, (void *)rec->ops->func); return 0; } -- 2.10.2
[toc] | [prev] | [next] | [standalone]
| From | Steven Rostedt <rostedt@goodmis.org> |
|---|---|
| Date | 2017-04-21 23:40 +0200 |
| Subject | [for-next][PATCH 08/33] selftests: ftrace: Add a test to test function triggers to start and stop tracing |
| Message-ID | <tyOrx-2qL-55@gated-at.bofh.it> |
| In reply to | #1628603 |
From: "Steven Rostedt (VMware)" <rostedt@goodmis.org>
This adds a test to test the function tiggers traceon and traceoff to make
sure that it starts and stops tracing when a function is hit.
The test performs the following:
o Enables all events
o Writes schedule:traceoff into set_ftrace_filter
o Makes sure the tigger exists in the file
o Makes sure the trace file no longer grows
o Makes sure that tracing_on is now zero
o Clears the trace file
o Makes sure it's still empty
o Removes the trigger
o Makes sure tracing is still off (tracing_on is zero)
o Writes schedule:traceon into set_ftrace_filter
o Makes sure the trace file is no longer empty
o Makes sure that tracing_on file is set to one
o Removes the trigger
o Makes sure the trigger is no longer there
o Writes schedule:traceoff:3 into set_ftrace_filter
o Makes sure that tracing_on turns off
. Writes 1 into tracing_on
. Makes sure that it turns off 2 more times
o Writes 1 into tracing_on
o Makes sure that tracing_on is still a one
Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
---
.../test.d/ftrace/func_traceonoff_triggers.tc | 171 +++++++++++++++++++++
1 file changed, 171 insertions(+)
create mode 100644 tools/testing/selftests/ftrace/test.d/ftrace/func_traceonoff_triggers.tc
diff --git a/tools/testing/selftests/ftrace/test.d/ftrace/func_traceonoff_triggers.tc b/tools/testing/selftests/ftrace/test.d/ftrace/func_traceonoff_triggers.tc
new file mode 100644
index 000000000000..3c60ca61fee3
--- /dev/null
+++ b/tools/testing/selftests/ftrace/test.d/ftrace/func_traceonoff_triggers.tc
@@ -0,0 +1,171 @@
+#!/bin/sh
+# description: ftrace - test for function traceon/off triggers
+#
+# Ftrace allows to add triggers to functions, such as enabling or disabling
+# tracing, enabling or disabling trace events, or recording a stack trace
+# within the ring buffer.
+#
+# This test is designed to test enabling and disabling tracing triggers
+#
+
+# The triggers are set within the set_ftrace_filter file
+if [ ! -f set_ftrace_filter ]; then
+ echo "set_ftrace_filter not found? Is dynamic ftrace not set?"
+ exit_unsupported
+fi
+
+do_reset() {
+ reset_ftrace_filter
+ reset_tracer
+ disable_events
+ clear_trace
+ enable_tracing
+}
+
+fail() { # mesg
+ do_reset
+ echo $1
+ exit $FAIL
+}
+
+SLEEP_TIME=".1"
+
+do_reset
+
+echo "Testing function probes with enabling disabling tracing:"
+
+cnt_trace() {
+ grep -v '^#' trace | wc -l
+}
+
+echo '** DISABLE TRACING'
+disable_tracing
+clear_trace
+
+cnt=`cnt_trace`
+if [ $cnt -ne 0 ]; then
+ fail "Found junk in trace"
+fi
+
+
+echo '** ENABLE EVENTS'
+
+echo 1 > events/enable
+
+echo '** ENABLE TRACING'
+enable_tracing
+
+cnt=`cnt_trace`
+if [ $cnt -eq 0 ]; then
+ fail "Nothing found in trace"
+fi
+
+# powerpc uses .schedule
+func="schedule"
+x=`grep '^\.schedule$' available_filter_functions | wc -l`
+if [ "$x" -eq 1 ]; then
+ func=".schedule"
+fi
+
+echo '** SET TRACEOFF'
+
+echo "$func:traceoff" > set_ftrace_filter
+
+cnt=`grep schedule set_ftrace_filter | wc -l`
+if [ $cnt -ne 1 ]; then
+ fail "Did not find traceoff trigger"
+fi
+
+cnt=`cnt_trace`
+sleep $SLEEP_TIME
+cnt2=`cnt_trace`
+
+if [ $cnt -ne $cnt2 ]; then
+ fail "Tracing is not stopped"
+fi
+
+on=`cat tracing_on`
+if [ $on != "0" ]; then
+ fail "Tracing is not off"
+fi
+
+line1=`cat trace | tail -1`
+sleep $SLEEP_TIME
+line2=`cat trace | tail -1`
+
+if [ "$line1" != "$line2" ]; then
+ fail "Tracing file is still changing"
+fi
+
+clear_trace
+
+cnt=`cnt_trace`
+if [ $cnt -ne 0 ]; then
+ fail "Tracing is still happeing"
+fi
+
+echo "!$func:traceoff" >> set_ftrace_filter
+
+cnt=`grep schedule set_ftrace_filter | wc -l`
+if [ $cnt -ne 0 ]; then
+ fail "traceoff trigger still exists"
+fi
+
+on=`cat tracing_on`
+if [ $on != "0" ]; then
+ fail "Tracing is started again"
+fi
+
+echo "$func:traceon" > set_ftrace_filter
+
+cnt=`grep schedule set_ftrace_filter | wc -l`
+if [ $cnt -ne 1 ]; then
+ fail "traceon trigger not found"
+fi
+
+cnt=`cnt_trace`
+if [ $cnt -eq 0 ]; then
+ fail "Tracing did not start"
+fi
+
+on=`cat tracing_on`
+if [ $on != "1" ]; then
+ fail "Tracing was not enabled"
+fi
+
+
+echo "!$func:traceon" >> set_ftrace_filter
+
+cnt=`grep schedule set_ftrace_filter | wc -l`
+if [ $cnt -ne 0 ]; then
+ fail "traceon trigger still exists"
+fi
+
+check_sleep() {
+ val=$1
+ sleep $SLEEP_TIME
+ cat set_ftrace_filter
+ on=`cat tracing_on`
+ if [ $on != "$val" ]; then
+ fail "Expected tracing_on to be $val, but it was $on"
+ fi
+}
+
+
+echo "$func:traceoff:3" > set_ftrace_filter
+check_sleep "0"
+echo 1 > tracing_on
+check_sleep "0"
+echo 1 > tracing_on
+check_sleep "0"
+echo 1 > tracing_on
+check_sleep "1"
+echo "!$func:traceoff:0" > set_ftrace_filter
+
+if grep -e traceon -e traceoff set_ftrace_filter; then
+ fail "Tracing on and off triggers still exist"
+fi
+
+disable_events
+
+exit 0
--
2.10.2
[toc] | [prev] | [next] | [standalone]
| From | Steven Rostedt <rostedt@goodmis.org> |
|---|---|
| Date | 2017-04-21 23:40 +0200 |
| Subject | [for-next][PATCH 14/33] ftrace: Added ftrace_func_mapper for function probe triggers |
| Message-ID | <tyOrx-2qL-61@gated-at.bofh.it> |
| In reply to | #1628603 |
From: "Steven Rostedt (VMware)" <rostedt@goodmis.org>
In order to move the ops to the function probes directly, they need a way to
map function ips to their own data without depending on the infrastructure
of the function probes, as the data field will be going away.
New helper functions are added that are based on the ftrace_hash code.
ftrace_func_mapper functions are there to let the probes map ips to their
data. These can be allocated by the probe ops, and referenced in the
function callbacks.
Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
---
kernel/trace/ftrace.c | 141 ++++++++++++++++++++++++++++++++++++++++++++
kernel/trace/trace.h | 14 +++++
kernel/trace/trace_events.c | 70 +++++++++++++++++-----
3 files changed, 210 insertions(+), 15 deletions(-)
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index d8873079bed4..ac47d1845fdb 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -3808,6 +3808,147 @@ static void ftrace_free_entry(struct ftrace_func_probe *entry)
kfree(entry);
}
+struct ftrace_func_map {
+ struct ftrace_func_entry entry;
+ void *data;
+};
+
+struct ftrace_func_mapper {
+ struct ftrace_hash hash;
+};
+
+/**
+ * allocate_ftrace_func_mapper - allocate a new ftrace_func_mapper
+ *
+ * Returns a ftrace_func_mapper descriptor that can be used to map ips to data.
+ */
+struct ftrace_func_mapper *allocate_ftrace_func_mapper(void)
+{
+ struct ftrace_hash *hash;
+
+ /*
+ * The mapper is simply a ftrace_hash, but since the entries
+ * in the hash are not ftrace_func_entry type, we define it
+ * as a separate structure.
+ */
+ hash = alloc_ftrace_hash(FTRACE_HASH_DEFAULT_BITS);
+ return (struct ftrace_func_mapper *)hash;
+}
+
+/**
+ * ftrace_func_mapper_find_ip - Find some data mapped to an ip
+ * @mapper: The mapper that has the ip maps
+ * @ip: the instruction pointer to find the data for
+ *
+ * Returns the data mapped to @ip if found otherwise NULL. The return
+ * is actually the address of the mapper data pointer. The address is
+ * returned for use cases where the data is no bigger than a long, and
+ * the user can use the data pointer as its data instead of having to
+ * allocate more memory for the reference.
+ */
+void **ftrace_func_mapper_find_ip(struct ftrace_func_mapper *mapper,
+ unsigned long ip)
+{
+ struct ftrace_func_entry *entry;
+ struct ftrace_func_map *map;
+
+ entry = ftrace_lookup_ip(&mapper->hash, ip);
+ if (!entry)
+ return NULL;
+
+ map = (struct ftrace_func_map *)entry;
+ return &map->data;
+}
+
+/**
+ * ftrace_func_mapper_add_ip - Map some data to an ip
+ * @mapper: The mapper that has the ip maps
+ * @ip: The instruction pointer address to map @data to
+ * @data: The data to map to @ip
+ *
+ * Returns 0 on succes otherwise an error.
+ */
+int ftrace_func_mapper_add_ip(struct ftrace_func_mapper *mapper,
+ unsigned long ip, void *data)
+{
+ struct ftrace_func_entry *entry;
+ struct ftrace_func_map *map;
+
+ entry = ftrace_lookup_ip(&mapper->hash, ip);
+ if (entry)
+ return -EBUSY;
+
+ map = kmalloc(sizeof(*map), GFP_KERNEL);
+ if (!map)
+ return -ENOMEM;
+
+ map->entry.ip = ip;
+ map->data = data;
+
+ __add_hash_entry(&mapper->hash, &map->entry);
+
+ return 0;
+}
+
+/**
+ * ftrace_func_mapper_remove_ip - Remove an ip from the mapping
+ * @mapper: The mapper that has the ip maps
+ * @ip: The instruction pointer address to remove the data from
+ *
+ * Returns the data if it is found, otherwise NULL.
+ * Note, if the data pointer is used as the data itself, (see
+ * ftrace_func_mapper_find_ip(), then the return value may be meaningless,
+ * if the data pointer was set to zero.
+ */
+void *ftrace_func_mapper_remove_ip(struct ftrace_func_mapper *mapper,
+ unsigned long ip)
+{
+ struct ftrace_func_entry *entry;
+ struct ftrace_func_map *map;
+ void *data;
+
+ entry = ftrace_lookup_ip(&mapper->hash, ip);
+ if (!entry)
+ return NULL;
+
+ map = (struct ftrace_func_map *)entry;
+ data = map->data;
+
+ remove_hash_entry(&mapper->hash, entry);
+ kfree(entry);
+
+ return data;
+}
+
+/**
+ * free_ftrace_func_mapper - free a mapping of ips and data
+ * @mapper: The mapper that has the ip maps
+ * @free_func: A function to be called on each data item.
+ *
+ * This is used to free the function mapper. The @free_func is optional
+ * and can be used if the data needs to be freed as well.
+ */
+void free_ftrace_func_mapper(struct ftrace_func_mapper *mapper,
+ ftrace_mapper_func free_func)
+{
+ struct ftrace_func_entry *entry;
+ struct ftrace_func_map *map;
+ struct hlist_head *hhd;
+ int size = 1 << mapper->hash.size_bits;
+ int i;
+
+ if (free_func && mapper->hash.count) {
+ for (i = 0; i < size; i++) {
+ hhd = &mapper->hash.buckets[i];
+ hlist_for_each_entry(entry, hhd, hlist) {
+ map = (struct ftrace_func_map *)entry;
+ free_func(map);
+ }
+ }
+ }
+ free_ftrace_hash(&mapper->hash);
+}
+
int
register_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
void *data)
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
index 0f915c264c19..dbbdee21bcc4 100644
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
@@ -944,8 +944,22 @@ struct ftrace_probe_ops {
unsigned long ip,
struct ftrace_probe_ops *ops,
void *data);
+ void *private_data;
};
+struct ftrace_func_mapper;
+typedef int (*ftrace_mapper_func)(void *data);
+
+struct ftrace_func_mapper *allocate_ftrace_func_mapper(void);
+void **ftrace_func_mapper_find_ip(struct ftrace_func_mapper *mapper,
+ unsigned long ip);
+int ftrace_func_mapper_add_ip(struct ftrace_func_mapper *mapper,
+ unsigned long ip, void *data);
+void *ftrace_func_mapper_remove_ip(struct ftrace_func_mapper *mapper,
+ unsigned long ip);
+void free_ftrace_func_mapper(struct ftrace_func_mapper *mapper,
+ ftrace_mapper_func free_func);
+
extern int
register_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
void *data);
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c
index 9dbac1881b03..ee308312fe87 100644
--- a/kernel/trace/trace_events.c
+++ b/kernel/trace/trace_events.c
@@ -2460,32 +2460,44 @@ struct event_probe_data {
bool enable;
};
+static void update_event_probe(struct event_probe_data *data)
+{
+ if (data->enable)
+ clear_bit(EVENT_FILE_FL_SOFT_DISABLED_BIT, &data->file->flags);
+ else
+ set_bit(EVENT_FILE_FL_SOFT_DISABLED_BIT, &data->file->flags);
+}
+
static void
event_enable_probe(unsigned long ip, unsigned long parent_ip,
struct ftrace_probe_ops *ops, void **_data)
{
- struct event_probe_data **pdata = (struct event_probe_data **)_data;
- struct event_probe_data *data = *pdata;
+ struct ftrace_func_mapper *mapper = ops->private_data;
+ struct event_probe_data *data;
+ void **pdata;
- if (!data)
+ pdata = ftrace_func_mapper_find_ip(mapper, ip);
+ if (!pdata || !*pdata)
return;
- if (data->enable)
- clear_bit(EVENT_FILE_FL_SOFT_DISABLED_BIT, &data->file->flags);
- else
- set_bit(EVENT_FILE_FL_SOFT_DISABLED_BIT, &data->file->flags);
+ data = *pdata;
+ update_event_probe(data);
}
static void
event_enable_count_probe(unsigned long ip, unsigned long parent_ip,
struct ftrace_probe_ops *ops, void **_data)
{
- struct event_probe_data **pdata = (struct event_probe_data **)_data;
- struct event_probe_data *data = *pdata;
+ struct ftrace_func_mapper *mapper = ops->private_data;
+ struct event_probe_data *data;
+ void **pdata;
- if (!data)
+ pdata = ftrace_func_mapper_find_ip(mapper, ip);
+ if (!pdata || !*pdata)
return;
+ data = *pdata;
+
if (!data->count)
return;
@@ -2496,14 +2508,23 @@ event_enable_count_probe(unsigned long ip, unsigned long parent_ip,
if (data->count != -1)
(data->count)--;
- event_enable_probe(ip, parent_ip, ops, _data);
+ update_event_probe(data);
}
static int
event_enable_print(struct seq_file *m, unsigned long ip,
struct ftrace_probe_ops *ops, void *_data)
{
- struct event_probe_data *data = _data;
+ struct ftrace_func_mapper *mapper = ops->private_data;
+ struct event_probe_data *data;
+ void **pdata;
+
+ pdata = ftrace_func_mapper_find_ip(mapper, ip);
+
+ if (WARN_ON_ONCE(!pdata || !*pdata))
+ return 0;
+
+ data = *pdata;
seq_printf(m, "%ps:", (void *)ip);
@@ -2524,10 +2545,17 @@ static int
event_enable_init(struct ftrace_probe_ops *ops, unsigned long ip,
void **_data)
{
+ struct ftrace_func_mapper *mapper = ops->private_data;
struct event_probe_data **pdata = (struct event_probe_data **)_data;
struct event_probe_data *data = *pdata;
+ int ret;
+
+ ret = ftrace_func_mapper_add_ip(mapper, ip, data);
+ if (ret < 0)
+ return ret;
data->ref++;
+
return 0;
}
@@ -2535,8 +2563,13 @@ static void
event_enable_free(struct ftrace_probe_ops *ops, unsigned long ip,
void **_data)
{
- struct event_probe_data **pdata = (struct event_probe_data **)_data;
- struct event_probe_data *data = *pdata;
+ struct ftrace_func_mapper *mapper = ops->private_data;
+ struct event_probe_data *data;
+
+ data = ftrace_func_mapper_remove_ip(mapper, ip);
+
+ if (WARN_ON_ONCE(!data))
+ return;
if (WARN_ON_ONCE(data->ref <= 0))
return;
@@ -2548,7 +2581,6 @@ event_enable_free(struct ftrace_probe_ops *ops, unsigned long ip,
module_put(data->file->event_call->mod);
kfree(data);
}
- *pdata = NULL;
}
static struct ftrace_probe_ops event_enable_probe_ops = {
@@ -2627,6 +2659,13 @@ event_enable_func(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;
@@ -2663,6 +2702,7 @@ event_enable_func(struct ftrace_hash *hash,
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,
--
2.10.2
[toc] | [prev] | [next] | [standalone]
| From | Steven Rostedt <rostedt@goodmis.org> |
|---|---|
| Date | 2017-04-21 23:40 +0200 |
| Subject | [for-next][PATCH 20/33] ftrace: Remove data field from ftrace_func_probe structure |
| Message-ID | <tyOrx-2qL-49@gated-at.bofh.it> |
| In reply to | #1628603 |
From: "Steven Rostedt (VMware)" <rostedt@goodmis.org>
No users of the function probes uses the data field anymore. Remove it, and
change the init function to take a void *data parameter instead of a
void **data, because the init will just get the data that the registering
function was received, and there's no state after it is called.
The other functions for ftrace_probe_ops still take the data parameter, but
it will currently only be passed NULL. It will stay as a parameter for
future data to be passed to these functions.
Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
---
kernel/trace/ftrace.c | 11 ++++-------
kernel/trace/trace.c | 4 ++--
kernel/trace/trace.h | 2 +-
kernel/trace/trace_events.c | 5 ++---
kernel/trace/trace_functions.c | 4 ++--
5 files changed, 11 insertions(+), 15 deletions(-)
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index 15f910a03822..f7fcab8f3aa1 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -1102,7 +1102,6 @@ struct ftrace_func_probe {
struct hlist_node node;
struct ftrace_probe_ops *ops;
unsigned long ip;
- void *data;
struct list_head free_list;
};
@@ -3152,7 +3151,7 @@ t_hash_show(struct seq_file *m, struct ftrace_iterator *iter)
return -EIO;
if (rec->ops->print)
- return rec->ops->print(m, rec->ip, rec->ops, rec->data);
+ return rec->ops->print(m, rec->ip, rec->ops, NULL);
seq_printf(m, "%ps:%ps\n", (void *)rec->ip, (void *)rec->ops->func);
@@ -3735,7 +3734,7 @@ static void function_trace_probe_call(unsigned long ip, unsigned long parent_ip,
preempt_disable_notrace();
hlist_for_each_entry_rcu_notrace(entry, hhd, node) {
if (entry->ip == ip)
- entry->ops->func(ip, parent_ip, entry->ops, &entry->data);
+ entry->ops->func(ip, parent_ip, entry->ops, NULL);
}
preempt_enable_notrace();
}
@@ -3800,7 +3799,7 @@ static bool __disable_ftrace_function_probe(void)
static void ftrace_free_entry(struct ftrace_func_probe *entry)
{
if (entry->ops->free)
- entry->ops->free(entry->ops, entry->ip, &entry->data);
+ entry->ops->free(entry->ops, entry->ip, NULL);
kfree(entry);
}
@@ -4007,15 +4006,13 @@ register_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
count++;
- entry->data = data;
-
/*
* The caller might want to do something special
* for each function we find. We call the callback
* to give the caller an opportunity to do so.
*/
if (ops->init) {
- if (ops->init(ops, rec->ip, &entry->data) < 0) {
+ if (ops->init(ops, rec->ip, data) < 0) {
/* caller does not like this func */
kfree(entry);
continue;
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 7febeb823c62..7a4d578d8887 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -6786,11 +6786,11 @@ ftrace_snapshot_print(struct seq_file *m, unsigned long ip,
static int
ftrace_snapshot_init(struct ftrace_probe_ops *ops, unsigned long ip,
- void **data)
+ void *data)
{
struct ftrace_func_mapper *mapper = ops->private_data;
- return ftrace_func_mapper_add_ip(mapper, ip, *data);
+ return ftrace_func_mapper_add_ip(mapper, ip, data);
}
static void
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
index 376d5a798489..86aa5a2222ba 100644
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
@@ -937,7 +937,7 @@ struct ftrace_probe_ops {
struct ftrace_probe_ops *ops,
void **data);
int (*init)(struct ftrace_probe_ops *ops,
- unsigned long ip, void **data);
+ unsigned long ip, void *data);
void (*free)(struct ftrace_probe_ops *ops,
unsigned long ip, void **data);
int (*print)(struct seq_file *m,
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c
index ee308312fe87..37902107c44f 100644
--- a/kernel/trace/trace_events.c
+++ b/kernel/trace/trace_events.c
@@ -2543,11 +2543,10 @@ event_enable_print(struct seq_file *m, unsigned long ip,
static int
event_enable_init(struct ftrace_probe_ops *ops, unsigned long ip,
- void **_data)
+ void *_data)
{
struct ftrace_func_mapper *mapper = ops->private_data;
- struct event_probe_data **pdata = (struct event_probe_data **)_data;
- struct event_probe_data *data = *pdata;
+ struct event_probe_data *data = _data;
int ret;
ret = ftrace_func_mapper_add_ip(mapper, ip, data);
diff --git a/kernel/trace/trace_functions.c b/kernel/trace/trace_functions.c
index d9cbde8575a8..56d0fe1e4ea1 100644
--- a/kernel/trace/trace_functions.c
+++ b/kernel/trace/trace_functions.c
@@ -509,11 +509,11 @@ ftrace_cpudump_print(struct seq_file *m, unsigned long ip,
static int
ftrace_count_init(struct ftrace_probe_ops *ops, unsigned long ip,
- void **data)
+ void *data)
{
struct ftrace_func_mapper *mapper = ops->private_data;
- return ftrace_func_mapper_add_ip(mapper, ip, *data);
+ return ftrace_func_mapper_add_ip(mapper, ip, data);
}
static void
--
2.10.2
[toc] | [prev] | [next] | [standalone]
| From | Steven Rostedt <rostedt@goodmis.org> |
|---|---|
| Date | 2017-04-21 23:40 +0200 |
| Subject | [for-next][PATCH 28/33] ftrace: Dynamically create the probe ftrace_ops for the trace_array |
| Message-ID | <tyOrx-2qL-53@gated-at.bofh.it> |
| In reply to | #1628603 |
From: "Steven Rostedt (VMware)" <rostedt@goodmis.org>
In order to eventually have each trace_array instance have its own unique
set of function probes (triggers), the trace array needs to hold the ops and
the filters for the probes.
This is the first step to accomplish this. Instead of having the private
data of the probe ops point to the trace_array, create a separate list that
the trace_array holds. There's only one private_data for a probe, we need
one per trace_array. The probe ftrace_ops will be dynamically created for
each instance, instead of being static.
Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
---
kernel/trace/ftrace.c | 192 ++++++++++++++++++++++++++++++-----------
kernel/trace/trace.c | 2 +-
kernel/trace/trace.h | 5 +-
kernel/trace/trace_events.c | 2 +-
kernel/trace/trace_functions.c | 2 +-
5 files changed, 146 insertions(+), 57 deletions(-)
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index e51cd6b51253..8fdc18500c61 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -1101,6 +1101,14 @@ struct ftrace_func_entry {
unsigned long ip;
};
+struct ftrace_func_probe {
+ struct ftrace_probe_ops *probe_ops;
+ struct ftrace_ops ops;
+ struct trace_array *tr;
+ struct list_head list;
+ int ref;
+};
+
/*
* We make these constant because no one should touch them,
* but they are used as the default "empty hash", to avoid allocating
@@ -3054,7 +3062,7 @@ struct ftrace_iterator {
loff_t func_pos;
struct ftrace_page *pg;
struct dyn_ftrace *func;
- struct ftrace_probe_ops *probe;
+ struct ftrace_func_probe *probe;
struct ftrace_func_entry *probe_entry;
struct trace_parser parser;
struct ftrace_hash *hash;
@@ -3088,7 +3096,7 @@ t_probe_next(struct seq_file *m, loff_t *pos)
if (!iter->probe) {
next = func_probes->next;
- iter->probe = list_entry(next, struct ftrace_probe_ops, list);
+ iter->probe = list_entry(next, struct ftrace_func_probe, list);
}
if (iter->probe_entry)
@@ -3102,7 +3110,7 @@ t_probe_next(struct seq_file *m, loff_t *pos)
if (iter->probe->list.next == func_probes)
return NULL;
next = iter->probe->list.next;
- iter->probe = list_entry(next, struct ftrace_probe_ops, list);
+ iter->probe = list_entry(next, struct ftrace_func_probe, list);
hash = iter->probe->ops.func_hash->filter_hash;
size = 1 << hash->size_bits;
iter->pidx = 0;
@@ -3166,8 +3174,9 @@ static void *t_probe_start(struct seq_file *m, loff_t *pos)
static int
t_probe_show(struct seq_file *m, struct ftrace_iterator *iter)
{
- struct ftrace_probe_ops *probe;
struct ftrace_func_entry *probe_entry;
+ struct ftrace_probe_ops *probe_ops;
+ struct ftrace_func_probe *probe;
probe = iter->probe;
probe_entry = iter->probe_entry;
@@ -3175,10 +3184,13 @@ t_probe_show(struct seq_file *m, struct ftrace_iterator *iter)
if (WARN_ON_ONCE(!probe || !probe_entry))
return -EIO;
- if (probe->print)
- return probe->print(m, probe_entry->ip, probe, NULL);
+ probe_ops = probe->probe_ops;
+
+ if (probe_ops->print)
+ return probe_ops->print(m, probe_entry->ip, probe_ops, NULL);
- seq_printf(m, "%ps:%ps\n", (void *)probe_entry->ip, (void *)probe->func);
+ seq_printf(m, "%ps:%ps\n", (void *)probe_entry->ip,
+ (void *)probe_ops->func);
return 0;
}
@@ -3791,9 +3803,10 @@ static void function_trace_probe_call(unsigned long ip, unsigned long parent_ip,
struct ftrace_ops *op, struct pt_regs *pt_regs)
{
struct ftrace_probe_ops *probe_ops;
- struct trace_array *tr = op->private;
+ struct ftrace_func_probe *probe;
- probe_ops = container_of(op, struct ftrace_probe_ops, ops);
+ probe = container_of(op, struct ftrace_func_probe, ops);
+ probe_ops = probe->probe_ops;
/*
* Disable preemption for these calls to prevent a RCU grace
@@ -3801,7 +3814,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, tr, probe_ops, NULL);
+ probe_ops->func(ip, parent_ip, probe->tr, probe_ops, NULL);
preempt_enable_notrace();
}
@@ -3946,11 +3959,41 @@ void free_ftrace_func_mapper(struct ftrace_func_mapper *mapper,
free_ftrace_hash(&mapper->hash);
}
+static void release_probe(struct ftrace_func_probe *probe)
+{
+ struct ftrace_probe_ops *probe_ops;
+
+ mutex_lock(&ftrace_lock);
+
+ WARN_ON(probe->ref <= 0);
+
+ /* Subtract the ref that was used to protect this instance */
+ probe->ref--;
+
+ if (!probe->ref) {
+ probe_ops = probe->probe_ops;
+ list_del(&probe->list);
+ kfree(probe);
+ }
+ mutex_unlock(&ftrace_lock);
+}
+
+static void acquire_probe_locked(struct ftrace_func_probe *probe)
+{
+ /*
+ * Add one ref to keep it from being freed when releasing the
+ * ftrace_lock mutex.
+ */
+ probe->ref++;
+}
+
int
register_ftrace_function_probe(char *glob, struct trace_array *tr,
- struct ftrace_probe_ops *ops, void *data)
+ struct ftrace_probe_ops *probe_ops,
+ void *data)
{
struct ftrace_func_entry *entry;
+ struct ftrace_func_probe *probe;
struct ftrace_hash **orig_hash;
struct ftrace_hash *old_hash;
struct ftrace_hash *hash;
@@ -3966,16 +4009,33 @@ register_ftrace_function_probe(char *glob, struct trace_array *tr,
if (WARN_ON(glob[0] == '!'))
return -EINVAL;
- if (!(ops->ops.flags & FTRACE_OPS_FL_INITIALIZED)) {
- ops->ops.func = function_trace_probe_call;
- ftrace_ops_init(&ops->ops);
- INIT_LIST_HEAD(&ops->list);
- ops->ops.private = tr;
+
+ mutex_lock(&ftrace_lock);
+ /* Check if the probe_ops is already registered */
+ list_for_each_entry(probe, &tr->func_probes, list) {
+ if (probe->probe_ops == probe_ops)
+ break;
}
+ if (&probe->list == &tr->func_probes) {
+ probe = kzalloc(sizeof(*probe), GFP_KERNEL);
+ if (!probe) {
+ mutex_unlock(&ftrace_lock);
+ return -ENOMEM;
+ }
+ probe->probe_ops = probe_ops;
+ probe->ops.func = function_trace_probe_call;
+ probe->tr = tr;
+ ftrace_ops_init(&probe->ops);
+ list_add(&probe->list, &tr->func_probes);
+ }
+
+ acquire_probe_locked(probe);
- mutex_lock(&ops->ops.func_hash->regex_lock);
+ mutex_unlock(&ftrace_lock);
+
+ mutex_lock(&probe->ops.func_hash->regex_lock);
- orig_hash = &ops->ops.func_hash->filter_hash;
+ orig_hash = &probe->ops.func_hash->filter_hash;
old_hash = *orig_hash;
hash = alloc_and_copy_ftrace_hash(FTRACE_HASH_DEFAULT_BITS, old_hash);
@@ -3998,8 +4058,9 @@ register_ftrace_function_probe(char *glob, struct trace_array *tr,
* for each function we find. We call the callback
* to give the caller an opportunity to do so.
*/
- if (ops->init) {
- ret = ops->init(ops, tr, entry->ip, data);
+ if (probe_ops->init) {
+ ret = probe_ops->init(probe_ops, tr,
+ entry->ip, data);
if (ret < 0)
goto out;
}
@@ -4009,16 +4070,22 @@ register_ftrace_function_probe(char *glob, struct trace_array *tr,
mutex_lock(&ftrace_lock);
- ret = ftrace_hash_move_and_update_ops(&ops->ops, orig_hash,
- hash, 1);
+ if (!count) {
+ /* Nothing was added? */
+ ret = -EINVAL;
+ goto out_unlock;
+ }
+
+ ret = ftrace_hash_move_and_update_ops(&probe->ops, orig_hash,
+ hash, 1);
if (ret < 0)
goto err_unlock;
- if (list_empty(&ops->list))
- list_add(&ops->list, &tr->func_probes);
+ /* One ref for each new function traced */
+ probe->ref += count;
- if (!(ops->ops.flags & FTRACE_OPS_FL_ENABLED))
- ret = ftrace_startup(&ops->ops, 0);
+ if (!(probe->ops.flags & FTRACE_OPS_FL_ENABLED))
+ ret = ftrace_startup(&probe->ops, 0);
out_unlock:
mutex_unlock(&ftrace_lock);
@@ -4026,13 +4093,15 @@ register_ftrace_function_probe(char *glob, struct trace_array *tr,
if (!ret)
ret = count;
out:
- mutex_unlock(&ops->ops.func_hash->regex_lock);
+ mutex_unlock(&probe->ops.func_hash->regex_lock);
free_ftrace_hash(hash);
+ release_probe(probe);
+
return ret;
err_unlock:
- if (!ops->free)
+ if (!probe_ops->free || !count)
goto out_unlock;
/* Failed to do the move, need to call the free functions */
@@ -4040,33 +4109,30 @@ 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;
- ops->free(ops, tr, entry->ip, NULL);
+ probe_ops->free(probe_ops, tr, entry->ip, NULL);
}
}
goto out_unlock;
}
int
-unregister_ftrace_function_probe_func(char *glob, struct ftrace_probe_ops *ops)
+unregister_ftrace_function_probe_func(char *glob, struct trace_array *tr,
+ struct ftrace_probe_ops *probe_ops)
{
struct ftrace_ops_hash old_hash_ops;
struct ftrace_func_entry *entry;
+ struct ftrace_func_probe *probe;
struct ftrace_glob func_g;
struct ftrace_hash **orig_hash;
struct ftrace_hash *old_hash;
struct ftrace_hash *hash = NULL;
struct hlist_node *tmp;
struct hlist_head hhd;
- struct trace_array *tr;
char str[KSYM_SYMBOL_LEN];
- int i, ret;
+ int count = 0;
+ int i, ret = -ENODEV;
int size;
- if (!(ops->ops.flags & FTRACE_OPS_FL_INITIALIZED))
- return -EINVAL;
-
- tr = ops->ops.private;
-
if (glob && (strcmp(glob, "*") == 0 || !strlen(glob)))
func_g.search = NULL;
else if (glob) {
@@ -4082,12 +4148,28 @@ unregister_ftrace_function_probe_func(char *glob, struct ftrace_probe_ops *ops)
return -EINVAL;
}
- mutex_lock(&ops->ops.func_hash->regex_lock);
+ mutex_lock(&ftrace_lock);
+ /* Check if the probe_ops is already registered */
+ list_for_each_entry(probe, &tr->func_probes, list) {
+ if (probe->probe_ops == probe_ops)
+ break;
+ }
+ if (&probe->list == &tr->func_probes)
+ goto err_unlock_ftrace;
+
+ ret = -EINVAL;
+ if (!(probe->ops.flags & FTRACE_OPS_FL_INITIALIZED))
+ goto err_unlock_ftrace;
+
+ acquire_probe_locked(probe);
- orig_hash = &ops->ops.func_hash->filter_hash;
+ mutex_unlock(&ftrace_lock);
+
+ mutex_lock(&probe->ops.func_hash->regex_lock);
+
+ orig_hash = &probe->ops.func_hash->filter_hash;
old_hash = *orig_hash;
- ret = -EINVAL;
if (ftrace_hash_empty(old_hash))
goto out_unlock;
@@ -4112,46 +4194,54 @@ unregister_ftrace_function_probe_func(char *glob, struct ftrace_probe_ops *ops)
if (!ftrace_match(str, &func_g))
continue;
}
-
+ count++;
remove_hash_entry(hash, entry);
hlist_add_head(&entry->hlist, &hhd);
}
}
/* Nothing found? */
- if (hlist_empty(&hhd)) {
+ if (!count) {
ret = -EINVAL;
goto out_unlock;
}
mutex_lock(&ftrace_lock);
- if (ftrace_hash_empty(hash)) {
- ftrace_shutdown(&ops->ops, 0);
- list_del_init(&ops->list);
- }
+ WARN_ON(probe->ref < count);
+ probe->ref -= count;
- ret = ftrace_hash_move_and_update_ops(&ops->ops, orig_hash,
+ if (ftrace_hash_empty(hash))
+ ftrace_shutdown(&probe->ops, 0);
+
+ ret = ftrace_hash_move_and_update_ops(&probe->ops, orig_hash,
hash, 1);
/* still need to update the function call sites */
if (ftrace_enabled && !ftrace_hash_empty(hash))
- ftrace_run_modify_code(&ops->ops, FTRACE_UPDATE_CALLS,
+ ftrace_run_modify_code(&probe->ops, FTRACE_UPDATE_CALLS,
&old_hash_ops);
synchronize_sched();
hlist_for_each_entry_safe(entry, tmp, &hhd, hlist) {
hlist_del(&entry->hlist);
- if (ops->free)
- ops->free(ops, tr, entry->ip, NULL);
+ if (probe_ops->free)
+ probe_ops->free(probe_ops, tr, entry->ip, NULL);
kfree(entry);
}
mutex_unlock(&ftrace_lock);
out_unlock:
- mutex_unlock(&ops->ops.func_hash->regex_lock);
+ mutex_unlock(&probe->ops.func_hash->regex_lock);
free_ftrace_hash(hash);
+
+ release_probe(probe);
+
+ return ret;
+
+ err_unlock_ftrace:
+ mutex_unlock(&ftrace_lock);
return ret;
}
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 368310e78d45..e61610e5e6e3 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -6832,7 +6832,7 @@ ftrace_trace_snapshot_callback(struct trace_array *tr, struct ftrace_hash *hash,
ops = param ? &snapshot_count_probe_ops : &snapshot_probe_ops;
if (glob[0] == '!')
- return unregister_ftrace_function_probe_func(glob+1, ops);
+ return unregister_ftrace_function_probe_func(glob+1, tr, ops);
if (!param)
goto out_reg;
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
index 390761804886..e978ecd257b8 100644
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
@@ -939,8 +939,6 @@ static inline void ftrace_pid_follow_fork(struct trace_array *tr, bool enable) {
#if defined(CONFIG_FUNCTION_TRACER) && defined(CONFIG_DYNAMIC_FTRACE)
struct ftrace_probe_ops {
- struct ftrace_ops ops;
- struct list_head list;
void (*func)(unsigned long ip,
unsigned long parent_ip,
struct trace_array *tr,
@@ -976,7 +974,8 @@ extern int
register_ftrace_function_probe(char *glob, struct trace_array *tr,
struct ftrace_probe_ops *ops, void *data);
extern int
-unregister_ftrace_function_probe_func(char *glob, struct ftrace_probe_ops *ops);
+unregister_ftrace_function_probe_func(char *glob, struct trace_array *tr,
+ struct ftrace_probe_ops *ops);
int register_ftrace_command(struct ftrace_func_command *cmd);
int unregister_ftrace_command(struct ftrace_func_command *cmd);
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c
index 713bec614312..48c7f70cbac7 100644
--- a/kernel/trace/trace_events.c
+++ b/kernel/trace/trace_events.c
@@ -2653,7 +2653,7 @@ event_enable_func(struct trace_array *tr, struct ftrace_hash *hash,
ops = param ? &event_disable_count_probe_ops : &event_disable_probe_ops;
if (glob[0] == '!') {
- ret = unregister_ftrace_function_probe_func(glob+1, ops);
+ ret = unregister_ftrace_function_probe_func(glob+1, tr, ops);
goto out;
}
diff --git a/kernel/trace/trace_functions.c b/kernel/trace/trace_functions.c
index 797f087183c5..b95f56ba9744 100644
--- a/kernel/trace/trace_functions.c
+++ b/kernel/trace/trace_functions.c
@@ -597,7 +597,7 @@ ftrace_trace_probe_callback(struct trace_array *tr,
return -EINVAL;
if (glob[0] == '!')
- return unregister_ftrace_function_probe_func(glob+1, ops);
+ return unregister_ftrace_function_probe_func(glob+1, tr, ops);
if (!param)
goto out_reg;
--
2.10.2
[toc] | [prev] | [next] | [standalone]
| From | Steven Rostedt <rostedt@goodmis.org> |
|---|---|
| Date | 2017-04-21 23:40 +0200 |
| Subject | [for-next][PATCH 25/33] ftrace: If the hash for a probe fails to update then free what was initialized |
| Message-ID | <tyOrx-2qL-57@gated-at.bofh.it> |
| In reply to | #1628603 |
From: "Steven Rostedt (VMware)" <rostedt@goodmis.org>
If the ftrace_hash_move_and_update_ops() fails, and an ops->free() function
exists, then it needs to be called on all the ops that were added by this
registration.
Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
---
kernel/trace/ftrace.c | 16 +++++++++++++++-
1 file changed, 15 insertions(+), 1 deletion(-)
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index 493c7ff7e860..8394055e6793 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -4003,7 +4003,7 @@ register_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
ret = ftrace_hash_move_and_update_ops(&ops->ops, orig_hash,
hash, 1);
if (ret < 0)
- goto out_unlock;
+ goto err_unlock;
if (list_empty(&ops->list))
list_add(&ops->list, &ftrace_func_probes);
@@ -4021,6 +4021,20 @@ register_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
free_ftrace_hash(hash);
return ret;
+
+ err_unlock:
+ if (!ops->free)
+ goto out_unlock;
+
+ /* Failed to do the move, need to call the free functions */
+ for (i = 0; i < size; i++) {
+ hlist_for_each_entry(entry, &hash->buckets[i], hlist) {
+ if (ftrace_lookup_ip(old_hash, entry->ip))
+ continue;
+ ops->free(ops, entry->ip, NULL);
+ }
+ }
+ goto out_unlock;
}
int
--
2.10.2
[toc] | [prev] | [next] | [standalone]
| From | Steven Rostedt <rostedt@goodmis.org> |
|---|---|
| Date | 2017-04-21 23:40 +0200 |
| Subject | [for-next][PATCH 16/33] ftrace: Convert the rest of the function trigger over to the mapping functions |
| Message-ID | <tyOrx-2qL-59@gated-at.bofh.it> |
| In reply to | #1628603 |
From: "Steven Rostedt (VMware)" <rostedt@goodmis.org>
As the data pointer for individual ips will soon be removed and no longer
passed to the callback function probe handlers, convert the rest of the function
trigger counters over to the new ftrace_func_mapper helper functions.
Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
---
kernel/trace/trace_functions.c | 123 ++++++++++++++++++++++++++++-------------
1 file changed, 85 insertions(+), 38 deletions(-)
diff --git a/kernel/trace/trace_functions.c b/kernel/trace/trace_functions.c
index b99f6231281e..d9cbde8575a8 100644
--- a/kernel/trace/trace_functions.c
+++ b/kernel/trace/trace_functions.c
@@ -267,10 +267,12 @@ static struct tracer function_trace __tracer_data =
};
#ifdef CONFIG_DYNAMIC_FTRACE
-static void update_traceon_count(void **data, bool on)
+static void update_traceon_count(struct ftrace_probe_ops *ops,
+ unsigned long ip, bool on)
{
- long *count = (long *)data;
- long old_count = *count;
+ struct ftrace_func_mapper *mapper = ops->private_data;
+ long *count;
+ long old_count;
/*
* Tracing gets disabled (or enabled) once per count.
@@ -301,7 +303,10 @@ static void update_traceon_count(void **data, bool on)
* setting the tracing_on file. But we currently don't care
* about that.
*/
- if (!old_count)
+ count = (long *)ftrace_func_mapper_find_ip(mapper, ip);
+ old_count = *count;
+
+ if (old_count <= 0)
return;
/* Make sure we see count before checking tracing state */
@@ -315,10 +320,6 @@ static void update_traceon_count(void **data, bool on)
else
tracing_off();
- /* unlimited? */
- if (old_count == -1)
- return;
-
/* Make sure tracing state is visible before updating count */
smp_wmb();
@@ -329,14 +330,14 @@ static void
ftrace_traceon_count(unsigned long ip, unsigned long parent_ip,
struct ftrace_probe_ops *ops, void **data)
{
- update_traceon_count(data, 1);
+ update_traceon_count(ops, ip, 1);
}
static void
ftrace_traceoff_count(unsigned long ip, unsigned long parent_ip,
struct ftrace_probe_ops *ops, void **data)
{
- update_traceon_count(data, 0);
+ update_traceon_count(ops, ip, 0);
}
static void
@@ -379,47 +380,56 @@ static void
ftrace_stacktrace_count(unsigned long ip, unsigned long parent_ip,
struct ftrace_probe_ops *ops, void **data)
{
- long *count = (long *)data;
+ struct ftrace_func_mapper *mapper = ops->private_data;
+ long *count;
long old_count;
long new_count;
+ if (!tracing_is_on())
+ return;
+
+ /* unlimited? */
+ if (!mapper) {
+ trace_dump_stack(STACK_SKIP);
+ return;
+ }
+
+ count = (long *)ftrace_func_mapper_find_ip(mapper, ip);
+
/*
* Stack traces should only execute the number of times the
* user specified in the counter.
*/
do {
-
- if (!tracing_is_on())
- return;
-
old_count = *count;
if (!old_count)
return;
- /* unlimited? */
- if (old_count == -1) {
- trace_dump_stack(STACK_SKIP);
- return;
- }
-
new_count = old_count - 1;
new_count = cmpxchg(count, old_count, new_count);
if (new_count == old_count)
trace_dump_stack(STACK_SKIP);
+ if (!tracing_is_on())
+ return;
+
} while (new_count != old_count);
}
-static int update_count(void **data)
+static int update_count(struct ftrace_probe_ops *ops, unsigned long ip)
{
- unsigned long *count = (long *)data;
+ struct ftrace_func_mapper *mapper = ops->private_data;
+ long *count = NULL;
- if (!*count)
- return 0;
+ if (mapper)
+ count = (long *)ftrace_func_mapper_find_ip(mapper, ip);
- if (*count != -1)
+ if (count) {
+ if (*count <= 0)
+ return 0;
(*count)--;
+ }
return 1;
}
@@ -428,7 +438,7 @@ static void
ftrace_dump_probe(unsigned long ip, unsigned long parent_ip,
struct ftrace_probe_ops *ops, void **data)
{
- if (update_count(data))
+ if (update_count(ops, ip))
ftrace_dump(DUMP_ALL);
}
@@ -437,22 +447,26 @@ static void
ftrace_cpudump_probe(unsigned long ip, unsigned long parent_ip,
struct ftrace_probe_ops *ops, void **data)
{
- if (update_count(data))
+ if (update_count(ops, ip))
ftrace_dump(DUMP_ORIG);
}
static int
ftrace_probe_print(const char *name, struct seq_file *m,
- unsigned long ip, void *data)
+ unsigned long ip, struct ftrace_probe_ops *ops)
{
- long count = (long)data;
+ struct ftrace_func_mapper *mapper = ops->private_data;
+ long *count = NULL;
seq_printf(m, "%ps:%s", (void *)ip, name);
- if (count == -1)
- seq_puts(m, ":unlimited\n");
+ if (mapper)
+ count = (long *)ftrace_func_mapper_find_ip(mapper, ip);
+
+ if (count)
+ seq_printf(m, ":count=%ld\n", *count);
else
- seq_printf(m, ":count=%ld\n", count);
+ seq_puts(m, ":unlimited\n");
return 0;
}
@@ -461,55 +475,82 @@ static int
ftrace_traceon_print(struct seq_file *m, unsigned long ip,
struct ftrace_probe_ops *ops, void *data)
{
- return ftrace_probe_print("traceon", m, ip, data);
+ return ftrace_probe_print("traceon", m, ip, ops);
}
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, data);
+ return ftrace_probe_print("traceoff", m, ip, ops);
}
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, data);
+ return ftrace_probe_print("stacktrace", m, ip, ops);
}
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, data);
+ return ftrace_probe_print("dump", m, ip, ops);
}
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, data);
+ return ftrace_probe_print("cpudump", m, ip, ops);
+}
+
+
+static int
+ftrace_count_init(struct ftrace_probe_ops *ops, unsigned long ip,
+ void **data)
+{
+ struct ftrace_func_mapper *mapper = ops->private_data;
+
+ return ftrace_func_mapper_add_ip(mapper, ip, *data);
+}
+
+static void
+ftrace_count_free(struct ftrace_probe_ops *ops, unsigned long ip,
+ void **_data)
+{
+ struct ftrace_func_mapper *mapper = ops->private_data;
+
+ ftrace_func_mapper_remove_ip(mapper, ip);
}
static struct ftrace_probe_ops traceon_count_probe_ops = {
.func = ftrace_traceon_count,
.print = ftrace_traceon_print,
+ .init = ftrace_count_init,
+ .free = ftrace_count_free,
};
static struct ftrace_probe_ops traceoff_count_probe_ops = {
.func = ftrace_traceoff_count,
.print = ftrace_traceoff_print,
+ .init = ftrace_count_init,
+ .free = ftrace_count_free,
};
static struct ftrace_probe_ops stacktrace_count_probe_ops = {
.func = ftrace_stacktrace_count,
.print = ftrace_stacktrace_print,
+ .init = ftrace_count_init,
+ .free = ftrace_count_free,
};
static struct ftrace_probe_ops dump_probe_ops = {
.func = ftrace_dump_probe,
.print = ftrace_dump_print,
+ .init = ftrace_count_init,
+ .free = ftrace_count_free,
};
static struct ftrace_probe_ops cpudump_probe_ops = {
@@ -558,6 +599,12 @@ ftrace_trace_probe_callback(struct ftrace_probe_ops *ops,
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.
--
2.10.2
[toc] | [prev] | [next] | [standalone]
| From | Steven Rostedt <rostedt@goodmis.org> |
|---|---|
| Date | 2017-04-21 23:50 +0200 |
| Subject | [for-next][PATCH 01/33] ftrace: Fix removing of second function probe |
| Message-ID | <tyOBb-2u9-1@gated-at.bofh.it> |
| In reply to | #1628603 |
From: "Steven Rostedt (VMware)" <rostedt@goodmis.org>
When two function probes are added to set_ftrace_filter, and then one of
them is removed, the update to the function locations is not performed, and
the record keeping of the function states are corrupted, and causes an
ftrace_bug() to occur.
This is easily reproducable by adding two probes, removing one, and then
adding it back again.
# cd /sys/kernel/debug/tracing
# echo schedule:traceoff > set_ftrace_filter
# echo do_IRQ:traceoff > set_ftrace_filter
# echo \!do_IRQ:traceoff > /debug/tracing/set_ftrace_filter
# echo do_IRQ:traceoff > set_ftrace_filter
Causes:
------------[ cut here ]------------
WARNING: CPU: 2 PID: 1098 at kernel/trace/ftrace.c:2369 ftrace_get_addr_curr+0x143/0x220
Modules linked in: [...]
CPU: 2 PID: 1098 Comm: bash Not tainted 4.10.0-test+ #405
Hardware name: Hewlett-Packard HP Compaq Pro 6300 SFF/339A, BIOS K01 v02.05 05/07/2012
Call Trace:
dump_stack+0x68/0x9f
__warn+0x111/0x130
? trace_irq_work_interrupt+0xa0/0xa0
warn_slowpath_null+0x1d/0x20
ftrace_get_addr_curr+0x143/0x220
? __fentry__+0x10/0x10
ftrace_replace_code+0xe3/0x4f0
? ftrace_int3_handler+0x90/0x90
? printk+0x99/0xb5
? 0xffffffff81000000
ftrace_modify_all_code+0x97/0x110
arch_ftrace_update_code+0x10/0x20
ftrace_run_update_code+0x1c/0x60
ftrace_run_modify_code.isra.48.constprop.62+0x8e/0xd0
register_ftrace_function_probe+0x4b6/0x590
? ftrace_startup+0x310/0x310
? debug_lockdep_rcu_enabled.part.4+0x1a/0x30
? update_stack_state+0x88/0x110
? ftrace_regex_write.isra.43.part.44+0x1d3/0x320
? preempt_count_sub+0x18/0xd0
? mutex_lock_nested+0x104/0x800
? ftrace_regex_write.isra.43.part.44+0x1d3/0x320
? __unwind_start+0x1c0/0x1c0
? _mutex_lock_nest_lock+0x800/0x800
ftrace_trace_probe_callback.isra.3+0xc0/0x130
? func_set_flag+0xe0/0xe0
? __lock_acquire+0x642/0x1790
? __might_fault+0x1e/0x20
? trace_get_user+0x398/0x470
? strcmp+0x35/0x60
ftrace_trace_onoff_callback+0x48/0x70
ftrace_regex_write.isra.43.part.44+0x251/0x320
? match_records+0x420/0x420
ftrace_filter_write+0x2b/0x30
__vfs_write+0xd7/0x330
? do_loop_readv_writev+0x120/0x120
? locks_remove_posix+0x90/0x2f0
? do_lock_file_wait+0x160/0x160
? __lock_is_held+0x93/0x100
? rcu_read_lock_sched_held+0x5c/0xb0
? preempt_count_sub+0x18/0xd0
? __sb_start_write+0x10a/0x230
? vfs_write+0x222/0x240
vfs_write+0xef/0x240
SyS_write+0xab/0x130
? SyS_read+0x130/0x130
? trace_hardirqs_on_caller+0x182/0x280
? trace_hardirqs_on_thunk+0x1a/0x1c
entry_SYSCALL_64_fastpath+0x18/0xad
RIP: 0033:0x7fe61c157c30
RSP: 002b:00007ffe87890258 EFLAGS: 00000246 ORIG_RAX: 0000000000000001
RAX: ffffffffffffffda RBX: ffffffff8114a410 RCX: 00007fe61c157c30
RDX: 0000000000000010 RSI: 000055814798f5e0 RDI: 0000000000000001
RBP: ffff8800c9027f98 R08: 00007fe61c422740 R09: 00007fe61ca53700
R10: 0000000000000073 R11: 0000000000000246 R12: 0000558147a36400
R13: 00007ffe8788f160 R14: 0000000000000024 R15: 00007ffe8788f15c
? trace_hardirqs_off_caller+0xc0/0x110
---[ end trace 99fa09b3d9869c2c ]---
Bad trampoline accounting at: ffffffff81cc3b00 (do_IRQ+0x0/0x150)
Cc: stable@vger.kernel.org
Fixes: 59df055f1991 ("ftrace: trace different functions with a different tracer")
Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
---
kernel/trace/ftrace.c | 20 ++++++++++++++++----
1 file changed, 16 insertions(+), 4 deletions(-)
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index 34f63e78d661..4b6459a57fbc 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -3780,23 +3780,24 @@ static void __enable_ftrace_function_probe(struct ftrace_ops_hash *old_hash)
ftrace_probe_registered = 1;
}
-static void __disable_ftrace_function_probe(void)
+static bool __disable_ftrace_function_probe(void)
{
int i;
if (!ftrace_probe_registered)
- return;
+ return false;
for (i = 0; i < FTRACE_FUNC_HASHSIZE; i++) {
struct hlist_head *hhd = &ftrace_func_hash[i];
if (hhd->first)
- return;
+ return false;
}
/* no more funcs left */
ftrace_shutdown(&trace_probe_ops, 0);
ftrace_probe_registered = 0;
+ return true;
}
@@ -3926,6 +3927,7 @@ static void
__unregister_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
void *data, int flags)
{
+ struct ftrace_ops_hash old_hash_ops;
struct ftrace_func_entry *rec_entry;
struct ftrace_func_probe *entry;
struct ftrace_func_probe *p;
@@ -3937,6 +3939,7 @@ __unregister_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
struct hlist_node *tmp;
char str[KSYM_SYMBOL_LEN];
int i, ret;
+ bool disabled;
if (glob && (strcmp(glob, "*") == 0 || !strlen(glob)))
func_g.search = NULL;
@@ -3955,6 +3958,10 @@ __unregister_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
mutex_lock(&trace_probe_ops.func_hash->regex_lock);
+ old_hash_ops.filter_hash = old_hash;
+ /* Probes only have filters */
+ old_hash_ops.notrace_hash = NULL;
+
hash = alloc_and_copy_ftrace_hash(FTRACE_HASH_DEFAULT_BITS, *orig_hash);
if (!hash)
/* Hmm, should report this somehow */
@@ -3992,12 +3999,17 @@ __unregister_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
}
}
mutex_lock(&ftrace_lock);
- __disable_ftrace_function_probe();
+ disabled = __disable_ftrace_function_probe();
/*
* Remove after the disable is called. Otherwise, if the last
* probe is removed, a null hash means *all enabled*.
*/
ret = ftrace_hash_move(&trace_probe_ops, 1, orig_hash, hash);
+
+ /* still need to update the function call sites */
+ if (ftrace_enabled && !disabled)
+ ftrace_run_modify_code(&trace_probe_ops, FTRACE_UPDATE_CALLS,
+ &old_hash_ops);
synchronize_sched();
if (!ret)
free_ftrace_hash_rcu(old_hash);
--
2.10.2
[toc] | [prev] | [next] | [standalone]
| From | Steven Rostedt <rostedt@goodmis.org> |
|---|---|
| Date | 2017-04-21 23:50 +0200 |
| Subject | [for-next][PATCH 09/33] selftests: ftrace: Add test to test reading of set_ftrace_file |
| Message-ID | <tyOBb-2u9-5@gated-at.bofh.it> |
| In reply to | #1628603 |
From: "Steven Rostedt (VMware)" <rostedt@goodmis.org>
The set_ftrace_file lists both functions that are filtered, as well as
function probes (triggers) that are attached to a function, like traceon or
stacktrace, etc. The reading of this file is not as trivial as most pseudo
files are, and there's been various bugs that have appeared in the past
when there's a mix of probes and functions listed. There's also a difference
when reading the file using dd with a block size of 1.
This test performs the following:
o Resets set_ftrace_filter
o Makes sure only "#### all functions enabled ####" is listed
(All checks uses cat, and dd with bs=1 and bs=100)
o Adds a traceon trigger to schedule
o Checks if only "#### all function enabled ####" and the trigger is there.
o Adds tracing of schedule
o Checks if only schedule and the trigger is there
o Adds tracing of do_IRQ as well
o Checks if only schedule, do_IRQ and the trigger is there
o Adds a traceon trigger to do_IRQ
o Checks if only schedule, do_IRQ and both triggers are there
o Removes tracing of do_IRQ
o Checks if only schedule and both triggers are there
o Removes tracing of schedule
o Checks if only "#### all functions enabled ####" and both triggers are there
o Removes the triggers
o Checks if only "#### all functions enabled ####" is there
o Adds tracing of schedule
o Checks if only schedule is there
o Adds tracing of do_IRQ
o Checks if only schedule and do_IRQ are there
Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
---
.../ftrace/test.d/ftrace/func_set_ftrace_file.tc | 132 +++++++++++++++++++++
1 file changed, 132 insertions(+)
create mode 100644 tools/testing/selftests/ftrace/test.d/ftrace/func_set_ftrace_file.tc
diff --git a/tools/testing/selftests/ftrace/test.d/ftrace/func_set_ftrace_file.tc b/tools/testing/selftests/ftrace/test.d/ftrace/func_set_ftrace_file.tc
new file mode 100644
index 000000000000..113b4d9bc733
--- /dev/null
+++ b/tools/testing/selftests/ftrace/test.d/ftrace/func_set_ftrace_file.tc
@@ -0,0 +1,132 @@
+#!/bin/sh
+# description: ftrace - test reading of set_ftrace_filter
+#
+# The set_ftrace_filter file of ftrace is used to list functions as well as
+# triggers (probes) attached to functions. The code to read this file is not
+# straight forward and has had various bugs in the past. This test is designed
+# to add functions and triggers to that file in various ways and read that
+# file in various ways (cat vs dd).
+#
+
+# The triggers are set within the set_ftrace_filter file
+if [ ! -f set_ftrace_filter ]; then
+ echo "set_ftrace_filter not found? Is dynamic ftrace not set?"
+ exit_unsupported
+fi
+
+do_reset() {
+ reset_tracer
+ reset_ftrace_filter
+ disable_events
+ clear_trace
+ enable_tracing
+}
+
+fail() { # mesg
+ do_reset
+ echo $1
+ exit $FAIL
+}
+
+do_reset
+
+FILTER=set_ftrace_filter
+FUNC1="schedule"
+FUNC2="do_IRQ"
+
+ALL_FUNCS="#### all functions enabled ####"
+
+test_func() {
+ if ! echo "$1" | grep -q "^$2\$"; then
+ return 0
+ fi
+ echo "$1" | grep -v "^$2\$"
+ return 1
+}
+
+check_set_ftrace_filter() {
+ cat=`cat $FILTER`
+ dd1=`dd if=$FILTER bs=1 | grep -v -e 'records in' -e 'records out' -e 'bytes copied'`
+ dd100=`dd if=$FILTER bs=100 | grep -v -e 'records in' -e 'records out' -e 'bytes copied'`
+
+ echo "Testing '$@'"
+
+ while [ $# -gt 0 ]; do
+ echo "test $1"
+ if cat=`test_func "$cat" "$1"`; then
+ return 0
+ fi
+ if dd1=`test_func "$dd1" "$1"`; then
+ return 0
+ fi
+ if dd100=`test_func "$dd100" "$1"`; then
+ return 0
+ fi
+ shift
+ done
+
+ if [ -n "$cat" ]; then
+ return 0
+ fi
+ if [ -n "$dd1" ]; then
+ return 0
+ fi
+ if [ -n "$dd100" ]; then
+ return 0
+ fi
+ return 1;
+}
+
+if check_set_ftrace_filter "$ALL_FUNCS"; then
+ fail "Expected only $ALL_FUNCS"
+fi
+
+echo "$FUNC1:traceoff" > set_ftrace_filter
+if check_set_ftrace_filter "$ALL_FUNCS" "$FUNC1:traceoff:unlimited"; then
+ fail "Expected $ALL_FUNCS and $FUNC1:traceoff:unlimited"
+fi
+
+echo "$FUNC1" > set_ftrace_filter
+if check_set_ftrace_filter "$FUNC1" "$FUNC1:traceoff:unlimited"; then
+ fail "Expected $FUNC1 and $FUNC1:traceoff:unlimited"
+fi
+
+echo "$FUNC2" >> set_ftrace_filter
+if check_set_ftrace_filter "$FUNC1" "$FUNC2" "$FUNC1:traceoff:unlimited"; then
+ fail "Expected $FUNC1 $FUNC2 and $FUNC1:traceoff:unlimited"
+fi
+
+echo "$FUNC2:traceoff" >> set_ftrace_filter
+if check_set_ftrace_filter "$FUNC1" "$FUNC2" "$FUNC1:traceoff:unlimited" "$FUNC2:traceoff:unlimited"; then
+ fail "Expected $FUNC1 $FUNC2 $FUNC1:traceoff:unlimited and $FUNC2:traceoff:unlimited"
+fi
+
+echo "$FUNC1" > set_ftrace_filter
+if check_set_ftrace_filter "$FUNC1" "$FUNC1:traceoff:unlimited" "$FUNC2:traceoff:unlimited"; then
+ fail "Expected $FUNC1 $FUNC1:traceoff:unlimited and $FUNC2:traceoff:unlimited"
+fi
+
+echo > set_ftrace_filter
+if check_set_ftrace_filter "$ALL_FUNCS" "$FUNC1:traceoff:unlimited" "$FUNC2:traceoff:unlimited"; then
+ fail "Expected $ALL_FUNCS $FUNC1:traceoff:unlimited and $FUNC2:traceoff:unlimited"
+fi
+
+reset_ftrace_filter
+
+if check_set_ftrace_filter "$ALL_FUNCS"; then
+ fail "Expected $ALL_FUNCS"
+fi
+
+echo "$FUNC1" > set_ftrace_filter
+if check_set_ftrace_filter "$FUNC1" ; then
+ fail "Expected $FUNC1"
+fi
+
+echo "$FUNC2" >> set_ftrace_filter
+if check_set_ftrace_filter "$FUNC1" "$FUNC2" ; then
+ fail "Expected $FUNC1 and $FUNC2"
+fi
+
+do_reset
+
+exit 0
--
2.10.2
[toc] | [prev] | [next] | [standalone]
| From | Steven Rostedt <rostedt@goodmis.org> |
|---|---|
| Date | 2017-04-21 23:50 +0200 |
| Subject | [for-next][PATCH 13/33] ftrace: Pass probe ops to probe function |
| Message-ID | <tyOBb-2u9-11@gated-at.bofh.it> |
| In reply to | #1628603 |
From: "Steven Rostedt (VMware)" <rostedt@goodmis.org>
In preparation to cleaning up the probe function registration code, the
"data" parameter will eventually be removed from the probe->func() call.
Instead it will receive its own "ops" function, in which it can set up its
own data that it needs to map.
Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
---
kernel/trace/ftrace.c | 2 +-
kernel/trace/trace.c | 6 ++++--
kernel/trace/trace.h | 1 +
kernel/trace/trace_events.c | 8 +++++---
kernel/trace/trace_functions.c | 24 ++++++++++++++++--------
5 files changed, 27 insertions(+), 14 deletions(-)
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index b6dc29583c86..d8873079bed4 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -3739,7 +3739,7 @@ static void function_trace_probe_call(unsigned long ip, unsigned long parent_ip,
preempt_disable_notrace();
hlist_for_each_entry_rcu_notrace(entry, hhd, node) {
if (entry->ip == ip)
- entry->ops->func(ip, parent_ip, &entry->data);
+ entry->ops->func(ip, parent_ip, entry->ops, &entry->data);
}
preempt_enable_notrace();
}
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 8a5064a03ddf..41e9a20f91f0 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -6735,13 +6735,15 @@ static const struct file_operations tracing_dyn_info_fops = {
#if defined(CONFIG_TRACER_SNAPSHOT) && defined(CONFIG_DYNAMIC_FTRACE)
static void
-ftrace_snapshot(unsigned long ip, unsigned long parent_ip, void **data)
+ftrace_snapshot(unsigned long ip, unsigned long parent_ip,
+ struct ftrace_probe_ops *ops, void **data)
{
tracing_snapshot();
}
static void
-ftrace_count_snapshot(unsigned long ip, unsigned long parent_ip, void **data)
+ftrace_count_snapshot(unsigned long ip, unsigned long parent_ip,
+ struct ftrace_probe_ops *ops, void **data)
{
unsigned long *count = (long *)data;
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
index a63411c53c5e..0f915c264c19 100644
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
@@ -934,6 +934,7 @@ static inline void ftrace_pid_follow_fork(struct trace_array *tr, bool enable) {
struct ftrace_probe_ops {
void (*func)(unsigned long ip,
unsigned long parent_ip,
+ struct ftrace_probe_ops *ops,
void **data);
int (*init)(struct ftrace_probe_ops *ops,
unsigned long ip, void **data);
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c
index 93116549a284..9dbac1881b03 100644
--- a/kernel/trace/trace_events.c
+++ b/kernel/trace/trace_events.c
@@ -2461,7 +2461,8 @@ struct event_probe_data {
};
static void
-event_enable_probe(unsigned long ip, unsigned long parent_ip, void **_data)
+event_enable_probe(unsigned long ip, unsigned long parent_ip,
+ struct ftrace_probe_ops *ops, void **_data)
{
struct event_probe_data **pdata = (struct event_probe_data **)_data;
struct event_probe_data *data = *pdata;
@@ -2476,7 +2477,8 @@ event_enable_probe(unsigned long ip, unsigned long parent_ip, void **_data)
}
static void
-event_enable_count_probe(unsigned long ip, unsigned long parent_ip, void **_data)
+event_enable_count_probe(unsigned long ip, unsigned long parent_ip,
+ struct ftrace_probe_ops *ops, void **_data)
{
struct event_probe_data **pdata = (struct event_probe_data **)_data;
struct event_probe_data *data = *pdata;
@@ -2494,7 +2496,7 @@ event_enable_count_probe(unsigned long ip, unsigned long parent_ip, void **_data
if (data->count != -1)
(data->count)--;
- event_enable_probe(ip, parent_ip, _data);
+ event_enable_probe(ip, parent_ip, ops, _data);
}
static int
diff --git a/kernel/trace/trace_functions.c b/kernel/trace/trace_functions.c
index 4199ca61b0e5..b99f6231281e 100644
--- a/kernel/trace/trace_functions.c
+++ b/kernel/trace/trace_functions.c
@@ -326,19 +326,22 @@ static void update_traceon_count(void **data, bool on)
}
static void
-ftrace_traceon_count(unsigned long ip, unsigned long parent_ip, void **data)
+ftrace_traceon_count(unsigned long ip, unsigned long parent_ip,
+ struct ftrace_probe_ops *ops, void **data)
{
update_traceon_count(data, 1);
}
static void
-ftrace_traceoff_count(unsigned long ip, unsigned long parent_ip, void **data)
+ftrace_traceoff_count(unsigned long ip, unsigned long parent_ip,
+ struct ftrace_probe_ops *ops, void **data)
{
update_traceon_count(data, 0);
}
static void
-ftrace_traceon(unsigned long ip, unsigned long parent_ip, void **data)
+ftrace_traceon(unsigned long ip, unsigned long parent_ip,
+ struct ftrace_probe_ops *ops, void **data)
{
if (tracing_is_on())
return;
@@ -347,7 +350,8 @@ ftrace_traceon(unsigned long ip, unsigned long parent_ip, void **data)
}
static void
-ftrace_traceoff(unsigned long ip, unsigned long parent_ip, void **data)
+ftrace_traceoff(unsigned long ip, unsigned long parent_ip,
+ struct ftrace_probe_ops *ops, void **data)
{
if (!tracing_is_on())
return;
@@ -365,13 +369,15 @@ ftrace_traceoff(unsigned long ip, unsigned long parent_ip, void **data)
#define STACK_SKIP 4
static void
-ftrace_stacktrace(unsigned long ip, unsigned long parent_ip, void **data)
+ftrace_stacktrace(unsigned long ip, unsigned long parent_ip,
+ struct ftrace_probe_ops *ops, void **data)
{
trace_dump_stack(STACK_SKIP);
}
static void
-ftrace_stacktrace_count(unsigned long ip, unsigned long parent_ip, void **data)
+ftrace_stacktrace_count(unsigned long ip, unsigned long parent_ip,
+ struct ftrace_probe_ops *ops, void **data)
{
long *count = (long *)data;
long old_count;
@@ -419,7 +425,8 @@ static int update_count(void **data)
}
static void
-ftrace_dump_probe(unsigned long ip, unsigned long parent_ip, void **data)
+ftrace_dump_probe(unsigned long ip, unsigned long parent_ip,
+ struct ftrace_probe_ops *ops, void **data)
{
if (update_count(data))
ftrace_dump(DUMP_ALL);
@@ -427,7 +434,8 @@ ftrace_dump_probe(unsigned long ip, unsigned long parent_ip, void **data)
/* Only dump the current CPU buffer. */
static void
-ftrace_cpudump_probe(unsigned long ip, unsigned long parent_ip, void **data)
+ftrace_cpudump_probe(unsigned long ip, unsigned long parent_ip,
+ struct ftrace_probe_ops *ops, void **data)
{
if (update_count(data))
ftrace_dump(DUMP_ORIG);
--
2.10.2
[toc] | [prev] | [next] | [standalone]
| From | Steven Rostedt <rostedt@goodmis.org> |
|---|---|
| Date | 2017-04-21 23:50 +0200 |
| Subject | [for-next][PATCH 07/33] selftests: ftrace: Add a selftest to test event enable/disable func trigger |
| Message-ID | <tyOBb-2u9-7@gated-at.bofh.it> |
| In reply to | #1628603 |
From: "Steven Rostedt (VMware)" <rostedt@goodmis.org>
This adds a test to enable and disable trace events via the function
triggers. It tests enabling and disabling the sched:sched_switch event via
the the event_enable and event_disable function triggers attached to the
schedule() kernel function.
The test does the following:
o disable all events
o disables or enables the sched_switch event
o writes schedule:event_enable/disable:sched:sched_switch into set_ftrace_filter
o 5 times it checks to make sure:
. Writes 0/1 into the sched_switch/enable
. Checks that the sched_switch/enable goes back to 1/0
o Resets the events
o writes schedule:event_enable/disable:sched:sched_switch:3 into set_ftrace_filter
o Does a loop of 3 to see that sched_switch/enable file gets updated
o Makes sure the sched_switch/enable stops getting updated
Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
---
.../ftrace/test.d/ftrace/func_event_triggers.tc | 113 +++++++++++++++++++++
1 file changed, 113 insertions(+)
create mode 100644 tools/testing/selftests/ftrace/test.d/ftrace/func_event_triggers.tc
diff --git a/tools/testing/selftests/ftrace/test.d/ftrace/func_event_triggers.tc b/tools/testing/selftests/ftrace/test.d/ftrace/func_event_triggers.tc
new file mode 100644
index 000000000000..5c60afca24a6
--- /dev/null
+++ b/tools/testing/selftests/ftrace/test.d/ftrace/func_event_triggers.tc
@@ -0,0 +1,113 @@
+#!/bin/sh
+# description: ftrace - test for function event triggers
+#
+# Ftrace allows to add triggers to functions, such as enabling or disabling
+# tracing, enabling or disabling trace events, or recording a stack trace
+# within the ring buffer.
+#
+# This test is designed to test event triggers
+#
+
+# The triggers are set within the set_ftrace_filter file
+if [ ! -f set_ftrace_filter ]; then
+ echo "set_ftrace_filter not found? Is dynamic ftrace not set?"
+ exit_unsupported
+fi
+
+do_reset() {
+ reset_ftrace_filter
+ reset_tracer
+ disable_events
+ clear_trace
+ enable_tracing
+}
+
+fail() { # mesg
+ do_reset
+ echo $1
+ exit $FAIL
+}
+
+SLEEP_TIME=".1"
+
+do_reset
+
+echo "Testing function probes with events:"
+
+EVENT="sched:sched_switch"
+EVENT_ENABLE="events/sched/sched_switch/enable"
+
+cnt_trace() {
+ grep -v '^#' trace | wc -l
+}
+
+test_event_enabled() {
+ val=$1
+
+ e=`cat $EVENT_ENABLE`
+ if [ "$e" != $val ]; then
+ echo "Expected $val but found $e"
+ exit -1
+ fi
+}
+
+run_enable_disable() {
+ enable=$1 # enable
+ Enable=$2 # Enable
+ check_disable=$3 # 0
+ check_enable_star=$4 # 1*
+ check_disable_star=$5 # 0*
+
+ cnt=`cnt_trace`
+ if [ $cnt -ne 0 ]; then
+ fail "Found junk in trace file"
+ fi
+
+ echo "$Enable event all the time"
+
+ echo $check_disable > $EVENT_ENABLE
+ sleep $SLEEP_TIME
+
+ test_event_enabled $check_disable
+
+ echo "schedule:${enable}_event:$EVENT" > set_ftrace_filter
+
+ echo " make sure it works 5 times"
+
+ for i in `seq 5`; do
+ sleep $SLEEP_TIME
+ echo " test $i"
+ test_event_enabled $check_enable_star
+
+ echo $check_disable > $EVENT_ENABLE
+ done
+ sleep $SLEEP_TIME
+ echo " make sure it's still works"
+ test_event_enabled $check_enable_star
+
+ reset_ftrace_filter
+
+ echo " make sure it only works 3 times"
+
+ echo $check_disable > $EVENT_ENABLE
+ sleep $SLEEP_TIME
+
+ echo "schedule:${enable}_event:$EVENT:3" > set_ftrace_filter
+
+ for i in `seq 3`; do
+ sleep $SLEEP_TIME
+ echo " test $i"
+ test_event_enabled $check_enable_star
+
+ echo $check_disable > $EVENT_ENABLE
+ done
+
+ sleep $SLEEP_TIME
+ echo " make sure it stop working"
+ test_event_enabled $check_disable_star
+
+ do_reset
+}
+
+run_enable_disable enable Enable 0 "1*" "0*"
+run_enable_disable disable Disable 1 "0*" "1*"
--
2.10.2
[toc] | [prev] | [next] | [standalone]
| From | Steven Rostedt <rostedt@goodmis.org> |
|---|---|
| Date | 2017-04-21 23:50 +0200 |
| Subject | [for-next][PATCH 05/33] selftests: ftrace: Add -l/--logdir option |
| Message-ID | <tyOBc-2u9-25@gated-at.bofh.it> |
| In reply to | #1628603 |
From: Namhyung Kim <namhyung@kernel.org>
In my virtual machine setup, running ftracetest failed on creating
LOG_DIR on a read-only filesystem. It'd be convenient to provide an
option to specify a different directory as log directory.
Link: http://lkml.kernel.org/r/20170417024430.21194-4-namhyung@kernel.org
Cc: Ingo Molnar <mingo@kernel.org>
Acked-by: Masami Hiramatsu <mhiramat@kernel.org>
Cc: Shuah Khan <shuahkh@osg.samsung.com>
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
---
tools/testing/selftests/ftrace/ftracetest | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/tools/testing/selftests/ftrace/ftracetest b/tools/testing/selftests/ftrace/ftracetest
index 52e3c4df28d6..a8631d978725 100755
--- a/tools/testing/selftests/ftrace/ftracetest
+++ b/tools/testing/selftests/ftrace/ftracetest
@@ -16,6 +16,7 @@ echo " -k|--keep Keep passed test logs"
echo " -v|--verbose Increase verbosity of test messages"
echo " -vv Alias of -v -v (Show all results in stdout)"
echo " -d|--debug Debug mode (trace all shell commands)"
+echo " -l|--logdir <dir> Save logs on the <dir>"
exit $1
}
@@ -64,6 +65,10 @@ parse_opts() { # opts
DEBUG=1
shift 1
;;
+ --logdir|-l)
+ LOG_DIR=$2
+ shift 2
+ ;;
*.tc)
if [ -f "$1" ]; then
OPT_TEST_CASES="$OPT_TEST_CASES `abspath $1`"
--
2.10.2
[toc] | [prev] | [next] | [standalone]
| From | Steven Rostedt <rostedt@goodmis.org> |
|---|---|
| Date | 2017-04-21 23:50 +0200 |
| Subject | [for-next][PATCH 02/33] ftrace: Fix indexing of t_hash_start() from t_next() |
| Message-ID | <tyOBc-2u9-29@gated-at.bofh.it> |
| In reply to | #1628603 |
From: "Steven Rostedt (VMware)" <rostedt@goodmis.org>
t_hash_start() does not increment *pos, where as t_next() must. But when
t_next() does increment *pos, it must still pass in the original *pos to
t_hash_start() otherwise it will skip the first instance:
# cd /sys/kernel/debug/tracing
# echo schedule:traceoff > set_ftrace_filter
# echo do_IRQ:traceoff > set_ftrace_filter
# echo call_rcu > set_ftrace_filter
# cat set_ftrace_filter
call_rcu
schedule:traceoff:unlimited
do_IRQ:traceoff:unlimited
The above called t_hash_start() from t_start() as there was only one
function (call_rcu), but if we add another function:
# echo xfrm_policy_destroy_rcu >> set_ftrace_filter
# cat set_ftrace_filter
call_rcu
xfrm_policy_destroy_rcu
do_IRQ:traceoff:unlimited
The "schedule:traceoff" disappears.
Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
---
kernel/trace/ftrace.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index 4b6459a57fbc..b21a3e61ac74 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -3205,6 +3205,7 @@ static void *
t_next(struct seq_file *m, void *v, loff_t *pos)
{
struct ftrace_iterator *iter = m->private;
+ loff_t l = *pos; /* t_hash_start() must use original pos */
void *ret;
if (unlikely(ftrace_disabled))
@@ -3216,13 +3217,13 @@ t_next(struct seq_file *m, void *v, loff_t *pos)
if (iter->flags & FTRACE_ITER_PRINTALL) {
/* next must increment pos, and t_hash_start does not */
(*pos)++;
- return t_hash_start(m, pos);
+ return t_hash_start(m, &l);
}
ret = t_func_next(m, pos);
if (!ret)
- return t_hash_start(m, pos);
+ return t_hash_start(m, &l);
return ret;
}
--
2.10.2
[toc] | [prev] | [next] | [standalone]
| From | Steven Rostedt <rostedt@goodmis.org> |
|---|---|
| Date | 2017-04-21 23:50 +0200 |
| Subject | [for-next][PATCH 11/33] ftrace: Move the function commands into the tracing directory |
| Message-ID | <tyOBc-2u9-39@gated-at.bofh.it> |
| In reply to | #1628603 |
From: "Steven Rostedt (VMware)" <rostedt@goodmis.org>
As nothing outside the tracing directory uses the function command mechanism,
I'm moving the prototypes out of the include/linux/ftrace.h and into the
local kernel/trace/trace.h header. I plan on making them hook to the
trace_array structure which is local to kernel/trace, and I do not want to
expose it to the rest of the kernel. This requires that the command functions
must also be local to tracing. But luckily nothing else uses them.
Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
---
include/linux/ftrace.h | 19 -------------------
kernel/trace/trace.h | 20 ++++++++++++++++++++
2 files changed, 20 insertions(+), 19 deletions(-)
diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
index 3e790ff1c501..774e7a95c201 100644
--- a/include/linux/ftrace.h
+++ b/include/linux/ftrace.h
@@ -326,14 +326,6 @@ static inline void stack_tracer_disable(void) { }
static inline void stack_tracer_enable(void) { }
#endif
-struct ftrace_func_command {
- struct list_head list;
- char *name;
- int (*func)(struct ftrace_hash *hash,
- char *func, char *cmd,
- char *params, int enable);
-};
-
#ifdef CONFIG_DYNAMIC_FTRACE
int ftrace_arch_code_modify_prepare(void);
@@ -421,9 +413,6 @@ void ftrace_set_global_notrace(unsigned char *buf, int len, int reset);
void ftrace_free_filter(struct ftrace_ops *ops);
void ftrace_ops_set_global_filter(struct ftrace_ops *ops);
-int register_ftrace_command(struct ftrace_func_command *cmd);
-int unregister_ftrace_command(struct ftrace_func_command *cmd);
-
enum {
FTRACE_UPDATE_CALLS = (1 << 0),
FTRACE_DISABLE_CALLS = (1 << 1),
@@ -639,14 +628,6 @@ static inline void ftrace_enable_daemon(void) { }
static inline void ftrace_module_init(struct module *mod) { }
static inline void ftrace_module_enable(struct module *mod) { }
static inline void ftrace_release_mod(struct module *mod) { }
-static inline __init int register_ftrace_command(struct ftrace_func_command *cmd)
-{
- return -EINVAL;
-}
-static inline __init int unregister_ftrace_command(char *cmd_name)
-{
- return -EINVAL;
-}
static inline int ftrace_text_reserved(const void *start, const void *end)
{
return 0;
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
index 2ff6d49fa5ca..a63411c53c5e 100644
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
@@ -880,6 +880,13 @@ print_graph_function_flags(struct trace_iterator *iter, u32 flags)
extern struct list_head ftrace_pids;
#ifdef CONFIG_FUNCTION_TRACER
+struct ftrace_func_command {
+ struct list_head list;
+ char *name;
+ int (*func)(struct ftrace_hash *hash,
+ char *func, char *cmd,
+ char *params, int enable);
+};
extern bool ftrace_filter_param __initdata;
static inline int ftrace_trace_task(struct trace_array *tr)
{
@@ -948,10 +955,23 @@ extern void
unregister_ftrace_function_probe_func(char *glob, struct ftrace_probe_ops *ops);
extern void unregister_ftrace_function_probe_all(char *glob);
+int register_ftrace_command(struct ftrace_func_command *cmd);
+int unregister_ftrace_command(struct ftrace_func_command *cmd);
+
void ftrace_create_filter_files(struct ftrace_ops *ops,
struct dentry *parent);
void ftrace_destroy_filter_files(struct ftrace_ops *ops);
#else
+struct ftrace_func_command;
+
+static inline __init int register_ftrace_command(struct ftrace_func_command *cmd)
+{
+ return -EINVAL;
+}
+static inline __init int unregister_ftrace_command(char *cmd_name)
+{
+ return -EINVAL;
+}
/*
* The ops parameter passed in is usually undefined.
* This must be a macro.
--
2.10.2
[toc] | [prev] | [standalone]
Back to top | Article view | linux.kernel
csiph-web