linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [for-next][PATCH 00/33] tracing: More updates for 4.12
@ 2017-04-21 21:30 Steven Rostedt
  2017-04-21 21:30 ` [for-next][PATCH 01/33] ftrace: Fix removing of second function probe Steven Rostedt
                   ` (32 more replies)
  0 siblings, 33 replies; 36+ messages in thread
From: Steven Rostedt @ 2017-04-21 21:30 UTC (permalink / raw)
  To: linux-kernel; +Cc: Ingo Molnar, Andrew Morton

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

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [for-next][PATCH 01/33] ftrace: Fix removing of second function probe
  2017-04-21 21:30 [for-next][PATCH 00/33] tracing: More updates for 4.12 Steven Rostedt
@ 2017-04-21 21:30 ` Steven Rostedt
  2017-04-21 21:30 ` [for-next][PATCH 02/33] ftrace: Fix indexing of t_hash_start() from t_next() Steven Rostedt
                   ` (31 subsequent siblings)
  32 siblings, 0 replies; 36+ messages in thread
From: Steven Rostedt @ 2017-04-21 21:30 UTC (permalink / raw)
  To: linux-kernel; +Cc: Ingo Molnar, Andrew Morton, stable

[-- Attachment #1: 0001-ftrace-Fix-removing-of-second-function-probe.patch --]
[-- Type: text/plain, Size: 5839 bytes --]

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

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [for-next][PATCH 02/33] ftrace: Fix indexing of t_hash_start() from t_next()
  2017-04-21 21:30 [for-next][PATCH 00/33] tracing: More updates for 4.12 Steven Rostedt
  2017-04-21 21:30 ` [for-next][PATCH 01/33] ftrace: Fix removing of second function probe Steven Rostedt
@ 2017-04-21 21:30 ` Steven Rostedt
  2017-04-21 21:30 ` [for-next][PATCH 03/33] tracing: Have the trace_event benchmark thread call cond_resched_rcu_qs() Steven Rostedt
                   ` (30 subsequent siblings)
  32 siblings, 0 replies; 36+ messages in thread
From: Steven Rostedt @ 2017-04-21 21:30 UTC (permalink / raw)
  To: linux-kernel; +Cc: Ingo Molnar, Andrew Morton

[-- Attachment #1: 0002-ftrace-Fix-indexing-of-t_hash_start-from-t_next.patch --]
[-- Type: text/plain, Size: 1748 bytes --]

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

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [for-next][PATCH 03/33] tracing: Have the trace_event benchmark thread call cond_resched_rcu_qs()
  2017-04-21 21:30 [for-next][PATCH 00/33] tracing: More updates for 4.12 Steven Rostedt
  2017-04-21 21:30 ` [for-next][PATCH 01/33] ftrace: Fix removing of second function probe Steven Rostedt
  2017-04-21 21:30 ` [for-next][PATCH 02/33] ftrace: Fix indexing of t_hash_start() from t_next() Steven Rostedt
@ 2017-04-21 21:30 ` Steven Rostedt
  2017-04-21 21:30 ` [for-next][PATCH 04/33] ftrace: Add function-fork trace option Steven Rostedt
                   ` (29 subsequent siblings)
  32 siblings, 0 replies; 36+ messages in thread
From: Steven Rostedt @ 2017-04-21 21:30 UTC (permalink / raw)
  To: linux-kernel; +Cc: Ingo Molnar, Andrew Morton, Paul E. McKenney

[-- Attachment #1: 0003-tracing-Have-the-trace_event-benchmark-thread-call-c.patch --]
[-- Type: text/plain, Size: 1634 bytes --]

From: "Steven Rostedt (VMware)" <rostedt@goodmis.org>

The trace_event benchmark thread runs in kernel space in an infinite loop
while also calling cond_resched() in case anything else wants to schedule
in. Unfortunately, on a PREEMPT kernel, that makes it a nop, in which case,
this will never voluntarily schedule. That will cause synchronize_rcu_tasks()
to forever block on this thread, while it is running.

This is exactly what cond_resched_rcu_qs() is for. Use that instead.

Acked-by: "Paul E. McKenney" <paulmck@linux.vnet.ibm.com>
Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
---
 kernel/trace/trace_benchmark.c | 14 +++++++++++---
 1 file changed, 11 insertions(+), 3 deletions(-)

diff --git a/kernel/trace/trace_benchmark.c b/kernel/trace/trace_benchmark.c
index e49fbe901cfc..16a8cf02eee9 100644
--- a/kernel/trace/trace_benchmark.c
+++ b/kernel/trace/trace_benchmark.c
@@ -153,10 +153,18 @@ static int benchmark_event_kthread(void *arg)
 		trace_do_benchmark();
 
 		/*
-		 * We don't go to sleep, but let others
-		 * run as well.
+		 * We don't go to sleep, but let others run as well.
+		 * This is bascially a "yield()" to let any task that
+		 * wants to run, schedule in, but if the CPU is idle,
+		 * we'll keep burning cycles.
+		 *
+		 * Note the _rcu_qs() version of cond_resched() will
+		 * notify synchronize_rcu_tasks() that this thread has
+		 * passed a quiescent state for rcu_tasks. Otherwise
+		 * this thread will never voluntarily schedule which would
+		 * block synchronize_rcu_tasks() indefinitely.
 		 */
-		cond_resched();
+		cond_resched_rcu_qs();
 	}
 
 	return 0;
-- 
2.10.2

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [for-next][PATCH 04/33] ftrace: Add function-fork trace option
  2017-04-21 21:30 [for-next][PATCH 00/33] tracing: More updates for 4.12 Steven Rostedt
                   ` (2 preceding siblings ...)
  2017-04-21 21:30 ` [for-next][PATCH 03/33] tracing: Have the trace_event benchmark thread call cond_resched_rcu_qs() Steven Rostedt
@ 2017-04-21 21:30 ` Steven Rostedt
  2017-04-21 21:30 ` [for-next][PATCH 05/33] selftests: ftrace: Add -l/--logdir option Steven Rostedt
                   ` (28 subsequent siblings)
  32 siblings, 0 replies; 36+ messages in thread
From: Steven Rostedt @ 2017-04-21 21:30 UTC (permalink / raw)
  To: linux-kernel; +Cc: Ingo Molnar, Andrew Morton, Namhyung Kim

[-- Attachment #1: 0004-ftrace-Add-function-fork-trace-option.patch --]
[-- Type: text/plain, Size: 4490 bytes --]

From: Namhyung Kim <namhyung@kernel.org>

The function-fork option is same as event-fork that it tracks task
fork/exit and set the pid filter properly.  This can be useful if user
wants to trace selected tasks including their children only.

Link: http://lkml.kernel.org/r/20170417024430.21194-3-namhyung@kernel.org

Signed-off-by: Namhyung Kim <namhyung@kernel.org>
Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
---
 kernel/trace/ftrace.c | 37 +++++++++++++++++++++++++++++++++++++
 kernel/trace/trace.c  |  5 ++++-
 kernel/trace/trace.h  |  6 +++++-
 3 files changed, 46 insertions(+), 2 deletions(-)

diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index b21a3e61ac74..b5ce7ea67e02 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -5600,6 +5600,43 @@ ftrace_filter_pid_sched_switch_probe(void *data, bool preempt,
 		       trace_ignore_this_task(pid_list, next));
 }
 
+static void
+ftrace_pid_follow_sched_process_fork(void *data,
+				     struct task_struct *self,
+				     struct task_struct *task)
+{
+	struct trace_pid_list *pid_list;
+	struct trace_array *tr = data;
+
+	pid_list = rcu_dereference_sched(tr->function_pids);
+	trace_filter_add_remove_task(pid_list, self, task);
+}
+
+static void
+ftrace_pid_follow_sched_process_exit(void *data, struct task_struct *task)
+{
+	struct trace_pid_list *pid_list;
+	struct trace_array *tr = data;
+
+	pid_list = rcu_dereference_sched(tr->function_pids);
+	trace_filter_add_remove_task(pid_list, NULL, task);
+}
+
+void ftrace_pid_follow_fork(struct trace_array *tr, bool enable)
+{
+	if (enable) {
+		register_trace_sched_process_fork(ftrace_pid_follow_sched_process_fork,
+						  tr);
+		register_trace_sched_process_exit(ftrace_pid_follow_sched_process_exit,
+						  tr);
+	} else {
+		unregister_trace_sched_process_fork(ftrace_pid_follow_sched_process_fork,
+						    tr);
+		unregister_trace_sched_process_exit(ftrace_pid_follow_sched_process_exit,
+						    tr);
+	}
+}
+
 static void clear_ftrace_pids(struct trace_array *tr)
 {
 	struct trace_pid_list *pid_list;
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index b5d4b80f2d45..8a5064a03ddf 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -257,7 +257,7 @@ unsigned long long ns2usecs(u64 nsec)
 
 /* trace_flags that are default zero for instances */
 #define ZEROED_TRACE_FLAGS \
-	TRACE_ITER_EVENT_FORK
+	(TRACE_ITER_EVENT_FORK | TRACE_ITER_FUNC_FORK)
 
 /*
  * The global_trace is the descriptor that holds the top-level tracing
@@ -4205,6 +4205,9 @@ int set_tracer_flag(struct trace_array *tr, unsigned int mask, int enabled)
 	if (mask == TRACE_ITER_EVENT_FORK)
 		trace_event_follow_fork(tr, enabled);
 
+	if (mask == TRACE_ITER_FUNC_FORK)
+		ftrace_pid_follow_fork(tr, enabled);
+
 	if (mask == TRACE_ITER_OVERWRITE) {
 		ring_buffer_change_overwrite(tr->trace_buffer.buffer, enabled);
 #ifdef CONFIG_TRACER_MAX_TRACE
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
index 571acee52a32..31a4997b67c6 100644
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
@@ -897,6 +897,7 @@ void ftrace_init_tracefs(struct trace_array *tr, struct dentry *d_tracer);
 void ftrace_init_tracefs_toplevel(struct trace_array *tr,
 				  struct dentry *d_tracer);
 int init_function_trace(void);
+void ftrace_pid_follow_fork(struct trace_array *tr, bool enable);
 #else
 static inline int ftrace_trace_task(struct trace_array *tr)
 {
@@ -916,6 +917,7 @@ static inline void ftrace_reset_array_ops(struct trace_array *tr) { }
 static inline void ftrace_init_tracefs(struct trace_array *tr, struct dentry *d) { }
 static inline void ftrace_init_tracefs_toplevel(struct trace_array *tr, struct dentry *d) { }
 static inline int init_function_trace(void) { return 0; }
+static inline void ftrace_pid_follow_fork(struct trace_array *tr, bool enable) { }
 /* ftace_func_t type is not defined, use macro instead of static inline */
 #define ftrace_init_array_ops(tr, func) do { } while (0)
 #endif /* CONFIG_FUNCTION_TRACER */
@@ -989,11 +991,13 @@ extern int trace_get_user(struct trace_parser *parser, const char __user *ubuf,
 
 #ifdef CONFIG_FUNCTION_TRACER
 # define FUNCTION_FLAGS						\
-		C(FUNCTION,		"function-trace"),
+		C(FUNCTION,		"function-trace"),	\
+		C(FUNC_FORK,		"function-fork"),
 # define FUNCTION_DEFAULT_FLAGS		TRACE_ITER_FUNCTION
 #else
 # define FUNCTION_FLAGS
 # define FUNCTION_DEFAULT_FLAGS		0UL
+# define TRACE_ITER_FUNC_FORK		0UL
 #endif
 
 #ifdef CONFIG_STACKTRACE
-- 
2.10.2

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [for-next][PATCH 05/33] selftests: ftrace: Add -l/--logdir option
  2017-04-21 21:30 [for-next][PATCH 00/33] tracing: More updates for 4.12 Steven Rostedt
                   ` (3 preceding siblings ...)
  2017-04-21 21:30 ` [for-next][PATCH 04/33] ftrace: Add function-fork trace option Steven Rostedt
@ 2017-04-21 21:30 ` Steven Rostedt
  2017-04-21 21:30 ` [for-next][PATCH 06/33] selftests: ftrace: Add a way to reset triggers in the set_ftrace_filter file Steven Rostedt
                   ` (27 subsequent siblings)
  32 siblings, 0 replies; 36+ messages in thread
From: Steven Rostedt @ 2017-04-21 21:30 UTC (permalink / raw)
  To: linux-kernel
  Cc: Ingo Molnar, Andrew Morton, Masami Hiramatsu, Shuah Khan, Namhyung Kim

[-- Attachment #1: 0005-selftests-ftrace-Add-l-logdir-option.patch --]
[-- Type: text/plain, Size: 1425 bytes --]

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

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [for-next][PATCH 06/33] selftests: ftrace: Add a way to reset triggers in the set_ftrace_filter file
  2017-04-21 21:30 [for-next][PATCH 00/33] tracing: More updates for 4.12 Steven Rostedt
                   ` (4 preceding siblings ...)
  2017-04-21 21:30 ` [for-next][PATCH 05/33] selftests: ftrace: Add -l/--logdir option Steven Rostedt
@ 2017-04-21 21:30 ` Steven Rostedt
  2017-04-21 21:30 ` [for-next][PATCH 07/33] selftests: ftrace: Add a selftest to test event enable/disable func trigger Steven Rostedt
                   ` (26 subsequent siblings)
  32 siblings, 0 replies; 36+ messages in thread
From: Steven Rostedt @ 2017-04-21 21:30 UTC (permalink / raw)
  To: linux-kernel; +Cc: Ingo Molnar, Andrew Morton

[-- Attachment #1: 0006-selftests-ftrace-Add-a-way-to-reset-triggers-in-the-.patch --]
[-- Type: text/plain, Size: 1657 bytes --]

From: "Steven Rostedt (VMware)" <rostedt@goodmis.org>

Just writing into the set_ftrace_filter file does not reset triggers, even
though it can reset the function list. Triggers require writing the trigger
name with a "!" prepended. It's worse that it requires the number if the
trigger has a count associated to it.

Add a reset_ftrace_filter function to the ftrace self tests to allow for the
tests to have a generic way to clear them. It also resets any functions that
are listed in that file as well.

Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
---
 tools/testing/selftests/ftrace/test.d/functions | 21 +++++++++++++++++++++
 1 file changed, 21 insertions(+)

diff --git a/tools/testing/selftests/ftrace/test.d/functions b/tools/testing/selftests/ftrace/test.d/functions
index 91de1a8e4f19..9aec6fcb7729 100644
--- a/tools/testing/selftests/ftrace/test.d/functions
+++ b/tools/testing/selftests/ftrace/test.d/functions
@@ -30,6 +30,27 @@ reset_events_filter() { # reset all current setting filters
     done
 }
 
+reset_ftrace_filter() { # reset all triggers in set_ftrace_filter
+    echo > set_ftrace_filter
+    grep -v '^#' set_ftrace_filter | while read t; do
+	tr=`echo $t | cut -d: -f2`
+	if [ "$tr" == "" ]; then
+	    continue
+	fi
+	if [ $tr == "enable_event" -o $tr == "disable_event" ]; then
+	    tr=`echo $t | cut -d: -f1-4`
+	    limit=`echo $t | cut -d: -f5`
+	else
+	    tr=`echo $t | cut -d: -f1-2`
+	    limit=`echo $t | cut -d: -f3`
+	fi
+	if [ "$limit" != "unlimited" ]; then
+	    tr="$tr:$limit"
+	fi
+	echo "!$tr" > set_ftrace_filter
+    done
+}
+
 disable_events() {
     echo 0 > events/enable
 }
-- 
2.10.2

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [for-next][PATCH 07/33] selftests: ftrace: Add a selftest to test event enable/disable func trigger
  2017-04-21 21:30 [for-next][PATCH 00/33] tracing: More updates for 4.12 Steven Rostedt
                   ` (5 preceding siblings ...)
  2017-04-21 21:30 ` [for-next][PATCH 06/33] selftests: ftrace: Add a way to reset triggers in the set_ftrace_filter file Steven Rostedt
@ 2017-04-21 21:30 ` Steven Rostedt
  2017-04-21 21:30 ` [for-next][PATCH 08/33] selftests: ftrace: Add a test to test function triggers to start and stop tracing Steven Rostedt
                   ` (25 subsequent siblings)
  32 siblings, 0 replies; 36+ messages in thread
From: Steven Rostedt @ 2017-04-21 21:30 UTC (permalink / raw)
  To: linux-kernel; +Cc: Ingo Molnar, Andrew Morton

[-- Attachment #1: 0007-selftests-ftrace-Add-a-selftest-to-test-event-enable.patch --]
[-- Type: text/plain, Size: 3870 bytes --]

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

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [for-next][PATCH 08/33] selftests: ftrace: Add a test to test function triggers to start and stop tracing
  2017-04-21 21:30 [for-next][PATCH 00/33] tracing: More updates for 4.12 Steven Rostedt
                   ` (6 preceding siblings ...)
  2017-04-21 21:30 ` [for-next][PATCH 07/33] selftests: ftrace: Add a selftest to test event enable/disable func trigger Steven Rostedt
@ 2017-04-21 21:30 ` Steven Rostedt
  2017-04-21 21:30 ` [for-next][PATCH 09/33] selftests: ftrace: Add test to test reading of set_ftrace_file Steven Rostedt
                   ` (24 subsequent siblings)
  32 siblings, 0 replies; 36+ messages in thread
From: Steven Rostedt @ 2017-04-21 21:30 UTC (permalink / raw)
  To: linux-kernel; +Cc: Ingo Molnar, Andrew Morton

[-- Attachment #1: 0008-selftests-ftrace-Add-a-test-to-test-function-trigger.patch --]
[-- Type: text/plain, Size: 4977 bytes --]

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

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [for-next][PATCH 09/33] selftests: ftrace: Add test to test reading of set_ftrace_file
  2017-04-21 21:30 [for-next][PATCH 00/33] tracing: More updates for 4.12 Steven Rostedt
                   ` (7 preceding siblings ...)
  2017-04-21 21:30 ` [for-next][PATCH 08/33] selftests: ftrace: Add a test to test function triggers to start and stop tracing Steven Rostedt
@ 2017-04-21 21:30 ` Steven Rostedt
  2017-05-22  3:23   ` Masami Hiramatsu
  2017-04-21 21:30 ` [for-next][PATCH 10/33] ftrace: Move the probe function into the tracing directory Steven Rostedt
                   ` (23 subsequent siblings)
  32 siblings, 1 reply; 36+ messages in thread
From: Steven Rostedt @ 2017-04-21 21:30 UTC (permalink / raw)
  To: linux-kernel; +Cc: Ingo Molnar, Andrew Morton

[-- Attachment #1: 0009-selftests-ftrace-Add-test-to-test-reading-of-set_ftr.patch --]
[-- Type: text/plain, Size: 5520 bytes --]

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

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [for-next][PATCH 10/33] ftrace: Move the probe function into the tracing directory
  2017-04-21 21:30 [for-next][PATCH 00/33] tracing: More updates for 4.12 Steven Rostedt
                   ` (8 preceding siblings ...)
  2017-04-21 21:30 ` [for-next][PATCH 09/33] selftests: ftrace: Add test to test reading of set_ftrace_file Steven Rostedt
@ 2017-04-21 21:30 ` Steven Rostedt
  2017-04-21 21:30 ` [for-next][PATCH 11/33] ftrace: Move the function commands " Steven Rostedt
                   ` (22 subsequent siblings)
  32 siblings, 0 replies; 36+ messages in thread
From: Steven Rostedt @ 2017-04-21 21:30 UTC (permalink / raw)
  To: linux-kernel; +Cc: Ingo Molnar, Andrew Morton

[-- Attachment #1: 0010-ftrace-Move-the-probe-function-into-the-tracing-dire.patch --]
[-- Type: text/plain, Size: 3175 bytes --]

From: "Steven Rostedt (VMware)" <rostedt@goodmis.org>

As nothing outside the tracing directory uses the function probes 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 probe 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 | 24 ------------------------
 kernel/trace/trace.h   | 25 +++++++++++++++++++++++++
 2 files changed, 25 insertions(+), 24 deletions(-)

diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
index 06b2990a35e4..3e790ff1c501 100644
--- a/include/linux/ftrace.h
+++ b/include/linux/ftrace.h
@@ -360,30 +360,6 @@ void ftrace_bug(int err, struct dyn_ftrace *rec);
 
 struct seq_file;
 
-struct ftrace_probe_ops {
-	void			(*func)(unsigned long ip,
-					unsigned long parent_ip,
-					void **data);
-	int			(*init)(struct ftrace_probe_ops *ops,
-					unsigned long ip, void **data);
-	void			(*free)(struct ftrace_probe_ops *ops,
-					unsigned long ip, void **data);
-	int			(*print)(struct seq_file *m,
-					 unsigned long ip,
-					 struct ftrace_probe_ops *ops,
-					 void *data);
-};
-
-extern int
-register_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
-			      void *data);
-extern void
-unregister_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
-				void *data);
-extern void
-unregister_ftrace_function_probe_func(char *glob, struct ftrace_probe_ops *ops);
-extern void unregister_ftrace_function_probe_all(char *glob);
-
 extern int ftrace_text_reserved(const void *start, const void *end);
 
 extern int ftrace_nr_registered_ops(void);
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
index 31a4997b67c6..2ff6d49fa5ca 100644
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
@@ -923,6 +923,31 @@ static inline void ftrace_pid_follow_fork(struct trace_array *tr, bool enable) {
 #endif /* CONFIG_FUNCTION_TRACER */
 
 #if defined(CONFIG_FUNCTION_TRACER) && defined(CONFIG_DYNAMIC_FTRACE)
+
+struct ftrace_probe_ops {
+	void			(*func)(unsigned long ip,
+					unsigned long parent_ip,
+					void **data);
+	int			(*init)(struct ftrace_probe_ops *ops,
+					unsigned long ip, void **data);
+	void			(*free)(struct ftrace_probe_ops *ops,
+					unsigned long ip, void **data);
+	int			(*print)(struct seq_file *m,
+					 unsigned long ip,
+					 struct ftrace_probe_ops *ops,
+					 void *data);
+};
+
+extern int
+register_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
+			      void *data);
+extern void
+unregister_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
+				void *data);
+extern void
+unregister_ftrace_function_probe_func(char *glob, struct ftrace_probe_ops *ops);
+extern void unregister_ftrace_function_probe_all(char *glob);
+
 void ftrace_create_filter_files(struct ftrace_ops *ops,
 				struct dentry *parent);
 void ftrace_destroy_filter_files(struct ftrace_ops *ops);
-- 
2.10.2

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [for-next][PATCH 11/33] ftrace: Move the function commands into the tracing directory
  2017-04-21 21:30 [for-next][PATCH 00/33] tracing: More updates for 4.12 Steven Rostedt
                   ` (9 preceding siblings ...)
  2017-04-21 21:30 ` [for-next][PATCH 10/33] ftrace: Move the probe function into the tracing directory Steven Rostedt
@ 2017-04-21 21:30 ` Steven Rostedt
  2017-04-21 21:30 ` [for-next][PATCH 12/33] ftrace: Remove unused "flags" field from struct ftrace_func_probe Steven Rostedt
                   ` (21 subsequent siblings)
  32 siblings, 0 replies; 36+ messages in thread
From: Steven Rostedt @ 2017-04-21 21:30 UTC (permalink / raw)
  To: linux-kernel; +Cc: Ingo Molnar, Andrew Morton

[-- Attachment #1: 0011-ftrace-Move-the-function-commands-into-the-tracing-d.patch --]
[-- Type: text/plain, Size: 3611 bytes --]

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

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [for-next][PATCH 12/33] ftrace: Remove unused "flags" field from struct ftrace_func_probe
  2017-04-21 21:30 [for-next][PATCH 00/33] tracing: More updates for 4.12 Steven Rostedt
                   ` (10 preceding siblings ...)
  2017-04-21 21:30 ` [for-next][PATCH 11/33] ftrace: Move the function commands " Steven Rostedt
@ 2017-04-21 21:30 ` Steven Rostedt
  2017-04-21 21:30 ` [for-next][PATCH 13/33] ftrace: Pass probe ops to probe function Steven Rostedt
                   ` (20 subsequent siblings)
  32 siblings, 0 replies; 36+ messages in thread
From: Steven Rostedt @ 2017-04-21 21:30 UTC (permalink / raw)
  To: linux-kernel; +Cc: Ingo Molnar, Andrew Morton

[-- Attachment #1: 0012-ftrace-Remove-unused-flags-field-from-struct-ftrace_.patch --]
[-- Type: text/plain, Size: 695 bytes --]

From: "Steven Rostedt (VMware)" <rostedt@goodmis.org>

Nothing uses "flags" in the ftrace_func_probe descriptor. Remove it.

Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
---
 kernel/trace/ftrace.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index b5ce7ea67e02..b6dc29583c86 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -1101,7 +1101,6 @@ static struct hlist_head ftrace_func_hash[FTRACE_FUNC_HASHSIZE] __read_mostly;
 struct ftrace_func_probe {
 	struct hlist_node	node;
 	struct ftrace_probe_ops	*ops;
-	unsigned long		flags;
 	unsigned long		ip;
 	void			*data;
 	struct list_head	free_list;
-- 
2.10.2

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [for-next][PATCH 13/33] ftrace: Pass probe ops to probe function
  2017-04-21 21:30 [for-next][PATCH 00/33] tracing: More updates for 4.12 Steven Rostedt
                   ` (11 preceding siblings ...)
  2017-04-21 21:30 ` [for-next][PATCH 12/33] ftrace: Remove unused "flags" field from struct ftrace_func_probe Steven Rostedt
@ 2017-04-21 21:30 ` Steven Rostedt
  2017-04-21 21:30 ` [for-next][PATCH 14/33] ftrace: Added ftrace_func_mapper for function probe triggers Steven Rostedt
                   ` (19 subsequent siblings)
  32 siblings, 0 replies; 36+ messages in thread
From: Steven Rostedt @ 2017-04-21 21:30 UTC (permalink / raw)
  To: linux-kernel; +Cc: Ingo Molnar, Andrew Morton

[-- Attachment #1: 0013-ftrace-Pass-probe-ops-to-probe-function.patch --]
[-- Type: text/plain, Size: 6351 bytes --]

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

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [for-next][PATCH 14/33] ftrace: Added ftrace_func_mapper for function probe triggers
  2017-04-21 21:30 [for-next][PATCH 00/33] tracing: More updates for 4.12 Steven Rostedt
                   ` (12 preceding siblings ...)
  2017-04-21 21:30 ` [for-next][PATCH 13/33] ftrace: Pass probe ops to probe function Steven Rostedt
@ 2017-04-21 21:30 ` Steven Rostedt
  2017-04-21 21:30 ` [for-next][PATCH 15/33] tracing: Have the snapshot trigger use the mapping helper functions Steven Rostedt
                   ` (18 subsequent siblings)
  32 siblings, 0 replies; 36+ messages in thread
From: Steven Rostedt @ 2017-04-21 21:30 UTC (permalink / raw)
  To: linux-kernel; +Cc: Ingo Molnar, Andrew Morton

[-- Attachment #1: 0014-ftrace-Added-ftrace_func_mapper-for-function-probe-t.patch --]
[-- Type: text/plain, Size: 10004 bytes --]

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

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [for-next][PATCH 15/33] tracing: Have the snapshot trigger use the mapping helper functions
  2017-04-21 21:30 [for-next][PATCH 00/33] tracing: More updates for 4.12 Steven Rostedt
                   ` (13 preceding siblings ...)
  2017-04-21 21:30 ` [for-next][PATCH 14/33] ftrace: Added ftrace_func_mapper for function probe triggers Steven Rostedt
@ 2017-04-21 21:30 ` Steven Rostedt
  2017-04-21 21:30 ` [for-next][PATCH 16/33] ftrace: Convert the rest of the function trigger over to the mapping functions Steven Rostedt
                   ` (17 subsequent siblings)
  32 siblings, 0 replies; 36+ messages in thread
From: Steven Rostedt @ 2017-04-21 21:30 UTC (permalink / raw)
  To: linux-kernel; +Cc: Ingo Molnar, Andrew Morton

[-- Attachment #1: 0015-tracing-Have-the-snapshot-trigger-use-the-mapping-he.patch --]
[-- Type: text/plain, Size: 2922 bytes --]

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

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [for-next][PATCH 16/33] ftrace: Convert the rest of the function trigger over to the mapping functions
  2017-04-21 21:30 [for-next][PATCH 00/33] tracing: More updates for 4.12 Steven Rostedt
                   ` (14 preceding siblings ...)
  2017-04-21 21:30 ` [for-next][PATCH 15/33] tracing: Have the snapshot trigger use the mapping helper functions Steven Rostedt
@ 2017-04-21 21:30 ` Steven Rostedt
  2017-04-21 21:30 ` [for-next][PATCH 17/33] ftrace: Remove unused unregister_ftrace_function_probe() function Steven Rostedt
                   ` (16 subsequent siblings)
  32 siblings, 0 replies; 36+ messages in thread
From: Steven Rostedt @ 2017-04-21 21:30 UTC (permalink / raw)
  To: linux-kernel; +Cc: Ingo Molnar, Andrew Morton

[-- Attachment #1: 0016-ftrace-Convert-the-rest-of-the-function-trigger-over.patch --]
[-- Type: text/plain, Size: 7511 bytes --]

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

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [for-next][PATCH 17/33] ftrace: Remove unused unregister_ftrace_function_probe() function
  2017-04-21 21:30 [for-next][PATCH 00/33] tracing: More updates for 4.12 Steven Rostedt
                   ` (15 preceding siblings ...)
  2017-04-21 21:30 ` [for-next][PATCH 16/33] ftrace: Convert the rest of the function trigger over to the mapping functions Steven Rostedt
@ 2017-04-21 21:30 ` Steven Rostedt
  2017-04-21 21:30 ` [for-next][PATCH 18/33] ftrace: Remove unused unregister_ftrace_function_probe_all() function Steven Rostedt
                   ` (15 subsequent siblings)
  32 siblings, 0 replies; 36+ messages in thread
From: Steven Rostedt @ 2017-04-21 21:30 UTC (permalink / raw)
  To: linux-kernel; +Cc: Ingo Molnar, Andrew Morton

[-- Attachment #1: 0017-ftrace-Remove-unused-unregister_ftrace_function_prob.patch --]
[-- Type: text/plain, Size: 2613 bytes --]

From: "Steven Rostedt (VMware)" <rostedt@goodmis.org>

Nothing calls unregister_ftrace_function_probe(). Remove it as well as the
flag PROBE_TEST_DATA, as this function was the only one to set it.

Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
---
 kernel/trace/ftrace.c | 18 +++---------------
 kernel/trace/trace.h  |  3 ---
 2 files changed, 3 insertions(+), 18 deletions(-)

diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index ac47d1845fdb..5448089e6028 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -4061,12 +4061,11 @@ register_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
 
 enum {
 	PROBE_TEST_FUNC		= 1,
-	PROBE_TEST_DATA		= 2
 };
 
 static void
 __unregister_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
-				  void *data, int flags)
+				   int flags)
 {
 	struct ftrace_ops_hash old_hash_ops;
 	struct ftrace_func_entry *rec_entry;
@@ -4119,9 +4118,6 @@ __unregister_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
 			if ((flags & PROBE_TEST_FUNC) && entry->ops != ops)
 				continue;
 
-			if ((flags & PROBE_TEST_DATA) && entry->data != data)
-				continue;
-
 			/* do this last, since it is the most expensive */
 			if (func_g.search) {
 				kallsyms_lookup(entry->ip, NULL, NULL,
@@ -4167,22 +4163,14 @@ __unregister_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
 }
 
 void
-unregister_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
-				void *data)
-{
-	__unregister_ftrace_function_probe(glob, ops, data,
-					  PROBE_TEST_FUNC | PROBE_TEST_DATA);
-}
-
-void
 unregister_ftrace_function_probe_func(char *glob, struct ftrace_probe_ops *ops)
 {
-	__unregister_ftrace_function_probe(glob, ops, NULL, PROBE_TEST_FUNC);
+	__unregister_ftrace_function_probe(glob, ops, PROBE_TEST_FUNC);
 }
 
 void unregister_ftrace_function_probe_all(char *glob)
 {
-	__unregister_ftrace_function_probe(glob, NULL, NULL, 0);
+	__unregister_ftrace_function_probe(glob, NULL, 0);
 }
 
 static LIST_HEAD(ftrace_commands);
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
index dbbdee21bcc4..507a62e9192e 100644
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
@@ -964,9 +964,6 @@ extern int
 register_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
 			      void *data);
 extern void
-unregister_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
-				void *data);
-extern void
 unregister_ftrace_function_probe_func(char *glob, struct ftrace_probe_ops *ops);
 extern void unregister_ftrace_function_probe_all(char *glob);
 
-- 
2.10.2

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [for-next][PATCH 18/33] ftrace: Remove unused unregister_ftrace_function_probe_all() function
  2017-04-21 21:30 [for-next][PATCH 00/33] tracing: More updates for 4.12 Steven Rostedt
                   ` (16 preceding siblings ...)
  2017-04-21 21:30 ` [for-next][PATCH 17/33] ftrace: Remove unused unregister_ftrace_function_probe() function Steven Rostedt
@ 2017-04-21 21:30 ` Steven Rostedt
  2017-04-21 21:30 ` [for-next][PATCH 19/33] ftrace: Remove printing of data in showing of a function probe Steven Rostedt
                   ` (14 subsequent siblings)
  32 siblings, 0 replies; 36+ messages in thread
From: Steven Rostedt @ 2017-04-21 21:30 UTC (permalink / raw)
  To: linux-kernel; +Cc: Ingo Molnar, Andrew Morton

[-- Attachment #1: 0018-ftrace-Remove-unused-unregister_ftrace_function_prob.patch --]
[-- Type: text/plain, Size: 2592 bytes --]

From: "Steven Rostedt (VMware)" <rostedt@goodmis.org>

There are no users of unregister_ftrace_function_probe_all(). The only probe
function that is used is unregister_ftrace_function_probe_func(). Rename the
internal static function __unregister_ftrace_function_probe() to
unregister_ftrace_function_probe_func() and make it global.

Also remove the PROBE_TEST_FUNC as it would be always set.

Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
---
 kernel/trace/ftrace.c | 22 +++-------------------
 kernel/trace/trace.h  |  1 -
 2 files changed, 3 insertions(+), 20 deletions(-)

diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index 5448089e6028..1c31c74d0819 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -4059,13 +4059,8 @@ register_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
 	return count;
 }
 
-enum {
-	PROBE_TEST_FUNC		= 1,
-};
-
-static void
-__unregister_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
-				   int flags)
+void
+unregister_ftrace_function_probe_func(char *glob, struct ftrace_probe_ops *ops)
 {
 	struct ftrace_ops_hash old_hash_ops;
 	struct ftrace_func_entry *rec_entry;
@@ -4115,7 +4110,7 @@ __unregister_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
 		hlist_for_each_entry_safe(entry, tmp, hhd, node) {
 
 			/* break up if statements for readability */
-			if ((flags & PROBE_TEST_FUNC) && entry->ops != ops)
+			if (entry->ops != ops)
 				continue;
 
 			/* do this last, since it is the most expensive */
@@ -4162,17 +4157,6 @@ __unregister_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
 	free_ftrace_hash(hash);
 }
 
-void
-unregister_ftrace_function_probe_func(char *glob, struct ftrace_probe_ops *ops)
-{
-	__unregister_ftrace_function_probe(glob, ops, PROBE_TEST_FUNC);
-}
-
-void unregister_ftrace_function_probe_all(char *glob)
-{
-	__unregister_ftrace_function_probe(glob, NULL, 0);
-}
-
 static LIST_HEAD(ftrace_commands);
 static DEFINE_MUTEX(ftrace_cmd_mutex);
 
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
index 507a62e9192e..376d5a798489 100644
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
@@ -965,7 +965,6 @@ register_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
 			      void *data);
 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);
-- 
2.10.2

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [for-next][PATCH 19/33] ftrace: Remove printing of data in showing of a function probe
  2017-04-21 21:30 [for-next][PATCH 00/33] tracing: More updates for 4.12 Steven Rostedt
                   ` (17 preceding siblings ...)
  2017-04-21 21:30 ` [for-next][PATCH 18/33] ftrace: Remove unused unregister_ftrace_function_probe_all() function Steven Rostedt
@ 2017-04-21 21:30 ` Steven Rostedt
  2017-04-21 21:30 ` [for-next][PATCH 20/33] ftrace: Remove data field from ftrace_func_probe structure Steven Rostedt
                   ` (13 subsequent siblings)
  32 siblings, 0 replies; 36+ messages in thread
From: Steven Rostedt @ 2017-04-21 21:30 UTC (permalink / raw)
  To: linux-kernel; +Cc: Ingo Molnar, Andrew Morton

[-- Attachment #1: 0019-ftrace-Remove-printing-of-data-in-showing-of-a-funct.patch --]
[-- Type: text/plain, Size: 973 bytes --]

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

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [for-next][PATCH 20/33] ftrace: Remove data field from ftrace_func_probe structure
  2017-04-21 21:30 [for-next][PATCH 00/33] tracing: More updates for 4.12 Steven Rostedt
                   ` (18 preceding siblings ...)
  2017-04-21 21:30 ` [for-next][PATCH 19/33] ftrace: Remove printing of data in showing of a function probe Steven Rostedt
@ 2017-04-21 21:30 ` Steven Rostedt
  2017-04-21 21:30 ` [for-next][PATCH 21/33] ftrace: Add helper function ftrace_hash_move_and_update_ops() Steven Rostedt
                   ` (12 subsequent siblings)
  32 siblings, 0 replies; 36+ messages in thread
From: Steven Rostedt @ 2017-04-21 21:30 UTC (permalink / raw)
  To: linux-kernel; +Cc: Ingo Molnar, Andrew Morton

[-- Attachment #1: 0020-ftrace-Remove-data-field-from-ftrace_func_probe-stru.patch --]
[-- Type: text/plain, Size: 4970 bytes --]

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

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [for-next][PATCH 21/33] ftrace: Add helper function ftrace_hash_move_and_update_ops()
  2017-04-21 21:30 [for-next][PATCH 00/33] tracing: More updates for 4.12 Steven Rostedt
                   ` (19 preceding siblings ...)
  2017-04-21 21:30 ` [for-next][PATCH 20/33] ftrace: Remove data field from ftrace_func_probe structure Steven Rostedt
@ 2017-04-21 21:30 ` Steven Rostedt
  2017-04-21 21:30 ` [for-next][PATCH 22/33] ftrace: Have unregister_ftrace_function_probe_func() return a value Steven Rostedt
                   ` (11 subsequent siblings)
  32 siblings, 0 replies; 36+ messages in thread
From: Steven Rostedt @ 2017-04-21 21:30 UTC (permalink / raw)
  To: linux-kernel; +Cc: Ingo Molnar, Andrew Morton

[-- Attachment #1: 0021-ftrace-Add-helper-function-ftrace_hash_move_and_upda.patch --]
[-- Type: text/plain, Size: 5210 bytes --]

From: "Steven Rostedt (VMware)" <rostedt@goodmis.org>

The processes of updating a ops filter_hash is a bit complex, and requires
setting up an old hash to perform the update. This is done exactly the same
in two locations for the same reasons. Create a helper function that does it
in one place.

Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
---
 kernel/trace/ftrace.c | 105 +++++++++++++++++++++++++-------------------------
 1 file changed, 53 insertions(+), 52 deletions(-)

diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index f7fcab8f3aa1..5c8d8eea9e7c 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -3674,6 +3674,56 @@ ftrace_match_records(struct ftrace_hash *hash, char *buff, int len)
 	return match_records(hash, buff, len, NULL);
 }
 
+static void ftrace_ops_update_code(struct ftrace_ops *ops,
+				   struct ftrace_ops_hash *old_hash)
+{
+	struct ftrace_ops *op;
+
+	if (!ftrace_enabled)
+		return;
+
+	if (ops->flags & FTRACE_OPS_FL_ENABLED) {
+		ftrace_run_modify_code(ops, FTRACE_UPDATE_CALLS, old_hash);
+		return;
+	}
+
+	/*
+	 * If this is the shared global_ops filter, then we need to
+	 * check if there is another ops that shares it, is enabled.
+	 * If so, we still need to run the modify code.
+	 */
+	if (ops->func_hash != &global_ops.local_hash)
+		return;
+
+	do_for_each_ftrace_op(op, ftrace_ops_list) {
+		if (op->func_hash == &global_ops.local_hash &&
+		    op->flags & FTRACE_OPS_FL_ENABLED) {
+			ftrace_run_modify_code(op, FTRACE_UPDATE_CALLS, old_hash);
+			/* Only need to do this once */
+			return;
+		}
+	} while_for_each_ftrace_op(op);
+}
+
+static int ftrace_hash_move_and_update_ops(struct ftrace_ops *ops,
+					   struct ftrace_hash **orig_hash,
+					   struct ftrace_hash *hash,
+					   int enable)
+{
+	struct ftrace_ops_hash old_hash_ops;
+	struct ftrace_hash *old_hash;
+	int ret;
+
+	old_hash = *orig_hash;
+	old_hash_ops.filter_hash = ops->func_hash->filter_hash;
+	old_hash_ops.notrace_hash = ops->func_hash->notrace_hash;
+	ret = ftrace_hash_move(ops, enable, orig_hash, hash);
+	if (!ret) {
+		ftrace_ops_update_code(ops, &old_hash_ops);
+		free_ftrace_hash_rcu(old_hash);
+	}
+	return ret;
+}
 
 /*
  * We register the module command as a template to show others how
@@ -4306,44 +4356,11 @@ ftrace_match_addr(struct ftrace_hash *hash, unsigned long ip, int remove)
 	return add_hash_entry(hash, ip);
 }
 
-static void ftrace_ops_update_code(struct ftrace_ops *ops,
-				   struct ftrace_ops_hash *old_hash)
-{
-	struct ftrace_ops *op;
-
-	if (!ftrace_enabled)
-		return;
-
-	if (ops->flags & FTRACE_OPS_FL_ENABLED) {
-		ftrace_run_modify_code(ops, FTRACE_UPDATE_CALLS, old_hash);
-		return;
-	}
-
-	/*
-	 * If this is the shared global_ops filter, then we need to
-	 * check if there is another ops that shares it, is enabled.
-	 * If so, we still need to run the modify code.
-	 */
-	if (ops->func_hash != &global_ops.local_hash)
-		return;
-
-	do_for_each_ftrace_op(op, ftrace_ops_list) {
-		if (op->func_hash == &global_ops.local_hash &&
-		    op->flags & FTRACE_OPS_FL_ENABLED) {
-			ftrace_run_modify_code(op, FTRACE_UPDATE_CALLS, old_hash);
-			/* Only need to do this once */
-			return;
-		}
-	} while_for_each_ftrace_op(op);
-}
-
 static int
 ftrace_set_hash(struct ftrace_ops *ops, unsigned char *buf, int len,
 		unsigned long ip, int remove, int reset, int enable)
 {
 	struct ftrace_hash **orig_hash;
-	struct ftrace_ops_hash old_hash_ops;
-	struct ftrace_hash *old_hash;
 	struct ftrace_hash *hash;
 	int ret;
 
@@ -4378,14 +4395,7 @@ ftrace_set_hash(struct ftrace_ops *ops, unsigned char *buf, int len,
 	}
 
 	mutex_lock(&ftrace_lock);
-	old_hash = *orig_hash;
-	old_hash_ops.filter_hash = ops->func_hash->filter_hash;
-	old_hash_ops.notrace_hash = ops->func_hash->notrace_hash;
-	ret = ftrace_hash_move(ops, enable, orig_hash, hash);
-	if (!ret) {
-		ftrace_ops_update_code(ops, &old_hash_ops);
-		free_ftrace_hash_rcu(old_hash);
-	}
+	ret = ftrace_hash_move_and_update_ops(ops, orig_hash, hash, enable);
 	mutex_unlock(&ftrace_lock);
 
  out_regex_unlock:
@@ -4624,10 +4634,8 @@ static void __init set_ftrace_early_filters(void)
 int ftrace_regex_release(struct inode *inode, struct file *file)
 {
 	struct seq_file *m = (struct seq_file *)file->private_data;
-	struct ftrace_ops_hash old_hash_ops;
 	struct ftrace_iterator *iter;
 	struct ftrace_hash **orig_hash;
-	struct ftrace_hash *old_hash;
 	struct trace_parser *parser;
 	int filter_hash;
 	int ret;
@@ -4657,15 +4665,8 @@ int ftrace_regex_release(struct inode *inode, struct file *file)
 			orig_hash = &iter->ops->func_hash->notrace_hash;
 
 		mutex_lock(&ftrace_lock);
-		old_hash = *orig_hash;
-		old_hash_ops.filter_hash = iter->ops->func_hash->filter_hash;
-		old_hash_ops.notrace_hash = iter->ops->func_hash->notrace_hash;
-		ret = ftrace_hash_move(iter->ops, filter_hash,
-				       orig_hash, iter->hash);
-		if (!ret) {
-			ftrace_ops_update_code(iter->ops, &old_hash_ops);
-			free_ftrace_hash_rcu(old_hash);
-		}
+		ret = ftrace_hash_move_and_update_ops(iter->ops, orig_hash,
+						      iter->hash, filter_hash);
 		mutex_unlock(&ftrace_lock);
 	} else {
 		/* For read only, the hash is the ops hash */
-- 
2.10.2

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [for-next][PATCH 22/33] ftrace: Have unregister_ftrace_function_probe_func() return a value
  2017-04-21 21:30 [for-next][PATCH 00/33] tracing: More updates for 4.12 Steven Rostedt
                   ` (20 preceding siblings ...)
  2017-04-21 21:30 ` [for-next][PATCH 21/33] ftrace: Add helper function ftrace_hash_move_and_update_ops() Steven Rostedt
@ 2017-04-21 21:30 ` Steven Rostedt
  2017-04-21 21:30 ` [for-next][PATCH 23/33] ftrace: Have each function probe use its own ftrace_ops Steven Rostedt
                   ` (10 subsequent siblings)
  32 siblings, 0 replies; 36+ messages in thread
From: Steven Rostedt @ 2017-04-21 21:30 UTC (permalink / raw)
  To: linux-kernel; +Cc: Ingo Molnar, Andrew Morton

[-- Attachment #1: 0022-ftrace-Have-unregister_ftrace_function_probe_func-re.patch --]
[-- Type: text/plain, Size: 4385 bytes --]

From: "Steven Rostedt (VMware)" <rostedt@goodmis.org>

Currently unregister_ftrace_function_probe_func() is a void function. It
does not give any feedback if an error occurred or no item was found to
remove and nothing was done.

Change it to return status and success if it removed something. Also update
the callers to return that feedback to the user.

Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
---
 kernel/trace/ftrace.c          | 14 +++++++++++---
 kernel/trace/trace.c           |  6 ++----
 kernel/trace/trace.h           |  2 +-
 kernel/trace/trace_events.c    |  3 +--
 kernel/trace/trace_functions.c |  6 ++----
 5 files changed, 17 insertions(+), 14 deletions(-)

diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index 5c8d8eea9e7c..cbae7fb1be15 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -4102,7 +4102,7 @@ register_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
 	return count;
 }
 
-void
+int
 unregister_ftrace_function_probe_func(char *glob, struct ftrace_probe_ops *ops)
 {
 	struct ftrace_ops_hash old_hash_ops;
@@ -4131,7 +4131,7 @@ unregister_ftrace_function_probe_func(char *glob, struct ftrace_probe_ops *ops)
 
 		/* we do not support '!' for function probes */
 		if (WARN_ON(not))
-			return;
+			return -EINVAL;
 	}
 
 	mutex_lock(&trace_probe_ops.func_hash->regex_lock);
@@ -4140,9 +4140,9 @@ unregister_ftrace_function_probe_func(char *glob, struct ftrace_probe_ops *ops)
 	/* Probes only have filters */
 	old_hash_ops.notrace_hash = NULL;
 
+	ret = -ENOMEM;
 	hash = alloc_and_copy_ftrace_hash(FTRACE_HASH_DEFAULT_BITS, *orig_hash);
 	if (!hash)
-		/* Hmm, should report this somehow */
 		goto out_unlock;
 
 	INIT_LIST_HEAD(&free_list);
@@ -4173,6 +4173,13 @@ unregister_ftrace_function_probe_func(char *glob, struct ftrace_probe_ops *ops)
 			list_add(&entry->free_list, &free_list);
 		}
 	}
+
+	/* Nothing found? */
+	if (list_empty(&free_list)) {
+		ret = -EINVAL;
+		goto out_unlock;
+	}
+
 	mutex_lock(&ftrace_lock);
 	disabled = __disable_ftrace_function_probe();
 	/*
@@ -4198,6 +4205,7 @@ unregister_ftrace_function_probe_func(char *glob, struct ftrace_probe_ops *ops)
  out_unlock:
 	mutex_unlock(&trace_probe_ops.func_hash->regex_lock);
 	free_ftrace_hash(hash);
+	return ret;
 }
 
 static LIST_HEAD(ftrace_commands);
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 7a4d578d8887..64a4418a5106 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -6829,10 +6829,8 @@ ftrace_trace_snapshot_callback(struct ftrace_hash *hash,
 
 	ops = param ? &snapshot_count_probe_ops :  &snapshot_probe_ops;
 
-	if (glob[0] == '!') {
-		unregister_ftrace_function_probe_func(glob+1, ops);
-		return 0;
-	}
+	if (glob[0] == '!')
+		return unregister_ftrace_function_probe_func(glob+1, ops);
 
 	if (!param)
 		goto out_reg;
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
index 86aa5a2222ba..31d80bff9ee6 100644
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
@@ -963,7 +963,7 @@ void free_ftrace_func_mapper(struct ftrace_func_mapper *mapper,
 extern int
 register_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
 			      void *data);
-extern void
+extern int
 unregister_ftrace_function_probe_func(char *glob, struct ftrace_probe_ops *ops);
 
 int register_ftrace_command(struct ftrace_func_command *cmd);
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c
index 37902107c44f..9e07a5b3869b 100644
--- a/kernel/trace/trace_events.c
+++ b/kernel/trace/trace_events.c
@@ -2652,8 +2652,7 @@ event_enable_func(struct ftrace_hash *hash,
 		ops = param ? &event_disable_count_probe_ops : &event_disable_probe_ops;
 
 	if (glob[0] == '!') {
-		unregister_ftrace_function_probe_func(glob+1, ops);
-		ret = 0;
+		ret = unregister_ftrace_function_probe_func(glob+1, ops);
 		goto out;
 	}
 
diff --git a/kernel/trace/trace_functions.c b/kernel/trace/trace_functions.c
index 56d0fe1e4ea1..dcb4d37ed4bd 100644
--- a/kernel/trace/trace_functions.c
+++ b/kernel/trace/trace_functions.c
@@ -586,10 +586,8 @@ ftrace_trace_probe_callback(struct ftrace_probe_ops *ops,
 	if (!enable)
 		return -EINVAL;
 
-	if (glob[0] == '!') {
-		unregister_ftrace_function_probe_func(glob+1, ops);
-		return 0;
-	}
+	if (glob[0] == '!')
+		return unregister_ftrace_function_probe_func(glob+1, ops);
 
 	if (!param)
 		goto out_reg;
-- 
2.10.2

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [for-next][PATCH 23/33] ftrace: Have each function probe use its own ftrace_ops
  2017-04-21 21:30 [for-next][PATCH 00/33] tracing: More updates for 4.12 Steven Rostedt
                   ` (21 preceding siblings ...)
  2017-04-21 21:30 ` [for-next][PATCH 22/33] ftrace: Have unregister_ftrace_function_probe_func() return a value Steven Rostedt
@ 2017-04-21 21:30 ` Steven Rostedt
  2017-04-21 21:30 ` [for-next][PATCH 24/33] ftrace: Have the function probes call their own function Steven Rostedt
                   ` (9 subsequent siblings)
  32 siblings, 0 replies; 36+ messages in thread
From: Steven Rostedt @ 2017-04-21 21:30 UTC (permalink / raw)
  To: linux-kernel; +Cc: Ingo Molnar, Andrew Morton

[-- Attachment #1: 0023-ftrace-Have-each-function-probe-use-its-own-ftrace_o.patch --]
[-- Type: text/plain, Size: 10092 bytes --]

From: "Steven Rostedt (VMware)" <rostedt@goodmis.org>

Have the function probes have their own ftrace_ops, and remove the
trace_probe_ops. This simplifies some of the ftrace infrastructure code.

Individual entries for each function is still allocated for the use of the
output for set_ftrace_filter, but they will be removed soon too.

Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
---
 kernel/trace/ftrace.c | 246 ++++++++++++++++++++------------------------------
 kernel/trace/trace.h  |   1 +
 2 files changed, 99 insertions(+), 148 deletions(-)

diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index cbae7fb1be15..cf6b7263199a 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -3789,63 +3789,6 @@ static void function_trace_probe_call(unsigned long ip, unsigned long parent_ip,
 	preempt_enable_notrace();
 }
 
-static struct ftrace_ops trace_probe_ops __read_mostly =
-{
-	.func		= function_trace_probe_call,
-	.flags		= FTRACE_OPS_FL_INITIALIZED,
-	INIT_OPS_HASH(trace_probe_ops)
-};
-
-static int ftrace_probe_registered;
-
-static void __enable_ftrace_function_probe(struct ftrace_ops_hash *old_hash)
-{
-	int ret;
-	int i;
-
-	if (ftrace_probe_registered) {
-		/* still need to update the function call sites */
-		if (ftrace_enabled)
-			ftrace_run_modify_code(&trace_probe_ops, FTRACE_UPDATE_CALLS,
-					       old_hash);
-		return;
-	}
-
-	for (i = 0; i < FTRACE_FUNC_HASHSIZE; i++) {
-		struct hlist_head *hhd = &ftrace_func_hash[i];
-		if (hhd->first)
-			break;
-	}
-	/* Nothing registered? */
-	if (i == FTRACE_FUNC_HASHSIZE)
-		return;
-
-	ret = ftrace_startup(&trace_probe_ops, 0);
-
-	ftrace_probe_registered = 1;
-}
-
-static bool __disable_ftrace_function_probe(void)
-{
-	int i;
-
-	if (!ftrace_probe_registered)
-		return false;
-
-	for (i = 0; i < FTRACE_FUNC_HASHSIZE; i++) {
-		struct hlist_head *hhd = &ftrace_func_hash[i];
-		if (hhd->first)
-			return false;
-	}
-
-	/* no more funcs left */
-	ftrace_shutdown(&trace_probe_ops, 0);
-
-	ftrace_probe_registered = 0;
-	return true;
-}
-
-
 static void ftrace_free_entry(struct ftrace_func_probe *entry)
 {
 	if (entry->ops->free)
@@ -3996,110 +3939,110 @@ void free_ftrace_func_mapper(struct ftrace_func_mapper *mapper,
 
 int
 register_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
-			      void *data)
+			       void *data)
 {
-	struct ftrace_ops_hash old_hash_ops;
-	struct ftrace_func_probe *entry;
-	struct ftrace_glob func_g;
-	struct ftrace_hash **orig_hash = &trace_probe_ops.func_hash->filter_hash;
-	struct ftrace_hash *old_hash = *orig_hash;
+	struct ftrace_func_entry *entry;
+	struct ftrace_func_probe *probe;
+	struct ftrace_hash **orig_hash;
+	struct ftrace_hash *old_hash;
 	struct ftrace_hash *hash;
-	struct ftrace_page *pg;
-	struct dyn_ftrace *rec;
-	int not;
+	struct hlist_head hl;
+	struct hlist_node *n;
 	unsigned long key;
 	int count = 0;
+	int size;
 	int ret;
+	int i;
 
-	func_g.type = filter_parse_regex(glob, strlen(glob),
-			&func_g.search, &not);
-	func_g.len = strlen(func_g.search);
-
-	/* we do not support '!' for function probes */
-	if (WARN_ON(not))
+	/* We do not support '!' for function probes */
+	if (WARN_ON(glob[0] == '!'))
 		return -EINVAL;
 
-	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, old_hash);
-	if (!hash) {
-		count = -ENOMEM;
-		goto out;
+	if (!(ops->ops.flags & FTRACE_OPS_FL_INITIALIZED)) {
+		ops->ops.func = function_trace_probe_call;
+		ftrace_ops_init(&ops->ops);
 	}
 
-	if (unlikely(ftrace_disabled)) {
-		count = -ENODEV;
-		goto out;
-	}
-
-	mutex_lock(&ftrace_lock);
+	mutex_lock(&ops->ops.func_hash->regex_lock);
 
-	do_for_each_ftrace_rec(pg, rec) {
+	orig_hash = &ops->ops.func_hash->filter_hash;
+	old_hash = *orig_hash;
+	hash = alloc_and_copy_ftrace_hash(FTRACE_HASH_DEFAULT_BITS, old_hash);
 
-		if (rec->flags & FTRACE_FL_DISABLED)
-			continue;
+	ret = ftrace_match_records(hash, glob, strlen(glob));
 
-		if (!ftrace_match_record(rec, &func_g, NULL, 0))
-			continue;
+	/* Nothing found? */
+	if (!ret)
+		ret = -EINVAL;
 
-		entry = kmalloc(sizeof(*entry), GFP_KERNEL);
-		if (!entry) {
-			/* If we did not process any, then return error */
-			if (!count)
-				count = -ENOMEM;
-			goto out_unlock;
-		}
+	if (ret < 0)
+		goto out;
 
-		count++;
+	INIT_HLIST_HEAD(&hl);
 
-		/*
-		 * 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, data) < 0) {
-				/* caller does not like this func */
-				kfree(entry);
+	size = 1 << hash->size_bits;
+	for (i = 0; i < size; i++) {
+		hlist_for_each_entry(entry, &hash->buckets[i], hlist) {
+			if (ftrace_lookup_ip(old_hash, entry->ip))
 				continue;
+			probe = kmalloc(sizeof(*probe), GFP_KERNEL);
+			if (!probe) {
+				count = -ENOMEM;
+				goto err_free;
 			}
-		}
+			probe->ops = ops;
+			probe->ip = entry->ip;
+			/*
+			 * 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 && ops->init(ops, entry->ip, data) < 0) {
+				kfree(probe);
+				goto err_free;
+			}
+			hlist_add_head(&probe->node, &hl);
 
-		ret = enter_record(hash, rec, 0);
-		if (ret < 0) {
-			kfree(entry);
-			count = ret;
-			goto out_unlock;
+			count++;
 		}
+	}
 
-		entry->ops = ops;
-		entry->ip = rec->ip;
+	mutex_lock(&ftrace_lock);
 
-		key = hash_long(entry->ip, FTRACE_HASH_BITS);
-		hlist_add_head_rcu(&entry->node, &ftrace_func_hash[key]);
+	ret = ftrace_hash_move_and_update_ops(&ops->ops, orig_hash,
+						      hash, 1);
+	if (ret < 0)
+		goto err_free_unlock;
 
-	} while_for_each_ftrace_rec();
+	hlist_for_each_entry_safe(probe, n, &hl, node) {
+		hlist_del(&probe->node);
+		key = hash_long(probe->ip, FTRACE_HASH_BITS);
+		hlist_add_head_rcu(&probe->node, &ftrace_func_hash[key]);
+	}
 
-	ret = ftrace_hash_move(&trace_probe_ops, 1, orig_hash, hash);
+	if (!(ops->ops.flags & FTRACE_OPS_FL_ENABLED))
+		ret = ftrace_startup(&ops->ops, 0);
 
-	__enable_ftrace_function_probe(&old_hash_ops);
+	mutex_unlock(&ftrace_lock);
 
 	if (!ret)
-		free_ftrace_hash_rcu(old_hash);
-	else
-		count = ret;
-
- out_unlock:
-	mutex_unlock(&ftrace_lock);
+		ret = count;
  out:
-	mutex_unlock(&trace_probe_ops.func_hash->regex_lock);
+	mutex_unlock(&ops->ops.func_hash->regex_lock);
 	free_ftrace_hash(hash);
 
-	return count;
+	return ret;
+
+ err_free_unlock:
+	mutex_unlock(&ftrace_lock);
+ err_free:
+	hlist_for_each_entry_safe(probe, n, &hl, node) {
+		hlist_del(&probe->node);
+		if (ops->free)
+			ops->free(ops, probe->ip, NULL);
+		kfree(probe);
+	}
+	goto out;
 }
 
 int
@@ -4110,14 +4053,16 @@ unregister_ftrace_function_probe_func(char *glob, struct ftrace_probe_ops *ops)
 	struct ftrace_func_probe *entry;
 	struct ftrace_func_probe *p;
 	struct ftrace_glob func_g;
-	struct ftrace_hash **orig_hash = &trace_probe_ops.func_hash->filter_hash;
-	struct ftrace_hash *old_hash = *orig_hash;
+	struct ftrace_hash **orig_hash;
+	struct ftrace_hash *old_hash;
 	struct list_head free_list;
-	struct ftrace_hash *hash;
+	struct ftrace_hash *hash = NULL;
 	struct hlist_node *tmp;
 	char str[KSYM_SYMBOL_LEN];
 	int i, ret;
-	bool disabled;
+
+	if (!(ops->ops.flags & FTRACE_OPS_FL_INITIALIZED))
+		return -EINVAL;
 
 	if (glob && (strcmp(glob, "*") == 0 || !strlen(glob)))
 		func_g.search = NULL;
@@ -4134,14 +4079,21 @@ unregister_ftrace_function_probe_func(char *glob, struct ftrace_probe_ops *ops)
 			return -EINVAL;
 	}
 
-	mutex_lock(&trace_probe_ops.func_hash->regex_lock);
+	mutex_lock(&ops->ops.func_hash->regex_lock);
+
+	orig_hash = &ops->ops.func_hash->filter_hash;
+	old_hash = *orig_hash;
+
+	ret = -EINVAL;
+	if (ftrace_hash_empty(old_hash))
+		goto out_unlock;
 
 	old_hash_ops.filter_hash = old_hash;
 	/* Probes only have filters */
 	old_hash_ops.notrace_hash = NULL;
 
 	ret = -ENOMEM;
-	hash = alloc_and_copy_ftrace_hash(FTRACE_HASH_DEFAULT_BITS, *orig_hash);
+	hash = alloc_and_copy_ftrace_hash(FTRACE_HASH_DEFAULT_BITS, old_hash);
 	if (!hash)
 		goto out_unlock;
 
@@ -4181,20 +4133,18 @@ unregister_ftrace_function_probe_func(char *glob, struct ftrace_probe_ops *ops)
 	}
 
 	mutex_lock(&ftrace_lock);
-	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);
+
+	if (ftrace_hash_empty(hash))
+		ftrace_shutdown(&ops->ops, 0);
+
+	ret = ftrace_hash_move_and_update_ops(&ops->ops, orig_hash,
+					      hash, 1);
 
 	/* still need to update the function call sites */
-	if (ftrace_enabled && !disabled)
-		ftrace_run_modify_code(&trace_probe_ops, FTRACE_UPDATE_CALLS,
+	if (ftrace_enabled && !ftrace_hash_empty(hash))
+		ftrace_run_modify_code(&ops->ops, FTRACE_UPDATE_CALLS,
 				       &old_hash_ops);
 	synchronize_sched();
-	if (!ret)
-		free_ftrace_hash_rcu(old_hash);
 
 	list_for_each_entry_safe(entry, p, &free_list, free_list) {
 		list_del(&entry->free_list);
@@ -4203,7 +4153,7 @@ unregister_ftrace_function_probe_func(char *glob, struct ftrace_probe_ops *ops)
 	mutex_unlock(&ftrace_lock);
 
  out_unlock:
-	mutex_unlock(&trace_probe_ops.func_hash->regex_lock);
+	mutex_unlock(&ops->ops.func_hash->regex_lock);
 	free_ftrace_hash(hash);
 	return ret;
 }
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
index 31d80bff9ee6..e16c67c49de4 100644
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
@@ -932,6 +932,7 @@ 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;
 	void			(*func)(unsigned long ip,
 					unsigned long parent_ip,
 					struct ftrace_probe_ops *ops,
-- 
2.10.2

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [for-next][PATCH 24/33] ftrace: Have the function probes call their own function
  2017-04-21 21:30 [for-next][PATCH 00/33] tracing: More updates for 4.12 Steven Rostedt
                   ` (22 preceding siblings ...)
  2017-04-21 21:30 ` [for-next][PATCH 23/33] ftrace: Have each function probe use its own ftrace_ops Steven Rostedt
@ 2017-04-21 21:30 ` Steven Rostedt
  2017-04-21 21:30 ` [for-next][PATCH 25/33] ftrace: If the hash for a probe fails to update then free what was initialized Steven Rostedt
                   ` (8 subsequent siblings)
  32 siblings, 0 replies; 36+ messages in thread
From: Steven Rostedt @ 2017-04-21 21:30 UTC (permalink / raw)
  To: linux-kernel; +Cc: Ingo Molnar, Andrew Morton

[-- Attachment #1: 0024-ftrace-Have-the-function-probes-call-their-own-funct.patch --]
[-- Type: text/plain, Size: 14838 bytes --]

From: "Steven Rostedt (VMware)" <rostedt@goodmis.org>

Now that the function probes have their own ftrace_ops, there's no reason to
continue using the ftrace_func_hash to find which probe to call in the
function callback. The ops that is passed in to the function callback is
part of the probe_ops to call.

Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
---
 include/linux/ftrace.h |   4 +-
 kernel/trace/ftrace.c  | 225 +++++++++++++++++++++----------------------------
 kernel/trace/trace.h   |   1 +
 3 files changed, 101 insertions(+), 129 deletions(-)

diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
index 774e7a95c201..6d2a63e4ea52 100644
--- a/include/linux/ftrace.h
+++ b/include/linux/ftrace.h
@@ -443,8 +443,8 @@ enum {
 	FTRACE_ITER_FILTER	= (1 << 0),
 	FTRACE_ITER_NOTRACE	= (1 << 1),
 	FTRACE_ITER_PRINTALL	= (1 << 2),
-	FTRACE_ITER_DO_HASH	= (1 << 3),
-	FTRACE_ITER_HASH	= (1 << 4),
+	FTRACE_ITER_DO_PROBES	= (1 << 3),
+	FTRACE_ITER_PROBE	= (1 << 4),
 	FTRACE_ITER_ENABLED	= (1 << 5),
 };
 
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index cf6b7263199a..493c7ff7e860 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -1096,14 +1096,7 @@ static bool update_all_ops;
 # error Dynamic ftrace depends on MCOUNT_RECORD
 #endif
 
-static struct hlist_head ftrace_func_hash[FTRACE_FUNC_HASHSIZE] __read_mostly;
-
-struct ftrace_func_probe {
-	struct hlist_node	node;
-	struct ftrace_probe_ops	*ops;
-	unsigned long		ip;
-	struct list_head	free_list;
-};
+static LIST_HEAD(ftrace_func_probes);
 
 struct ftrace_func_entry {
 	struct hlist_node hlist;
@@ -1270,7 +1263,7 @@ static void
 remove_hash_entry(struct ftrace_hash *hash,
 		  struct ftrace_func_entry *entry)
 {
-	hlist_del(&entry->hlist);
+	hlist_del_rcu(&entry->hlist);
 	hash->count--;
 }
 
@@ -3063,35 +3056,58 @@ struct ftrace_iterator {
 	loff_t				func_pos;
 	struct ftrace_page		*pg;
 	struct dyn_ftrace		*func;
-	struct ftrace_func_probe	*probe;
+	struct ftrace_probe_ops		*probe;
+	struct ftrace_func_entry	*probe_entry;
 	struct trace_parser		parser;
 	struct ftrace_hash		*hash;
 	struct ftrace_ops		*ops;
-	int				hidx;
+	int				pidx;
 	int				idx;
 	unsigned			flags;
 };
 
 static void *
-t_hash_next(struct seq_file *m, loff_t *pos)
+t_probe_next(struct seq_file *m, loff_t *pos)
 {
 	struct ftrace_iterator *iter = m->private;
+	struct ftrace_hash *hash;
+	struct list_head *next;
 	struct hlist_node *hnd = NULL;
 	struct hlist_head *hhd;
+	int size;
 
 	(*pos)++;
 	iter->pos = *pos;
 
-	if (iter->probe)
-		hnd = &iter->probe->node;
- retry:
-	if (iter->hidx >= FTRACE_FUNC_HASHSIZE)
+	if (list_empty(&ftrace_func_probes))
 		return NULL;
 
-	hhd = &ftrace_func_hash[iter->hidx];
+	if (!iter->probe) {
+		next = ftrace_func_probes.next;
+		iter->probe = list_entry(next, struct ftrace_probe_ops, list);
+	}
+
+	if (iter->probe_entry)
+		hnd = &iter->probe_entry->hlist;
+
+	hash = iter->probe->ops.func_hash->filter_hash;
+	size = 1 << hash->size_bits;
+
+ retry:
+	if (iter->pidx >= size) {
+		if (iter->probe->list.next == &ftrace_func_probes)
+			return NULL;
+		next = iter->probe->list.next;
+		iter->probe = list_entry(next, struct ftrace_probe_ops, list);
+		hash = iter->probe->ops.func_hash->filter_hash;
+		size = 1 << hash->size_bits;
+		iter->pidx = 0;
+	}
+
+	hhd = &hash->buckets[iter->pidx];
 
 	if (hlist_empty(hhd)) {
-		iter->hidx++;
+		iter->pidx++;
 		hnd = NULL;
 		goto retry;
 	}
@@ -3101,7 +3117,7 @@ t_hash_next(struct seq_file *m, loff_t *pos)
 	else {
 		hnd = hnd->next;
 		if (!hnd) {
-			iter->hidx++;
+			iter->pidx++;
 			goto retry;
 		}
 	}
@@ -3109,26 +3125,28 @@ t_hash_next(struct seq_file *m, loff_t *pos)
 	if (WARN_ON_ONCE(!hnd))
 		return NULL;
 
-	iter->probe = hlist_entry(hnd, struct ftrace_func_probe, node);
+	iter->probe_entry = hlist_entry(hnd, struct ftrace_func_entry, hlist);
 
 	return iter;
 }
 
-static void *t_hash_start(struct seq_file *m, loff_t *pos)
+static void *t_probe_start(struct seq_file *m, loff_t *pos)
 {
 	struct ftrace_iterator *iter = m->private;
 	void *p = NULL;
 	loff_t l;
 
-	if (!(iter->flags & FTRACE_ITER_DO_HASH))
+	if (!(iter->flags & FTRACE_ITER_DO_PROBES))
 		return NULL;
 
 	if (iter->func_pos > *pos)
 		return NULL;
 
-	iter->hidx = 0;
+	iter->probe = NULL;
+	iter->probe_entry = NULL;
+	iter->pidx = 0;
 	for (l = 0; l <= (*pos - iter->func_pos); ) {
-		p = t_hash_next(m, &l);
+		p = t_probe_next(m, &l);
 		if (!p)
 			break;
 	}
@@ -3136,24 +3154,27 @@ static void *t_hash_start(struct seq_file *m, loff_t *pos)
 		return NULL;
 
 	/* Only set this if we have an item */
-	iter->flags |= FTRACE_ITER_HASH;
+	iter->flags |= FTRACE_ITER_PROBE;
 
 	return iter;
 }
 
 static int
-t_hash_show(struct seq_file *m, struct ftrace_iterator *iter)
+t_probe_show(struct seq_file *m, struct ftrace_iterator *iter)
 {
-	struct ftrace_func_probe *rec;
+	struct ftrace_probe_ops *probe;
+	struct ftrace_func_entry *probe_entry;
 
-	rec = iter->probe;
-	if (WARN_ON_ONCE(!rec))
+	probe = iter->probe;
+	probe_entry = iter->probe_entry;
+
+	if (WARN_ON_ONCE(!probe || !probe_entry))
 		return -EIO;
 
-	if (rec->ops->print)
-		return rec->ops->print(m, rec->ip, rec->ops, NULL);
+	if (probe->print)
+		return probe->print(m, probe_entry->ip, probe, NULL);
 
-	seq_printf(m, "%ps:%ps\n", (void *)rec->ip, (void *)rec->ops->func);
+	seq_printf(m, "%ps:%ps\n", (void *)probe_entry->ip, (void *)probe->func);
 
 	return 0;
 }
@@ -3205,19 +3226,19 @@ t_next(struct seq_file *m, void *v, loff_t *pos)
 	if (unlikely(ftrace_disabled))
 		return NULL;
 
-	if (iter->flags & FTRACE_ITER_HASH)
-		return t_hash_next(m, pos);
+	if (iter->flags & FTRACE_ITER_PROBE)
+		return t_probe_next(m, pos);
 
 	if (iter->flags & FTRACE_ITER_PRINTALL) {
-		/* next must increment pos, and t_hash_start does not */
+		/* next must increment pos, and t_probe_start does not */
 		(*pos)++;
-		return t_hash_start(m, &l);
+		return t_probe_start(m, &l);
 	}
 
 	ret = t_func_next(m, pos);
 
 	if (!ret)
-		return t_hash_start(m, &l);
+		return t_probe_start(m, &l);
 
 	return ret;
 }
@@ -3226,7 +3247,7 @@ static void reset_iter_read(struct ftrace_iterator *iter)
 {
 	iter->pos = 0;
 	iter->func_pos = 0;
-	iter->flags &= ~(FTRACE_ITER_PRINTALL | FTRACE_ITER_HASH);
+	iter->flags &= ~(FTRACE_ITER_PRINTALL | FTRACE_ITER_PROBE);
 }
 
 static void *t_start(struct seq_file *m, loff_t *pos)
@@ -3255,15 +3276,15 @@ static void *t_start(struct seq_file *m, loff_t *pos)
 	    ftrace_hash_empty(iter->hash)) {
 		iter->func_pos = 1; /* Account for the message */
 		if (*pos > 0)
-			return t_hash_start(m, pos);
+			return t_probe_start(m, pos);
 		iter->flags |= FTRACE_ITER_PRINTALL;
 		/* reset in case of seek/pread */
-		iter->flags &= ~FTRACE_ITER_HASH;
+		iter->flags &= ~FTRACE_ITER_PROBE;
 		return iter;
 	}
 
-	if (iter->flags & FTRACE_ITER_HASH)
-		return t_hash_start(m, pos);
+	if (iter->flags & FTRACE_ITER_PROBE)
+		return t_probe_start(m, pos);
 
 	/*
 	 * Unfortunately, we need to restart at ftrace_pages_start
@@ -3279,7 +3300,7 @@ static void *t_start(struct seq_file *m, loff_t *pos)
 	}
 
 	if (!p)
-		return t_hash_start(m, pos);
+		return t_probe_start(m, pos);
 
 	return iter;
 }
@@ -3310,8 +3331,8 @@ static int t_show(struct seq_file *m, void *v)
 	struct ftrace_iterator *iter = m->private;
 	struct dyn_ftrace *rec;
 
-	if (iter->flags & FTRACE_ITER_HASH)
-		return t_hash_show(m, iter);
+	if (iter->flags & FTRACE_ITER_PROBE)
+		return t_probe_show(m, iter);
 
 	if (iter->flags & FTRACE_ITER_PRINTALL) {
 		if (iter->flags & FTRACE_ITER_NOTRACE)
@@ -3490,7 +3511,7 @@ ftrace_filter_open(struct inode *inode, struct file *file)
 	struct ftrace_ops *ops = inode->i_private;
 
 	return ftrace_regex_open(ops,
-			FTRACE_ITER_FILTER | FTRACE_ITER_DO_HASH,
+			FTRACE_ITER_FILTER | FTRACE_ITER_DO_PROBES,
 			inode, file);
 }
 
@@ -3765,16 +3786,9 @@ core_initcall(ftrace_mod_cmd_init);
 static void function_trace_probe_call(unsigned long ip, unsigned long parent_ip,
 				      struct ftrace_ops *op, struct pt_regs *pt_regs)
 {
-	struct ftrace_func_probe *entry;
-	struct hlist_head *hhd;
-	unsigned long key;
-
-	key = hash_long(ip, FTRACE_HASH_BITS);
+	struct ftrace_probe_ops *probe_ops;
 
-	hhd = &ftrace_func_hash[key];
-
-	if (hlist_empty(hhd))
-		return;
+	probe_ops = container_of(op, struct ftrace_probe_ops, ops);
 
 	/*
 	 * Disable preemption for these calls to prevent a RCU grace
@@ -3782,20 +3796,10 @@ 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();
-	hlist_for_each_entry_rcu_notrace(entry, hhd, node) {
-		if (entry->ip == ip)
-			entry->ops->func(ip, parent_ip, entry->ops, NULL);
-	}
+	probe_ops->func(ip, parent_ip, probe_ops, NULL);
 	preempt_enable_notrace();
 }
 
-static void ftrace_free_entry(struct ftrace_func_probe *entry)
-{
-	if (entry->ops->free)
-		entry->ops->free(entry->ops, entry->ip, NULL);
-	kfree(entry);
-}
-
 struct ftrace_func_map {
 	struct ftrace_func_entry	entry;
 	void				*data;
@@ -3942,13 +3946,9 @@ register_ftrace_function_probe(char *glob, struct ftrace_probe_ops *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;
-	struct hlist_head hl;
-	struct hlist_node *n;
-	unsigned long key;
 	int count = 0;
 	int size;
 	int ret;
@@ -3961,6 +3961,7 @@ register_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
 	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);
 	}
 
 	mutex_lock(&ops->ops.func_hash->regex_lock);
@@ -3978,31 +3979,21 @@ register_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
 	if (ret < 0)
 		goto out;
 
-	INIT_HLIST_HEAD(&hl);
-
 	size = 1 << hash->size_bits;
 	for (i = 0; i < size; i++) {
 		hlist_for_each_entry(entry, &hash->buckets[i], hlist) {
 			if (ftrace_lookup_ip(old_hash, entry->ip))
 				continue;
-			probe = kmalloc(sizeof(*probe), GFP_KERNEL);
-			if (!probe) {
-				count = -ENOMEM;
-				goto err_free;
-			}
-			probe->ops = ops;
-			probe->ip = entry->ip;
 			/*
 			 * 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 && ops->init(ops, entry->ip, data) < 0) {
-				kfree(probe);
-				goto err_free;
+			if (ops->init) {
+				ret = ops->init(ops, entry->ip, data);
+				if (ret < 0)
+					goto out;
 			}
-			hlist_add_head(&probe->node, &hl);
-
 			count++;
 		}
 	}
@@ -4012,17 +4003,15 @@ 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 err_free_unlock;
+		goto out_unlock;
 
-	hlist_for_each_entry_safe(probe, n, &hl, node) {
-		hlist_del(&probe->node);
-		key = hash_long(probe->ip, FTRACE_HASH_BITS);
-		hlist_add_head_rcu(&probe->node, &ftrace_func_hash[key]);
-	}
+	if (list_empty(&ops->list))
+		list_add(&ops->list, &ftrace_func_probes);
 
 	if (!(ops->ops.flags & FTRACE_OPS_FL_ENABLED))
 		ret = ftrace_startup(&ops->ops, 0);
 
+ out_unlock:
 	mutex_unlock(&ftrace_lock);
 
 	if (!ret)
@@ -4032,34 +4021,22 @@ register_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
 	free_ftrace_hash(hash);
 
 	return ret;
-
- err_free_unlock:
-	mutex_unlock(&ftrace_lock);
- err_free:
-	hlist_for_each_entry_safe(probe, n, &hl, node) {
-		hlist_del(&probe->node);
-		if (ops->free)
-			ops->free(ops, probe->ip, NULL);
-		kfree(probe);
-	}
-	goto out;
 }
 
 int
 unregister_ftrace_function_probe_func(char *glob, struct ftrace_probe_ops *ops)
 {
 	struct ftrace_ops_hash old_hash_ops;
-	struct ftrace_func_entry *rec_entry;
-	struct ftrace_func_probe *entry;
-	struct ftrace_func_probe *p;
+	struct ftrace_func_entry *entry;
 	struct ftrace_glob func_g;
 	struct ftrace_hash **orig_hash;
 	struct ftrace_hash *old_hash;
-	struct list_head free_list;
 	struct ftrace_hash *hash = NULL;
 	struct hlist_node *tmp;
+	struct hlist_head hhd;
 	char str[KSYM_SYMBOL_LEN];
 	int i, ret;
+	int size;
 
 	if (!(ops->ops.flags & FTRACE_OPS_FL_INITIALIZED))
 		return -EINVAL;
@@ -4097,18 +4074,12 @@ unregister_ftrace_function_probe_func(char *glob, struct ftrace_probe_ops *ops)
 	if (!hash)
 		goto out_unlock;
 
-	INIT_LIST_HEAD(&free_list);
-
-	for (i = 0; i < FTRACE_FUNC_HASHSIZE; i++) {
-		struct hlist_head *hhd = &ftrace_func_hash[i];
+	INIT_HLIST_HEAD(&hhd);
 
-		hlist_for_each_entry_safe(entry, tmp, hhd, node) {
-
-			/* break up if statements for readability */
-			if (entry->ops != ops)
-				continue;
+	size = 1 << hash->size_bits;
+	for (i = 0; i < size; i++) {
+		hlist_for_each_entry_safe(entry, tmp, &hash->buckets[i], hlist) {
 
-			/* do this last, since it is the most expensive */
 			if (func_g.search) {
 				kallsyms_lookup(entry->ip, NULL, NULL,
 						NULL, str);
@@ -4116,26 +4087,24 @@ unregister_ftrace_function_probe_func(char *glob, struct ftrace_probe_ops *ops)
 					continue;
 			}
 
-			rec_entry = ftrace_lookup_ip(hash, entry->ip);
-			/* It is possible more than one entry had this ip */
-			if (rec_entry)
-				free_hash_entry(hash, rec_entry);
-
-			hlist_del_rcu(&entry->node);
-			list_add(&entry->free_list, &free_list);
+			remove_hash_entry(hash, entry);
+			hlist_add_head(&entry->hlist, &hhd);
 		}
 	}
 
 	/* Nothing found? */
-	if (list_empty(&free_list)) {
+	if (hlist_empty(&hhd)) {
 		ret = -EINVAL;
 		goto out_unlock;
 	}
 
 	mutex_lock(&ftrace_lock);
 
-	if (ftrace_hash_empty(hash))
+	if (ftrace_hash_empty(hash)) {
 		ftrace_shutdown(&ops->ops, 0);
+		list_del_init(&ops->list);
+	}
+
 
 	ret = ftrace_hash_move_and_update_ops(&ops->ops, orig_hash,
 					      hash, 1);
@@ -4146,9 +4115,11 @@ unregister_ftrace_function_probe_func(char *glob, struct ftrace_probe_ops *ops)
 				       &old_hash_ops);
 	synchronize_sched();
 
-	list_for_each_entry_safe(entry, p, &free_list, free_list) {
-		list_del(&entry->free_list);
-		ftrace_free_entry(entry);
+	hlist_for_each_entry_safe(entry, tmp, &hhd, hlist) {
+		hlist_del(&entry->hlist);
+		if (ops->free)
+			ops->free(ops, entry->ip, NULL);
+		kfree(entry);
 	}
 	mutex_unlock(&ftrace_lock);
 
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
index e16c67c49de4..d457addcc224 100644
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
@@ -933,6 +933,7 @@ static inline void ftrace_pid_follow_fork(struct trace_array *tr, bool enable) {
 
 struct ftrace_probe_ops {
 	struct ftrace_ops	ops;
+	struct list_head	list;
 	void			(*func)(unsigned long ip,
 					unsigned long parent_ip,
 					struct ftrace_probe_ops *ops,
-- 
2.10.2

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [for-next][PATCH 25/33] ftrace: If the hash for a probe fails to update then free what was initialized
  2017-04-21 21:30 [for-next][PATCH 00/33] tracing: More updates for 4.12 Steven Rostedt
                   ` (23 preceding siblings ...)
  2017-04-21 21:30 ` [for-next][PATCH 24/33] ftrace: Have the function probes call their own function Steven Rostedt
@ 2017-04-21 21:30 ` Steven Rostedt
  2017-04-21 21:30 ` [for-next][PATCH 26/33] tracing: Have the trace_array hold the list of registered func probes Steven Rostedt
                   ` (7 subsequent siblings)
  32 siblings, 0 replies; 36+ messages in thread
From: Steven Rostedt @ 2017-04-21 21:30 UTC (permalink / raw)
  To: linux-kernel; +Cc: Ingo Molnar, Andrew Morton

[-- Attachment #1: 0025-ftrace-If-the-hash-for-a-probe-fails-to-update-then-.patch --]
[-- Type: text/plain, Size: 1343 bytes --]

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

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [for-next][PATCH 26/33] tracing: Have the trace_array hold the list of registered func probes
  2017-04-21 21:30 [for-next][PATCH 00/33] tracing: More updates for 4.12 Steven Rostedt
                   ` (24 preceding siblings ...)
  2017-04-21 21:30 ` [for-next][PATCH 25/33] ftrace: If the hash for a probe fails to update then free what was initialized Steven Rostedt
@ 2017-04-21 21:30 ` Steven Rostedt
  2017-04-21 21:30 ` [for-next][PATCH 27/33] tracing: Pass the trace_array into ftrace_probe_ops functions Steven Rostedt
                   ` (6 subsequent siblings)
  32 siblings, 0 replies; 36+ messages in thread
From: Steven Rostedt @ 2017-04-21 21:30 UTC (permalink / raw)
  To: linux-kernel; +Cc: Ingo Molnar, Andrew Morton

[-- Attachment #1: 0026-tracing-Have-the-trace_array-hold-the-list-of-regist.patch --]
[-- Type: text/plain, Size: 11652 bytes --]

From: "Steven Rostedt (VMware)" <rostedt@goodmis.org>

Add a link list to the trace_array to hold func probes that are registered.
Currently, all function probes are the same for all instances as it was
before, that is, only the top level trace_array holds the function probes.
But this lays the ground work to have function probes be attached to
individual instances, and having the event trigger only affect events in the
given instance. But that work is still to be done.

Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
---
 kernel/trace/ftrace.c          | 41 +++++++++++++++++++++++++++++------------
 kernel/trace/trace.c           |  6 ++++--
 kernel/trace/trace.h           | 13 ++++++++++---
 kernel/trace/trace_events.c    |  5 ++---
 kernel/trace/trace_functions.c | 21 +++++++++++----------
 5 files changed, 56 insertions(+), 30 deletions(-)

diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index 8394055e6793..ea208e93f000 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -1096,8 +1096,6 @@ static bool update_all_ops;
 # error Dynamic ftrace depends on MCOUNT_RECORD
 #endif
 
-static LIST_HEAD(ftrace_func_probes);
-
 struct ftrace_func_entry {
 	struct hlist_node hlist;
 	unsigned long ip;
@@ -3070,6 +3068,8 @@ static void *
 t_probe_next(struct seq_file *m, loff_t *pos)
 {
 	struct ftrace_iterator *iter = m->private;
+	struct trace_array *tr = global_ops.private;
+	struct list_head *func_probes;
 	struct ftrace_hash *hash;
 	struct list_head *next;
 	struct hlist_node *hnd = NULL;
@@ -3079,11 +3079,15 @@ t_probe_next(struct seq_file *m, loff_t *pos)
 	(*pos)++;
 	iter->pos = *pos;
 
-	if (list_empty(&ftrace_func_probes))
+	if (!tr)
+		return NULL;
+
+	func_probes = &tr->func_probes;
+	if (list_empty(func_probes))
 		return NULL;
 
 	if (!iter->probe) {
-		next = ftrace_func_probes.next;
+		next = func_probes->next;
 		iter->probe = list_entry(next, struct ftrace_probe_ops, list);
 	}
 
@@ -3095,7 +3099,7 @@ t_probe_next(struct seq_file *m, loff_t *pos)
 
  retry:
 	if (iter->pidx >= size) {
-		if (iter->probe->list.next == &ftrace_func_probes)
+		if (iter->probe->list.next == func_probes)
 			return NULL;
 		next = iter->probe->list.next;
 		iter->probe = list_entry(next, struct ftrace_probe_ops, list);
@@ -3752,7 +3756,7 @@ static int ftrace_hash_move_and_update_ops(struct ftrace_ops *ops,
  */
 
 static int
-ftrace_mod_callback(struct ftrace_hash *hash,
+ftrace_mod_callback(struct trace_array *tr, struct ftrace_hash *hash,
 		    char *func, char *cmd, char *module, int enable)
 {
 	int ret;
@@ -3942,8 +3946,8 @@ void free_ftrace_func_mapper(struct ftrace_func_mapper *mapper,
 }
 
 int
-register_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
-			       void *data)
+register_ftrace_function_probe(char *glob, struct trace_array *tr,
+			       struct ftrace_probe_ops *ops, void *data)
 {
 	struct ftrace_func_entry *entry;
 	struct ftrace_hash **orig_hash;
@@ -3954,6 +3958,9 @@ register_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
 	int ret;
 	int i;
 
+	if (WARN_ON(!tr))
+		return -EINVAL;
+
 	/* We do not support '!' for function probes */
 	if (WARN_ON(glob[0] == '!'))
 		return -EINVAL;
@@ -4006,7 +4013,7 @@ register_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
 		goto err_unlock;
 
 	if (list_empty(&ops->list))
-		list_add(&ops->list, &ftrace_func_probes);
+		list_add(&ops->list, &tr->func_probes);
 
 	if (!(ops->ops.flags & FTRACE_OPS_FL_ENABLED))
 		ret = ftrace_startup(&ops->ops, 0);
@@ -4192,9 +4199,11 @@ __init int unregister_ftrace_command(struct ftrace_func_command *cmd)
 	return ret;
 }
 
-static int ftrace_process_regex(struct ftrace_hash *hash,
+static int ftrace_process_regex(struct ftrace_iterator *iter,
 				char *buff, int len, int enable)
 {
+	struct ftrace_hash *hash = iter->hash;
+	struct trace_array *tr = global_ops.private;
 	char *func, *command, *next = buff;
 	struct ftrace_func_command *p;
 	int ret = -EINVAL;
@@ -4214,10 +4223,13 @@ static int ftrace_process_regex(struct ftrace_hash *hash,
 
 	command = strsep(&next, ":");
 
+	if (WARN_ON_ONCE(!tr))
+		return -EINVAL;
+
 	mutex_lock(&ftrace_cmd_mutex);
 	list_for_each_entry(p, &ftrace_commands, list) {
 		if (strcmp(p->name, command) == 0) {
-			ret = p->func(hash, func, command, next, enable);
+			ret = p->func(tr, hash, func, command, next, enable);
 			goto out_unlock;
 		}
 	}
@@ -4254,7 +4266,7 @@ ftrace_regex_write(struct file *file, const char __user *ubuf,
 
 	if (read >= 0 && trace_parser_loaded(parser) &&
 	    !trace_parser_cont(parser)) {
-		ret = ftrace_process_regex(iter->hash, parser->buffer,
+		ret = ftrace_process_regex(iter, parser->buffer,
 					   parser->idx, enable);
 		trace_parser_clear(parser);
 		if (ret < 0)
@@ -5441,6 +5453,10 @@ static void ftrace_update_trampoline(struct ftrace_ops *ops)
 	arch_ftrace_update_trampoline(ops);
 }
 
+void ftrace_init_trace_array(struct trace_array *tr)
+{
+	INIT_LIST_HEAD(&tr->func_probes);
+}
 #else
 
 static struct ftrace_ops global_ops = {
@@ -5495,6 +5511,7 @@ __init void ftrace_init_global_array_ops(struct trace_array *tr)
 {
 	tr->ops = &global_ops;
 	tr->ops->private = tr;
+	ftrace_init_trace_array(tr);
 }
 
 void ftrace_init_array_ops(struct trace_array *tr, ftrace_func_t func)
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 64a4418a5106..86598293787a 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -6815,7 +6815,7 @@ static struct ftrace_probe_ops snapshot_count_probe_ops = {
 };
 
 static int
-ftrace_trace_snapshot_callback(struct ftrace_hash *hash,
+ftrace_trace_snapshot_callback(struct trace_array *tr, struct ftrace_hash *hash,
 			       char *glob, char *cmd, char *param, int enable)
 {
 	struct ftrace_probe_ops *ops;
@@ -6855,7 +6855,7 @@ ftrace_trace_snapshot_callback(struct ftrace_hash *hash,
 		return ret;
 
  out_reg:
-	ret = register_ftrace_function_probe(glob, ops, count);
+	ret = register_ftrace_function_probe(glob, tr, ops, count);
 
 	if (ret >= 0)
 		alloc_snapshot(&global_trace);
@@ -7468,6 +7468,8 @@ static int instance_mkdir(const char *name)
 		goto out_free_tr;
 	}
 
+	ftrace_init_trace_array(tr);
+
 	init_tracer_tracefs(tr, tr->dir);
 	init_trace_flags_index(tr);
 	__update_tracer_options(tr);
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
index d457addcc224..68ff25e4cb19 100644
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
@@ -262,6 +262,9 @@ struct trace_array {
 #ifdef CONFIG_FUNCTION_TRACER
 	struct ftrace_ops	*ops;
 	struct trace_pid_list	__rcu *function_pids;
+#ifdef CONFIG_DYNAMIC_FTRACE
+	struct list_head	func_probes;
+#endif
 	/* function tracing enabled */
 	int			function_enabled;
 #endif
@@ -696,6 +699,9 @@ extern void trace_event_follow_fork(struct trace_array *tr, bool enable);
 
 #ifdef CONFIG_DYNAMIC_FTRACE
 extern unsigned long ftrace_update_tot_cnt;
+void ftrace_init_trace_array(struct trace_array *tr);
+#else
+static inline void ftrace_init_trace_array(struct trace_array *tr) { }
 #endif
 #define DYN_FTRACE_TEST_NAME trace_selftest_dynamic_test_func
 extern int DYN_FTRACE_TEST_NAME(void);
@@ -883,7 +889,8 @@ extern struct list_head ftrace_pids;
 struct ftrace_func_command {
 	struct list_head	list;
 	char			*name;
-	int			(*func)(struct ftrace_hash *hash,
+	int			(*func)(struct trace_array *tr,
+					struct ftrace_hash *hash,
 					char *func, char *cmd,
 					char *params, int enable);
 };
@@ -963,8 +970,8 @@ 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);
+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);
 
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c
index 9e07a5b3869b..f0d6e5aef53e 100644
--- a/kernel/trace/trace_events.c
+++ b/kernel/trace/trace_events.c
@@ -2611,10 +2611,9 @@ static struct ftrace_probe_ops event_disable_count_probe_ops = {
 };
 
 static int
-event_enable_func(struct ftrace_hash *hash,
+event_enable_func(struct trace_array *tr, struct ftrace_hash *hash,
 		  char *glob, char *cmd, char *param, int enabled)
 {
-	struct trace_array *tr = top_trace_array();
 	struct trace_event_file *file;
 	struct ftrace_probe_ops *ops;
 	struct event_probe_data *data;
@@ -2701,7 +2700,7 @@ event_enable_func(struct ftrace_hash *hash,
 	if (ret < 0)
 		goto out_put;
 
-	ret = register_ftrace_function_probe(glob, ops, data);
+	ret = register_ftrace_function_probe(glob, tr, ops, data);
 	/*
 	 * The above returns on success the # of functions enabled,
 	 * but if it didn't find any functions it returns zero.
diff --git a/kernel/trace/trace_functions.c b/kernel/trace/trace_functions.c
index dcb4d37ed4bd..2c8961b35401 100644
--- a/kernel/trace/trace_functions.c
+++ b/kernel/trace/trace_functions.c
@@ -574,7 +574,8 @@ static struct ftrace_probe_ops stacktrace_probe_ops = {
 };
 
 static int
-ftrace_trace_probe_callback(struct ftrace_probe_ops *ops,
+ftrace_trace_probe_callback(struct trace_array *tr,
+			    struct ftrace_probe_ops *ops,
 			    struct ftrace_hash *hash, char *glob,
 			    char *cmd, char *param, int enable)
 {
@@ -612,13 +613,13 @@ ftrace_trace_probe_callback(struct ftrace_probe_ops *ops,
 		return ret;
 
  out_reg:
-	ret = register_ftrace_function_probe(glob, ops, count);
+	ret = register_ftrace_function_probe(glob, tr, ops, count);
 
 	return ret < 0 ? ret : 0;
 }
 
 static int
-ftrace_trace_onoff_callback(struct ftrace_hash *hash,
+ftrace_trace_onoff_callback(struct trace_array *tr, struct ftrace_hash *hash,
 			    char *glob, char *cmd, char *param, int enable)
 {
 	struct ftrace_probe_ops *ops;
@@ -629,24 +630,24 @@ ftrace_trace_onoff_callback(struct ftrace_hash *hash,
 	else
 		ops = param ? &traceoff_count_probe_ops : &traceoff_probe_ops;
 
-	return ftrace_trace_probe_callback(ops, hash, glob, cmd,
+	return ftrace_trace_probe_callback(tr, ops, hash, glob, cmd,
 					   param, enable);
 }
 
 static int
-ftrace_stacktrace_callback(struct ftrace_hash *hash,
+ftrace_stacktrace_callback(struct trace_array *tr, struct ftrace_hash *hash,
 			   char *glob, char *cmd, char *param, int enable)
 {
 	struct ftrace_probe_ops *ops;
 
 	ops = param ? &stacktrace_count_probe_ops : &stacktrace_probe_ops;
 
-	return ftrace_trace_probe_callback(ops, hash, glob, cmd,
+	return ftrace_trace_probe_callback(tr, ops, hash, glob, cmd,
 					   param, enable);
 }
 
 static int
-ftrace_dump_callback(struct ftrace_hash *hash,
+ftrace_dump_callback(struct trace_array *tr, struct ftrace_hash *hash,
 			   char *glob, char *cmd, char *param, int enable)
 {
 	struct ftrace_probe_ops *ops;
@@ -654,12 +655,12 @@ ftrace_dump_callback(struct ftrace_hash *hash,
 	ops = &dump_probe_ops;
 
 	/* Only dump once. */
-	return ftrace_trace_probe_callback(ops, hash, glob, cmd,
+	return ftrace_trace_probe_callback(tr, ops, hash, glob, cmd,
 					   "1", enable);
 }
 
 static int
-ftrace_cpudump_callback(struct ftrace_hash *hash,
+ftrace_cpudump_callback(struct trace_array *tr, struct ftrace_hash *hash,
 			   char *glob, char *cmd, char *param, int enable)
 {
 	struct ftrace_probe_ops *ops;
@@ -667,7 +668,7 @@ ftrace_cpudump_callback(struct ftrace_hash *hash,
 	ops = &cpudump_probe_ops;
 
 	/* Only dump once. */
-	return ftrace_trace_probe_callback(ops, hash, glob, cmd,
+	return ftrace_trace_probe_callback(tr, ops, hash, glob, cmd,
 					   "1", enable);
 }
 
-- 
2.10.2

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [for-next][PATCH 27/33] tracing: Pass the trace_array into ftrace_probe_ops functions
  2017-04-21 21:30 [for-next][PATCH 00/33] tracing: More updates for 4.12 Steven Rostedt
                   ` (25 preceding siblings ...)
  2017-04-21 21:30 ` [for-next][PATCH 26/33] tracing: Have the trace_array hold the list of registered func probes Steven Rostedt
@ 2017-04-21 21:30 ` Steven Rostedt
  2017-04-21 21:30 ` [for-next][PATCH 28/33] ftrace: Dynamically create the probe ftrace_ops for the trace_array Steven Rostedt
                   ` (5 subsequent siblings)
  32 siblings, 0 replies; 36+ messages in thread
From: Steven Rostedt @ 2017-04-21 21:30 UTC (permalink / raw)
  To: linux-kernel; +Cc: Ingo Molnar, Andrew Morton

[-- Attachment #1: 0027-tracing-Pass-the-trace_array-into-ftrace_probe_ops-f.patch --]
[-- Type: text/plain, Size: 11385 bytes --]

From: "Steven Rostedt (VMware)" <rostedt@goodmis.org>

Pass the trace_array associated to a ftrace_probe_ops into the probe_ops
func(), init() and free() functions. The trace_array is the descriptor that
describes a tracing instance. This will help create the infrastructure that
will allow having function probes unique to tracing instances.

Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
---
 kernel/trace/ftrace.c          | 13 +++++++++----
 kernel/trace/trace.c           | 14 ++++++++------
 kernel/trace/trace.h           |  3 +++
 kernel/trace/trace_events.c    | 16 +++++++++-------
 kernel/trace/trace_functions.c | 35 ++++++++++++++++++++++-------------
 5 files changed, 51 insertions(+), 30 deletions(-)

diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index ea208e93f000..e51cd6b51253 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -3791,6 +3791,7 @@ 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;
 
 	probe_ops = container_of(op, struct ftrace_probe_ops, ops);
 
@@ -3800,7 +3801,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_ops, NULL);
+	probe_ops->func(ip, parent_ip, tr, probe_ops, NULL);
 	preempt_enable_notrace();
 }
 
@@ -3969,6 +3970,7 @@ register_ftrace_function_probe(char *glob, struct trace_array *tr,
 		ops->ops.func = function_trace_probe_call;
 		ftrace_ops_init(&ops->ops);
 		INIT_LIST_HEAD(&ops->list);
+		ops->ops.private = tr;
 	}
 
 	mutex_lock(&ops->ops.func_hash->regex_lock);
@@ -3997,7 +3999,7 @@ register_ftrace_function_probe(char *glob, struct trace_array *tr,
 			 * to give the caller an opportunity to do so.
 			 */
 			if (ops->init) {
-				ret = ops->init(ops, entry->ip, data);
+				ret = ops->init(ops, tr, entry->ip, data);
 				if (ret < 0)
 					goto out;
 			}
@@ -4038,7 +4040,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;
-			ops->free(ops, entry->ip, NULL);
+			ops->free(ops, tr, entry->ip, NULL);
 		}
 	}
 	goto out_unlock;
@@ -4055,6 +4057,7 @@ unregister_ftrace_function_probe_func(char *glob, struct ftrace_probe_ops *ops)
 	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 size;
@@ -4062,6 +4065,8 @@ unregister_ftrace_function_probe_func(char *glob, struct ftrace_probe_ops *ops)
 	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) {
@@ -4139,7 +4144,7 @@ unregister_ftrace_function_probe_func(char *glob, struct ftrace_probe_ops *ops)
 	hlist_for_each_entry_safe(entry, tmp, &hhd, hlist) {
 		hlist_del(&entry->hlist);
 		if (ops->free)
-			ops->free(ops, entry->ip, NULL);
+			ops->free(ops, tr, entry->ip, NULL);
 		kfree(entry);
 	}
 	mutex_unlock(&ftrace_lock);
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 86598293787a..368310e78d45 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -6736,14 +6736,16 @@ 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,
-		struct ftrace_probe_ops *ops, void **data)
+		struct trace_array *tr, struct ftrace_probe_ops *ops,
+		void **data)
 {
 	tracing_snapshot();
 }
 
 static void
 ftrace_count_snapshot(unsigned long ip, unsigned long parent_ip,
-		      struct ftrace_probe_ops *ops, void **data)
+		      struct trace_array *tr, struct ftrace_probe_ops *ops,
+		      void **data)
 {
 	struct ftrace_func_mapper *mapper = ops->private_data;
 	long *count = NULL;
@@ -6785,8 +6787,8 @@ 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)
+ftrace_snapshot_init(struct ftrace_probe_ops *ops, struct trace_array *tr,
+		     unsigned long ip, void *data)
 {
 	struct ftrace_func_mapper *mapper = ops->private_data;
 
@@ -6794,8 +6796,8 @@ ftrace_snapshot_init(struct ftrace_probe_ops *ops, unsigned long ip,
 }
 
 static void
-ftrace_snapshot_free(struct ftrace_probe_ops *ops, unsigned long ip,
-		     void **_data)
+ftrace_snapshot_free(struct ftrace_probe_ops *ops, struct trace_array *tr,
+		     unsigned long ip, void **data)
 {
 	struct ftrace_func_mapper *mapper = ops->private_data;
 
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
index 68ff25e4cb19..390761804886 100644
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
@@ -943,11 +943,14 @@ struct ftrace_probe_ops {
 	struct list_head	list;
 	void			(*func)(unsigned long ip,
 					unsigned long parent_ip,
+					struct trace_array *tr,
 					struct ftrace_probe_ops *ops,
 					void **data);
 	int			(*init)(struct ftrace_probe_ops *ops,
+					struct trace_array *tr,
 					unsigned long ip, void *data);
 	void			(*free)(struct ftrace_probe_ops *ops,
+					struct trace_array *tr,
 					unsigned long ip, void **data);
 	int			(*print)(struct seq_file *m,
 					 unsigned long ip,
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c
index f0d6e5aef53e..713bec614312 100644
--- a/kernel/trace/trace_events.c
+++ b/kernel/trace/trace_events.c
@@ -2470,7 +2470,8 @@ static void update_event_probe(struct event_probe_data *data)
 
 static void
 event_enable_probe(unsigned long ip, unsigned long parent_ip,
-		   struct ftrace_probe_ops *ops, void **_data)
+		   struct trace_array *tr, struct ftrace_probe_ops *ops,
+		   void **_data)
 {
 	struct ftrace_func_mapper *mapper = ops->private_data;
 	struct event_probe_data *data;
@@ -2486,7 +2487,8 @@ event_enable_probe(unsigned long ip, unsigned long parent_ip,
 
 static void
 event_enable_count_probe(unsigned long ip, unsigned long parent_ip,
-			 struct ftrace_probe_ops *ops, void **_data)
+			 struct trace_array *tr, struct ftrace_probe_ops *ops,
+			 void **_data)
 {
 	struct ftrace_func_mapper *mapper = ops->private_data;
 	struct event_probe_data *data;
@@ -2513,7 +2515,7 @@ event_enable_count_probe(unsigned long ip, unsigned long parent_ip,
 
 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;
@@ -2542,8 +2544,8 @@ 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)
+event_enable_init(struct ftrace_probe_ops *ops, struct trace_array *tr,
+		  unsigned long ip, void *_data)
 {
 	struct ftrace_func_mapper *mapper = ops->private_data;
 	struct event_probe_data *data = _data;
@@ -2559,8 +2561,8 @@ event_enable_init(struct ftrace_probe_ops *ops, unsigned long ip,
 }
 
 static void
-event_enable_free(struct ftrace_probe_ops *ops, unsigned long ip,
-		  void **_data)
+event_enable_free(struct ftrace_probe_ops *ops, struct trace_array *tr,
+		  unsigned long ip, void **_data)
 {
 	struct ftrace_func_mapper *mapper = ops->private_data;
 	struct event_probe_data *data;
diff --git a/kernel/trace/trace_functions.c b/kernel/trace/trace_functions.c
index 2c8961b35401..797f087183c5 100644
--- a/kernel/trace/trace_functions.c
+++ b/kernel/trace/trace_functions.c
@@ -328,21 +328,24 @@ static void update_traceon_count(struct ftrace_probe_ops *ops,
 
 static void
 ftrace_traceon_count(unsigned long ip, unsigned long parent_ip,
-		     struct ftrace_probe_ops *ops, void **data)
+		     struct trace_array *tr, struct ftrace_probe_ops *ops,
+		     void **data)
 {
 	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)
+		      struct trace_array *tr, struct ftrace_probe_ops *ops,
+		      void **data)
 {
 	update_traceon_count(ops, ip, 0);
 }
 
 static void
 ftrace_traceon(unsigned long ip, unsigned long parent_ip,
-	       struct ftrace_probe_ops *ops, void **data)
+	       struct trace_array *tr, struct ftrace_probe_ops *ops,
+	       void **data)
 {
 	if (tracing_is_on())
 		return;
@@ -352,7 +355,8 @@ ftrace_traceon(unsigned long ip, unsigned long parent_ip,
 
 static void
 ftrace_traceoff(unsigned long ip, unsigned long parent_ip,
-		struct ftrace_probe_ops *ops, void **data)
+		struct trace_array *tr, struct ftrace_probe_ops *ops,
+		void **data)
 {
 	if (!tracing_is_on())
 		return;
@@ -371,14 +375,16 @@ ftrace_traceoff(unsigned long ip, unsigned long parent_ip,
 
 static void
 ftrace_stacktrace(unsigned long ip, unsigned long parent_ip,
-		  struct ftrace_probe_ops *ops, void **data)
+		  struct trace_array *tr, struct ftrace_probe_ops *ops,
+		  void **data)
 {
 	trace_dump_stack(STACK_SKIP);
 }
 
 static void
 ftrace_stacktrace_count(unsigned long ip, unsigned long parent_ip,
-			struct ftrace_probe_ops *ops, void **data)
+			struct trace_array *tr, struct ftrace_probe_ops *ops,
+			void **data)
 {
 	struct ftrace_func_mapper *mapper = ops->private_data;
 	long *count;
@@ -436,7 +442,8 @@ 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 ftrace_probe_ops *ops, void **data)
+		  struct trace_array *tr, struct ftrace_probe_ops *ops,
+		  void **data)
 {
 	if (update_count(ops, ip))
 		ftrace_dump(DUMP_ALL);
@@ -445,7 +452,8 @@ ftrace_dump_probe(unsigned long ip, unsigned long parent_ip,
 /* Only dump the current CPU buffer. */
 static void
 ftrace_cpudump_probe(unsigned long ip, unsigned long parent_ip,
-	struct ftrace_probe_ops *ops, void **data)
+		     struct trace_array *tr, struct ftrace_probe_ops *ops,
+		     void **data)
 {
 	if (update_count(ops, ip))
 		ftrace_dump(DUMP_ORIG);
@@ -473,7 +481,8 @@ ftrace_probe_print(const char *name, struct seq_file *m,
 
 static int
 ftrace_traceon_print(struct seq_file *m, unsigned long ip,
-			 struct ftrace_probe_ops *ops, void *data)
+		     struct ftrace_probe_ops *ops,
+		     void *data)
 {
 	return ftrace_probe_print("traceon", m, ip, ops);
 }
@@ -508,8 +517,8 @@ 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)
+ftrace_count_init(struct ftrace_probe_ops *ops, struct trace_array *tr,
+		  unsigned long ip, void *data)
 {
 	struct ftrace_func_mapper *mapper = ops->private_data;
 
@@ -517,8 +526,8 @@ ftrace_count_init(struct ftrace_probe_ops *ops, unsigned long ip,
 }
 
 static void
-ftrace_count_free(struct ftrace_probe_ops *ops, unsigned long ip,
-		  void **_data)
+ftrace_count_free(struct ftrace_probe_ops *ops, struct trace_array *tr,
+		  unsigned long ip, void **_data)
 {
 	struct ftrace_func_mapper *mapper = ops->private_data;
 
-- 
2.10.2

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [for-next][PATCH 28/33] ftrace: Dynamically create the probe ftrace_ops for the trace_array
  2017-04-21 21:30 [for-next][PATCH 00/33] tracing: More updates for 4.12 Steven Rostedt
                   ` (26 preceding siblings ...)
  2017-04-21 21:30 ` [for-next][PATCH 27/33] tracing: Pass the trace_array into ftrace_probe_ops functions Steven Rostedt
@ 2017-04-21 21:30 ` Steven Rostedt
  2017-04-21 21:30 ` [for-next][PATCH 29/33] tracing/ftrace: Add a better way to pass data via the probe functions Steven Rostedt
                   ` (4 subsequent siblings)
  32 siblings, 0 replies; 36+ messages in thread
From: Steven Rostedt @ 2017-04-21 21:30 UTC (permalink / raw)
  To: linux-kernel; +Cc: Ingo Molnar, Andrew Morton

[-- Attachment #1: 0028-ftrace-Dynamically-create-the-probe-ftrace_ops-for-t.patch --]
[-- Type: text/plain, Size: 14226 bytes --]

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

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [for-next][PATCH 29/33] tracing/ftrace: Add a better way to pass data via the probe functions
  2017-04-21 21:30 [for-next][PATCH 00/33] tracing: More updates for 4.12 Steven Rostedt
                   ` (27 preceding siblings ...)
  2017-04-21 21:30 ` [for-next][PATCH 28/33] ftrace: Dynamically create the probe ftrace_ops for the trace_array Steven Rostedt
@ 2017-04-21 21:30 ` Steven Rostedt
  2017-04-21 21:30 ` [for-next][PATCH 30/33] tracing/ftrace: Allow instances to have their own function probes Steven Rostedt
                   ` (3 subsequent siblings)
  32 siblings, 0 replies; 36+ messages in thread
From: Steven Rostedt @ 2017-04-21 21:30 UTC (permalink / raw)
  To: linux-kernel; +Cc: Ingo Molnar, Andrew Morton

[-- Attachment #1: 0029-tracing-ftrace-Add-a-better-way-to-pass-data-via-the.patch --]
[-- Type: text/plain, Size: 19791 bytes --]

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

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [for-next][PATCH 30/33] tracing/ftrace: Allow instances to have their own function probes
  2017-04-21 21:30 [for-next][PATCH 00/33] tracing: More updates for 4.12 Steven Rostedt
                   ` (28 preceding siblings ...)
  2017-04-21 21:30 ` [for-next][PATCH 29/33] tracing/ftrace: Add a better way to pass data via the probe functions Steven Rostedt
@ 2017-04-21 21:30 ` Steven Rostedt
  2017-04-21 21:30 ` [for-next][PATCH 31/33] tracing/ftrace: Enable snapshot function trigger to work with instances Steven Rostedt
                   ` (2 subsequent siblings)
  32 siblings, 0 replies; 36+ messages in thread
From: Steven Rostedt @ 2017-04-21 21:30 UTC (permalink / raw)
  To: linux-kernel; +Cc: Ingo Molnar, Andrew Morton

[-- Attachment #1: 0030-tracing-ftrace-Allow-instances-to-have-their-own-fun.patch --]
[-- Type: text/plain, Size: 1316 bytes --]

From: "Steven Rostedt (VMware)" <rostedt@goodmis.org>

Pass around the local trace_array that is the descriptor for tracing
instances, when enabling and disabling probes. This by default sets the
enable/disable of event probe triggers to work with instances.

The other probes will need some more work to get them working with
instances.

Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
---
 kernel/trace/ftrace.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index 774e9108e5dc..6615197e6597 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -3077,7 +3077,7 @@ static void *
 t_probe_next(struct seq_file *m, loff_t *pos)
 {
 	struct ftrace_iterator *iter = m->private;
-	struct trace_array *tr = global_ops.private;
+	struct trace_array *tr = iter->ops->private;
 	struct list_head *func_probes;
 	struct ftrace_hash *hash;
 	struct list_head *next;
@@ -4311,7 +4311,7 @@ static int ftrace_process_regex(struct ftrace_iterator *iter,
 				char *buff, int len, int enable)
 {
 	struct ftrace_hash *hash = iter->hash;
-	struct trace_array *tr = global_ops.private;
+	struct trace_array *tr = iter->ops->private;
 	char *func, *command, *next = buff;
 	struct ftrace_func_command *p;
 	int ret = -EINVAL;
-- 
2.10.2

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [for-next][PATCH 31/33] tracing/ftrace: Enable snapshot function trigger to work with instances
  2017-04-21 21:30 [for-next][PATCH 00/33] tracing: More updates for 4.12 Steven Rostedt
                   ` (29 preceding siblings ...)
  2017-04-21 21:30 ` [for-next][PATCH 30/33] tracing/ftrace: Allow instances to have their own function probes Steven Rostedt
@ 2017-04-21 21:30 ` Steven Rostedt
  2017-04-21 21:30 ` [for-next][PATCH 32/33] tracing/ftrace: Allow for the traceonoff probe be unique to instances Steven Rostedt
  2017-04-21 21:30 ` [for-next][PATCH 33/33] tracing/ftrace: Allow for instances to trigger their own stacktrace probes Steven Rostedt
  32 siblings, 0 replies; 36+ messages in thread
From: Steven Rostedt @ 2017-04-21 21:30 UTC (permalink / raw)
  To: linux-kernel; +Cc: Ingo Molnar, Andrew Morton

[-- Attachment #1: 0031-tracing-ftrace-Enable-snapshot-function-trigger-to-w.patch --]
[-- Type: text/plain, Size: 3103 bytes --]

From: "Steven Rostedt (VMware)" <rostedt@goodmis.org>

Modify the snapshot probe trigger to work with instances. This way the
snapshot function trigger will only affect the instance that it is added to
in the set_ftrace_filter file.

Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
---
 kernel/trace/trace.c | 44 +++++++++++++++++++++++++-------------------
 1 file changed, 25 insertions(+), 19 deletions(-)

diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 18256cd7ad2c..57e9c546bebb 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -894,23 +894,8 @@ int __trace_bputs(unsigned long ip, const char *str)
 EXPORT_SYMBOL_GPL(__trace_bputs);
 
 #ifdef CONFIG_TRACER_SNAPSHOT
-/**
- * trace_snapshot - take a snapshot of the current buffer.
- *
- * This causes a swap between the snapshot buffer and the current live
- * tracing buffer. You can use this to take snapshots of the live
- * trace when some condition is triggered, but continue to trace.
- *
- * Note, make sure to allocate the snapshot with either
- * a tracing_snapshot_alloc(), or by doing it manually
- * with: echo 1 > /sys/kernel/debug/tracing/snapshot
- *
- * If the snapshot buffer is not allocated, it will stop tracing.
- * Basically making a permanent snapshot.
- */
-void tracing_snapshot(void)
+static void tracing_snapshot_instance(struct trace_array *tr)
 {
-	struct trace_array *tr = &global_trace;
 	struct tracer *tracer = tr->current_trace;
 	unsigned long flags;
 
@@ -938,6 +923,27 @@ void tracing_snapshot(void)
 	update_max_tr(tr, current, smp_processor_id());
 	local_irq_restore(flags);
 }
+
+/**
+ * trace_snapshot - take a snapshot of the current buffer.
+ *
+ * This causes a swap between the snapshot buffer and the current live
+ * tracing buffer. You can use this to take snapshots of the live
+ * trace when some condition is triggered, but continue to trace.
+ *
+ * Note, make sure to allocate the snapshot with either
+ * a tracing_snapshot_alloc(), or by doing it manually
+ * with: echo 1 > /sys/kernel/debug/tracing/snapshot
+ *
+ * If the snapshot buffer is not allocated, it will stop tracing.
+ * Basically making a permanent snapshot.
+ */
+void tracing_snapshot(void)
+{
+	struct trace_array *tr = &global_trace;
+
+	tracing_snapshot_instance(tr);
+}
 EXPORT_SYMBOL_GPL(tracing_snapshot);
 
 static int resize_buffer_duplicate_size(struct trace_buffer *trace_buf,
@@ -6739,7 +6745,7 @@ ftrace_snapshot(unsigned long ip, unsigned long parent_ip,
 		struct trace_array *tr, struct ftrace_probe_ops *ops,
 		void *data)
 {
-	tracing_snapshot();
+	tracing_snapshot_instance(tr);
 }
 
 static void
@@ -6761,7 +6767,7 @@ ftrace_count_snapshot(unsigned long ip, unsigned long parent_ip,
 		(*count)--;
 	}
 
-	tracing_snapshot();
+	tracing_snapshot_instance(tr);
 }
 
 static int
@@ -6868,7 +6874,7 @@ ftrace_trace_snapshot_callback(struct trace_array *tr, struct ftrace_hash *hash,
 	ret = register_ftrace_function_probe(glob, tr, ops, count);
 
 	if (ret >= 0)
-		alloc_snapshot(&global_trace);
+		alloc_snapshot(tr);
 
 	return ret < 0 ? ret : 0;
 }
-- 
2.10.2

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [for-next][PATCH 32/33] tracing/ftrace: Allow for the traceonoff probe be unique to instances
  2017-04-21 21:30 [for-next][PATCH 00/33] tracing: More updates for 4.12 Steven Rostedt
                   ` (30 preceding siblings ...)
  2017-04-21 21:30 ` [for-next][PATCH 31/33] tracing/ftrace: Enable snapshot function trigger to work with instances Steven Rostedt
@ 2017-04-21 21:30 ` Steven Rostedt
  2017-04-21 21:30 ` [for-next][PATCH 33/33] tracing/ftrace: Allow for instances to trigger their own stacktrace probes Steven Rostedt
  32 siblings, 0 replies; 36+ messages in thread
From: Steven Rostedt @ 2017-04-21 21:30 UTC (permalink / raw)
  To: linux-kernel; +Cc: Ingo Molnar, Andrew Morton

[-- Attachment #1: 0032-tracing-ftrace-Allow-for-the-traceonoff-probe-be-uni.patch --]
[-- Type: text/plain, Size: 3909 bytes --]

From: "Steven Rostedt (VMware)" <rostedt@goodmis.org>

Have the traceon/off function probe triggers affect only the instance they
are set in. This required making the trace_on/off accessible for other files
in the tracing directory.

Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
---
 kernel/trace/trace.c           |  4 ++--
 kernel/trace/trace.h           |  2 ++
 kernel/trace/trace_functions.c | 21 +++++++++++----------
 3 files changed, 15 insertions(+), 12 deletions(-)

diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 57e9c546bebb..60c904fa5480 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -757,7 +757,7 @@ __trace_buffer_lock_reserve(struct ring_buffer *buffer,
 	return event;
 }
 
-static void tracer_tracing_on(struct trace_array *tr)
+void tracer_tracing_on(struct trace_array *tr)
 {
 	if (tr->trace_buffer.buffer)
 		ring_buffer_record_on(tr->trace_buffer.buffer);
@@ -1045,7 +1045,7 @@ void tracing_snapshot_alloc(void)
 EXPORT_SYMBOL_GPL(tracing_snapshot_alloc);
 #endif /* CONFIG_TRACER_SNAPSHOT */
 
-static void tracer_tracing_off(struct trace_array *tr)
+void tracer_tracing_off(struct trace_array *tr)
 {
 	if (tr->trace_buffer.buffer)
 		ring_buffer_record_off(tr->trace_buffer.buffer);
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
index 8f6754fba778..bc011c1f3d71 100644
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
@@ -582,6 +582,8 @@ void tracing_reset_all_online_cpus(void);
 int tracing_open_generic(struct inode *inode, struct file *filp);
 bool tracing_is_disabled(void);
 int tracer_tracing_is_on(struct trace_array *tr);
+void tracer_tracing_on(struct trace_array *tr);
+void tracer_tracing_off(struct trace_array *tr);
 struct dentry *trace_create_file(const char *name,
 				 umode_t mode,
 				 struct dentry *parent,
diff --git a/kernel/trace/trace_functions.c b/kernel/trace/trace_functions.c
index 7775e1ca5bad..8c30ca733a5c 100644
--- a/kernel/trace/trace_functions.c
+++ b/kernel/trace/trace_functions.c
@@ -268,7 +268,8 @@ 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,
+				 struct trace_array *tr, bool on,
 				 void *data)
 {
 	struct ftrace_func_mapper *mapper = data;
@@ -313,13 +314,13 @@ static void update_traceon_count(struct ftrace_probe_ops *ops,
 	/* Make sure we see count before checking tracing state */
 	smp_rmb();
 
-	if (on == !!tracing_is_on())
+	if (on == !!tracer_tracing_is_on(tr))
 		return;
 
 	if (on)
-		tracing_on();
+		tracer_tracing_on(tr);
 	else
-		tracing_off();
+		tracer_tracing_off(tr);
 
 	/* Make sure tracing state is visible before updating count */
 	smp_wmb();
@@ -332,7 +333,7 @@ ftrace_traceon_count(unsigned long ip, unsigned long parent_ip,
 		     struct trace_array *tr, struct ftrace_probe_ops *ops,
 		     void *data)
 {
-	update_traceon_count(ops, ip, 1, data);
+	update_traceon_count(ops, ip, tr, 1, data);
 }
 
 static void
@@ -340,7 +341,7 @@ ftrace_traceoff_count(unsigned long ip, unsigned long parent_ip,
 		      struct trace_array *tr, struct ftrace_probe_ops *ops,
 		      void *data)
 {
-	update_traceon_count(ops, ip, 0, data);
+	update_traceon_count(ops, ip, tr, 0, data);
 }
 
 static void
@@ -348,10 +349,10 @@ ftrace_traceon(unsigned long ip, unsigned long parent_ip,
 	       struct trace_array *tr, struct ftrace_probe_ops *ops,
 	       void *data)
 {
-	if (tracing_is_on())
+	if (tracer_tracing_is_on(tr))
 		return;
 
-	tracing_on();
+	tracer_tracing_on(tr);
 }
 
 static void
@@ -359,10 +360,10 @@ ftrace_traceoff(unsigned long ip, unsigned long parent_ip,
 		struct trace_array *tr, struct ftrace_probe_ops *ops,
 		void *data)
 {
-	if (!tracing_is_on())
+	if (!tracer_tracing_is_on(tr))
 		return;
 
-	tracing_off();
+	tracer_tracing_off(tr);
 }
 
 /*
-- 
2.10.2

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [for-next][PATCH 33/33] tracing/ftrace: Allow for instances to trigger their own stacktrace probes
  2017-04-21 21:30 [for-next][PATCH 00/33] tracing: More updates for 4.12 Steven Rostedt
                   ` (31 preceding siblings ...)
  2017-04-21 21:30 ` [for-next][PATCH 32/33] tracing/ftrace: Allow for the traceonoff probe be unique to instances Steven Rostedt
@ 2017-04-21 21:30 ` Steven Rostedt
  32 siblings, 0 replies; 36+ messages in thread
From: Steven Rostedt @ 2017-04-21 21:30 UTC (permalink / raw)
  To: linux-kernel; +Cc: Ingo Molnar, Andrew Morton

[-- Attachment #1: 0033-tracing-ftrace-Allow-for-instances-to-trigger-their-.patch --]
[-- Type: text/plain, Size: 2364 bytes --]

From: "Steven Rostedt (VMware)" <rostedt@goodmis.org>

Have the stacktrace function trigger probe trigger stack traces within the
instance that they were added to in the set_ftrace_filter.

 ># cd /sys/kernel/debug/tracing
 ># mkdir instances/foo
 ># cd instances/foo
 ># echo schedule:stacktrace:1 > set_ftrace_filter
 ># cat trace
 # tracer: nop
 #
 # entries-in-buffer/entries-written: 1/1   #P:4
 #
 #                              _-----=> irqs-off
 #                             / _----=> need-resched
 #                            | / _---=> hardirq/softirq
 #                            || / _--=> preempt-depth
 #                            ||| /     delay
 #           TASK-PID   CPU#  ||||    TIMESTAMP  FUNCTION
 #              | |       |   ||||       |         |
           <idle>-0     [001] .N.2   202.585010: <stack trace>
  =>
  => schedule
  => schedule_preempt_disabled
  => do_idle
  => cpu_startup_entry
  => start_secondary
  => verify_cpu

Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
---
 kernel/trace/trace_functions.c | 17 ++++++++++++++---
 1 file changed, 14 insertions(+), 3 deletions(-)

diff --git a/kernel/trace/trace_functions.c b/kernel/trace/trace_functions.c
index 8c30ca733a5c..a3bddbfd0874 100644
--- a/kernel/trace/trace_functions.c
+++ b/kernel/trace/trace_functions.c
@@ -375,12 +375,23 @@ ftrace_traceoff(unsigned long ip, unsigned long parent_ip,
  */
 #define STACK_SKIP 4
 
+static __always_inline void trace_stack(struct trace_array *tr)
+{
+	unsigned long flags;
+	int pc;
+
+	local_save_flags(flags);
+	pc = preempt_count();
+
+	__trace_stack(tr, flags, STACK_SKIP, pc);
+}
+
 static void
 ftrace_stacktrace(unsigned long ip, unsigned long parent_ip,
 		  struct trace_array *tr, struct ftrace_probe_ops *ops,
 		  void *data)
 {
-	trace_dump_stack(STACK_SKIP);
+	trace_stack(tr);
 }
 
 static void
@@ -398,7 +409,7 @@ ftrace_stacktrace_count(unsigned long ip, unsigned long parent_ip,
 
 	/* unlimited? */
 	if (!mapper) {
-		trace_dump_stack(STACK_SKIP);
+		trace_stack(tr);
 		return;
 	}
 
@@ -417,7 +428,7 @@ ftrace_stacktrace_count(unsigned long ip, unsigned long parent_ip,
 		new_count = old_count - 1;
 		new_count = cmpxchg(count, old_count, new_count);
 		if (new_count == old_count)
-			trace_dump_stack(STACK_SKIP);
+			trace_stack(tr);
 
 		if (!tracing_is_on())
 			return;
-- 
2.10.2

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* Re: [for-next][PATCH 09/33] selftests: ftrace: Add test to test reading of set_ftrace_file
  2017-04-21 21:30 ` [for-next][PATCH 09/33] selftests: ftrace: Add test to test reading of set_ftrace_file Steven Rostedt
@ 2017-05-22  3:23   ` Masami Hiramatsu
  2017-05-26 15:02     ` Steven Rostedt
  0 siblings, 1 reply; 36+ messages in thread
From: Masami Hiramatsu @ 2017-05-22  3:23 UTC (permalink / raw)
  To: Steven Rostedt; +Cc: linux-kernel, Ingo Molnar, Andrew Morton

Hi Steve,

On Fri, 21 Apr 2017 17:30:29 -0400
Steven Rostedt <rostedt@goodmis.org> wrote:

> 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.

Would you know which commit fixed this dd/cat differences on
set_ftrace_filter? When I've run this test on 4.9-stable kernel,
it failed because the result of "dd -bs=1" and "cat" on
set_ftrace_filter were different.

Thank you,

> 
> 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
> 
> 


-- 
Masami Hiramatsu <mhiramat@kernel.org>

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [for-next][PATCH 09/33] selftests: ftrace: Add test to test reading of set_ftrace_file
  2017-05-22  3:23   ` Masami Hiramatsu
@ 2017-05-26 15:02     ` Steven Rostedt
  0 siblings, 0 replies; 36+ messages in thread
From: Steven Rostedt @ 2017-05-26 15:02 UTC (permalink / raw)
  To: Masami Hiramatsu; +Cc: linux-kernel, Ingo Molnar, Andrew Morton

On Mon, 22 May 2017 12:23:08 +0900
Masami Hiramatsu <mhiramat@kernel.org> wrote:

> Hi Steve,
> 
> On Fri, 21 Apr 2017 17:30:29 -0400
> Steven Rostedt <rostedt@goodmis.org> wrote:
> 
> > 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.  
> 
> Would you know which commit fixed this dd/cat differences on
> set_ftrace_filter? When I've run this test on 4.9-stable kernel,
> it failed because the result of "dd -bs=1" and "cat" on
> set_ftrace_filter were different.
>

Probably one of the patches in this series before this one.

-- Steve

^ permalink raw reply	[flat|nested] 36+ messages in thread

end of thread, other threads:[~2017-05-26 15:02 UTC | newest]

Thread overview: 36+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-04-21 21:30 [for-next][PATCH 00/33] tracing: More updates for 4.12 Steven Rostedt
2017-04-21 21:30 ` [for-next][PATCH 01/33] ftrace: Fix removing of second function probe Steven Rostedt
2017-04-21 21:30 ` [for-next][PATCH 02/33] ftrace: Fix indexing of t_hash_start() from t_next() Steven Rostedt
2017-04-21 21:30 ` [for-next][PATCH 03/33] tracing: Have the trace_event benchmark thread call cond_resched_rcu_qs() Steven Rostedt
2017-04-21 21:30 ` [for-next][PATCH 04/33] ftrace: Add function-fork trace option Steven Rostedt
2017-04-21 21:30 ` [for-next][PATCH 05/33] selftests: ftrace: Add -l/--logdir option Steven Rostedt
2017-04-21 21:30 ` [for-next][PATCH 06/33] selftests: ftrace: Add a way to reset triggers in the set_ftrace_filter file Steven Rostedt
2017-04-21 21:30 ` [for-next][PATCH 07/33] selftests: ftrace: Add a selftest to test event enable/disable func trigger Steven Rostedt
2017-04-21 21:30 ` [for-next][PATCH 08/33] selftests: ftrace: Add a test to test function triggers to start and stop tracing Steven Rostedt
2017-04-21 21:30 ` [for-next][PATCH 09/33] selftests: ftrace: Add test to test reading of set_ftrace_file Steven Rostedt
2017-05-22  3:23   ` Masami Hiramatsu
2017-05-26 15:02     ` Steven Rostedt
2017-04-21 21:30 ` [for-next][PATCH 10/33] ftrace: Move the probe function into the tracing directory Steven Rostedt
2017-04-21 21:30 ` [for-next][PATCH 11/33] ftrace: Move the function commands " Steven Rostedt
2017-04-21 21:30 ` [for-next][PATCH 12/33] ftrace: Remove unused "flags" field from struct ftrace_func_probe Steven Rostedt
2017-04-21 21:30 ` [for-next][PATCH 13/33] ftrace: Pass probe ops to probe function Steven Rostedt
2017-04-21 21:30 ` [for-next][PATCH 14/33] ftrace: Added ftrace_func_mapper for function probe triggers Steven Rostedt
2017-04-21 21:30 ` [for-next][PATCH 15/33] tracing: Have the snapshot trigger use the mapping helper functions Steven Rostedt
2017-04-21 21:30 ` [for-next][PATCH 16/33] ftrace: Convert the rest of the function trigger over to the mapping functions Steven Rostedt
2017-04-21 21:30 ` [for-next][PATCH 17/33] ftrace: Remove unused unregister_ftrace_function_probe() function Steven Rostedt
2017-04-21 21:30 ` [for-next][PATCH 18/33] ftrace: Remove unused unregister_ftrace_function_probe_all() function Steven Rostedt
2017-04-21 21:30 ` [for-next][PATCH 19/33] ftrace: Remove printing of data in showing of a function probe Steven Rostedt
2017-04-21 21:30 ` [for-next][PATCH 20/33] ftrace: Remove data field from ftrace_func_probe structure Steven Rostedt
2017-04-21 21:30 ` [for-next][PATCH 21/33] ftrace: Add helper function ftrace_hash_move_and_update_ops() Steven Rostedt
2017-04-21 21:30 ` [for-next][PATCH 22/33] ftrace: Have unregister_ftrace_function_probe_func() return a value Steven Rostedt
2017-04-21 21:30 ` [for-next][PATCH 23/33] ftrace: Have each function probe use its own ftrace_ops Steven Rostedt
2017-04-21 21:30 ` [for-next][PATCH 24/33] ftrace: Have the function probes call their own function Steven Rostedt
2017-04-21 21:30 ` [for-next][PATCH 25/33] ftrace: If the hash for a probe fails to update then free what was initialized Steven Rostedt
2017-04-21 21:30 ` [for-next][PATCH 26/33] tracing: Have the trace_array hold the list of registered func probes Steven Rostedt
2017-04-21 21:30 ` [for-next][PATCH 27/33] tracing: Pass the trace_array into ftrace_probe_ops functions Steven Rostedt
2017-04-21 21:30 ` [for-next][PATCH 28/33] ftrace: Dynamically create the probe ftrace_ops for the trace_array Steven Rostedt
2017-04-21 21:30 ` [for-next][PATCH 29/33] tracing/ftrace: Add a better way to pass data via the probe functions Steven Rostedt
2017-04-21 21:30 ` [for-next][PATCH 30/33] tracing/ftrace: Allow instances to have their own function probes Steven Rostedt
2017-04-21 21:30 ` [for-next][PATCH 31/33] tracing/ftrace: Enable snapshot function trigger to work with instances Steven Rostedt
2017-04-21 21:30 ` [for-next][PATCH 32/33] tracing/ftrace: Allow for the traceonoff probe be unique to instances Steven Rostedt
2017-04-21 21:30 ` [for-next][PATCH 33/33] tracing/ftrace: Allow for instances to trigger their own stacktrace probes Steven Rostedt

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).