All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/21] tracing/probe: Add multi-probes per event support
@ 2019-05-31 15:16 Masami Hiramatsu
  2019-05-31 15:16 ` [PATCH 01/21] tracing/kprobe: Set print format right after parsed command Masami Hiramatsu
                   ` (20 more replies)
  0 siblings, 21 replies; 31+ messages in thread
From: Masami Hiramatsu @ 2019-05-31 15:16 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: Masami Hiramatsu, Ingo Molnar, linux-kernel, Tom Zanussi,
	Ravi Bangoria, Namhyung Kim, Arnaldo Carvalho de Melo

Hello,

This is a series to add multi-probes per event support to probe-event.

For trace-event, we can insert same trace-event on several places
on the code, and those can record similar information as a same event
with same format.

This series implements similar feature on probe-event. Since the probe
event is based on the compiled binary, sometimes we find that the target
source line is complied into several different addresses, e.g. inlined
function, unrolled loop, etc. In those cases, it is useful to put a
same probe-event on different addresses.

With this series, we can append multi probes on one event as below

  # echo p:testevent _do_fork r1=%ax r2=%dx > kprobe_events
  # echo p:testevent fork_idle r1=%ax r2=%cx >> kprobe_events
  # kprobe_events
  p:kprobes/testevent _do_fork r1=%ax r2=%dx
  p:kprobes/testevent fork_idle r1=%ax r2=%cx

This means testevent is hit on both of _do_fork and fork_idle.
As you can see, the appended event must have same number of arguments
and those must have same 'type' and 'name' as original one. This is like
a function signature, it checks whether the appending event has the same
type and name of event arguments and same probe type, but doesn't care
about the assignment.

So, below appending commands will be rejected.

  # echo p:testevent _do_fork r1=%ax r2=%dx > kprobe_events
  # echo p:testevent fork_idle r1=%ax >> kprobe_events
  (No 2nd argument)
  # echo p:testevent fork_idle r1=%ax r2=%ax:x8 >> kprobe_events
  (The type of 2nd argument is different)

If one inlined code has an argument on a register, but another
inlined code has fixed value (as a result of optimization),
you can also specify the fixed immediate value, e.g.

  # echo p:testevent _do_fork r1=%ax r2=%dx > kprobe_events
  # echo p:testevent fork_idle r1=%ax r2=\1 >> kprobe_events

Of course, it is hard to find those assignment changes by manual.
I'm preparing another series of patches for perf-probe, which will
automatically find such "cloned" targets and fold those into one
event.
(Should I merge that series into this series?)

Thank you,

---

Masami Hiramatsu (21):
      tracing/kprobe: Set print format right after parsed command
      tracing/uprobe: Set print format when parsing command
      tracing/probe: Add trace_probe init and free functions
      tracing/probe: Add trace_event_call register API for trace_probe
      tracing/probe: Add trace_event_file access APIs for trace_probe
      tracing/probe: Add trace flag access APIs for trace_probe
      tracing/probe: Add probe event name and group name accesses APIs
      tracing/probe: Add trace_event_call accesses APIs
      tracing/kprobe: Check registered state using kprobe
      tracing/probe: Split trace_event related data from trace_probe
      tracing/dynevent: Delete all matched events
      tracing/dynevent: Pass extra arguments to match operation
      tracing/kprobe: Add multi-probe per event support
      tracing/uprobe: Add multi-probe per uprobe event support
      tracing/kprobe: Add per-probe delete from event
      tracing/uprobe: Add per-probe delete from event
      tracing/probe: Add immediate parameter support
      tracing/probe: Add immediate string parameter support
      selftests/ftrace: Add a testcase for kprobe multiprobe event
      selftests/ftrace: Add syntax error test for immediates
      selftests/ftrace: Add syntax error test for multiprobe


 Documentation/trace/kprobetrace.rst                |    1 
 Documentation/trace/uprobetracer.rst               |    1 
 kernel/trace/trace.c                               |    8 
 kernel/trace/trace_dynevent.c                      |   10 
 kernel/trace/trace_dynevent.h                      |    7 
 kernel/trace/trace_events_hist.c                   |    4 
 kernel/trace/trace_kprobe.c                        |  408 +++++++++++---------
 kernel/trace/trace_probe.c                         |  247 ++++++++++++
 kernel/trace/trace_probe.h                         |  121 +++++-
 kernel/trace/trace_uprobe.c                        |  358 ++++++++++--------
 tools/testing/selftests/ftrace/test.d/functions    |    2 
 .../ftrace/test.d/kprobe/kprobe_multiprobe.tc      |   35 ++
 .../ftrace/test.d/kprobe/kprobe_syntax_errors.tc   |   15 +
 13 files changed, 830 insertions(+), 387 deletions(-)
 create mode 100644 tools/testing/selftests/ftrace/test.d/kprobe/kprobe_multiprobe.tc

--
Masami Hiramatsu (Linaro) <mhiramat@kernel.org>

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

* [PATCH 01/21] tracing/kprobe: Set print format right after parsed command
  2019-05-31 15:16 [PATCH 00/21] tracing/probe: Add multi-probes per event support Masami Hiramatsu
@ 2019-05-31 15:16 ` Masami Hiramatsu
  2019-05-31 15:16 ` [PATCH 02/21] tracing/uprobe: Set print format when parsing command Masami Hiramatsu
                   ` (19 subsequent siblings)
  20 siblings, 0 replies; 31+ messages in thread
From: Masami Hiramatsu @ 2019-05-31 15:16 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: Masami Hiramatsu, Ingo Molnar, linux-kernel, Tom Zanussi,
	Ravi Bangoria, Namhyung Kim, Arnaldo Carvalho de Melo

Set event call's print format right after parsed command for
simplifying (un)register_kprobe_event().

Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
---
 kernel/trace/trace_kprobe.c |   25 +++++++++----------------
 1 file changed, 9 insertions(+), 16 deletions(-)

diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c
index 7958da2fd922..01fc49f08b70 100644
--- a/kernel/trace/trace_kprobe.c
+++ b/kernel/trace/trace_kprobe.c
@@ -272,6 +272,7 @@ static void free_trace_kprobe(struct trace_kprobe *tk)
 
 	kfree(tk->tp.call.class->system);
 	kfree(tk->tp.call.name);
+	kfree(tk->tp.call.print_fmt);
 	kfree(tk->symbol);
 	free_percpu(tk->nhit);
 	kfree(tk);
@@ -730,6 +731,10 @@ static int trace_kprobe_create(int argc, const char *argv[])
 			goto error;	/* This can be -ENOMEM */
 	}
 
+	ret = traceprobe_set_print_fmt(&tk->tp, is_return);
+	if (ret < 0)
+		goto error;
+
 	ret = register_trace_kprobe(tk);
 	if (ret) {
 		trace_probe_log_set_index(1);
@@ -1416,18 +1421,14 @@ static int register_kprobe_event(struct trace_kprobe *tk)
 
 	init_trace_event_call(tk, call);
 
-	if (traceprobe_set_print_fmt(&tk->tp, trace_kprobe_is_return(tk)) < 0)
-		return -ENOMEM;
 	ret = register_trace_event(&call->event);
-	if (!ret) {
-		kfree(call->print_fmt);
+	if (!ret)
 		return -ENODEV;
-	}
+
 	ret = trace_add_event_call(call);
 	if (ret) {
 		pr_info("Failed to register kprobe event: %s\n",
 			trace_event_name(call));
-		kfree(call->print_fmt);
 		unregister_trace_event(&call->event);
 	}
 	return ret;
@@ -1435,13 +1436,8 @@ static int register_kprobe_event(struct trace_kprobe *tk)
 
 static int unregister_kprobe_event(struct trace_kprobe *tk)
 {
-	int ret;
-
 	/* tp->event is unregistered in trace_remove_event_call() */
-	ret = trace_remove_event_call(&tk->tp.call);
-	if (!ret)
-		kfree(tk->tp.call.print_fmt);
-	return ret;
+	return trace_remove_event_call(&tk->tp.call);
 }
 
 #ifdef CONFIG_PERF_EVENTS
@@ -1479,10 +1475,8 @@ create_local_trace_kprobe(char *func, void *addr, unsigned long offs,
 	}
 
 	ret = __register_trace_kprobe(tk);
-	if (ret < 0) {
-		kfree(tk->tp.call.print_fmt);
+	if (ret < 0)
 		goto error;
-	}
 
 	return &tk->tp.call;
 error:
@@ -1503,7 +1497,6 @@ void destroy_local_trace_kprobe(struct trace_event_call *event_call)
 
 	__unregister_trace_kprobe(tk);
 
-	kfree(tk->tp.call.print_fmt);
 	free_trace_kprobe(tk);
 }
 #endif /* CONFIG_PERF_EVENTS */


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

* [PATCH 02/21] tracing/uprobe: Set print format when parsing command
  2019-05-31 15:16 [PATCH 00/21] tracing/probe: Add multi-probes per event support Masami Hiramatsu
  2019-05-31 15:16 ` [PATCH 01/21] tracing/kprobe: Set print format right after parsed command Masami Hiramatsu
@ 2019-05-31 15:16 ` Masami Hiramatsu
  2019-05-31 15:17 ` [PATCH 03/21] tracing/probe: Add trace_probe init and free functions Masami Hiramatsu
                   ` (18 subsequent siblings)
  20 siblings, 0 replies; 31+ messages in thread
From: Masami Hiramatsu @ 2019-05-31 15:16 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: Masami Hiramatsu, Ingo Molnar, linux-kernel, Tom Zanussi,
	Ravi Bangoria, Namhyung Kim, Arnaldo Carvalho de Melo

Set event call's print format right after parsed command for
simplifying (un)register_uprobe_event().

Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
---
 kernel/trace/trace_uprobe.c |   25 +++++++------------------
 1 file changed, 7 insertions(+), 18 deletions(-)

diff --git a/kernel/trace/trace_uprobe.c b/kernel/trace/trace_uprobe.c
index 3d6b868830f3..34ce671b6080 100644
--- a/kernel/trace/trace_uprobe.c
+++ b/kernel/trace/trace_uprobe.c
@@ -345,6 +345,7 @@ static void free_trace_uprobe(struct trace_uprobe *tu)
 	path_put(&tu->path);
 	kfree(tu->tp.call.class->system);
 	kfree(tu->tp.call.name);
+	kfree(tu->tp.call.print_fmt);
 	kfree(tu->filename);
 	kfree(tu);
 }
@@ -592,6 +593,10 @@ static int trace_uprobe_create(int argc, const char **argv)
 			goto error;
 	}
 
+	ret = traceprobe_set_print_fmt(&tu->tp, is_ret_probe(tu));
+	if (ret < 0)
+		goto error;
+
 	ret = register_trace_uprobe(tu);
 	if (!ret)
 		goto out;
@@ -1362,21 +1367,15 @@ static int register_uprobe_event(struct trace_uprobe *tu)
 
 	init_trace_event_call(tu, call);
 
-	if (traceprobe_set_print_fmt(&tu->tp, is_ret_probe(tu)) < 0)
-		return -ENOMEM;
-
 	ret = register_trace_event(&call->event);
-	if (!ret) {
-		kfree(call->print_fmt);
+	if (!ret)
 		return -ENODEV;
-	}
 
 	ret = trace_add_event_call(call);
 
 	if (ret) {
 		pr_info("Failed to register uprobe event: %s\n",
 			trace_event_name(call));
-		kfree(call->print_fmt);
 		unregister_trace_event(&call->event);
 	}
 
@@ -1385,15 +1384,8 @@ static int register_uprobe_event(struct trace_uprobe *tu)
 
 static int unregister_uprobe_event(struct trace_uprobe *tu)
 {
-	int ret;
-
 	/* tu->event is unregistered in trace_remove_event_call() */
-	ret = trace_remove_event_call(&tu->tp.call);
-	if (ret)
-		return ret;
-	kfree(tu->tp.call.print_fmt);
-	tu->tp.call.print_fmt = NULL;
-	return 0;
+	return trace_remove_event_call(&tu->tp.call);
 }
 
 #ifdef CONFIG_PERF_EVENTS
@@ -1452,9 +1444,6 @@ void destroy_local_trace_uprobe(struct trace_event_call *event_call)
 
 	tu = container_of(event_call, struct trace_uprobe, tp.call);
 
-	kfree(tu->tp.call.print_fmt);
-	tu->tp.call.print_fmt = NULL;
-
 	free_trace_uprobe(tu);
 }
 #endif /* CONFIG_PERF_EVENTS */


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

* [PATCH 03/21] tracing/probe: Add trace_probe init and free functions
  2019-05-31 15:16 [PATCH 00/21] tracing/probe: Add multi-probes per event support Masami Hiramatsu
  2019-05-31 15:16 ` [PATCH 01/21] tracing/kprobe: Set print format right after parsed command Masami Hiramatsu
  2019-05-31 15:16 ` [PATCH 02/21] tracing/uprobe: Set print format when parsing command Masami Hiramatsu
@ 2019-05-31 15:17 ` Masami Hiramatsu
  2019-05-31 15:17 ` [PATCH 04/21] tracing/probe: Add trace_event_call register API for trace_probe Masami Hiramatsu
                   ` (17 subsequent siblings)
  20 siblings, 0 replies; 31+ messages in thread
From: Masami Hiramatsu @ 2019-05-31 15:17 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: Masami Hiramatsu, Ingo Molnar, linux-kernel, Tom Zanussi,
	Ravi Bangoria, Namhyung Kim, Arnaldo Carvalho de Melo

Add common trace_probe init and cleanup function in
trace_probe.c, and use it from trace_kprobe.c and trace_uprobe.c

Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
---
 kernel/trace/trace_kprobe.c |   49 +++++++++++--------------------------------
 kernel/trace/trace_probe.c  |   36 ++++++++++++++++++++++++++++++++
 kernel/trace/trace_probe.h  |    4 ++++
 kernel/trace/trace_uprobe.c |   27 ++++--------------------
 4 files changed, 58 insertions(+), 58 deletions(-)

diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c
index 01fc49f08b70..c43c2d419ded 100644
--- a/kernel/trace/trace_kprobe.c
+++ b/kernel/trace/trace_kprobe.c
@@ -197,6 +197,16 @@ static int kprobe_dispatcher(struct kprobe *kp, struct pt_regs *regs);
 static int kretprobe_dispatcher(struct kretprobe_instance *ri,
 				struct pt_regs *regs);
 
+static void free_trace_kprobe(struct trace_kprobe *tk)
+{
+	if (tk) {
+		trace_probe_cleanup(&tk->tp);
+		kfree(tk->symbol);
+		free_percpu(tk->nhit);
+		kfree(tk);
+	}
+}
+
 /*
  * Allocate new trace_probe and initialize it (including kprobes).
  */
@@ -235,49 +245,17 @@ static struct trace_kprobe *alloc_trace_kprobe(const char *group,
 
 	tk->rp.maxactive = maxactive;
 
-	if (!event || !group) {
-		ret = -EINVAL;
-		goto error;
-	}
-
-	tk->tp.call.class = &tk->tp.class;
-	tk->tp.call.name = kstrdup(event, GFP_KERNEL);
-	if (!tk->tp.call.name)
-		goto error;
-
-	tk->tp.class.system = kstrdup(group, GFP_KERNEL);
-	if (!tk->tp.class.system)
+	ret = trace_probe_init(&tk->tp, event, group);
+	if (ret < 0)
 		goto error;
 
 	dyn_event_init(&tk->devent, &trace_kprobe_ops);
-	INIT_LIST_HEAD(&tk->tp.files);
 	return tk;
 error:
-	kfree(tk->tp.call.name);
-	kfree(tk->symbol);
-	free_percpu(tk->nhit);
-	kfree(tk);
+	free_trace_kprobe(tk);
 	return ERR_PTR(ret);
 }
 
-static void free_trace_kprobe(struct trace_kprobe *tk)
-{
-	int i;
-
-	if (!tk)
-		return;
-
-	for (i = 0; i < tk->tp.nr_args; i++)
-		traceprobe_free_probe_arg(&tk->tp.args[i]);
-
-	kfree(tk->tp.call.class->system);
-	kfree(tk->tp.call.name);
-	kfree(tk->tp.call.print_fmt);
-	kfree(tk->symbol);
-	free_percpu(tk->nhit);
-	kfree(tk);
-}
-
 static struct trace_kprobe *find_trace_kprobe(const char *event,
 					      const char *group)
 {
@@ -1400,7 +1378,6 @@ static struct trace_event_functions kprobe_funcs = {
 static inline void init_trace_event_call(struct trace_kprobe *tk,
 					 struct trace_event_call *call)
 {
-	INIT_LIST_HEAD(&call->class->fields);
 	if (trace_kprobe_is_return(tk)) {
 		call->event.funcs = &kretprobe_funcs;
 		call->class->define_fields = kretprobe_event_define_fields;
diff --git a/kernel/trace/trace_probe.c b/kernel/trace/trace_probe.c
index b6b0593844cd..fe4ee2e73d92 100644
--- a/kernel/trace/trace_probe.c
+++ b/kernel/trace/trace_probe.c
@@ -884,3 +884,39 @@ int traceprobe_define_arg_fields(struct trace_event_call *event_call,
 	}
 	return 0;
 }
+
+
+void trace_probe_cleanup(struct trace_probe *tp)
+{
+	int i;
+
+	for (i = 0; i < tp->nr_args; i++)
+		traceprobe_free_probe_arg(&tp->args[i]);
+
+	kfree(tp->call.class->system);
+	kfree(tp->call.name);
+	kfree(tp->call.print_fmt);
+}
+
+int trace_probe_init(struct trace_probe *tp, const char *event,
+		     const char *group)
+{
+	if (!event || !group)
+		return -EINVAL;
+
+	tp->call.class = &tp->class;
+	tp->call.name = kstrdup(event, GFP_KERNEL);
+	if (!tp->call.name)
+		return -ENOMEM;
+
+	tp->class.system = kstrdup(group, GFP_KERNEL);
+	if (!tp->class.system) {
+		kfree(tp->call.name);
+		tp->call.name = NULL;
+		return -ENOMEM;
+	}
+	INIT_LIST_HEAD(&tp->files);
+	INIT_LIST_HEAD(&tp->class.fields);
+
+	return 0;
+}
diff --git a/kernel/trace/trace_probe.h b/kernel/trace/trace_probe.h
index 42816358dd48..818b1d7693ba 100644
--- a/kernel/trace/trace_probe.h
+++ b/kernel/trace/trace_probe.h
@@ -248,6 +248,10 @@ static inline bool trace_probe_is_registered(struct trace_probe *tp)
 	return !!(tp->flags & TP_FLAG_REGISTERED);
 }
 
+int trace_probe_init(struct trace_probe *tp, const char *event,
+		     const char *group);
+void trace_probe_cleanup(struct trace_probe *tp);
+
 /* Check the name is good for event/group/fields */
 static inline bool is_good_name(const char *name)
 {
diff --git a/kernel/trace/trace_uprobe.c b/kernel/trace/trace_uprobe.c
index 34ce671b6080..b18b7eb1a76f 100644
--- a/kernel/trace/trace_uprobe.c
+++ b/kernel/trace/trace_uprobe.c
@@ -300,25 +300,17 @@ static struct trace_uprobe *
 alloc_trace_uprobe(const char *group, const char *event, int nargs, bool is_ret)
 {
 	struct trace_uprobe *tu;
-
-	if (!event || !group)
-		return ERR_PTR(-EINVAL);
+	int ret;
 
 	tu = kzalloc(SIZEOF_TRACE_UPROBE(nargs), GFP_KERNEL);
 	if (!tu)
 		return ERR_PTR(-ENOMEM);
 
-	tu->tp.call.class = &tu->tp.class;
-	tu->tp.call.name = kstrdup(event, GFP_KERNEL);
-	if (!tu->tp.call.name)
-		goto error;
-
-	tu->tp.class.system = kstrdup(group, GFP_KERNEL);
-	if (!tu->tp.class.system)
+	ret = trace_probe_init(&tu->tp, event, group);
+	if (ret < 0)
 		goto error;
 
 	dyn_event_init(&tu->devent, &trace_uprobe_ops);
-	INIT_LIST_HEAD(&tu->tp.files);
 	tu->consumer.handler = uprobe_dispatcher;
 	if (is_ret)
 		tu->consumer.ret_handler = uretprobe_dispatcher;
@@ -326,26 +318,18 @@ alloc_trace_uprobe(const char *group, const char *event, int nargs, bool is_ret)
 	return tu;
 
 error:
-	kfree(tu->tp.call.name);
 	kfree(tu);
 
-	return ERR_PTR(-ENOMEM);
+	return ERR_PTR(ret);
 }
 
 static void free_trace_uprobe(struct trace_uprobe *tu)
 {
-	int i;
-
 	if (!tu)
 		return;
 
-	for (i = 0; i < tu->tp.nr_args; i++)
-		traceprobe_free_probe_arg(&tu->tp.args[i]);
-
 	path_put(&tu->path);
-	kfree(tu->tp.call.class->system);
-	kfree(tu->tp.call.name);
-	kfree(tu->tp.call.print_fmt);
+	trace_probe_cleanup(&tu->tp);
 	kfree(tu->filename);
 	kfree(tu);
 }
@@ -1351,7 +1335,6 @@ static struct trace_event_functions uprobe_funcs = {
 static inline void init_trace_event_call(struct trace_uprobe *tu,
 					 struct trace_event_call *call)
 {
-	INIT_LIST_HEAD(&call->class->fields);
 	call->event.funcs = &uprobe_funcs;
 	call->class->define_fields = uprobe_event_define_fields;
 


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

* [PATCH 04/21] tracing/probe: Add trace_event_call register API for trace_probe
  2019-05-31 15:16 [PATCH 00/21] tracing/probe: Add multi-probes per event support Masami Hiramatsu
                   ` (2 preceding siblings ...)
  2019-05-31 15:17 ` [PATCH 03/21] tracing/probe: Add trace_probe init and free functions Masami Hiramatsu
@ 2019-05-31 15:17 ` Masami Hiramatsu
  2019-05-31 15:17 ` [PATCH 05/21] tracing/probe: Add trace_event_file access APIs " Masami Hiramatsu
                   ` (16 subsequent siblings)
  20 siblings, 0 replies; 31+ messages in thread
From: Masami Hiramatsu @ 2019-05-31 15:17 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: Masami Hiramatsu, Ingo Molnar, linux-kernel, Tom Zanussi,
	Ravi Bangoria, Namhyung Kim, Arnaldo Carvalho de Melo

Since trace_event_call is a field of trace_probe, these
operations should be done in trace_probe.c. trace_kprobe
and trace_uprobe use new functions to register/unregister
trace_event_call.

Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
---
 kernel/trace/trace_kprobe.c |   20 +++-----------------
 kernel/trace/trace_probe.c  |   16 ++++++++++++++++
 kernel/trace/trace_probe.h  |    6 ++++++
 kernel/trace/trace_uprobe.c |   22 +++-------------------
 4 files changed, 28 insertions(+), 36 deletions(-)

diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c
index c43c2d419ded..7f802ee27266 100644
--- a/kernel/trace/trace_kprobe.c
+++ b/kernel/trace/trace_kprobe.c
@@ -1393,28 +1393,14 @@ static inline void init_trace_event_call(struct trace_kprobe *tk,
 
 static int register_kprobe_event(struct trace_kprobe *tk)
 {
-	struct trace_event_call *call = &tk->tp.call;
-	int ret = 0;
-
-	init_trace_event_call(tk, call);
-
-	ret = register_trace_event(&call->event);
-	if (!ret)
-		return -ENODEV;
+	init_trace_event_call(tk, &tk->tp.call);
 
-	ret = trace_add_event_call(call);
-	if (ret) {
-		pr_info("Failed to register kprobe event: %s\n",
-			trace_event_name(call));
-		unregister_trace_event(&call->event);
-	}
-	return ret;
+	return trace_probe_register_event_call(&tk->tp);
 }
 
 static int unregister_kprobe_event(struct trace_kprobe *tk)
 {
-	/* tp->event is unregistered in trace_remove_event_call() */
-	return trace_remove_event_call(&tk->tp.call);
+	return trace_probe_unregister_event_call(&tk->tp);
 }
 
 #ifdef CONFIG_PERF_EVENTS
diff --git a/kernel/trace/trace_probe.c b/kernel/trace/trace_probe.c
index fe4ee2e73d92..509a26024b4f 100644
--- a/kernel/trace/trace_probe.c
+++ b/kernel/trace/trace_probe.c
@@ -920,3 +920,19 @@ int trace_probe_init(struct trace_probe *tp, const char *event,
 
 	return 0;
 }
+
+int trace_probe_register_event_call(struct trace_probe *tp)
+{
+	struct trace_event_call *call = &tp->call;
+	int ret;
+
+	ret = register_trace_event(&call->event);
+	if (!ret)
+		return -ENODEV;
+
+	ret = trace_add_event_call(call);
+	if (ret)
+		unregister_trace_event(&call->event);
+
+	return ret;
+}
diff --git a/kernel/trace/trace_probe.h b/kernel/trace/trace_probe.h
index 818b1d7693ba..01d7b222e004 100644
--- a/kernel/trace/trace_probe.h
+++ b/kernel/trace/trace_probe.h
@@ -251,6 +251,12 @@ static inline bool trace_probe_is_registered(struct trace_probe *tp)
 int trace_probe_init(struct trace_probe *tp, const char *event,
 		     const char *group);
 void trace_probe_cleanup(struct trace_probe *tp);
+int trace_probe_register_event_call(struct trace_probe *tp);
+static inline int trace_probe_unregister_event_call(struct trace_probe *tp)
+{
+	/* tp->event is unregistered in trace_remove_event_call() */
+	return trace_remove_event_call(&tp->call);
+}
 
 /* Check the name is good for event/group/fields */
 static inline bool is_good_name(const char *name)
diff --git a/kernel/trace/trace_uprobe.c b/kernel/trace/trace_uprobe.c
index b18b7eb1a76f..c262494fa793 100644
--- a/kernel/trace/trace_uprobe.c
+++ b/kernel/trace/trace_uprobe.c
@@ -1345,30 +1345,14 @@ static inline void init_trace_event_call(struct trace_uprobe *tu,
 
 static int register_uprobe_event(struct trace_uprobe *tu)
 {
-	struct trace_event_call *call = &tu->tp.call;
-	int ret = 0;
-
-	init_trace_event_call(tu, call);
-
-	ret = register_trace_event(&call->event);
-	if (!ret)
-		return -ENODEV;
-
-	ret = trace_add_event_call(call);
-
-	if (ret) {
-		pr_info("Failed to register uprobe event: %s\n",
-			trace_event_name(call));
-		unregister_trace_event(&call->event);
-	}
+	init_trace_event_call(tu, &tu->tp.call);
 
-	return ret;
+	return trace_probe_register_event_call(&tu->tp);
 }
 
 static int unregister_uprobe_event(struct trace_uprobe *tu)
 {
-	/* tu->event is unregistered in trace_remove_event_call() */
-	return trace_remove_event_call(&tu->tp.call);
+	return trace_probe_unregister_event_call(&tu->tp);
 }
 
 #ifdef CONFIG_PERF_EVENTS


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

* [PATCH 05/21] tracing/probe: Add trace_event_file access APIs for trace_probe
  2019-05-31 15:16 [PATCH 00/21] tracing/probe: Add multi-probes per event support Masami Hiramatsu
                   ` (3 preceding siblings ...)
  2019-05-31 15:17 ` [PATCH 04/21] tracing/probe: Add trace_event_call register API for trace_probe Masami Hiramatsu
@ 2019-05-31 15:17 ` Masami Hiramatsu
  2019-05-31 15:17 ` [PATCH 06/21] tracing/probe: Add trace flag " Masami Hiramatsu
                   ` (15 subsequent siblings)
  20 siblings, 0 replies; 31+ messages in thread
From: Masami Hiramatsu @ 2019-05-31 15:17 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: Masami Hiramatsu, Ingo Molnar, linux-kernel, Tom Zanussi,
	Ravi Bangoria, Namhyung Kim, Arnaldo Carvalho de Melo

Add trace_event_file access APIs for trace_probe data structure.
This simplifies enabling/disabling operations in uprobe and kprobe
events so that those don't touch deep inside the trace_probe.

This also removing a redundant synchronization when the
kprobe event is used from perf, since the perf itself uses
tracepoint_synchronize_unregister() after disabling (ftrace-
defined) event, thus we don't have to synchronize in that
path. Also we don't need to identify local trace_kprobe too
anymore.

Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
---
 kernel/trace/trace_kprobe.c |   85 +++++++++++++++----------------------------
 kernel/trace/trace_probe.c  |   47 ++++++++++++++++++++++++
 kernel/trace/trace_probe.h  |   36 ++++++++++--------
 kernel/trace/trace_uprobe.c |   42 +++++++--------------
 4 files changed, 109 insertions(+), 101 deletions(-)

diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c
index 7f802ee27266..87a52094378c 100644
--- a/kernel/trace/trace_kprobe.c
+++ b/kernel/trace/trace_kprobe.c
@@ -290,34 +290,27 @@ static inline int __enable_trace_kprobe(struct trace_kprobe *tk)
 static int
 enable_trace_kprobe(struct trace_kprobe *tk, struct trace_event_file *file)
 {
-	struct event_file_link *link;
+	bool enabled = trace_probe_is_enabled(&tk->tp);
 	int ret = 0;
 
 	if (file) {
-		link = kmalloc(sizeof(*link), GFP_KERNEL);
-		if (!link) {
-			ret = -ENOMEM;
-			goto out;
-		}
-
-		link->file = file;
-		list_add_tail_rcu(&link->list, &tk->tp.files);
+		ret = trace_probe_add_file(&tk->tp, file);
+		if (ret)
+			return ret;
+	} else
+		tk->tp.flags |= TP_FLAG_PROFILE;
 
-		tk->tp.flags |= TP_FLAG_TRACE;
-		ret = __enable_trace_kprobe(tk);
-		if (ret) {
-			list_del_rcu(&link->list);
-			kfree(link);
-			tk->tp.flags &= ~TP_FLAG_TRACE;
-		}
+	if (enabled)
+		return 0;
 
-	} else {
-		tk->tp.flags |= TP_FLAG_PROFILE;
-		ret = __enable_trace_kprobe(tk);
-		if (ret)
+	ret = __enable_trace_kprobe(tk);
+	if (ret) {
+		if (file)
+			trace_probe_remove_file(&tk->tp, file);
+		else
 			tk->tp.flags &= ~TP_FLAG_PROFILE;
 	}
- out:
+
 	return ret;
 }
 
@@ -328,54 +321,34 @@ enable_trace_kprobe(struct trace_kprobe *tk, struct trace_event_file *file)
 static int
 disable_trace_kprobe(struct trace_kprobe *tk, struct trace_event_file *file)
 {
-	struct event_file_link *link = NULL;
-	int wait = 0;
+	struct trace_probe *tp = &tk->tp;
 	int ret = 0;
 
 	if (file) {
-		link = find_event_file_link(&tk->tp, file);
-		if (!link) {
-			ret = -EINVAL;
-			goto out;
-		}
-
-		list_del_rcu(&link->list);
-		wait = 1;
-		if (!list_empty(&tk->tp.files))
+		if (!trace_probe_get_file_link(tp, file))
+			return -ENOENT;
+		if (!trace_probe_has_single_file(tp))
 			goto out;
-
-		tk->tp.flags &= ~TP_FLAG_TRACE;
+		tp->flags &= ~TP_FLAG_TRACE;
 	} else
-		tk->tp.flags &= ~TP_FLAG_PROFILE;
+		tp->flags &= ~TP_FLAG_PROFILE;
 
-	if (!trace_probe_is_enabled(&tk->tp) && trace_probe_is_registered(&tk->tp)) {
+	if (!trace_probe_is_enabled(tp) && trace_probe_is_registered(tp)) {
 		if (trace_kprobe_is_return(tk))
 			disable_kretprobe(&tk->rp);
 		else
 			disable_kprobe(&tk->rp.kp);
-		wait = 1;
 	}
 
-	/*
-	 * if tk is not added to any list, it must be a local trace_kprobe
-	 * created with perf_event_open. We don't need to wait for these
-	 * trace_kprobes
-	 */
-	if (list_empty(&tk->devent.list))
-		wait = 0;
  out:
-	if (wait) {
+	if (file)
 		/*
-		 * Synchronize with kprobe_trace_func/kretprobe_trace_func
-		 * to ensure disabled (all running handlers are finished).
-		 * This is not only for kfree(), but also the caller,
-		 * trace_remove_event_call() supposes it for releasing
-		 * event_call related objects, which will be accessed in
-		 * the kprobe_trace_func/kretprobe_trace_func.
+		 * Synchronization is done in below function. For perf event,
+		 * file == NULL and perf_trace_event_unreg() calls
+		 * tracepoint_synchronize_unregister() to ensure synchronize
+		 * event. We don't need to care about it.
 		 */
-		synchronize_rcu();
-		kfree(link);	/* Ignored if link == NULL */
-	}
+		trace_probe_remove_file(tp, file);
 
 	return ret;
 }
@@ -1044,7 +1017,7 @@ kprobe_trace_func(struct trace_kprobe *tk, struct pt_regs *regs)
 {
 	struct event_file_link *link;
 
-	list_for_each_entry_rcu(link, &tk->tp.files, list)
+	trace_probe_for_each_link_rcu(link, &tk->tp)
 		__kprobe_trace_func(tk, regs, link->file);
 }
 NOKPROBE_SYMBOL(kprobe_trace_func);
@@ -1094,7 +1067,7 @@ kretprobe_trace_func(struct trace_kprobe *tk, struct kretprobe_instance *ri,
 {
 	struct event_file_link *link;
 
-	list_for_each_entry_rcu(link, &tk->tp.files, list)
+	trace_probe_for_each_link_rcu(link, &tk->tp)
 		__kretprobe_trace_func(tk, ri, regs, link->file);
 }
 NOKPROBE_SYMBOL(kretprobe_trace_func);
diff --git a/kernel/trace/trace_probe.c b/kernel/trace/trace_probe.c
index 509a26024b4f..abb05608a09d 100644
--- a/kernel/trace/trace_probe.c
+++ b/kernel/trace/trace_probe.c
@@ -936,3 +936,50 @@ int trace_probe_register_event_call(struct trace_probe *tp)
 
 	return ret;
 }
+
+int trace_probe_add_file(struct trace_probe *tp, struct trace_event_file *file)
+{
+	struct event_file_link *link;
+
+	link = kmalloc(sizeof(*link), GFP_KERNEL);
+	if (!link)
+		return -ENOMEM;
+
+	link->file = file;
+	INIT_LIST_HEAD(&link->list);
+	list_add_tail_rcu(&link->list, &tp->files);
+	tp->flags |= TP_FLAG_TRACE;
+	return 0;
+}
+
+struct event_file_link *trace_probe_get_file_link(struct trace_probe *tp,
+						  struct trace_event_file *file)
+{
+	struct event_file_link *link;
+
+	trace_probe_for_each_link(link, tp) {
+		if (link->file == file)
+			return link;
+	}
+
+	return NULL;
+}
+
+int trace_probe_remove_file(struct trace_probe *tp,
+			    struct trace_event_file *file)
+{
+	struct event_file_link *link;
+
+	link = trace_probe_get_file_link(tp, file);
+	if (!link)
+		return -ENOENT;
+
+	list_del_rcu(&link->list);
+	synchronize_rcu();
+	kfree(link);
+
+	if (list_empty(&tp->files))
+		tp->flags &= ~TP_FLAG_TRACE;
+
+	return 0;
+}
diff --git a/kernel/trace/trace_probe.h b/kernel/trace/trace_probe.h
index 01d7b222e004..ab02007e131d 100644
--- a/kernel/trace/trace_probe.h
+++ b/kernel/trace/trace_probe.h
@@ -248,16 +248,32 @@ static inline bool trace_probe_is_registered(struct trace_probe *tp)
 	return !!(tp->flags & TP_FLAG_REGISTERED);
 }
 
-int trace_probe_init(struct trace_probe *tp, const char *event,
-		     const char *group);
-void trace_probe_cleanup(struct trace_probe *tp);
-int trace_probe_register_event_call(struct trace_probe *tp);
 static inline int trace_probe_unregister_event_call(struct trace_probe *tp)
 {
 	/* tp->event is unregistered in trace_remove_event_call() */
 	return trace_remove_event_call(&tp->call);
 }
 
+static inline bool trace_probe_has_single_file(struct trace_probe *tp)
+{
+	return !!list_is_singular(&tp->files);
+}
+
+int trace_probe_init(struct trace_probe *tp, const char *event,
+		     const char *group);
+void trace_probe_cleanup(struct trace_probe *tp);
+int trace_probe_register_event_call(struct trace_probe *tp);
+int trace_probe_add_file(struct trace_probe *tp, struct trace_event_file *file);
+int trace_probe_remove_file(struct trace_probe *tp,
+			    struct trace_event_file *file);
+struct event_file_link *trace_probe_get_file_link(struct trace_probe *tp,
+						struct trace_event_file *file);
+
+#define trace_probe_for_each_link(pos, tp)	\
+	list_for_each_entry(pos, &(tp)->files, list)
+#define trace_probe_for_each_link_rcu(pos, tp)	\
+	list_for_each_entry_rcu(pos, &(tp)->files, list)
+
 /* Check the name is good for event/group/fields */
 static inline bool is_good_name(const char *name)
 {
@@ -270,18 +286,6 @@ static inline bool is_good_name(const char *name)
 	return true;
 }
 
-static inline struct event_file_link *
-find_event_file_link(struct trace_probe *tp, struct trace_event_file *file)
-{
-	struct event_file_link *link;
-
-	list_for_each_entry(link, &tp->files, list)
-		if (link->file == file)
-			return link;
-
-	return NULL;
-}
-
 #define TPARG_FL_RETURN BIT(0)
 #define TPARG_FL_KERNEL BIT(1)
 #define TPARG_FL_FENTRY BIT(2)
diff --git a/kernel/trace/trace_uprobe.c b/kernel/trace/trace_uprobe.c
index c262494fa793..a9f8045b6695 100644
--- a/kernel/trace/trace_uprobe.c
+++ b/kernel/trace/trace_uprobe.c
@@ -863,7 +863,7 @@ static int uprobe_trace_func(struct trace_uprobe *tu, struct pt_regs *regs,
 		return 0;
 
 	rcu_read_lock();
-	list_for_each_entry_rcu(link, &tu->tp.files, list)
+	trace_probe_for_each_link_rcu(link, &tu->tp)
 		__uprobe_trace_func(tu, 0, regs, ucb, dsize, link->file);
 	rcu_read_unlock();
 
@@ -877,7 +877,7 @@ static void uretprobe_trace_func(struct trace_uprobe *tu, unsigned long func,
 	struct event_file_link *link;
 
 	rcu_read_lock();
-	list_for_each_entry_rcu(link, &tu->tp.files, list)
+	trace_probe_for_each_link_rcu(link, &tu->tp)
 		__uprobe_trace_func(tu, func, regs, ucb, dsize, link->file);
 	rcu_read_unlock();
 }
@@ -924,21 +924,15 @@ probe_event_enable(struct trace_uprobe *tu, struct trace_event_file *file,
 		   filter_func_t filter)
 {
 	bool enabled = trace_probe_is_enabled(&tu->tp);
-	struct event_file_link *link = NULL;
 	int ret;
 
 	if (file) {
 		if (tu->tp.flags & TP_FLAG_PROFILE)
 			return -EINTR;
 
-		link = kmalloc(sizeof(*link), GFP_KERNEL);
-		if (!link)
-			return -ENOMEM;
-
-		link->file = file;
-		list_add_tail_rcu(&link->list, &tu->tp.files);
-
-		tu->tp.flags |= TP_FLAG_TRACE;
+		ret = trace_probe_add_file(&tu->tp, file);
+		if (ret < 0)
+			return ret;
 	} else {
 		if (tu->tp.flags & TP_FLAG_TRACE)
 			return -EINTR;
@@ -973,13 +967,11 @@ probe_event_enable(struct trace_uprobe *tu, struct trace_event_file *file,
 	uprobe_buffer_disable();
 
  err_flags:
-	if (file) {
-		list_del(&link->list);
-		kfree(link);
-		tu->tp.flags &= ~TP_FLAG_TRACE;
-	} else {
+	if (file)
+		trace_probe_remove_file(&tu->tp, file);
+	else
 		tu->tp.flags &= ~TP_FLAG_PROFILE;
-	}
+
 	return ret;
 }
 
@@ -990,26 +982,18 @@ probe_event_disable(struct trace_uprobe *tu, struct trace_event_file *file)
 		return;
 
 	if (file) {
-		struct event_file_link *link;
-
-		link = find_event_file_link(&tu->tp, file);
-		if (!link)
+		if (trace_probe_remove_file(&tu->tp, file) < 0)
 			return;
 
-		list_del_rcu(&link->list);
-		/* synchronize with u{,ret}probe_trace_func */
-		synchronize_rcu();
-		kfree(link);
-
-		if (!list_empty(&tu->tp.files))
+		if (trace_probe_is_enabled(&tu->tp))
 			return;
-	}
+	} else
+		tu->tp.flags &= ~TP_FLAG_PROFILE;
 
 	WARN_ON(!uprobe_filter_is_empty(&tu->filter));
 
 	uprobe_unregister(tu->inode, tu->offset, &tu->consumer);
 	tu->inode = NULL;
-	tu->tp.flags &= file ? ~TP_FLAG_TRACE : ~TP_FLAG_PROFILE;
 
 	uprobe_buffer_disable();
 }


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

* [PATCH 06/21] tracing/probe: Add trace flag access APIs for trace_probe
  2019-05-31 15:16 [PATCH 00/21] tracing/probe: Add multi-probes per event support Masami Hiramatsu
                   ` (4 preceding siblings ...)
  2019-05-31 15:17 ` [PATCH 05/21] tracing/probe: Add trace_event_file access APIs " Masami Hiramatsu
@ 2019-05-31 15:17 ` Masami Hiramatsu
  2019-05-31 15:17 ` [PATCH 07/21] tracing/probe: Add probe event name and group name accesses APIs Masami Hiramatsu
                   ` (14 subsequent siblings)
  20 siblings, 0 replies; 31+ messages in thread
From: Masami Hiramatsu @ 2019-05-31 15:17 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: Masami Hiramatsu, Ingo Molnar, linux-kernel, Tom Zanussi,
	Ravi Bangoria, Namhyung Kim, Arnaldo Carvalho de Melo

Add trace_probe_test/set/clear_flag() functions for accessing
trace_probe.flag field.
This flags field should not be accessed directly.

Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
---
 kernel/trace/trace_kprobe.c |   20 ++++++++++----------
 kernel/trace/trace_probe.c  |    4 ++--
 kernel/trace/trace_probe.h  |   22 ++++++++++++++++++++--
 kernel/trace/trace_uprobe.c |   18 +++++++++---------
 4 files changed, 41 insertions(+), 23 deletions(-)

diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c
index 87a52094378c..c3ab84cb25c8 100644
--- a/kernel/trace/trace_kprobe.c
+++ b/kernel/trace/trace_kprobe.c
@@ -298,7 +298,7 @@ enable_trace_kprobe(struct trace_kprobe *tk, struct trace_event_file *file)
 		if (ret)
 			return ret;
 	} else
-		tk->tp.flags |= TP_FLAG_PROFILE;
+		trace_probe_set_flag(&tk->tp, TP_FLAG_PROFILE);
 
 	if (enabled)
 		return 0;
@@ -308,7 +308,7 @@ enable_trace_kprobe(struct trace_kprobe *tk, struct trace_event_file *file)
 		if (file)
 			trace_probe_remove_file(&tk->tp, file);
 		else
-			tk->tp.flags &= ~TP_FLAG_PROFILE;
+			trace_probe_clear_flag(&tk->tp, TP_FLAG_PROFILE);
 	}
 
 	return ret;
@@ -329,9 +329,9 @@ disable_trace_kprobe(struct trace_kprobe *tk, struct trace_event_file *file)
 			return -ENOENT;
 		if (!trace_probe_has_single_file(tp))
 			goto out;
-		tp->flags &= ~TP_FLAG_TRACE;
+		trace_probe_clear_flag(tp, TP_FLAG_TRACE);
 	} else
-		tp->flags &= ~TP_FLAG_PROFILE;
+		trace_probe_clear_flag(tp, TP_FLAG_PROFILE);
 
 	if (!trace_probe_is_enabled(tp) && trace_probe_is_registered(tp)) {
 		if (trace_kprobe_is_return(tk))
@@ -408,7 +408,7 @@ static int __register_trace_kprobe(struct trace_kprobe *tk)
 		ret = register_kprobe(&tk->rp.kp);
 
 	if (ret == 0)
-		tk->tp.flags |= TP_FLAG_REGISTERED;
+		trace_probe_set_flag(&tk->tp, TP_FLAG_REGISTERED);
 	return ret;
 }
 
@@ -420,7 +420,7 @@ static void __unregister_trace_kprobe(struct trace_kprobe *tk)
 			unregister_kretprobe(&tk->rp);
 		else
 			unregister_kprobe(&tk->rp.kp);
-		tk->tp.flags &= ~TP_FLAG_REGISTERED;
+		trace_probe_clear_flag(&tk->tp, TP_FLAG_REGISTERED);
 		/* Cleanup kprobe for reuse */
 		if (tk->rp.kp.symbol_name)
 			tk->rp.kp.addr = NULL;
@@ -1313,10 +1313,10 @@ static int kprobe_dispatcher(struct kprobe *kp, struct pt_regs *regs)
 
 	raw_cpu_inc(*tk->nhit);
 
-	if (tk->tp.flags & TP_FLAG_TRACE)
+	if (trace_probe_test_flag(&tk->tp, TP_FLAG_TRACE))
 		kprobe_trace_func(tk, regs);
 #ifdef CONFIG_PERF_EVENTS
-	if (tk->tp.flags & TP_FLAG_PROFILE)
+	if (trace_probe_test_flag(&tk->tp, TP_FLAG_PROFILE))
 		ret = kprobe_perf_func(tk, regs);
 #endif
 	return ret;
@@ -1330,10 +1330,10 @@ kretprobe_dispatcher(struct kretprobe_instance *ri, struct pt_regs *regs)
 
 	raw_cpu_inc(*tk->nhit);
 
-	if (tk->tp.flags & TP_FLAG_TRACE)
+	if (trace_probe_test_flag(&tk->tp, TP_FLAG_TRACE))
 		kretprobe_trace_func(tk, ri, regs);
 #ifdef CONFIG_PERF_EVENTS
-	if (tk->tp.flags & TP_FLAG_PROFILE)
+	if (trace_probe_test_flag(&tk->tp, TP_FLAG_PROFILE))
 		kretprobe_perf_func(tk, ri, regs);
 #endif
 	return 0;	/* We don't tweek kernel, so just return 0 */
diff --git a/kernel/trace/trace_probe.c b/kernel/trace/trace_probe.c
index abb05608a09d..323a11ad1dad 100644
--- a/kernel/trace/trace_probe.c
+++ b/kernel/trace/trace_probe.c
@@ -948,7 +948,7 @@ int trace_probe_add_file(struct trace_probe *tp, struct trace_event_file *file)
 	link->file = file;
 	INIT_LIST_HEAD(&link->list);
 	list_add_tail_rcu(&link->list, &tp->files);
-	tp->flags |= TP_FLAG_TRACE;
+	trace_probe_set_flag(tp, TP_FLAG_TRACE);
 	return 0;
 }
 
@@ -979,7 +979,7 @@ int trace_probe_remove_file(struct trace_probe *tp,
 	kfree(link);
 
 	if (list_empty(&tp->files))
-		tp->flags &= ~TP_FLAG_TRACE;
+		trace_probe_clear_flag(tp, TP_FLAG_TRACE);
 
 	return 0;
 }
diff --git a/kernel/trace/trace_probe.h b/kernel/trace/trace_probe.h
index ab02007e131d..87d48d850b63 100644
--- a/kernel/trace/trace_probe.h
+++ b/kernel/trace/trace_probe.h
@@ -238,14 +238,32 @@ struct event_file_link {
 	struct list_head		list;
 };
 
+static inline bool trace_probe_test_flag(struct trace_probe *tp,
+					 unsigned int flag)
+{
+	return !!(tp->flags & flag);
+}
+
+static inline void trace_probe_set_flag(struct trace_probe *tp,
+					unsigned int flag)
+{
+	tp->flags |= flag;
+}
+
+static inline void trace_probe_clear_flag(struct trace_probe *tp,
+					  unsigned int flag)
+{
+	tp->flags &= ~flag;
+}
+
 static inline bool trace_probe_is_enabled(struct trace_probe *tp)
 {
-	return !!(tp->flags & (TP_FLAG_TRACE | TP_FLAG_PROFILE));
+	return trace_probe_test_flag(tp, TP_FLAG_TRACE | TP_FLAG_PROFILE);
 }
 
 static inline bool trace_probe_is_registered(struct trace_probe *tp)
 {
-	return !!(tp->flags & TP_FLAG_REGISTERED);
+	return trace_probe_test_flag(tp, TP_FLAG_REGISTERED);
 }
 
 static inline int trace_probe_unregister_event_call(struct trace_probe *tp)
diff --git a/kernel/trace/trace_uprobe.c b/kernel/trace/trace_uprobe.c
index a9f8045b6695..f8e23ed47823 100644
--- a/kernel/trace/trace_uprobe.c
+++ b/kernel/trace/trace_uprobe.c
@@ -927,17 +927,17 @@ probe_event_enable(struct trace_uprobe *tu, struct trace_event_file *file,
 	int ret;
 
 	if (file) {
-		if (tu->tp.flags & TP_FLAG_PROFILE)
+		if (trace_probe_test_flag(&tu->tp, TP_FLAG_PROFILE))
 			return -EINTR;
 
 		ret = trace_probe_add_file(&tu->tp, file);
 		if (ret < 0)
 			return ret;
 	} else {
-		if (tu->tp.flags & TP_FLAG_TRACE)
+		if (trace_probe_test_flag(&tu->tp, TP_FLAG_TRACE))
 			return -EINTR;
 
-		tu->tp.flags |= TP_FLAG_PROFILE;
+		trace_probe_set_flag(&tu->tp, TP_FLAG_PROFILE);
 	}
 
 	WARN_ON(!uprobe_filter_is_empty(&tu->filter));
@@ -970,7 +970,7 @@ probe_event_enable(struct trace_uprobe *tu, struct trace_event_file *file,
 	if (file)
 		trace_probe_remove_file(&tu->tp, file);
 	else
-		tu->tp.flags &= ~TP_FLAG_PROFILE;
+		trace_probe_clear_flag(&tu->tp, TP_FLAG_PROFILE);
 
 	return ret;
 }
@@ -988,7 +988,7 @@ probe_event_disable(struct trace_uprobe *tu, struct trace_event_file *file)
 		if (trace_probe_is_enabled(&tu->tp))
 			return;
 	} else
-		tu->tp.flags &= ~TP_FLAG_PROFILE;
+		trace_probe_clear_flag(&tu->tp, TP_FLAG_PROFILE);
 
 	WARN_ON(!uprobe_filter_is_empty(&tu->filter));
 
@@ -1266,11 +1266,11 @@ static int uprobe_dispatcher(struct uprobe_consumer *con, struct pt_regs *regs)
 	ucb = uprobe_buffer_get();
 	store_trace_args(ucb->buf, &tu->tp, regs, esize, dsize);
 
-	if (tu->tp.flags & TP_FLAG_TRACE)
+	if (trace_probe_test_flag(&tu->tp, TP_FLAG_TRACE))
 		ret |= uprobe_trace_func(tu, regs, ucb, dsize);
 
 #ifdef CONFIG_PERF_EVENTS
-	if (tu->tp.flags & TP_FLAG_PROFILE)
+	if (trace_probe_test_flag(&tu->tp, TP_FLAG_PROFILE))
 		ret |= uprobe_perf_func(tu, regs, ucb, dsize);
 #endif
 	uprobe_buffer_put(ucb);
@@ -1301,11 +1301,11 @@ static int uretprobe_dispatcher(struct uprobe_consumer *con,
 	ucb = uprobe_buffer_get();
 	store_trace_args(ucb->buf, &tu->tp, regs, esize, dsize);
 
-	if (tu->tp.flags & TP_FLAG_TRACE)
+	if (trace_probe_test_flag(&tu->tp, TP_FLAG_TRACE))
 		uretprobe_trace_func(tu, func, regs, ucb, dsize);
 
 #ifdef CONFIG_PERF_EVENTS
-	if (tu->tp.flags & TP_FLAG_PROFILE)
+	if (trace_probe_test_flag(&tu->tp, TP_FLAG_PROFILE))
 		uretprobe_perf_func(tu, func, regs, ucb, dsize);
 #endif
 	uprobe_buffer_put(ucb);


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

* [PATCH 07/21] tracing/probe: Add probe event name and group name accesses APIs
  2019-05-31 15:16 [PATCH 00/21] tracing/probe: Add multi-probes per event support Masami Hiramatsu
                   ` (5 preceding siblings ...)
  2019-05-31 15:17 ` [PATCH 06/21] tracing/probe: Add trace flag " Masami Hiramatsu
@ 2019-05-31 15:17 ` Masami Hiramatsu
  2019-05-31 15:17 ` [PATCH 08/21] tracing/probe: Add trace_event_call " Masami Hiramatsu
                   ` (13 subsequent siblings)
  20 siblings, 0 replies; 31+ messages in thread
From: Masami Hiramatsu @ 2019-05-31 15:17 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: Masami Hiramatsu, Ingo Molnar, linux-kernel, Tom Zanussi,
	Ravi Bangoria, Namhyung Kim, Arnaldo Carvalho de Melo

Add trace_probe_name() and trace_probe_group_name() functions
for accessing probe name and group name of trace_probe.

Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
---
 kernel/trace/trace_kprobe.c |   24 ++++++++++++------------
 kernel/trace/trace_probe.h  |   10 ++++++++++
 kernel/trace/trace_uprobe.c |   22 +++++++++++-----------
 3 files changed, 33 insertions(+), 23 deletions(-)

diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c
index c3ab84cb25c8..3cf8cee4f276 100644
--- a/kernel/trace/trace_kprobe.c
+++ b/kernel/trace/trace_kprobe.c
@@ -142,8 +142,8 @@ static bool trace_kprobe_match(const char *system, const char *event,
 {
 	struct trace_kprobe *tk = to_trace_kprobe(ev);
 
-	return strcmp(trace_event_name(&tk->tp.call), event) == 0 &&
-	    (!system || strcmp(tk->tp.call.class->system, system) == 0);
+	return strcmp(trace_probe_name(&tk->tp), event) == 0 &&
+	    (!system || strcmp(trace_probe_group_name(&tk->tp), system) == 0);
 }
 
 static nokprobe_inline unsigned long trace_kprobe_nhit(struct trace_kprobe *tk)
@@ -263,8 +263,8 @@ static struct trace_kprobe *find_trace_kprobe(const char *event,
 	struct trace_kprobe *tk;
 
 	for_each_trace_kprobe(tk, pos)
-		if (strcmp(trace_event_name(&tk->tp.call), event) == 0 &&
-		    strcmp(tk->tp.call.class->system, group) == 0)
+		if (strcmp(trace_probe_name(&tk->tp), event) == 0 &&
+		    strcmp(trace_probe_group_name(&tk->tp), group) == 0)
 			return tk;
 	return NULL;
 }
@@ -453,8 +453,8 @@ static int register_trace_kprobe(struct trace_kprobe *tk)
 	mutex_lock(&event_mutex);
 
 	/* Delete old (same name) event if exist */
-	old_tk = find_trace_kprobe(trace_event_name(&tk->tp.call),
-			tk->tp.call.class->system);
+	old_tk = find_trace_kprobe(trace_probe_name(&tk->tp),
+				   trace_probe_group_name(&tk->tp));
 	if (old_tk) {
 		ret = unregister_trace_kprobe(old_tk);
 		if (ret < 0)
@@ -507,7 +507,7 @@ static int trace_kprobe_module_callback(struct notifier_block *nb,
 			ret = __register_trace_kprobe(tk);
 			if (ret)
 				pr_warn("Failed to re-register probe %s on %s: %d\n",
-					trace_event_name(&tk->tp.call),
+					trace_probe_name(&tk->tp),
 					mod->name, ret);
 		}
 	}
@@ -737,8 +737,8 @@ static int trace_kprobe_show(struct seq_file *m, struct dyn_event *ev)
 	int i;
 
 	seq_putc(m, trace_kprobe_is_return(tk) ? 'r' : 'p');
-	seq_printf(m, ":%s/%s", tk->tp.call.class->system,
-			trace_event_name(&tk->tp.call));
+	seq_printf(m, ":%s/%s", trace_probe_group_name(&tk->tp),
+				trace_probe_name(&tk->tp));
 
 	if (!tk->symbol)
 		seq_printf(m, " 0x%p", tk->rp.kp.addr);
@@ -812,7 +812,7 @@ static int probes_profile_seq_show(struct seq_file *m, void *v)
 
 	tk = to_trace_kprobe(ev);
 	seq_printf(m, "  %-44s %15lu %15lu\n",
-		   trace_event_name(&tk->tp.call),
+		   trace_probe_name(&tk->tp),
 		   trace_kprobe_nhit(tk),
 		   tk->rp.kp.nmissed);
 
@@ -1084,7 +1084,7 @@ print_kprobe_event(struct trace_iterator *iter, int flags,
 	field = (struct kprobe_trace_entry_head *)iter->ent;
 	tp = container_of(event, struct trace_probe, call.event);
 
-	trace_seq_printf(s, "%s: (", trace_event_name(&tp->call));
+	trace_seq_printf(s, "%s: (", trace_probe_name(tp));
 
 	if (!seq_print_ip_sym(s, field->ip, flags | TRACE_ITER_SYM_OFFSET))
 		goto out;
@@ -1111,7 +1111,7 @@ print_kretprobe_event(struct trace_iterator *iter, int flags,
 	field = (struct kretprobe_trace_entry_head *)iter->ent;
 	tp = container_of(event, struct trace_probe, call.event);
 
-	trace_seq_printf(s, "%s: (", trace_event_name(&tp->call));
+	trace_seq_printf(s, "%s: (", trace_probe_name(tp));
 
 	if (!seq_print_ip_sym(s, field->ret_ip, flags | TRACE_ITER_SYM_OFFSET))
 		goto out;
diff --git a/kernel/trace/trace_probe.h b/kernel/trace/trace_probe.h
index 87d48d850b63..67424cb5d5d6 100644
--- a/kernel/trace/trace_probe.h
+++ b/kernel/trace/trace_probe.h
@@ -266,6 +266,16 @@ static inline bool trace_probe_is_registered(struct trace_probe *tp)
 	return trace_probe_test_flag(tp, TP_FLAG_REGISTERED);
 }
 
+static inline const char *trace_probe_name(struct trace_probe *tp)
+{
+	return trace_event_name(&tp->call);
+}
+
+static inline const char *trace_probe_group_name(struct trace_probe *tp)
+{
+	return tp->call.class->system;
+}
+
 static inline int trace_probe_unregister_event_call(struct trace_probe *tp)
 {
 	/* tp->event is unregistered in trace_remove_event_call() */
diff --git a/kernel/trace/trace_uprobe.c b/kernel/trace/trace_uprobe.c
index f8e23ed47823..09fdba3ee9d9 100644
--- a/kernel/trace/trace_uprobe.c
+++ b/kernel/trace/trace_uprobe.c
@@ -289,8 +289,8 @@ static bool trace_uprobe_match(const char *system, const char *event,
 {
 	struct trace_uprobe *tu = to_trace_uprobe(ev);
 
-	return strcmp(trace_event_name(&tu->tp.call), event) == 0 &&
-		(!system || strcmp(tu->tp.call.class->system, system) == 0);
+	return strcmp(trace_probe_name(&tu->tp), event) == 0 &&
+	    (!system || strcmp(trace_probe_group_name(&tu->tp), system) == 0);
 }
 
 /*
@@ -340,8 +340,8 @@ static struct trace_uprobe *find_probe_event(const char *event, const char *grou
 	struct trace_uprobe *tu;
 
 	for_each_trace_uprobe(tu, pos)
-		if (strcmp(trace_event_name(&tu->tp.call), event) == 0 &&
-		    strcmp(tu->tp.call.class->system, group) == 0)
+		if (strcmp(trace_probe_name(&tu->tp), event) == 0 &&
+		    strcmp(trace_probe_group_name(&tu->tp), group) == 0)
 			return tu;
 
 	return NULL;
@@ -376,8 +376,8 @@ static struct trace_uprobe *find_old_trace_uprobe(struct trace_uprobe *new)
 	struct trace_uprobe *tmp, *old = NULL;
 	struct inode *new_inode = d_real_inode(new->path.dentry);
 
-	old = find_probe_event(trace_event_name(&new->tp.call),
-				new->tp.call.class->system);
+	old = find_probe_event(trace_probe_name(&new->tp),
+				trace_probe_group_name(&new->tp));
 
 	for_each_trace_uprobe(tmp, pos) {
 		if ((old ? old != tmp : true) &&
@@ -624,8 +624,8 @@ static int trace_uprobe_show(struct seq_file *m, struct dyn_event *ev)
 	char c = is_ret_probe(tu) ? 'r' : 'p';
 	int i;
 
-	seq_printf(m, "%c:%s/%s %s:0x%0*lx", c, tu->tp.call.class->system,
-			trace_event_name(&tu->tp.call), tu->filename,
+	seq_printf(m, "%c:%s/%s %s:0x%0*lx", c, trace_probe_group_name(&tu->tp),
+			trace_probe_name(&tu->tp), tu->filename,
 			(int)(sizeof(void *) * 2), tu->offset);
 
 	if (tu->ref_ctr_offset)
@@ -695,7 +695,7 @@ static int probes_profile_seq_show(struct seq_file *m, void *v)
 
 	tu = to_trace_uprobe(ev);
 	seq_printf(m, "  %s %-44s %15lu\n", tu->filename,
-			trace_event_name(&tu->tp.call), tu->nhit);
+			trace_probe_name(&tu->tp), tu->nhit);
 	return 0;
 }
 
@@ -896,12 +896,12 @@ print_uprobe_event(struct trace_iterator *iter, int flags, struct trace_event *e
 
 	if (is_ret_probe(tu)) {
 		trace_seq_printf(s, "%s: (0x%lx <- 0x%lx)",
-				 trace_event_name(&tu->tp.call),
+				 trace_probe_name(&tu->tp),
 				 entry->vaddr[1], entry->vaddr[0]);
 		data = DATAOF_TRACE_ENTRY(entry, true);
 	} else {
 		trace_seq_printf(s, "%s: (0x%lx)",
-				 trace_event_name(&tu->tp.call),
+				 trace_probe_name(&tu->tp),
 				 entry->vaddr[0]);
 		data = DATAOF_TRACE_ENTRY(entry, false);
 	}


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

* [PATCH 08/21] tracing/probe: Add trace_event_call accesses APIs
  2019-05-31 15:16 [PATCH 00/21] tracing/probe: Add multi-probes per event support Masami Hiramatsu
                   ` (6 preceding siblings ...)
  2019-05-31 15:17 ` [PATCH 07/21] tracing/probe: Add probe event name and group name accesses APIs Masami Hiramatsu
@ 2019-05-31 15:17 ` Masami Hiramatsu
  2019-05-31 15:18 ` [PATCH 09/21] tracing/kprobe: Check registered state using kprobe Masami Hiramatsu
                   ` (12 subsequent siblings)
  20 siblings, 0 replies; 31+ messages in thread
From: Masami Hiramatsu @ 2019-05-31 15:17 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: Masami Hiramatsu, Ingo Molnar, linux-kernel, Tom Zanussi,
	Ravi Bangoria, Namhyung Kim, Arnaldo Carvalho de Melo

Add trace_event_call access APIs for trace_probe.
Instead of accessing trace_probe.call directly, use those
accesses by trace_probe_event_call() method. This hides
the relationship of trace_event_call and trace_probe from
trace_kprobe and trace_uprobe.

Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
---
 kernel/trace/trace_kprobe.c |   23 ++++++++++++-----------
 kernel/trace/trace_probe.c  |   24 ++++++++++++++----------
 kernel/trace/trace_probe.h  |    6 ++++++
 kernel/trace/trace_uprobe.c |   15 ++++++++-------
 4 files changed, 40 insertions(+), 28 deletions(-)

diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c
index 3cf8cee4f276..62362ad1ad98 100644
--- a/kernel/trace/trace_kprobe.c
+++ b/kernel/trace/trace_kprobe.c
@@ -985,7 +985,7 @@ __kprobe_trace_func(struct trace_kprobe *tk, struct pt_regs *regs,
 	struct ring_buffer *buffer;
 	int size, dsize, pc;
 	unsigned long irq_flags;
-	struct trace_event_call *call = &tk->tp.call;
+	struct trace_event_call *call = trace_probe_event_call(&tk->tp);
 
 	WARN_ON(call != trace_file->event_call);
 
@@ -1033,7 +1033,7 @@ __kretprobe_trace_func(struct trace_kprobe *tk, struct kretprobe_instance *ri,
 	struct ring_buffer *buffer;
 	int size, pc, dsize;
 	unsigned long irq_flags;
-	struct trace_event_call *call = &tk->tp.call;
+	struct trace_event_call *call = trace_probe_event_call(&tk->tp);
 
 	WARN_ON(call != trace_file->event_call);
 
@@ -1163,7 +1163,7 @@ static int kretprobe_event_define_fields(struct trace_event_call *event_call)
 static int
 kprobe_perf_func(struct trace_kprobe *tk, struct pt_regs *regs)
 {
-	struct trace_event_call *call = &tk->tp.call;
+	struct trace_event_call *call = trace_probe_event_call(&tk->tp);
 	struct kprobe_trace_entry_head *entry;
 	struct hlist_head *head;
 	int size, __size, dsize;
@@ -1213,7 +1213,7 @@ static void
 kretprobe_perf_func(struct trace_kprobe *tk, struct kretprobe_instance *ri,
 		    struct pt_regs *regs)
 {
-	struct trace_event_call *call = &tk->tp.call;
+	struct trace_event_call *call = trace_probe_event_call(&tk->tp);
 	struct kretprobe_trace_entry_head *entry;
 	struct hlist_head *head;
 	int size, __size, dsize;
@@ -1348,9 +1348,10 @@ static struct trace_event_functions kprobe_funcs = {
 	.trace		= print_kprobe_event
 };
 
-static inline void init_trace_event_call(struct trace_kprobe *tk,
-					 struct trace_event_call *call)
+static inline void init_trace_event_call(struct trace_kprobe *tk)
 {
+	struct trace_event_call *call = trace_probe_event_call(&tk->tp);
+
 	if (trace_kprobe_is_return(tk)) {
 		call->event.funcs = &kretprobe_funcs;
 		call->class->define_fields = kretprobe_event_define_fields;
@@ -1366,7 +1367,7 @@ static inline void init_trace_event_call(struct trace_kprobe *tk,
 
 static int register_kprobe_event(struct trace_kprobe *tk)
 {
-	init_trace_event_call(tk, &tk->tp.call);
+	init_trace_event_call(tk);
 
 	return trace_probe_register_event_call(&tk->tp);
 }
@@ -1403,7 +1404,7 @@ create_local_trace_kprobe(char *func, void *addr, unsigned long offs,
 		return ERR_CAST(tk);
 	}
 
-	init_trace_event_call(tk, &tk->tp.call);
+	init_trace_event_call(tk);
 
 	if (traceprobe_set_print_fmt(&tk->tp, trace_kprobe_is_return(tk)) < 0) {
 		ret = -ENOMEM;
@@ -1414,7 +1415,7 @@ create_local_trace_kprobe(char *func, void *addr, unsigned long offs,
 	if (ret < 0)
 		goto error;
 
-	return &tk->tp.call;
+	return trace_probe_event_call(&tk->tp);
 error:
 	free_trace_kprobe(tk);
 	return ERR_PTR(ret);
@@ -1447,7 +1448,7 @@ static __init void enable_boot_kprobe_events(void)
 	mutex_lock(&event_mutex);
 	for_each_trace_kprobe(tk, pos) {
 		list_for_each_entry(file, &tr->events, list)
-			if (file->event_call == &tk->tp.call)
+			if (file->event_call == trace_probe_event_call(&tk->tp))
 				trace_event_enable_disable(file, 1, 0);
 	}
 	mutex_unlock(&event_mutex);
@@ -1523,7 +1524,7 @@ find_trace_probe_file(struct trace_kprobe *tk, struct trace_array *tr)
 	struct trace_event_file *file;
 
 	list_for_each_entry(file, &tr->events, list)
-		if (file->event_call == &tk->tp.call)
+		if (file->event_call == trace_probe_event_call(&tk->tp))
 			return file;
 
 	return NULL;
diff --git a/kernel/trace/trace_probe.c b/kernel/trace/trace_probe.c
index 323a11ad1dad..dbef0d135075 100644
--- a/kernel/trace/trace_probe.c
+++ b/kernel/trace/trace_probe.c
@@ -844,6 +844,7 @@ static int __set_print_fmt(struct trace_probe *tp, char *buf, int len,
 
 int traceprobe_set_print_fmt(struct trace_probe *tp, bool is_return)
 {
+	struct trace_event_call *call = trace_probe_event_call(tp);
 	int len;
 	char *print_fmt;
 
@@ -855,7 +856,7 @@ int traceprobe_set_print_fmt(struct trace_probe *tp, bool is_return)
 
 	/* Second: actually write the @print_fmt */
 	__set_print_fmt(tp, print_fmt, len + 1, is_return);
-	tp->call.print_fmt = print_fmt;
+	call->print_fmt = print_fmt;
 
 	return 0;
 }
@@ -888,31 +889,34 @@ int traceprobe_define_arg_fields(struct trace_event_call *event_call,
 
 void trace_probe_cleanup(struct trace_probe *tp)
 {
+	struct trace_event_call *call = trace_probe_event_call(tp);
 	int i;
 
 	for (i = 0; i < tp->nr_args; i++)
 		traceprobe_free_probe_arg(&tp->args[i]);
 
-	kfree(tp->call.class->system);
-	kfree(tp->call.name);
-	kfree(tp->call.print_fmt);
+	kfree(call->class->system);
+	kfree(call->name);
+	kfree(call->print_fmt);
 }
 
 int trace_probe_init(struct trace_probe *tp, const char *event,
 		     const char *group)
 {
+	struct trace_event_call *call = trace_probe_event_call(tp);
+
 	if (!event || !group)
 		return -EINVAL;
 
-	tp->call.class = &tp->class;
-	tp->call.name = kstrdup(event, GFP_KERNEL);
-	if (!tp->call.name)
+	call->class = &tp->class;
+	call->name = kstrdup(event, GFP_KERNEL);
+	if (!call->name)
 		return -ENOMEM;
 
 	tp->class.system = kstrdup(group, GFP_KERNEL);
 	if (!tp->class.system) {
-		kfree(tp->call.name);
-		tp->call.name = NULL;
+		kfree(call->name);
+		call->name = NULL;
 		return -ENOMEM;
 	}
 	INIT_LIST_HEAD(&tp->files);
@@ -923,7 +927,7 @@ int trace_probe_init(struct trace_probe *tp, const char *event,
 
 int trace_probe_register_event_call(struct trace_probe *tp)
 {
-	struct trace_event_call *call = &tp->call;
+	struct trace_event_call *call = trace_probe_event_call(tp);
 	int ret;
 
 	ret = register_trace_event(&call->event);
diff --git a/kernel/trace/trace_probe.h b/kernel/trace/trace_probe.h
index 67424cb5d5d6..6c33d4aa36c3 100644
--- a/kernel/trace/trace_probe.h
+++ b/kernel/trace/trace_probe.h
@@ -276,6 +276,12 @@ static inline const char *trace_probe_group_name(struct trace_probe *tp)
 	return tp->call.class->system;
 }
 
+static inline struct trace_event_call *
+	trace_probe_event_call(struct trace_probe *tp)
+{
+	return &tp->call;
+}
+
 static inline int trace_probe_unregister_event_call(struct trace_probe *tp)
 {
 	/* tp->event is unregistered in trace_remove_event_call() */
diff --git a/kernel/trace/trace_uprobe.c b/kernel/trace/trace_uprobe.c
index 09fdba3ee9d9..7fb9353b47d9 100644
--- a/kernel/trace/trace_uprobe.c
+++ b/kernel/trace/trace_uprobe.c
@@ -821,7 +821,7 @@ static void __uprobe_trace_func(struct trace_uprobe *tu,
 	struct ring_buffer *buffer;
 	void *data;
 	int size, esize;
-	struct trace_event_call *call = &tu->tp.call;
+	struct trace_event_call *call = trace_probe_event_call(&tu->tp);
 
 	WARN_ON(call != trace_file->event_call);
 
@@ -1113,7 +1113,7 @@ static void __uprobe_perf_func(struct trace_uprobe *tu,
 			       unsigned long func, struct pt_regs *regs,
 			       struct uprobe_cpu_buffer *ucb, int dsize)
 {
-	struct trace_event_call *call = &tu->tp.call;
+	struct trace_event_call *call = trace_probe_event_call(&tu->tp);
 	struct uprobe_trace_entry_head *entry;
 	struct hlist_head *head;
 	void *data;
@@ -1316,9 +1316,10 @@ static struct trace_event_functions uprobe_funcs = {
 	.trace		= print_uprobe_event
 };
 
-static inline void init_trace_event_call(struct trace_uprobe *tu,
-					 struct trace_event_call *call)
+static inline void init_trace_event_call(struct trace_uprobe *tu)
 {
+	struct trace_event_call *call = trace_probe_event_call(&tu->tp);
+
 	call->event.funcs = &uprobe_funcs;
 	call->class->define_fields = uprobe_event_define_fields;
 
@@ -1329,7 +1330,7 @@ static inline void init_trace_event_call(struct trace_uprobe *tu,
 
 static int register_uprobe_event(struct trace_uprobe *tu)
 {
-	init_trace_event_call(tu, &tu->tp.call);
+	init_trace_event_call(tu);
 
 	return trace_probe_register_event_call(&tu->tp);
 }
@@ -1376,14 +1377,14 @@ create_local_trace_uprobe(char *name, unsigned long offs,
 	tu->path = path;
 	tu->ref_ctr_offset = ref_ctr_offset;
 	tu->filename = kstrdup(name, GFP_KERNEL);
-	init_trace_event_call(tu, &tu->tp.call);
+	init_trace_event_call(tu);
 
 	if (traceprobe_set_print_fmt(&tu->tp, is_ret_probe(tu)) < 0) {
 		ret = -ENOMEM;
 		goto error;
 	}
 
-	return &tu->tp.call;
+	return trace_probe_event_call(&tu->tp);
 error:
 	free_trace_uprobe(tu);
 	return ERR_PTR(ret);


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

* [PATCH 09/21] tracing/kprobe: Check registered state using kprobe
  2019-05-31 15:16 [PATCH 00/21] tracing/probe: Add multi-probes per event support Masami Hiramatsu
                   ` (7 preceding siblings ...)
  2019-05-31 15:17 ` [PATCH 08/21] tracing/probe: Add trace_event_call " Masami Hiramatsu
@ 2019-05-31 15:18 ` Masami Hiramatsu
  2019-05-31 15:18 ` [PATCH 10/21] tracing/probe: Split trace_event related data from trace_probe Masami Hiramatsu
                   ` (11 subsequent siblings)
  20 siblings, 0 replies; 31+ messages in thread
From: Masami Hiramatsu @ 2019-05-31 15:18 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: Masami Hiramatsu, Ingo Molnar, linux-kernel, Tom Zanussi,
	Ravi Bangoria, Namhyung Kim, Arnaldo Carvalho de Melo

Change registered check only by trace_kprobe and remove
TP_FLAG_REGISTERED from trace_probe, since this feature
is only used for trace_kprobe.

Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
---
 kernel/trace/trace_kprobe.c |   23 +++++++++++++++--------
 kernel/trace/trace_probe.h  |    6 ------
 2 files changed, 15 insertions(+), 14 deletions(-)

diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c
index 62362ad1ad98..9d483ad9bb6c 100644
--- a/kernel/trace/trace_kprobe.c
+++ b/kernel/trace/trace_kprobe.c
@@ -157,6 +157,12 @@ static nokprobe_inline unsigned long trace_kprobe_nhit(struct trace_kprobe *tk)
 	return nhit;
 }
 
+static nokprobe_inline bool trace_kprobe_is_registered(struct trace_kprobe *tk)
+{
+	return !(list_empty(&tk->rp.kp.list) &&
+		 hlist_unhashed(&tk->rp.kp.hlist));
+}
+
 /* Return 0 if it fails to find the symbol address */
 static nokprobe_inline
 unsigned long trace_kprobe_address(struct trace_kprobe *tk)
@@ -244,6 +250,8 @@ static struct trace_kprobe *alloc_trace_kprobe(const char *group,
 		tk->rp.kp.pre_handler = kprobe_dispatcher;
 
 	tk->rp.maxactive = maxactive;
+	INIT_HLIST_NODE(&tk->rp.kp.hlist);
+	INIT_LIST_HEAD(&tk->rp.kp.list);
 
 	ret = trace_probe_init(&tk->tp, event, group);
 	if (ret < 0)
@@ -273,7 +281,7 @@ static inline int __enable_trace_kprobe(struct trace_kprobe *tk)
 {
 	int ret = 0;
 
-	if (trace_probe_is_registered(&tk->tp) && !trace_kprobe_has_gone(tk)) {
+	if (trace_kprobe_is_registered(tk) && !trace_kprobe_has_gone(tk)) {
 		if (trace_kprobe_is_return(tk))
 			ret = enable_kretprobe(&tk->rp);
 		else
@@ -333,7 +341,7 @@ disable_trace_kprobe(struct trace_kprobe *tk, struct trace_event_file *file)
 	} else
 		trace_probe_clear_flag(tp, TP_FLAG_PROFILE);
 
-	if (!trace_probe_is_enabled(tp) && trace_probe_is_registered(tp)) {
+	if (!trace_probe_is_enabled(tp) && trace_kprobe_is_registered(tk)) {
 		if (trace_kprobe_is_return(tk))
 			disable_kretprobe(&tk->rp);
 		else
@@ -381,7 +389,7 @@ static int __register_trace_kprobe(struct trace_kprobe *tk)
 {
 	int i, ret;
 
-	if (trace_probe_is_registered(&tk->tp))
+	if (trace_kprobe_is_registered(tk))
 		return -EINVAL;
 
 	if (within_notrace_func(tk)) {
@@ -407,21 +415,20 @@ static int __register_trace_kprobe(struct trace_kprobe *tk)
 	else
 		ret = register_kprobe(&tk->rp.kp);
 
-	if (ret == 0)
-		trace_probe_set_flag(&tk->tp, TP_FLAG_REGISTERED);
 	return ret;
 }
 
 /* Internal unregister function - just handle k*probes and flags */
 static void __unregister_trace_kprobe(struct trace_kprobe *tk)
 {
-	if (trace_probe_is_registered(&tk->tp)) {
+	if (trace_kprobe_is_registered(tk)) {
 		if (trace_kprobe_is_return(tk))
 			unregister_kretprobe(&tk->rp);
 		else
 			unregister_kprobe(&tk->rp.kp);
-		trace_probe_clear_flag(&tk->tp, TP_FLAG_REGISTERED);
-		/* Cleanup kprobe for reuse */
+		/* Cleanup kprobe for reuse and mark it unregistered */
+		INIT_HLIST_NODE(&tk->rp.kp.hlist);
+		INIT_LIST_HEAD(&tk->rp.kp.list);
 		if (tk->rp.kp.symbol_name)
 			tk->rp.kp.addr = NULL;
 	}
diff --git a/kernel/trace/trace_probe.h b/kernel/trace/trace_probe.h
index 6c33d4aa36c3..d1714820efe1 100644
--- a/kernel/trace/trace_probe.h
+++ b/kernel/trace/trace_probe.h
@@ -55,7 +55,6 @@
 /* Flags for trace_probe */
 #define TP_FLAG_TRACE		1
 #define TP_FLAG_PROFILE		2
-#define TP_FLAG_REGISTERED	4
 
 /* data_loc: data location, compatible with u32 */
 #define make_data_loc(len, offs)	\
@@ -261,11 +260,6 @@ static inline bool trace_probe_is_enabled(struct trace_probe *tp)
 	return trace_probe_test_flag(tp, TP_FLAG_TRACE | TP_FLAG_PROFILE);
 }
 
-static inline bool trace_probe_is_registered(struct trace_probe *tp)
-{
-	return trace_probe_test_flag(tp, TP_FLAG_REGISTERED);
-}
-
 static inline const char *trace_probe_name(struct trace_probe *tp)
 {
 	return trace_event_name(&tp->call);


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

* [PATCH 10/21] tracing/probe: Split trace_event related data from trace_probe
  2019-05-31 15:16 [PATCH 00/21] tracing/probe: Add multi-probes per event support Masami Hiramatsu
                   ` (8 preceding siblings ...)
  2019-05-31 15:18 ` [PATCH 09/21] tracing/kprobe: Check registered state using kprobe Masami Hiramatsu
@ 2019-05-31 15:18 ` Masami Hiramatsu
  2019-06-18  1:56   ` Steven Rostedt
  2019-05-31 15:18 ` [PATCH 11/21] tracing/dynevent: Delete all matched events Masami Hiramatsu
                   ` (10 subsequent siblings)
  20 siblings, 1 reply; 31+ messages in thread
From: Masami Hiramatsu @ 2019-05-31 15:18 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: Masami Hiramatsu, Ingo Molnar, linux-kernel, Tom Zanussi,
	Ravi Bangoria, Namhyung Kim, Arnaldo Carvalho de Melo

Split the trace_event related data from trace_probe data structure
and introduce trace_probe_event data structure for its folder.
This trace_probe_event data structure can have multiple trace_probe.

Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
---
 kernel/trace/trace_kprobe.c |   99 ++++++++++++++++++++++-------------
 kernel/trace/trace_probe.c  |   53 +++++++++++++------
 kernel/trace/trace_probe.h  |   48 +++++++++++++----
 kernel/trace/trace_uprobe.c |  123 +++++++++++++++++++++++++++++--------------
 4 files changed, 221 insertions(+), 102 deletions(-)

diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c
index 9d483ad9bb6c..633edb88cd0e 100644
--- a/kernel/trace/trace_kprobe.c
+++ b/kernel/trace/trace_kprobe.c
@@ -180,9 +180,17 @@ unsigned long trace_kprobe_address(struct trace_kprobe *tk)
 	return addr;
 }
 
+static nokprobe_inline struct trace_kprobe *
+trace_kprobe_primary_from_call(struct trace_event_call *call)
+{
+	struct trace_probe *tp = trace_probe_primary_from_call(call);
+
+	return container_of(tp, struct trace_kprobe, tp);
+}
+
 bool trace_kprobe_on_func_entry(struct trace_event_call *call)
 {
-	struct trace_kprobe *tk = (struct trace_kprobe *)call->data;
+	struct trace_kprobe *tk = trace_kprobe_primary_from_call(call);
 
 	return kprobe_on_func_entry(tk->rp.kp.addr,
 			tk->rp.kp.addr ? NULL : tk->rp.kp.symbol_name,
@@ -191,7 +199,7 @@ bool trace_kprobe_on_func_entry(struct trace_event_call *call)
 
 bool trace_kprobe_error_injectable(struct trace_event_call *call)
 {
-	struct trace_kprobe *tk = (struct trace_kprobe *)call->data;
+	struct trace_kprobe *tk = trace_kprobe_primary_from_call(call);
 
 	return within_error_injection_list(trace_kprobe_address(tk));
 }
@@ -295,28 +303,40 @@ static inline int __enable_trace_kprobe(struct trace_kprobe *tk)
  * Enable trace_probe
  * if the file is NULL, enable "perf" handler, or enable "trace" handler.
  */
-static int
-enable_trace_kprobe(struct trace_kprobe *tk, struct trace_event_file *file)
+static int enable_trace_kprobe(struct trace_event_call *call,
+				struct trace_event_file *file)
 {
-	bool enabled = trace_probe_is_enabled(&tk->tp);
-	int ret = 0;
+	struct trace_probe *pos, *tp = trace_probe_primary_from_call(call);
+	struct trace_kprobe *tk;
+	bool enabled = trace_probe_is_enabled(tp);
+	int ret = 0, ecode;
 
 	if (file) {
-		ret = trace_probe_add_file(&tk->tp, file);
+		ret = trace_probe_add_file(tp, file);
 		if (ret)
 			return ret;
 	} else
-		trace_probe_set_flag(&tk->tp, TP_FLAG_PROFILE);
+		trace_probe_set_flag(tp, TP_FLAG_PROFILE);
 
 	if (enabled)
 		return 0;
 
-	ret = __enable_trace_kprobe(tk);
-	if (ret) {
+	enabled = false;
+	list_for_each_entry(pos, trace_probe_probe_list(tp), list) {
+		tk = container_of(pos, struct trace_kprobe, tp);
+		ecode = __enable_trace_kprobe(tk);
+		if (ecode)
+			ret = ecode;	/* Save the last error code */
+		else
+			enabled = true;
+	}
+
+	if (!enabled) {
+		/* No probe is enabled. Roll back */
 		if (file)
-			trace_probe_remove_file(&tk->tp, file);
+			trace_probe_remove_file(tp, file);
 		else
-			trace_probe_clear_flag(&tk->tp, TP_FLAG_PROFILE);
+			trace_probe_clear_flag(tp, TP_FLAG_PROFILE);
 	}
 
 	return ret;
@@ -326,10 +346,11 @@ enable_trace_kprobe(struct trace_kprobe *tk, struct trace_event_file *file)
  * Disable trace_probe
  * if the file is NULL, disable "perf" handler, or disable "trace" handler.
  */
-static int
-disable_trace_kprobe(struct trace_kprobe *tk, struct trace_event_file *file)
+static int disable_trace_kprobe(struct trace_event_call *call,
+				struct trace_event_file *file)
 {
-	struct trace_probe *tp = &tk->tp;
+	struct trace_probe *pos, *tp = trace_probe_primary_from_call(call);
+	struct trace_kprobe *tk;
 	int ret = 0;
 
 	if (file) {
@@ -341,7 +362,13 @@ disable_trace_kprobe(struct trace_kprobe *tk, struct trace_event_file *file)
 	} else
 		trace_probe_clear_flag(tp, TP_FLAG_PROFILE);
 
-	if (!trace_probe_is_enabled(tp) && trace_kprobe_is_registered(tk)) {
+	if (trace_probe_is_enabled(tp))
+		goto out;
+
+	list_for_each_entry(pos, trace_probe_probe_list(tp), list) {
+		tk = container_of(pos, struct trace_kprobe, tp);
+		if (!trace_kprobe_is_registered(tk))
+			continue;
 		if (trace_kprobe_is_return(tk))
 			disable_kretprobe(&tk->rp);
 		else
@@ -1089,7 +1116,8 @@ print_kprobe_event(struct trace_iterator *iter, int flags,
 	struct trace_probe *tp;
 
 	field = (struct kprobe_trace_entry_head *)iter->ent;
-	tp = container_of(event, struct trace_probe, call.event);
+	tp = trace_probe_primary_from_call(
+		container_of(event, struct trace_event_call, event));
 
 	trace_seq_printf(s, "%s: (", trace_probe_name(tp));
 
@@ -1116,7 +1144,8 @@ print_kretprobe_event(struct trace_iterator *iter, int flags,
 	struct trace_probe *tp;
 
 	field = (struct kretprobe_trace_entry_head *)iter->ent;
-	tp = container_of(event, struct trace_probe, call.event);
+	tp = trace_probe_primary_from_call(
+		container_of(event, struct trace_event_call, event));
 
 	trace_seq_printf(s, "%s: (", trace_probe_name(tp));
 
@@ -1145,23 +1174,23 @@ static int kprobe_event_define_fields(struct trace_event_call *event_call)
 {
 	int ret;
 	struct kprobe_trace_entry_head field;
-	struct trace_kprobe *tk = (struct trace_kprobe *)event_call->data;
+	struct trace_probe *tp = trace_probe_primary_from_call(event_call);
 
 	DEFINE_FIELD(unsigned long, ip, FIELD_STRING_IP, 0);
 
-	return traceprobe_define_arg_fields(event_call, sizeof(field), &tk->tp);
+	return traceprobe_define_arg_fields(event_call, sizeof(field), tp);
 }
 
 static int kretprobe_event_define_fields(struct trace_event_call *event_call)
 {
 	int ret;
 	struct kretprobe_trace_entry_head field;
-	struct trace_kprobe *tk = (struct trace_kprobe *)event_call->data;
+	struct trace_probe *tp = trace_probe_primary_from_call(event_call);
 
 	DEFINE_FIELD(unsigned long, func, FIELD_STRING_FUNC, 0);
 	DEFINE_FIELD(unsigned long, ret_ip, FIELD_STRING_RETIP, 0);
 
-	return traceprobe_define_arg_fields(event_call, sizeof(field), &tk->tp);
+	return traceprobe_define_arg_fields(event_call, sizeof(field), tp);
 }
 
 #ifdef CONFIG_PERF_EVENTS
@@ -1289,20 +1318,19 @@ int bpf_get_kprobe_info(const struct perf_event *event, u32 *fd_type,
 static int kprobe_register(struct trace_event_call *event,
 			   enum trace_reg type, void *data)
 {
-	struct trace_kprobe *tk = (struct trace_kprobe *)event->data;
 	struct trace_event_file *file = data;
 
 	switch (type) {
 	case TRACE_REG_REGISTER:
-		return enable_trace_kprobe(tk, file);
+		return enable_trace_kprobe(event, file);
 	case TRACE_REG_UNREGISTER:
-		return disable_trace_kprobe(tk, file);
+		return disable_trace_kprobe(event, file);
 
 #ifdef CONFIG_PERF_EVENTS
 	case TRACE_REG_PERF_REGISTER:
-		return enable_trace_kprobe(tk, NULL);
+		return enable_trace_kprobe(event, NULL);
 	case TRACE_REG_PERF_UNREGISTER:
-		return disable_trace_kprobe(tk, NULL);
+		return disable_trace_kprobe(event, NULL);
 	case TRACE_REG_PERF_OPEN:
 	case TRACE_REG_PERF_CLOSE:
 	case TRACE_REG_PERF_ADD:
@@ -1369,7 +1397,6 @@ static inline void init_trace_event_call(struct trace_kprobe *tk)
 
 	call->flags = TRACE_EVENT_FL_KPROBE;
 	call->class->reg = kprobe_register;
-	call->data = tk;
 }
 
 static int register_kprobe_event(struct trace_kprobe *tk)
@@ -1430,9 +1457,7 @@ create_local_trace_kprobe(char *func, void *addr, unsigned long offs,
 
 void destroy_local_trace_kprobe(struct trace_event_call *event_call)
 {
-	struct trace_kprobe *tk;
-
-	tk = container_of(event_call, struct trace_kprobe, tp.call);
+	struct trace_kprobe *tk = trace_kprobe_primary_from_call(event_call);
 
 	if (trace_probe_is_enabled(&tk->tp)) {
 		WARN_ON(1);
@@ -1577,7 +1602,8 @@ static __init int kprobe_trace_self_tests_init(void)
 				pr_warn("error on getting probe file.\n");
 				warn++;
 			} else
-				enable_trace_kprobe(tk, file);
+				enable_trace_kprobe(
+					trace_probe_event_call(&tk->tp), file);
 		}
 	}
 
@@ -1598,7 +1624,8 @@ static __init int kprobe_trace_self_tests_init(void)
 				pr_warn("error on getting probe file.\n");
 				warn++;
 			} else
-				enable_trace_kprobe(tk, file);
+				enable_trace_kprobe(
+					trace_probe_event_call(&tk->tp), file);
 		}
 	}
 
@@ -1631,7 +1658,8 @@ static __init int kprobe_trace_self_tests_init(void)
 			pr_warn("error on getting probe file.\n");
 			warn++;
 		} else
-			disable_trace_kprobe(tk, file);
+			disable_trace_kprobe(
+				trace_probe_event_call(&tk->tp), file);
 	}
 
 	tk = find_trace_kprobe("testprobe2", KPROBE_EVENT_SYSTEM);
@@ -1649,7 +1677,8 @@ static __init int kprobe_trace_self_tests_init(void)
 			pr_warn("error on getting probe file.\n");
 			warn++;
 		} else
-			disable_trace_kprobe(tk, file);
+			disable_trace_kprobe(
+				trace_probe_event_call(&tk->tp), file);
 	}
 
 	ret = trace_run_command("-:testprobe", create_or_delete_trace_kprobe);
diff --git a/kernel/trace/trace_probe.c b/kernel/trace/trace_probe.c
index dbef0d135075..28733bd6b607 100644
--- a/kernel/trace/trace_probe.c
+++ b/kernel/trace/trace_probe.c
@@ -889,40 +889,59 @@ int traceprobe_define_arg_fields(struct trace_event_call *event_call,
 
 void trace_probe_cleanup(struct trace_probe *tp)
 {
-	struct trace_event_call *call = trace_probe_event_call(tp);
 	int i;
 
 	for (i = 0; i < tp->nr_args; i++)
 		traceprobe_free_probe_arg(&tp->args[i]);
 
-	kfree(call->class->system);
-	kfree(call->name);
-	kfree(call->print_fmt);
+	if (tp->event) {
+		struct trace_event_call *call = trace_probe_event_call(tp);
+
+		kfree(tp->event->class.system);
+		kfree(call->name);
+		kfree(call->print_fmt);
+		kfree(tp->event);
+		tp->event = NULL;
+	}
 }
 
 int trace_probe_init(struct trace_probe *tp, const char *event,
 		     const char *group)
 {
-	struct trace_event_call *call = trace_probe_event_call(tp);
+	struct trace_event_call *call;
+	int ret = 0;
 
 	if (!event || !group)
 		return -EINVAL;
 
-	call->class = &tp->class;
-	call->name = kstrdup(event, GFP_KERNEL);
-	if (!call->name)
+	tp->event = kzalloc(sizeof(struct trace_probe_event), GFP_KERNEL);
+	if (!tp->event)
 		return -ENOMEM;
 
-	tp->class.system = kstrdup(group, GFP_KERNEL);
-	if (!tp->class.system) {
-		kfree(call->name);
-		call->name = NULL;
-		return -ENOMEM;
+	call = trace_probe_event_call(tp);
+	call->class = &tp->event->class;
+	call->name = kstrdup(event, GFP_KERNEL);
+	if (!call->name) {
+		ret = -ENOMEM;
+		goto error;
+	}
+
+	tp->event->class.system = kstrdup(group, GFP_KERNEL);
+	if (!tp->event->class.system) {
+		ret = -ENOMEM;
+		goto error;
 	}
-	INIT_LIST_HEAD(&tp->files);
-	INIT_LIST_HEAD(&tp->class.fields);
+	INIT_LIST_HEAD(&tp->event->files);
+	INIT_LIST_HEAD(&tp->event->class.fields);
+	INIT_LIST_HEAD(&tp->event->probes);
+	INIT_LIST_HEAD(&tp->list);
+	list_add(&tp->event->probes, &tp->list);
 
 	return 0;
+
+error:
+	trace_probe_cleanup(tp);
+	return ret;
 }
 
 int trace_probe_register_event_call(struct trace_probe *tp)
@@ -951,7 +970,7 @@ int trace_probe_add_file(struct trace_probe *tp, struct trace_event_file *file)
 
 	link->file = file;
 	INIT_LIST_HEAD(&link->list);
-	list_add_tail_rcu(&link->list, &tp->files);
+	list_add_tail_rcu(&link->list, &tp->event->files);
 	trace_probe_set_flag(tp, TP_FLAG_TRACE);
 	return 0;
 }
@@ -982,7 +1001,7 @@ int trace_probe_remove_file(struct trace_probe *tp,
 	synchronize_rcu();
 	kfree(link);
 
-	if (list_empty(&tp->files))
+	if (list_empty(&tp->event->files))
 		trace_probe_clear_flag(tp, TP_FLAG_TRACE);
 
 	return 0;
diff --git a/kernel/trace/trace_probe.h b/kernel/trace/trace_probe.h
index d1714820efe1..0b84abb884c2 100644
--- a/kernel/trace/trace_probe.h
+++ b/kernel/trace/trace_probe.h
@@ -222,11 +222,18 @@ struct probe_arg {
 	const struct fetch_type	*type;	/* Type of this argument */
 };
 
-struct trace_probe {
+/* Event call and class holder */
+struct trace_probe_event {
 	unsigned int			flags;	/* For TP_FLAG_* */
 	struct trace_event_class	class;
 	struct trace_event_call		call;
 	struct list_head 		files;
+	struct list_head		probes;
+};
+
+struct trace_probe {
+	struct list_head		list;
+	struct trace_probe_event	*event;
 	ssize_t				size;	/* trace entry size */
 	unsigned int			nr_args;
 	struct probe_arg		args[];
@@ -240,19 +247,19 @@ struct event_file_link {
 static inline bool trace_probe_test_flag(struct trace_probe *tp,
 					 unsigned int flag)
 {
-	return !!(tp->flags & flag);
+	return !!(tp->event->flags & flag);
 }
 
 static inline void trace_probe_set_flag(struct trace_probe *tp,
 					unsigned int flag)
 {
-	tp->flags |= flag;
+	tp->event->flags |= flag;
 }
 
 static inline void trace_probe_clear_flag(struct trace_probe *tp,
 					  unsigned int flag)
 {
-	tp->flags &= ~flag;
+	tp->event->flags &= ~flag;
 }
 
 static inline bool trace_probe_is_enabled(struct trace_probe *tp)
@@ -262,29 +269,48 @@ static inline bool trace_probe_is_enabled(struct trace_probe *tp)
 
 static inline const char *trace_probe_name(struct trace_probe *tp)
 {
-	return trace_event_name(&tp->call);
+	return trace_event_name(&tp->event->call);
 }
 
 static inline const char *trace_probe_group_name(struct trace_probe *tp)
 {
-	return tp->call.class->system;
+	return tp->event->call.class->system;
 }
 
 static inline struct trace_event_call *
 	trace_probe_event_call(struct trace_probe *tp)
 {
-	return &tp->call;
+	return &tp->event->call;
+}
+
+static inline struct trace_probe_event *
+trace_probe_event_from_call(struct trace_event_call *event_call)
+{
+	return container_of(event_call, struct trace_probe_event, call);
+}
+
+static inline struct trace_probe *
+trace_probe_primary_from_call(struct trace_event_call *call)
+{
+	struct trace_probe_event *tpe = trace_probe_event_from_call(call);
+
+	return list_first_entry(&tpe->probes, struct trace_probe, list);
+}
+
+static inline struct list_head *trace_probe_probe_list(struct trace_probe *tp)
+{
+	return &tp->event->probes;
 }
 
 static inline int trace_probe_unregister_event_call(struct trace_probe *tp)
 {
 	/* tp->event is unregistered in trace_remove_event_call() */
-	return trace_remove_event_call(&tp->call);
+	return trace_remove_event_call(&tp->event->call);
 }
 
 static inline bool trace_probe_has_single_file(struct trace_probe *tp)
 {
-	return !!list_is_singular(&tp->files);
+	return !!list_is_singular(&tp->event->files);
 }
 
 int trace_probe_init(struct trace_probe *tp, const char *event,
@@ -298,9 +324,9 @@ struct event_file_link *trace_probe_get_file_link(struct trace_probe *tp,
 						struct trace_event_file *file);
 
 #define trace_probe_for_each_link(pos, tp)	\
-	list_for_each_entry(pos, &(tp)->files, list)
+	list_for_each_entry(pos, &(tp)->event->files, list)
 #define trace_probe_for_each_link_rcu(pos, tp)	\
-	list_for_each_entry_rcu(pos, &(tp)->files, list)
+	list_for_each_entry_rcu(pos, &(tp)->event->files, list)
 
 /* Check the name is good for event/group/fields */
 static inline bool is_good_name(const char *name)
diff --git a/kernel/trace/trace_uprobe.c b/kernel/trace/trace_uprobe.c
index 7fb9353b47d9..3a9a7582400d 100644
--- a/kernel/trace/trace_uprobe.c
+++ b/kernel/trace/trace_uprobe.c
@@ -293,6 +293,14 @@ static bool trace_uprobe_match(const char *system, const char *event,
 	    (!system || strcmp(trace_probe_group_name(&tu->tp), system) == 0);
 }
 
+static nokprobe_inline struct trace_uprobe *
+trace_uprobe_primary_from_call(struct trace_event_call *call)
+{
+	struct trace_probe *tp = trace_probe_primary_from_call(call);
+
+	return container_of(tp, struct trace_uprobe, tp);
+}
+
 /*
  * Allocate new trace_uprobe and initialize it (including uprobes).
  */
@@ -892,7 +900,8 @@ print_uprobe_event(struct trace_iterator *iter, int flags, struct trace_event *e
 	u8 *data;
 
 	entry = (struct uprobe_trace_entry_head *)iter->ent;
-	tu = container_of(event, struct trace_uprobe, tp.call.event);
+	tu = trace_uprobe_primary_from_call(
+		container_of(event, struct trace_event_call, event));
 
 	if (is_ret_probe(tu)) {
 		trace_seq_printf(s, "%s: (0x%lx <- 0x%lx)",
@@ -919,27 +928,41 @@ typedef bool (*filter_func_t)(struct uprobe_consumer *self,
 				enum uprobe_filter_ctx ctx,
 				struct mm_struct *mm);
 
-static int
-probe_event_enable(struct trace_uprobe *tu, struct trace_event_file *file,
-		   filter_func_t filter)
+static int trace_uprobe_enable(struct trace_uprobe *tu, filter_func_t filter)
 {
-	bool enabled = trace_probe_is_enabled(&tu->tp);
-	int ret;
+	tu->consumer.filter = filter;
+	tu->inode = d_real_inode(tu->path.dentry);
+
+	if (tu->ref_ctr_offset)
+		return uprobe_register_refctr(tu->inode, tu->offset,
+				tu->ref_ctr_offset, &tu->consumer);
+	else
+		return uprobe_register(tu->inode, tu->offset, &tu->consumer);
+}
+
+static int probe_event_enable(struct trace_event_call *call,
+			struct trace_event_file *file, filter_func_t filter)
+{
+	struct trace_probe *pos, *tp = trace_probe_primary_from_call(call);
+	struct trace_uprobe *tu;
+	bool enabled = trace_probe_is_enabled(tp);
+	int ret = 0, ecode;
 
 	if (file) {
-		if (trace_probe_test_flag(&tu->tp, TP_FLAG_PROFILE))
+		if (trace_probe_test_flag(tp, TP_FLAG_PROFILE))
 			return -EINTR;
 
-		ret = trace_probe_add_file(&tu->tp, file);
+		ret = trace_probe_add_file(tp, file);
 		if (ret < 0)
 			return ret;
 	} else {
-		if (trace_probe_test_flag(&tu->tp, TP_FLAG_TRACE))
+		if (trace_probe_test_flag(tp, TP_FLAG_TRACE))
 			return -EINTR;
 
-		trace_probe_set_flag(&tu->tp, TP_FLAG_PROFILE);
+		trace_probe_set_flag(tp, TP_FLAG_PROFILE);
 	}
 
+	tu = container_of(tp, struct trace_uprobe, tp);
 	WARN_ON(!uprobe_filter_is_empty(&tu->filter));
 
 	if (enabled)
@@ -949,16 +972,16 @@ probe_event_enable(struct trace_uprobe *tu, struct trace_event_file *file,
 	if (ret)
 		goto err_flags;
 
-	tu->consumer.filter = filter;
-	tu->inode = d_real_inode(tu->path.dentry);
-	if (tu->ref_ctr_offset) {
-		ret = uprobe_register_refctr(tu->inode, tu->offset,
-				tu->ref_ctr_offset, &tu->consumer);
-	} else {
-		ret = uprobe_register(tu->inode, tu->offset, &tu->consumer);
+	enabled = false;
+	list_for_each_entry(pos, trace_probe_probe_list(tp), list) {
+		tu = container_of(pos, struct trace_uprobe, tp);
+		ecode = trace_uprobe_enable(tu, filter);
+		if (ecode)
+			ret = ecode;
+		else
+			enabled = true;
 	}
-
-	if (ret)
+	if (!enabled)
 		goto err_buffer;
 
 	return 0;
@@ -968,32 +991,39 @@ probe_event_enable(struct trace_uprobe *tu, struct trace_event_file *file,
 
  err_flags:
 	if (file)
-		trace_probe_remove_file(&tu->tp, file);
+		trace_probe_remove_file(tp, file);
 	else
-		trace_probe_clear_flag(&tu->tp, TP_FLAG_PROFILE);
+		trace_probe_clear_flag(tp, TP_FLAG_PROFILE);
 
 	return ret;
 }
 
-static void
-probe_event_disable(struct trace_uprobe *tu, struct trace_event_file *file)
+static void probe_event_disable(struct trace_event_call *call,
+				struct trace_event_file *file)
 {
-	if (!trace_probe_is_enabled(&tu->tp))
+	struct trace_probe *pos, *tp = trace_probe_primary_from_call(call);
+	struct trace_uprobe *tu;
+
+	if (!trace_probe_is_enabled(tp))
 		return;
 
 	if (file) {
-		if (trace_probe_remove_file(&tu->tp, file) < 0)
+		if (trace_probe_remove_file(tp, file) < 0)
 			return;
 
-		if (trace_probe_is_enabled(&tu->tp))
+		if (trace_probe_is_enabled(tp))
 			return;
 	} else
-		trace_probe_clear_flag(&tu->tp, TP_FLAG_PROFILE);
+		trace_probe_clear_flag(tp, TP_FLAG_PROFILE);
 
+	tu = container_of(tp, struct trace_uprobe, tp);
 	WARN_ON(!uprobe_filter_is_empty(&tu->filter));
 
-	uprobe_unregister(tu->inode, tu->offset, &tu->consumer);
-	tu->inode = NULL;
+	list_for_each_entry(pos, trace_probe_probe_list(tp), list) {
+		tu = container_of(pos, struct trace_uprobe, tp);
+		uprobe_unregister(tu->inode, tu->offset, &tu->consumer);
+		tu->inode = NULL;
+	}
 
 	uprobe_buffer_disable();
 }
@@ -1002,7 +1032,7 @@ static int uprobe_event_define_fields(struct trace_event_call *event_call)
 {
 	int ret, size;
 	struct uprobe_trace_entry_head field;
-	struct trace_uprobe *tu = event_call->data;
+	struct trace_uprobe *tu = trace_uprobe_primary_from_call(event_call);
 
 	if (is_ret_probe(tu)) {
 		DEFINE_FIELD(unsigned long, vaddr[0], FIELD_STRING_FUNC, 0);
@@ -1095,6 +1125,23 @@ static int uprobe_perf_open(struct trace_uprobe *tu, struct perf_event *event)
 	return err;
 }
 
+static int uprobe_perf_multi_call(struct trace_event_call *call,
+				  struct perf_event *event,
+		int (*op)(struct trace_uprobe *tu, struct perf_event *event))
+{
+	struct trace_probe *pos, *tp = trace_probe_primary_from_call(call);
+	struct trace_uprobe *tu;
+	int ret = 0;
+
+	list_for_each_entry(pos, trace_probe_probe_list(tp), list) {
+		tu = container_of(pos, struct trace_uprobe, tp);
+		ret = op(tu, event);
+		if (ret)
+			break;
+	}
+
+	return ret;
+}
 static bool uprobe_perf_filter(struct uprobe_consumer *uc,
 				enum uprobe_filter_ctx ctx, struct mm_struct *mm)
 {
@@ -1208,30 +1255,29 @@ static int
 trace_uprobe_register(struct trace_event_call *event, enum trace_reg type,
 		      void *data)
 {
-	struct trace_uprobe *tu = event->data;
 	struct trace_event_file *file = data;
 
 	switch (type) {
 	case TRACE_REG_REGISTER:
-		return probe_event_enable(tu, file, NULL);
+		return probe_event_enable(event, file, NULL);
 
 	case TRACE_REG_UNREGISTER:
-		probe_event_disable(tu, file);
+		probe_event_disable(event, file);
 		return 0;
 
 #ifdef CONFIG_PERF_EVENTS
 	case TRACE_REG_PERF_REGISTER:
-		return probe_event_enable(tu, NULL, uprobe_perf_filter);
+		return probe_event_enable(event, NULL, uprobe_perf_filter);
 
 	case TRACE_REG_PERF_UNREGISTER:
-		probe_event_disable(tu, NULL);
+		probe_event_disable(event, NULL);
 		return 0;
 
 	case TRACE_REG_PERF_OPEN:
-		return uprobe_perf_open(tu, data);
+		return uprobe_perf_multi_call(event, data, uprobe_perf_open);
 
 	case TRACE_REG_PERF_CLOSE:
-		return uprobe_perf_close(tu, data);
+		return uprobe_perf_multi_call(event, data, uprobe_perf_close);
 
 #endif
 	default:
@@ -1325,7 +1371,6 @@ static inline void init_trace_event_call(struct trace_uprobe *tu)
 
 	call->flags = TRACE_EVENT_FL_UPROBE;
 	call->class->reg = trace_uprobe_register;
-	call->data = tu;
 }
 
 static int register_uprobe_event(struct trace_uprobe *tu)
@@ -1394,7 +1439,7 @@ void destroy_local_trace_uprobe(struct trace_event_call *event_call)
 {
 	struct trace_uprobe *tu;
 
-	tu = container_of(event_call, struct trace_uprobe, tp.call);
+	tu = trace_uprobe_primary_from_call(event_call);
 
 	free_trace_uprobe(tu);
 }


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

* [PATCH 11/21] tracing/dynevent: Delete all matched events
  2019-05-31 15:16 [PATCH 00/21] tracing/probe: Add multi-probes per event support Masami Hiramatsu
                   ` (9 preceding siblings ...)
  2019-05-31 15:18 ` [PATCH 10/21] tracing/probe: Split trace_event related data from trace_probe Masami Hiramatsu
@ 2019-05-31 15:18 ` Masami Hiramatsu
  2019-05-31 15:18 ` [PATCH 12/21] tracing/dynevent: Pass extra arguments to match operation Masami Hiramatsu
                   ` (9 subsequent siblings)
  20 siblings, 0 replies; 31+ messages in thread
From: Masami Hiramatsu @ 2019-05-31 15:18 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: Masami Hiramatsu, Ingo Molnar, linux-kernel, Tom Zanussi,
	Ravi Bangoria, Namhyung Kim, Arnaldo Carvalho de Melo

When user gives an event name to delete, delete all
matched events instead of the first one.

This means if there are several events which have same
name but different group (subsystem) name, those are
removed if user passed only the event name, e.g.

  # cat kprobe_events
  p:group1/testevent _do_fork
  p:group2/testevent fork_idle
  # echo -:testevent >> kprobe_events
  # cat kprobe_events
  #

Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
---
 kernel/trace/trace_dynevent.c |    8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/kernel/trace/trace_dynevent.c b/kernel/trace/trace_dynevent.c
index fa100ed3b4de..1cc55c50c491 100644
--- a/kernel/trace/trace_dynevent.c
+++ b/kernel/trace/trace_dynevent.c
@@ -61,10 +61,12 @@ int dyn_event_release(int argc, char **argv, struct dyn_event_operations *type)
 	for_each_dyn_event_safe(pos, n) {
 		if (type && type != pos->ops)
 			continue;
-		if (pos->ops->match(system, event, pos)) {
-			ret = pos->ops->free(pos);
+		if (!pos->ops->match(system, event, pos))
+			continue;
+
+		ret = pos->ops->free(pos);
+		if (ret)
 			break;
-		}
 	}
 	mutex_unlock(&event_mutex);
 


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

* [PATCH 12/21] tracing/dynevent: Pass extra arguments to match operation
  2019-05-31 15:16 [PATCH 00/21] tracing/probe: Add multi-probes per event support Masami Hiramatsu
                   ` (10 preceding siblings ...)
  2019-05-31 15:18 ` [PATCH 11/21] tracing/dynevent: Delete all matched events Masami Hiramatsu
@ 2019-05-31 15:18 ` Masami Hiramatsu
  2019-05-31 15:18 ` [PATCH 13/21] tracing/kprobe: Add multi-probe per event support Masami Hiramatsu
                   ` (8 subsequent siblings)
  20 siblings, 0 replies; 31+ messages in thread
From: Masami Hiramatsu @ 2019-05-31 15:18 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: Masami Hiramatsu, Ingo Molnar, linux-kernel, Tom Zanussi,
	Ravi Bangoria, Namhyung Kim, Arnaldo Carvalho de Melo

Pass extra arguments to match operation for checking
exact match. If the event doesn't support exact match,
it will be ignored.

Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
---
 kernel/trace/trace_dynevent.c    |    4 +++-
 kernel/trace/trace_dynevent.h    |    7 ++++---
 kernel/trace/trace_events_hist.c |    4 ++--
 kernel/trace/trace_kprobe.c      |    4 ++--
 kernel/trace/trace_uprobe.c      |    4 ++--
 5 files changed, 13 insertions(+), 10 deletions(-)

diff --git a/kernel/trace/trace_dynevent.c b/kernel/trace/trace_dynevent.c
index 1cc55c50c491..a41fed46c285 100644
--- a/kernel/trace/trace_dynevent.c
+++ b/kernel/trace/trace_dynevent.c
@@ -47,6 +47,7 @@ int dyn_event_release(int argc, char **argv, struct dyn_event_operations *type)
 			return -EINVAL;
 		event++;
 	}
+	argc--; argv++;
 
 	p = strchr(event, '/');
 	if (p) {
@@ -61,7 +62,8 @@ int dyn_event_release(int argc, char **argv, struct dyn_event_operations *type)
 	for_each_dyn_event_safe(pos, n) {
 		if (type && type != pos->ops)
 			continue;
-		if (!pos->ops->match(system, event, pos))
+		if (!pos->ops->match(system, event,
+				argc, (const char **)argv, pos))
 			continue;
 
 		ret = pos->ops->free(pos);
diff --git a/kernel/trace/trace_dynevent.h b/kernel/trace/trace_dynevent.h
index 8c334064e4d6..46898138d2df 100644
--- a/kernel/trace/trace_dynevent.h
+++ b/kernel/trace/trace_dynevent.h
@@ -31,8 +31,9 @@ struct dyn_event;
  * @is_busy: Check whether given event is busy so that it can not be deleted.
  *  Return true if it is busy, otherwides false.
  * @free: Delete the given event. Return 0 if success, otherwides error.
- * @match: Check whether given event and system name match this event.
- *  Return true if it matches, otherwides false.
+ * @match: Check whether given event and system name match this event. The argc
+ *  and argv is used for exact match. Return true if it matches, otherwides
+ *  false.
  *
  * Except for @create, these methods are called under holding event_mutex.
  */
@@ -43,7 +44,7 @@ struct dyn_event_operations {
 	bool (*is_busy)(struct dyn_event *ev);
 	int (*free)(struct dyn_event *ev);
 	bool (*match)(const char *system, const char *event,
-			struct dyn_event *ev);
+		      int argc, const char **argv, struct dyn_event *ev);
 };
 
 /* Register new dyn_event type -- must be called at first */
diff --git a/kernel/trace/trace_events_hist.c b/kernel/trace/trace_events_hist.c
index ca6b0dff60c5..65e7d071ed28 100644
--- a/kernel/trace/trace_events_hist.c
+++ b/kernel/trace/trace_events_hist.c
@@ -374,7 +374,7 @@ static int synth_event_show(struct seq_file *m, struct dyn_event *ev);
 static int synth_event_release(struct dyn_event *ev);
 static bool synth_event_is_busy(struct dyn_event *ev);
 static bool synth_event_match(const char *system, const char *event,
-			      struct dyn_event *ev);
+			int argc, const char **argv, struct dyn_event *ev);
 
 static struct dyn_event_operations synth_event_ops = {
 	.create = synth_event_create,
@@ -422,7 +422,7 @@ static bool synth_event_is_busy(struct dyn_event *ev)
 }
 
 static bool synth_event_match(const char *system, const char *event,
-			      struct dyn_event *ev)
+			int argc, const char **argv, struct dyn_event *ev)
 {
 	struct synth_event *sev = to_synth_event(ev);
 
diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c
index 633edb88cd0e..b340bbc9a965 100644
--- a/kernel/trace/trace_kprobe.c
+++ b/kernel/trace/trace_kprobe.c
@@ -39,7 +39,7 @@ static int trace_kprobe_show(struct seq_file *m, struct dyn_event *ev);
 static int trace_kprobe_release(struct dyn_event *ev);
 static bool trace_kprobe_is_busy(struct dyn_event *ev);
 static bool trace_kprobe_match(const char *system, const char *event,
-			       struct dyn_event *ev);
+			int argc, const char **argv, struct dyn_event *ev);
 
 static struct dyn_event_operations trace_kprobe_ops = {
 	.create = trace_kprobe_create,
@@ -138,7 +138,7 @@ static bool trace_kprobe_is_busy(struct dyn_event *ev)
 }
 
 static bool trace_kprobe_match(const char *system, const char *event,
-			       struct dyn_event *ev)
+			int argc, const char **argv, struct dyn_event *ev)
 {
 	struct trace_kprobe *tk = to_trace_kprobe(ev);
 
diff --git a/kernel/trace/trace_uprobe.c b/kernel/trace/trace_uprobe.c
index 3a9a7582400d..b83cb38657ed 100644
--- a/kernel/trace/trace_uprobe.c
+++ b/kernel/trace/trace_uprobe.c
@@ -44,7 +44,7 @@ static int trace_uprobe_show(struct seq_file *m, struct dyn_event *ev);
 static int trace_uprobe_release(struct dyn_event *ev);
 static bool trace_uprobe_is_busy(struct dyn_event *ev);
 static bool trace_uprobe_match(const char *system, const char *event,
-			       struct dyn_event *ev);
+			int argc, const char **argv, struct dyn_event *ev);
 
 static struct dyn_event_operations trace_uprobe_ops = {
 	.create = trace_uprobe_create,
@@ -285,7 +285,7 @@ static bool trace_uprobe_is_busy(struct dyn_event *ev)
 }
 
 static bool trace_uprobe_match(const char *system, const char *event,
-			       struct dyn_event *ev)
+			int argc, const char **argv, struct dyn_event *ev)
 {
 	struct trace_uprobe *tu = to_trace_uprobe(ev);
 


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

* [PATCH 13/21] tracing/kprobe: Add multi-probe per event support
  2019-05-31 15:16 [PATCH 00/21] tracing/probe: Add multi-probes per event support Masami Hiramatsu
                   ` (11 preceding siblings ...)
  2019-05-31 15:18 ` [PATCH 12/21] tracing/dynevent: Pass extra arguments to match operation Masami Hiramatsu
@ 2019-05-31 15:18 ` Masami Hiramatsu
  2019-05-31 15:18 ` [PATCH 14/21] tracing/uprobe: Add multi-probe per uprobe " Masami Hiramatsu
                   ` (7 subsequent siblings)
  20 siblings, 0 replies; 31+ messages in thread
From: Masami Hiramatsu @ 2019-05-31 15:18 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: Masami Hiramatsu, Ingo Molnar, linux-kernel, Tom Zanussi,
	Ravi Bangoria, Namhyung Kim, Arnaldo Carvalho de Melo

Add multi-probe per one event support to kprobe events.
User can define several different probes on one trace event
if those events have same "event signature",
e.g.

  # echo p:testevent _do_fork > kprobe_events
  # echo p:testevent fork_idle >> kprobe_events
  # kprobe_events
  p:kprobes/testevent _do_fork
  p:kprobes/testevent fork_idle

The event signature is defined by kprobe type (retprobe or not),
the number of args, argument names, and argument types.

Note that this only support appending method. Delete event
operation will delete all probes on the event.

Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
---
 kernel/trace/trace.c        |    4 +--
 kernel/trace/trace_kprobe.c |   52 ++++++++++++++++++++++++++++++++++----
 kernel/trace/trace_probe.c  |   59 ++++++++++++++++++++++++++++++++++++-------
 kernel/trace/trace_probe.h  |   14 +++++++++-
 4 files changed, 111 insertions(+), 18 deletions(-)

diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 77b9c4ca5faa..8f5455046504 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -4813,11 +4813,11 @@ static const char readme_msg[] =
 #endif
 #endif /* CONFIG_STACK_TRACER */
 #ifdef CONFIG_DYNAMIC_EVENTS
-	"  dynamic_events\t\t- Add/remove/show the generic dynamic events\n"
+	"  dynamic_events\t\t- Create/append/remove/show the generic dynamic events\n"
 	"\t\t\t  Write into this file to define/undefine new trace events.\n"
 #endif
 #ifdef CONFIG_KPROBE_EVENTS
-	"  kprobe_events\t\t- Add/remove/show the kernel dynamic events\n"
+	"  kprobe_events\t\t- Create/append/remove/show the kernel dynamic events\n"
 	"\t\t\t  Write into this file to define/undefine new trace events.\n"
 #endif
 #ifdef CONFIG_UPROBE_EVENTS
diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c
index b340bbc9a965..84a164559a47 100644
--- a/kernel/trace/trace_kprobe.c
+++ b/kernel/trace/trace_kprobe.c
@@ -464,6 +464,10 @@ static void __unregister_trace_kprobe(struct trace_kprobe *tk)
 /* Unregister a trace_probe and probe_event */
 static int unregister_trace_kprobe(struct trace_kprobe *tk)
 {
+	/* If other probes are on the event, just unregister kprobe */
+	if (trace_probe_has_sibling(&tk->tp))
+		goto unreg;
+
 	/* Enabled event can not be unregistered */
 	if (trace_probe_is_enabled(&tk->tp))
 		return -EBUSY;
@@ -472,12 +476,38 @@ static int unregister_trace_kprobe(struct trace_kprobe *tk)
 	if (unregister_kprobe_event(tk))
 		return -EBUSY;
 
+unreg:
 	__unregister_trace_kprobe(tk);
 	dyn_event_remove(&tk->devent);
+	trace_probe_unlink(&tk->tp);
 
 	return 0;
 }
 
+static int append_trace_kprobe(struct trace_kprobe *tk, struct trace_kprobe *to)
+{
+	int ret;
+
+	/* Append to existing event */
+	ret = trace_probe_append(&tk->tp, &to->tp);
+	if (ret)
+		return ret;
+
+	/* Register k*probe */
+	ret = __register_trace_kprobe(tk);
+	if (ret == -ENOENT && !trace_kprobe_module_exist(tk)) {
+		pr_warn("This probe might be able to register after target module is loaded. Continue.\n");
+		ret = 0;
+	}
+
+	if (ret)
+		trace_probe_unlink(&tk->tp);
+	else
+		dyn_event_add(&tk->devent);
+
+	return ret;
+}
+
 /* Register a trace_probe and probe_event */
 static int register_trace_kprobe(struct trace_kprobe *tk)
 {
@@ -486,14 +516,24 @@ static int register_trace_kprobe(struct trace_kprobe *tk)
 
 	mutex_lock(&event_mutex);
 
-	/* Delete old (same name) event if exist */
 	old_tk = find_trace_kprobe(trace_probe_name(&tk->tp),
 				   trace_probe_group_name(&tk->tp));
 	if (old_tk) {
-		ret = unregister_trace_kprobe(old_tk);
-		if (ret < 0)
-			goto end;
-		free_trace_kprobe(old_tk);
+		if (trace_kprobe_is_return(tk) != trace_kprobe_is_return(old_tk)) {
+			trace_probe_log_set_index(0);
+			trace_probe_log_err(0, DIFF_PROBE_TYPE);
+			ret = -EEXIST;
+		} else {
+			ret = trace_probe_compare_arg_type(&tk->tp, &old_tk->tp);
+			if (ret) {
+				/* Note that argument starts index = 2 */
+				trace_probe_log_set_index(ret + 1);
+				trace_probe_log_err(0, DIFF_ARG_TYPE);
+				ret = -EEXIST;
+			} else
+				ret = append_trace_kprobe(tk, old_tk);
+		}
+		goto end;
 	}
 
 	/* Register new event */
@@ -727,7 +767,7 @@ static int trace_kprobe_create(int argc, const char *argv[])
 			trace_probe_log_err(0, BAD_INSN_BNDRY);
 		else if (ret == -ENOENT)
 			trace_probe_log_err(0, BAD_PROBE_ADDR);
-		else if (ret != -ENOMEM)
+		else if (ret != -ENOMEM && ret != -EEXIST)
 			trace_probe_log_err(0, FAIL_REG_PROBE);
 		goto error;
 	}
diff --git a/kernel/trace/trace_probe.c b/kernel/trace/trace_probe.c
index 28733bd6b607..651a1449acde 100644
--- a/kernel/trace/trace_probe.c
+++ b/kernel/trace/trace_probe.c
@@ -886,6 +886,35 @@ int traceprobe_define_arg_fields(struct trace_event_call *event_call,
 	return 0;
 }
 
+static void trace_probe_event_free(struct trace_probe_event *tpe)
+{
+	kfree(tpe->class.system);
+	kfree(tpe->call.name);
+	kfree(tpe->call.print_fmt);
+	kfree(tpe);
+}
+
+int trace_probe_append(struct trace_probe *tp, struct trace_probe *to)
+{
+	if (trace_probe_has_sibling(tp))
+		return -EBUSY;
+
+	list_del_init(&tp->list);
+	trace_probe_event_free(tp->event);
+
+	tp->event = to->event;
+	list_add_tail(&tp->list, trace_probe_probe_list(to));
+
+	return 0;
+}
+
+void trace_probe_unlink(struct trace_probe *tp)
+{
+	list_del_init(&tp->list);
+	if (list_empty(trace_probe_probe_list(tp)))
+		trace_probe_event_free(tp->event);
+	tp->event = NULL;
+}
 
 void trace_probe_cleanup(struct trace_probe *tp)
 {
@@ -894,15 +923,8 @@ void trace_probe_cleanup(struct trace_probe *tp)
 	for (i = 0; i < tp->nr_args; i++)
 		traceprobe_free_probe_arg(&tp->args[i]);
 
-	if (tp->event) {
-		struct trace_event_call *call = trace_probe_event_call(tp);
-
-		kfree(tp->event->class.system);
-		kfree(call->name);
-		kfree(call->print_fmt);
-		kfree(tp->event);
-		tp->event = NULL;
-	}
+	if (tp->event)
+		trace_probe_unlink(tp);
 }
 
 int trace_probe_init(struct trace_probe *tp, const char *event,
@@ -1006,3 +1028,22 @@ int trace_probe_remove_file(struct trace_probe *tp,
 
 	return 0;
 }
+
+/*
+ * Return the smallest index of different type argument (start from 1).
+ * If all argument types and name are same, return 0.
+ */
+int trace_probe_compare_arg_type(struct trace_probe *a, struct trace_probe *b)
+{
+	int i;
+
+	for (i = 0; i < a->nr_args; i++) {
+		if ((b->nr_args <= i) ||
+		    ((a->args[i].type != b->args[i].type) ||
+		     (a->args[i].count != b->args[i].count) ||
+		     strcmp(a->args[i].name, b->args[i].name)))
+			return i + 1;
+	}
+
+	return 0;
+}
diff --git a/kernel/trace/trace_probe.h b/kernel/trace/trace_probe.h
index 0b84abb884c2..39926e8a344b 100644
--- a/kernel/trace/trace_probe.h
+++ b/kernel/trace/trace_probe.h
@@ -302,6 +302,13 @@ static inline struct list_head *trace_probe_probe_list(struct trace_probe *tp)
 	return &tp->event->probes;
 }
 
+static inline bool trace_probe_has_sibling(struct trace_probe *tp)
+{
+	struct list_head *list = trace_probe_probe_list(tp);
+
+	return !list_empty(list) && !list_is_singular(list);
+}
+
 static inline int trace_probe_unregister_event_call(struct trace_probe *tp)
 {
 	/* tp->event is unregistered in trace_remove_event_call() */
@@ -316,12 +323,15 @@ static inline bool trace_probe_has_single_file(struct trace_probe *tp)
 int trace_probe_init(struct trace_probe *tp, const char *event,
 		     const char *group);
 void trace_probe_cleanup(struct trace_probe *tp);
+int trace_probe_append(struct trace_probe *tp, struct trace_probe *to);
+void trace_probe_unlink(struct trace_probe *tp);
 int trace_probe_register_event_call(struct trace_probe *tp);
 int trace_probe_add_file(struct trace_probe *tp, struct trace_event_file *file);
 int trace_probe_remove_file(struct trace_probe *tp,
 			    struct trace_event_file *file);
 struct event_file_link *trace_probe_get_file_link(struct trace_probe *tp,
 						struct trace_event_file *file);
+int trace_probe_compare_arg_type(struct trace_probe *a, struct trace_probe *b);
 
 #define trace_probe_for_each_link(pos, tp)	\
 	list_for_each_entry(pos, &(tp)->event->files, list)
@@ -419,7 +429,9 @@ extern int traceprobe_define_arg_fields(struct trace_event_call *event_call,
 	C(ARG_TOO_LONG,		"Argument expression is too long"),	\
 	C(NO_ARG_BODY,		"No argument expression"),		\
 	C(BAD_INSN_BNDRY,	"Probe point is not an instruction boundary"),\
-	C(FAIL_REG_PROBE,	"Failed to register probe event"),
+	C(FAIL_REG_PROBE,	"Failed to register probe event"),\
+	C(DIFF_PROBE_TYPE,	"Probe type is different from existing probe"),\
+	C(DIFF_ARG_TYPE,	"Argument type or name is different from existing probe"),
 
 #undef C
 #define C(a, b)		TP_ERR_##a


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

* [PATCH 14/21] tracing/uprobe: Add multi-probe per uprobe event support
  2019-05-31 15:16 [PATCH 00/21] tracing/probe: Add multi-probes per event support Masami Hiramatsu
                   ` (12 preceding siblings ...)
  2019-05-31 15:18 ` [PATCH 13/21] tracing/kprobe: Add multi-probe per event support Masami Hiramatsu
@ 2019-05-31 15:18 ` Masami Hiramatsu
  2019-05-31 15:19 ` [PATCH 15/21] tracing/kprobe: Add per-probe delete from event Masami Hiramatsu
                   ` (6 subsequent siblings)
  20 siblings, 0 replies; 31+ messages in thread
From: Masami Hiramatsu @ 2019-05-31 15:18 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: Masami Hiramatsu, Ingo Molnar, linux-kernel, Tom Zanussi,
	Ravi Bangoria, Namhyung Kim, Arnaldo Carvalho de Melo

Allow user to define several probes on one uprobe event.
Note that this only support appending method. So deleting
event will delete all probes on the event.

Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
---
 kernel/trace/trace.c        |    2 +
 kernel/trace/trace_uprobe.c |   60 ++++++++++++++++++++++++++++++-------------
 2 files changed, 43 insertions(+), 19 deletions(-)

diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 8f5455046504..73fbe3b0dd08 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -4821,7 +4821,7 @@ static const char readme_msg[] =
 	"\t\t\t  Write into this file to define/undefine new trace events.\n"
 #endif
 #ifdef CONFIG_UPROBE_EVENTS
-	"  uprobe_events\t\t- Add/remove/show the userspace dynamic events\n"
+	"  uprobe_events\t\t- Create/append/remove/show the userspace dynamic events\n"
 	"\t\t\t  Write into this file to define/undefine new trace events.\n"
 #endif
 #if defined(CONFIG_KPROBE_EVENTS) || defined(CONFIG_UPROBE_EVENTS)
diff --git a/kernel/trace/trace_uprobe.c b/kernel/trace/trace_uprobe.c
index b83cb38657ed..1bd6c29cc0f3 100644
--- a/kernel/trace/trace_uprobe.c
+++ b/kernel/trace/trace_uprobe.c
@@ -360,15 +360,32 @@ static int unregister_trace_uprobe(struct trace_uprobe *tu)
 {
 	int ret;
 
+	if (trace_probe_has_sibling(&tu->tp))
+		goto unreg;
+
 	ret = unregister_uprobe_event(tu);
 	if (ret)
 		return ret;
 
+unreg:
 	dyn_event_remove(&tu->devent);
+	trace_probe_unlink(&tu->tp);
 	free_trace_uprobe(tu);
 	return 0;
 }
 
+static int append_trace_uprobe(struct trace_uprobe *tu, struct trace_uprobe *to)
+{
+	int ret;
+
+	/* Append to existing event */
+	ret = trace_probe_append(&tu->tp, &to->tp);
+	if (!ret)
+		dyn_event_add(&tu->devent);
+
+	return ret;
+}
+
 /*
  * Uprobe with multiple reference counter is not allowed. i.e.
  * If inode and offset matches, reference counter offset *must*
@@ -378,25 +395,21 @@ static int unregister_trace_uprobe(struct trace_uprobe *tu)
  * as the new one does not conflict with any other existing
  * ones.
  */
-static struct trace_uprobe *find_old_trace_uprobe(struct trace_uprobe *new)
+static int validate_ref_ctr_offset(struct trace_uprobe *new)
 {
 	struct dyn_event *pos;
-	struct trace_uprobe *tmp, *old = NULL;
+	struct trace_uprobe *tmp;
 	struct inode *new_inode = d_real_inode(new->path.dentry);
 
-	old = find_probe_event(trace_probe_name(&new->tp),
-				trace_probe_group_name(&new->tp));
-
 	for_each_trace_uprobe(tmp, pos) {
-		if ((old ? old != tmp : true) &&
-		    new_inode == d_real_inode(tmp->path.dentry) &&
+		if (new_inode == d_real_inode(tmp->path.dentry) &&
 		    new->offset == tmp->offset &&
 		    new->ref_ctr_offset != tmp->ref_ctr_offset) {
 			pr_warn("Reference counter offset mismatch.");
-			return ERR_PTR(-EINVAL);
+			return -EINVAL;
 		}
 	}
-	return old;
+	return 0;
 }
 
 /* Register a trace_uprobe and probe_event */
@@ -407,18 +420,29 @@ static int register_trace_uprobe(struct trace_uprobe *tu)
 
 	mutex_lock(&event_mutex);
 
-	/* register as an event */
-	old_tu = find_old_trace_uprobe(tu);
-	if (IS_ERR(old_tu)) {
-		ret = PTR_ERR(old_tu);
+	ret = validate_ref_ctr_offset(tu);
+	if (ret)
 		goto end;
-	}
 
+	/* register as an event */
+	old_tu = find_probe_event(trace_probe_name(&tu->tp),
+				  trace_probe_group_name(&tu->tp));
 	if (old_tu) {
-		/* delete old event */
-		ret = unregister_trace_uprobe(old_tu);
-		if (ret)
-			goto end;
+		if (is_ret_probe(tu) != is_ret_probe(old_tu)) {
+			trace_probe_log_set_index(0);
+			trace_probe_log_err(0, DIFF_PROBE_TYPE);
+			ret = -EEXIST;
+		} else {
+			ret = trace_probe_compare_arg_type(&tu->tp, &old_tu->tp);
+			if (ret) {
+				/* Note that argument starts index = 2 */
+				trace_probe_log_set_index(ret + 1);
+				trace_probe_log_err(0, DIFF_ARG_TYPE);
+				ret = -EEXIST;
+			} else
+				ret = append_trace_uprobe(tu, old_tu);
+		}
+		goto end;
 	}
 
 	ret = register_uprobe_event(tu);


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

* [PATCH 15/21] tracing/kprobe: Add per-probe delete from event
  2019-05-31 15:16 [PATCH 00/21] tracing/probe: Add multi-probes per event support Masami Hiramatsu
                   ` (13 preceding siblings ...)
  2019-05-31 15:18 ` [PATCH 14/21] tracing/uprobe: Add multi-probe per uprobe " Masami Hiramatsu
@ 2019-05-31 15:19 ` Masami Hiramatsu
  2019-05-31 15:19 ` [PATCH 16/21] tracing/uprobe: " Masami Hiramatsu
                   ` (5 subsequent siblings)
  20 siblings, 0 replies; 31+ messages in thread
From: Masami Hiramatsu @ 2019-05-31 15:19 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: Masami Hiramatsu, Ingo Molnar, linux-kernel, Tom Zanussi,
	Ravi Bangoria, Namhyung Kim, Arnaldo Carvalho de Melo

Allow user to delete a probe from event. This is done by head
match. For example, if we have 2 probes on an event

$ cat kprobe_events
p:kprobes/testprobe _do_fork r1=%ax r2=%dx
p:kprobes/testprobe idle_fork r1=%ax r2=%cx

Then you can remove one of them by passing the head of definition
which identify the probe.

$ echo "-:kprobes/testprobe idle_fork" >> kprobe_events

Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
---
 kernel/trace/trace_kprobe.c |   25 ++++++++++++++++++++++++-
 kernel/trace/trace_probe.c  |   18 ++++++++++++++++++
 kernel/trace/trace_probe.h  |    2 ++
 3 files changed, 44 insertions(+), 1 deletion(-)

diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c
index 84a164559a47..b950a92976b0 100644
--- a/kernel/trace/trace_kprobe.c
+++ b/kernel/trace/trace_kprobe.c
@@ -137,13 +137,36 @@ static bool trace_kprobe_is_busy(struct dyn_event *ev)
 	return trace_probe_is_enabled(&tk->tp);
 }
 
+static bool trace_kprobe_match_command_head(struct trace_kprobe *tk,
+					    int argc, const char **argv)
+{
+	char buf[MAX_ARGSTR_LEN + 1];
+
+	if (!argc)
+		return true;
+
+	if (!tk->symbol)
+		snprintf(buf, sizeof(buf), "0x%p", tk->rp.kp.addr);
+	else if (tk->rp.kp.offset)
+		snprintf(buf, sizeof(buf), "%s+%u",
+			 trace_kprobe_symbol(tk), tk->rp.kp.offset);
+	else
+		snprintf(buf, sizeof(buf), "%s", trace_kprobe_symbol(tk));
+	if (strcmp(buf, argv[0]))
+		return false;
+	argc--; argv++;
+
+	return trace_probe_match_command_args(&tk->tp, argc, argv);
+}
+
 static bool trace_kprobe_match(const char *system, const char *event,
 			int argc, const char **argv, struct dyn_event *ev)
 {
 	struct trace_kprobe *tk = to_trace_kprobe(ev);
 
 	return strcmp(trace_probe_name(&tk->tp), event) == 0 &&
-	    (!system || strcmp(trace_probe_group_name(&tk->tp), system) == 0);
+	    (!system || strcmp(trace_probe_group_name(&tk->tp), system) == 0) &&
+	    trace_kprobe_match_command_head(tk, argc, argv);
 }
 
 static nokprobe_inline unsigned long trace_kprobe_nhit(struct trace_kprobe *tk)
diff --git a/kernel/trace/trace_probe.c b/kernel/trace/trace_probe.c
index 651a1449acde..f8c3c65c035d 100644
--- a/kernel/trace/trace_probe.c
+++ b/kernel/trace/trace_probe.c
@@ -1047,3 +1047,21 @@ int trace_probe_compare_arg_type(struct trace_probe *a, struct trace_probe *b)
 
 	return 0;
 }
+
+bool trace_probe_match_command_args(struct trace_probe *tp,
+				    int argc, const char **argv)
+{
+	char buf[MAX_ARGSTR_LEN + 1];
+	int i;
+
+	if (tp->nr_args < argc)
+		return false;
+
+	for (i = 0; i < argc; i++) {
+		snprintf(buf, sizeof(buf), "%s=%s",
+			 tp->args[i].name, tp->args[i].comm);
+		if (strcmp(buf, argv[i]))
+			return false;
+	}
+	return true;
+}
diff --git a/kernel/trace/trace_probe.h b/kernel/trace/trace_probe.h
index 39926e8a344b..2dcc4e317787 100644
--- a/kernel/trace/trace_probe.h
+++ b/kernel/trace/trace_probe.h
@@ -332,6 +332,8 @@ int trace_probe_remove_file(struct trace_probe *tp,
 struct event_file_link *trace_probe_get_file_link(struct trace_probe *tp,
 						struct trace_event_file *file);
 int trace_probe_compare_arg_type(struct trace_probe *a, struct trace_probe *b);
+bool trace_probe_match_command_args(struct trace_probe *tp,
+				    int argc, const char **argv);
 
 #define trace_probe_for_each_link(pos, tp)	\
 	list_for_each_entry(pos, &(tp)->event->files, list)


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

* [PATCH 16/21] tracing/uprobe: Add per-probe delete from event
  2019-05-31 15:16 [PATCH 00/21] tracing/probe: Add multi-probes per event support Masami Hiramatsu
                   ` (14 preceding siblings ...)
  2019-05-31 15:19 ` [PATCH 15/21] tracing/kprobe: Add per-probe delete from event Masami Hiramatsu
@ 2019-05-31 15:19 ` Masami Hiramatsu
  2019-06-18  2:16   ` Steven Rostedt
  2019-05-31 15:19 ` [PATCH 17/21] tracing/probe: Add immediate parameter support Masami Hiramatsu
                   ` (4 subsequent siblings)
  20 siblings, 1 reply; 31+ messages in thread
From: Masami Hiramatsu @ 2019-05-31 15:19 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: Masami Hiramatsu, Ingo Molnar, linux-kernel, Tom Zanussi,
	Ravi Bangoria, Namhyung Kim, Arnaldo Carvalho de Melo

Add per-probe delete method from one event passing the head of
definition. In other words, the events which match the head
N parameters are deleted.

Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
---
 kernel/trace/trace_uprobe.c |   31 ++++++++++++++++++++++++++++++-
 1 file changed, 30 insertions(+), 1 deletion(-)

diff --git a/kernel/trace/trace_uprobe.c b/kernel/trace/trace_uprobe.c
index 1bd6c29cc0f3..d2e200729c23 100644
--- a/kernel/trace/trace_uprobe.c
+++ b/kernel/trace/trace_uprobe.c
@@ -284,13 +284,42 @@ static bool trace_uprobe_is_busy(struct dyn_event *ev)
 	return trace_probe_is_enabled(&tu->tp);
 }
 
+static bool trace_uprobe_match_command_head(struct trace_uprobe *tu,
+					    int argc, const char **argv)
+{
+	char buf[MAX_ARGSTR_LEN + 1];
+	int len;
+
+	if (!argc)
+		return true;
+
+	len = strlen(tu->filename);
+	if (argv[0][len] != ':' || strncmp(tu->filename, argv[0], len))
+		return false;
+
+	if (tu->ref_ctr_offset == 0)
+		snprintf(buf, sizeof(buf), "0x%0*lx",
+				(int)(sizeof(void *) * 2), tu->offset);
+	else
+		snprintf(buf, sizeof(buf), "0x%0*lx(0x%lx)",
+				(int)(sizeof(void *) * 2), tu->offset,
+				tu->ref_ctr_offset);
+	if (strcmp(buf, &argv[0][len + 1]))
+		return false;
+
+	argc--; argv++;
+
+	return trace_probe_match_command_args(&tu->tp, argc, argv);
+}
+
 static bool trace_uprobe_match(const char *system, const char *event,
 			int argc, const char **argv, struct dyn_event *ev)
 {
 	struct trace_uprobe *tu = to_trace_uprobe(ev);
 
 	return strcmp(trace_probe_name(&tu->tp), event) == 0 &&
-	    (!system || strcmp(trace_probe_group_name(&tu->tp), system) == 0);
+	   (!system || strcmp(trace_probe_group_name(&tu->tp), system) == 0) &&
+	   trace_uprobe_match_command_head(tu, argc, argv);
 }
 
 static nokprobe_inline struct trace_uprobe *


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

* [PATCH 17/21] tracing/probe: Add immediate parameter support
  2019-05-31 15:16 [PATCH 00/21] tracing/probe: Add multi-probes per event support Masami Hiramatsu
                   ` (15 preceding siblings ...)
  2019-05-31 15:19 ` [PATCH 16/21] tracing/uprobe: " Masami Hiramatsu
@ 2019-05-31 15:19 ` Masami Hiramatsu
  2019-05-31 15:19 ` [PATCH 18/21] tracing/probe: Add immediate string " Masami Hiramatsu
                   ` (3 subsequent siblings)
  20 siblings, 0 replies; 31+ messages in thread
From: Masami Hiramatsu @ 2019-05-31 15:19 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: Masami Hiramatsu, Ingo Molnar, linux-kernel, Tom Zanussi,
	Ravi Bangoria, Namhyung Kim, Arnaldo Carvalho de Melo

Add immediate value parameter (\1234) support to
probe events. This allows you to specify an immediate
(or dummy) parameter instead of fetching from memory
or register.

This feature looks odd, but imagine when you put a probe
on a code to trace some data. If the code is compiled into
2 instructions and 1 instruction has a value but other has
nothing since it is optimized out.
In that case, you can not fold those into one event, even
if ftrace supported multiple probes on one event.
With this feature, you can set a dummy value like
foo=\deadbeef instead of something like foo=%di.

Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
---
 Documentation/trace/kprobetrace.rst  |    1 +
 Documentation/trace/uprobetracer.rst |    1 +
 kernel/trace/trace.c                 |    2 +-
 kernel/trace/trace_probe.c           |   18 ++++++++++++++++++
 kernel/trace/trace_probe.h           |    1 +
 5 files changed, 22 insertions(+), 1 deletion(-)

diff --git a/Documentation/trace/kprobetrace.rst b/Documentation/trace/kprobetrace.rst
index af776989caca..772467f65a36 100644
--- a/Documentation/trace/kprobetrace.rst
+++ b/Documentation/trace/kprobetrace.rst
@@ -52,6 +52,7 @@ Synopsis of kprobe_events
   $retval	: Fetch return value.(\*2)
   $comm		: Fetch current task comm.
   +|-[u]OFFS(FETCHARG) : Fetch memory at FETCHARG +|- OFFS address.(\*3)(\*4)
+  \IMM		: Store an immediate value to the argument.
   NAME=FETCHARG : Set NAME as the argument name of FETCHARG.
   FETCHARG:TYPE : Set TYPE as the type of FETCHARG. Currently, basic types
 		  (u8/u16/u32/u64/s8/s16/s32/s64), hexadecimal types
diff --git a/Documentation/trace/uprobetracer.rst b/Documentation/trace/uprobetracer.rst
index ab13319c66ac..2b4697c0bed7 100644
--- a/Documentation/trace/uprobetracer.rst
+++ b/Documentation/trace/uprobetracer.rst
@@ -45,6 +45,7 @@ Synopsis of uprobe_tracer
    $retval	: Fetch return value.(\*1)
    $comm	: Fetch current task comm.
    +|-[u]OFFS(FETCHARG) : Fetch memory at FETCHARG +|- OFFS address.(\*2)(\*3)
+   \IMM		: Store an immediate value to the argument.
    NAME=FETCHARG     : Set NAME as the argument name of FETCHARG.
    FETCHARG:TYPE     : Set TYPE as the type of FETCHARG. Currently, basic types
 		       (u8/u16/u32/u64/s8/s16/s32/s64), hexadecimal types
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 73fbe3b0dd08..3608535f1935 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -4846,7 +4846,7 @@ static const char readme_msg[] =
 #else
 	"\t           $stack<index>, $stack, $retval, $comm,\n"
 #endif
-	"\t           +|-[u]<offset>(<fetcharg>)\n"
+	"\t           +|-[u]<offset>(<fetcharg>), \\imm-value\n"
 	"\t     type: s8/16/32/64, u8/16/32/64, x8/16/32/64, string, symbol,\n"
 	"\t           b<bit-width>@<bit-offset>/<container-size>, ustring,\n"
 	"\t           <type>\\[<array-size>\\]\n"
diff --git a/kernel/trace/trace_probe.c b/kernel/trace/trace_probe.c
index f8c3c65c035d..fb90baec3cd8 100644
--- a/kernel/trace/trace_probe.c
+++ b/kernel/trace/trace_probe.c
@@ -316,6 +316,17 @@ static int parse_probe_vars(char *arg, const struct fetch_type *t,
 	return -EINVAL;
 }
 
+static int str_to_immediate(char *str, unsigned long *imm)
+{
+	if (isdigit(str[0]))
+		return kstrtoul(str, 0, imm);
+	else if (str[0] == '-')
+		return kstrtol(str, 0, (long *)imm);
+	else if (str[0] == '+')
+		return kstrtol(str + 1, 0, (long *)imm);
+	return -EINVAL;
+}
+
 /* Recursive argument parser */
 static int
 parse_probe_arg(char *arg, const struct fetch_type *type,
@@ -444,6 +455,13 @@ parse_probe_arg(char *arg, const struct fetch_type *type,
 			code->offset = offset;
 		}
 		break;
+	case '\\':	/* Immediate value */
+		ret = str_to_immediate(arg + 1, &code->immediate);
+		if (ret)
+			trace_probe_log_err(offs + 1, BAD_IMM);
+		else
+			code->op = FETCH_OP_IMM;
+		break;
 	}
 	if (!ret && code->op == FETCH_OP_NOP) {
 		/* Parsed, but do not find fetch method */
diff --git a/kernel/trace/trace_probe.h b/kernel/trace/trace_probe.h
index 2dcc4e317787..cc113b82a4ce 100644
--- a/kernel/trace/trace_probe.h
+++ b/kernel/trace/trace_probe.h
@@ -408,6 +408,7 @@ extern int traceprobe_define_arg_fields(struct trace_event_call *event_call,
 	C(BAD_VAR,		"Invalid $-valiable specified"),	\
 	C(BAD_REG_NAME,		"Invalid register name"),		\
 	C(BAD_MEM_ADDR,		"Invalid memory address"),		\
+	C(BAD_IMM,		"Invalid immediate value"),		\
 	C(FILE_ON_KPROBE,	"File offset is not available with kprobe"), \
 	C(BAD_FILE_OFFS,	"Invalid file offset value"),		\
 	C(SYM_ON_UPROBE,	"Symbol is not available with uprobe"),	\


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

* [PATCH 18/21] tracing/probe: Add immediate string parameter support
  2019-05-31 15:16 [PATCH 00/21] tracing/probe: Add multi-probes per event support Masami Hiramatsu
                   ` (16 preceding siblings ...)
  2019-05-31 15:19 ` [PATCH 17/21] tracing/probe: Add immediate parameter support Masami Hiramatsu
@ 2019-05-31 15:19 ` Masami Hiramatsu
  2019-05-31 15:19 ` [PATCH 19/21] selftests/ftrace: Add a testcase for kprobe multiprobe event Masami Hiramatsu
                   ` (2 subsequent siblings)
  20 siblings, 0 replies; 31+ messages in thread
From: Masami Hiramatsu @ 2019-05-31 15:19 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: Masami Hiramatsu, Ingo Molnar, linux-kernel, Tom Zanussi,
	Ravi Bangoria, Namhyung Kim, Arnaldo Carvalho de Melo

Add immediate string parameter (\"string") support to
probe events. This allows you to specify an immediate
(or dummy) parameter instead of fetching a string from
memory.

This feature looks odd, but imagine that you put a probe
on a code to trace some string data. If the code is
compiled into 2 instructions and 1 instruction has a
string on memory but other has no string since it is
optimized out. In that case, you can not fold those into
one event, even if ftrace supported multiple probes on
one event. With this feature, you can set a dummy string
like foo=\"(optimized)":string instead of something
like foo=+0(+0(%bp)):string.

Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
---
 kernel/trace/trace.c        |    2 +-
 kernel/trace/trace_kprobe.c |    3 ++
 kernel/trace/trace_probe.c  |   56 ++++++++++++++++++++++++++++++++-----------
 kernel/trace/trace_probe.h  |    2 ++
 kernel/trace/trace_uprobe.c |    3 ++
 5 files changed, 51 insertions(+), 15 deletions(-)

diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 3608535f1935..ff9c9e627a87 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -4846,7 +4846,7 @@ static const char readme_msg[] =
 #else
 	"\t           $stack<index>, $stack, $retval, $comm,\n"
 #endif
-	"\t           +|-[u]<offset>(<fetcharg>), \\imm-value\n"
+	"\t           +|-[u]<offset>(<fetcharg>), \\imm-value, \\\"imm-string\"\n"
 	"\t     type: s8/16/32/64, u8/16/32/64, x8/16/32/64, string, symbol,\n"
 	"\t           b<bit-width>@<bit-offset>/<container-size>, ustring,\n"
 	"\t           <type>\\[<array-size>\\]\n"
diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c
index b950a92976b0..a09040ac3cde 100644
--- a/kernel/trace/trace_kprobe.c
+++ b/kernel/trace/trace_kprobe.c
@@ -1055,6 +1055,9 @@ process_fetch_insn(struct fetch_insn *code, struct pt_regs *regs, void *dest,
 	case FETCH_OP_COMM:
 		val = (unsigned long)current->comm;
 		break;
+	case FETCH_OP_DATA:
+		val = (unsigned long)code->data;
+		break;
 #ifdef CONFIG_HAVE_FUNCTION_ARG_ACCESS_API
 	case FETCH_OP_ARG:
 		val = regs_get_kernel_argument(regs, code->param);
diff --git a/kernel/trace/trace_probe.c b/kernel/trace/trace_probe.c
index fb90baec3cd8..1e67fef06e53 100644
--- a/kernel/trace/trace_probe.c
+++ b/kernel/trace/trace_probe.c
@@ -327,6 +327,18 @@ static int str_to_immediate(char *str, unsigned long *imm)
 	return -EINVAL;
 }
 
+static int __parse_imm_string(char *str, char **pbuf, int offs)
+{
+	size_t len = strlen(str);
+
+	if (str[len - 1] != '"') {
+		trace_probe_log_err(offs + len, IMMSTR_NO_CLOSE);
+		return -EINVAL;
+	}
+	*pbuf = kstrndup(str, len - 1, GFP_KERNEL);
+	return 0;
+}
+
 /* Recursive argument parser */
 static int
 parse_probe_arg(char *arg, const struct fetch_type *type,
@@ -441,7 +453,8 @@ parse_probe_arg(char *arg, const struct fetch_type *type,
 			ret = parse_probe_arg(arg, t2, &code, end, flags, offs);
 			if (ret)
 				break;
-			if (code->op == FETCH_OP_COMM) {
+			if (code->op == FETCH_OP_COMM ||
+			    code->op == FETCH_OP_DATA) {
 				trace_probe_log_err(offs, COMM_CANT_DEREF);
 				return -EINVAL;
 			}
@@ -456,11 +469,19 @@ parse_probe_arg(char *arg, const struct fetch_type *type,
 		}
 		break;
 	case '\\':	/* Immediate value */
-		ret = str_to_immediate(arg + 1, &code->immediate);
-		if (ret)
-			trace_probe_log_err(offs + 1, BAD_IMM);
-		else
-			code->op = FETCH_OP_IMM;
+		if (arg[1] == '"') {	/* Immediate string */
+			ret = __parse_imm_string(arg + 2, &tmp, offs + 2);
+			if (ret)
+				break;
+			code->op = FETCH_OP_DATA;
+			code->data = tmp;
+		} else {
+			ret = str_to_immediate(arg + 1, &code->immediate);
+			if (ret)
+				trace_probe_log_err(offs + 1, BAD_IMM);
+			else
+				code->op = FETCH_OP_IMM;
+		}
 		break;
 	}
 	if (!ret && code->op == FETCH_OP_NOP) {
@@ -560,8 +581,11 @@ static int traceprobe_parse_probe_arg_body(char *arg, ssize_t *size,
 		}
 	}
 
-	/* Since $comm can not be dereferred, we can find $comm by strcmp */
-	if (strcmp(arg, "$comm") == 0) {
+	/*
+	 * Since $comm and immediate string can not be dereferred,
+	 * we can find those by strcmp.
+	 */
+	if (strcmp(arg, "$comm") == 0 || strncmp(arg, "\\\"", 2) == 0) {
 		/* The type of $comm must be "string", and not an array. */
 		if (parg->count || (t && strcmp(t, "string")))
 			return -EINVAL;
@@ -598,7 +622,8 @@ static int traceprobe_parse_probe_arg_body(char *arg, ssize_t *size,
 	if (!strcmp(parg->type->name, "string") ||
 	    !strcmp(parg->type->name, "ustring")) {
 		if (code->op != FETCH_OP_DEREF && code->op != FETCH_OP_UDEREF &&
-		    code->op != FETCH_OP_IMM && code->op != FETCH_OP_COMM) {
+		    code->op != FETCH_OP_IMM && code->op != FETCH_OP_COMM &&
+		    code->op != FETCH_OP_DATA) {
 			trace_probe_log_err(offset + (t ? (t - arg) : 0),
 					    BAD_STRING);
 			ret = -EINVAL;
@@ -607,9 +632,10 @@ static int traceprobe_parse_probe_arg_body(char *arg, ssize_t *size,
 		if ((code->op == FETCH_OP_IMM || code->op == FETCH_OP_COMM) ||
 		     parg->count) {
 			/*
-			 * IMM and COMM is pointing actual address, those must
-			 * be kept, and if parg->count != 0, this is an array
-			 * of string pointers instead of string address itself.
+			 * IMM, DATA and COMM is pointing actual address, those
+			 * must be kept, and if parg->count != 0, this is an
+			 * array of string pointers instead of string address
+			 * itself.
 			 */
 			code++;
 			if (code->op != FETCH_OP_NOP) {
@@ -683,7 +709,8 @@ static int traceprobe_parse_probe_arg_body(char *arg, ssize_t *size,
 fail:
 	if (ret) {
 		for (code = tmp; code < tmp + FETCH_INSN_MAX; code++)
-			if (code->op == FETCH_NOP_SYMBOL)
+			if (code->op == FETCH_NOP_SYMBOL ||
+			    code->op == FETCH_OP_DATA)
 				kfree(code->data);
 	}
 	kfree(tmp);
@@ -754,7 +781,8 @@ void traceprobe_free_probe_arg(struct probe_arg *arg)
 	struct fetch_insn *code = arg->code;
 
 	while (code && code->op != FETCH_OP_END) {
-		if (code->op == FETCH_NOP_SYMBOL)
+		if (code->op == FETCH_NOP_SYMBOL ||
+		    code->op == FETCH_OP_DATA)
 			kfree(code->data);
 		code++;
 	}
diff --git a/kernel/trace/trace_probe.h b/kernel/trace/trace_probe.h
index cc113b82a4ce..f805cc4cbe7c 100644
--- a/kernel/trace/trace_probe.h
+++ b/kernel/trace/trace_probe.h
@@ -89,6 +89,7 @@ enum fetch_op {
 	FETCH_OP_COMM,		/* Current comm */
 	FETCH_OP_ARG,		/* Function argument : .param */
 	FETCH_OP_FOFFS,		/* File offset: .immediate */
+	FETCH_OP_DATA,		/* Allocated data: .data */
 	// Stage 2 (dereference) op
 	FETCH_OP_DEREF,		/* Dereference: .offset */
 	FETCH_OP_UDEREF,	/* User-space Dereference: .offset */
@@ -409,6 +410,7 @@ extern int traceprobe_define_arg_fields(struct trace_event_call *event_call,
 	C(BAD_REG_NAME,		"Invalid register name"),		\
 	C(BAD_MEM_ADDR,		"Invalid memory address"),		\
 	C(BAD_IMM,		"Invalid immediate value"),		\
+	C(IMMSTR_NO_CLOSE,	"String is not closed with '\"'"),	\
 	C(FILE_ON_KPROBE,	"File offset is not available with kprobe"), \
 	C(BAD_FILE_OFFS,	"Invalid file offset value"),		\
 	C(SYM_ON_UPROBE,	"Symbol is not available with uprobe"),	\
diff --git a/kernel/trace/trace_uprobe.c b/kernel/trace/trace_uprobe.c
index d2e200729c23..3d269e2b2d1c 100644
--- a/kernel/trace/trace_uprobe.c
+++ b/kernel/trace/trace_uprobe.c
@@ -248,6 +248,9 @@ process_fetch_insn(struct fetch_insn *code, struct pt_regs *regs, void *dest,
 	case FETCH_OP_COMM:
 		val = FETCH_TOKEN_COMM;
 		break;
+	case FETCH_OP_DATA:
+		val = (unsigned long)code->data;
+		break;
 	case FETCH_OP_FOFFS:
 		val = translate_user_vaddr(code->immediate);
 		break;


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

* [PATCH 19/21] selftests/ftrace: Add a testcase for kprobe multiprobe event
  2019-05-31 15:16 [PATCH 00/21] tracing/probe: Add multi-probes per event support Masami Hiramatsu
                   ` (17 preceding siblings ...)
  2019-05-31 15:19 ` [PATCH 18/21] tracing/probe: Add immediate string " Masami Hiramatsu
@ 2019-05-31 15:19 ` Masami Hiramatsu
  2019-05-31 15:19 ` [PATCH 20/21] selftests/ftrace: Add syntax error test for immediates Masami Hiramatsu
  2019-05-31 15:20 ` [PATCH 21/21] selftests/ftrace: Add syntax error test for multiprobe Masami Hiramatsu
  20 siblings, 0 replies; 31+ messages in thread
From: Masami Hiramatsu @ 2019-05-31 15:19 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: Masami Hiramatsu, Ingo Molnar, linux-kernel, Tom Zanussi,
	Ravi Bangoria, Namhyung Kim, Arnaldo Carvalho de Melo

Add a testcase for kprobe event with multi-probe.

Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
---
 .../ftrace/test.d/kprobe/kprobe_multiprobe.tc      |   35 ++++++++++++++++++++
 1 file changed, 35 insertions(+)
 create mode 100644 tools/testing/selftests/ftrace/test.d/kprobe/kprobe_multiprobe.tc

diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_multiprobe.tc b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_multiprobe.tc
new file mode 100644
index 000000000000..44494bac86d1
--- /dev/null
+++ b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_multiprobe.tc
@@ -0,0 +1,35 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+# description: Create/delete multiprobe on kprobe event
+
+[ -f kprobe_events ] || exit_unsupported
+
+grep -q "Create/append/" README || exit_unsupported
+
+# Choose 2 symbols for target
+SYM1=_do_fork
+SYM2=do_exit
+EVENT_NAME=kprobes/testevent
+
+DEF1="p:$EVENT_NAME $SYM1"
+DEF2="p:$EVENT_NAME $SYM2"
+
+:;: "Define an event which has 2 probes" ;:
+echo $DEF1 >> kprobe_events
+echo $DEF2 >> kprobe_events
+cat kprobe_events | grep "$DEF1"
+cat kprobe_events | grep "$DEF2"
+
+:;: "Remove the event by name (should remove both)" ;:
+echo "-:$EVENT_NAME" >> kprobe_events
+test `cat kprobe_events | wc -l` -eq 0
+
+:;: "Remove just 1 event" ;:
+echo $DEF1 >> kprobe_events
+echo $DEF2 >> kprobe_events
+echo "-:$EVENT_NAME $SYM1" >> kprobe_events
+! cat kprobe_events | grep "$DEF1"
+cat kprobe_events | grep "$DEF2"
+
+:;: "Appending different type must fail" ;:
+! echo "$DEF1 \$stack" >> kprobe_events


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

* [PATCH 20/21] selftests/ftrace: Add syntax error test for immediates
  2019-05-31 15:16 [PATCH 00/21] tracing/probe: Add multi-probes per event support Masami Hiramatsu
                   ` (18 preceding siblings ...)
  2019-05-31 15:19 ` [PATCH 19/21] selftests/ftrace: Add a testcase for kprobe multiprobe event Masami Hiramatsu
@ 2019-05-31 15:19 ` Masami Hiramatsu
  2019-05-31 15:20 ` [PATCH 21/21] selftests/ftrace: Add syntax error test for multiprobe Masami Hiramatsu
  20 siblings, 0 replies; 31+ messages in thread
From: Masami Hiramatsu @ 2019-05-31 15:19 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: Masami Hiramatsu, Ingo Molnar, linux-kernel, Tom Zanussi,
	Ravi Bangoria, Namhyung Kim, Arnaldo Carvalho de Melo

Add syntax error test cases for immediate value and
immediate string.

Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
---
 .../ftrace/test.d/kprobe/kprobe_syntax_errors.tc   |    5 +++++
 1 file changed, 5 insertions(+)

diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_syntax_errors.tc b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_syntax_errors.tc
index 29faaec942c6..aa59944bcace 100644
--- a/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_syntax_errors.tc
+++ b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_syntax_errors.tc
@@ -41,6 +41,11 @@ check_error 'p vfs_read ^%none_reg'	# BAD_REG_NAME
 check_error 'p vfs_read ^@12345678abcde'	# BAD_MEM_ADDR
 check_error 'p vfs_read ^@+10'		# FILE_ON_KPROBE
 
+grep -q "imm-value" README && \
+check_error 'p vfs_read arg1=\^x'	# BAD_IMM
+grep -q "imm-string" README && \
+check_error 'p vfs_read arg1=\"abcd^'	# IMMSTR_NO_CLOSE
+
 check_error 'p vfs_read ^+0@0)'		# DEREF_NEED_BRACE
 check_error 'p vfs_read ^+0ab1(@0)'	# BAD_DEREF_OFFS
 check_error 'p vfs_read +0(+0(@0^)'	# DEREF_OPEN_BRACE


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

* [PATCH 21/21] selftests/ftrace: Add syntax error test for multiprobe
  2019-05-31 15:16 [PATCH 00/21] tracing/probe: Add multi-probes per event support Masami Hiramatsu
                   ` (19 preceding siblings ...)
  2019-05-31 15:19 ` [PATCH 20/21] selftests/ftrace: Add syntax error test for immediates Masami Hiramatsu
@ 2019-05-31 15:20 ` Masami Hiramatsu
  20 siblings, 0 replies; 31+ messages in thread
From: Masami Hiramatsu @ 2019-05-31 15:20 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: Masami Hiramatsu, Ingo Molnar, linux-kernel, Tom Zanussi,
	Ravi Bangoria, Namhyung Kim, Arnaldo Carvalho de Melo

Add syntax error test cases for multiprobe appending
errors.

Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
---
 tools/testing/selftests/ftrace/test.d/functions    |    2 +-
 .../ftrace/test.d/kprobe/kprobe_syntax_errors.tc   |   10 ++++++++++
 2 files changed, 11 insertions(+), 1 deletion(-)

diff --git a/tools/testing/selftests/ftrace/test.d/functions b/tools/testing/selftests/ftrace/test.d/functions
index 779ec11f61bd..1cac8cc2cb35 100644
--- a/tools/testing/selftests/ftrace/test.d/functions
+++ b/tools/testing/selftests/ftrace/test.d/functions
@@ -115,7 +115,7 @@ ftrace_errlog_check() { # err-prefix command-with-error-pos-by-^ command-file
     command=$(echo "$2" | tr -d ^)
     echo "Test command: $command"
     echo > error_log
-    (! echo "$command" > "$3" ) 2> /dev/null
+    (! echo "$command" >> "$3" ) 2> /dev/null
     grep "$1: error:" -A 3 error_log
     N=$(tail -n 1 error_log | wc -c)
     # "  Command: " and "^\n" => 13
diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_syntax_errors.tc b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_syntax_errors.tc
index aa59944bcace..39ef7ac1f51c 100644
--- a/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_syntax_errors.tc
+++ b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_syntax_errors.tc
@@ -87,4 +87,14 @@ case $(uname -m) in
     ;;
 esac
 
+# multiprobe errors
+if grep -q "Create/append/" README && grep -q "imm-value" README; then
+echo 'p:kprobes/testevent _do_fork' > kprobe_events
+check_error '^r:kprobes/testevent do_exit'	# DIFF_PROBE_TYPE
+echo 'p:kprobes/testevent _do_fork abcd=\1' > kprobe_events
+check_error 'p:kprobes/testevent _do_fork ^bcd=\1'	# DIFF_ARG_TYPE
+check_error 'p:kprobes/testevent _do_fork ^abcd=\1:u8'	# DIFF_ARG_TYPE
+check_error 'p:kprobes/testevent _do_fork ^abcd=\"foo"'	# DIFF_ARG_TYPE
+fi
+
 exit 0


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

* Re: [PATCH 10/21] tracing/probe: Split trace_event related data from trace_probe
  2019-05-31 15:18 ` [PATCH 10/21] tracing/probe: Split trace_event related data from trace_probe Masami Hiramatsu
@ 2019-06-18  1:56   ` Steven Rostedt
  2019-06-18 16:14     ` Masami Hiramatsu
  0 siblings, 1 reply; 31+ messages in thread
From: Steven Rostedt @ 2019-06-18  1:56 UTC (permalink / raw)
  To: Masami Hiramatsu
  Cc: Ingo Molnar, linux-kernel, Tom Zanussi, Ravi Bangoria,
	Namhyung Kim, Arnaldo Carvalho de Melo

On Sat,  1 Jun 2019 00:18:16 +0900
Masami Hiramatsu <mhiramat@kernel.org> wrote:

> Split the trace_event related data from trace_probe data structure
> and introduce trace_probe_event data structure for its folder.
> This trace_probe_event data structure can have multiple trace_probe.
> 
> Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
> ---
>  kernel/trace/trace_kprobe.c |   99 ++++++++++++++++++++++-------------
>  kernel/trace/trace_probe.c  |   53 +++++++++++++------
>  kernel/trace/trace_probe.h  |   48 +++++++++++++----
>  kernel/trace/trace_uprobe.c |  123 +++++++++++++++++++++++++++++--------------
>  4 files changed, 221 insertions(+), 102 deletions(-)
> 
> diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c
> index 9d483ad9bb6c..633edb88cd0e 100644
> --- a/kernel/trace/trace_kprobe.c
> +++ b/kernel/trace/trace_kprobe.c
> @@ -180,9 +180,17 @@ unsigned long trace_kprobe_address(struct trace_kprobe *tk)
>  	return addr;
>  }
>  
> +static nokprobe_inline struct trace_kprobe *
> +trace_kprobe_primary_from_call(struct trace_event_call *call)
> +{
> +	struct trace_probe *tp = trace_probe_primary_from_call(call);
> +
> +	return container_of(tp, struct trace_kprobe, tp);


Hmm, is there a possibility that trace_probe_primary_from_call() may
not have a primary?


> +}
> +
>  bool trace_kprobe_on_func_entry(struct trace_event_call *call)
>  {
> -	struct trace_kprobe *tk = (struct trace_kprobe *)call->data;
> +	struct trace_kprobe *tk = trace_kprobe_primary_from_call(call);
>  
>  	return kprobe_on_func_entry(tk->rp.kp.addr,
>  			tk->rp.kp.addr ? NULL : tk->rp.kp.symbol_name,
> @@ -191,7 +199,7 @@ bool trace_kprobe_on_func_entry(struct trace_event_call *call)
>  
>  bool trace_kprobe_error_injectable(struct trace_event_call *call)
>  {
> -	struct trace_kprobe *tk = (struct trace_kprobe *)call->data;
> +	struct trace_kprobe *tk = trace_kprobe_primary_from_call(call);
>  
>  	return within_error_injection_list(trace_kprobe_address(tk));
>  }
> @@ -295,28 +303,40 @@ static inline int __enable_trace_kprobe(struct trace_kprobe *tk)
>   * Enable trace_probe
>   * if the file is NULL, enable "perf" handler, or enable "trace" handler.
>   */
> -static int
> -enable_trace_kprobe(struct trace_kprobe *tk, struct trace_event_file *file)
> +static int enable_trace_kprobe(struct trace_event_call *call,
> +				struct trace_event_file *file)
>  {
> -	bool enabled = trace_probe_is_enabled(&tk->tp);
> -	int ret = 0;
> +	struct trace_probe *pos, *tp = trace_probe_primary_from_call(call);
> +	struct trace_kprobe *tk;
> +	bool enabled = trace_probe_is_enabled(tp);
> +	int ret = 0, ecode;
>  
>  	if (file) {
> -		ret = trace_probe_add_file(&tk->tp, file);
> +		ret = trace_probe_add_file(tp, file);
>  		if (ret)
>  			return ret;
>  	} else
> -		trace_probe_set_flag(&tk->tp, TP_FLAG_PROFILE);
> +		trace_probe_set_flag(tp, TP_FLAG_PROFILE);
>  
>  	if (enabled)
>  		return 0;
>  
> -	ret = __enable_trace_kprobe(tk);
> -	if (ret) {
> +	enabled = false;
> +	list_for_each_entry(pos, trace_probe_probe_list(tp), list) {
> +		tk = container_of(pos, struct trace_kprobe, tp);
> +		ecode = __enable_trace_kprobe(tk);
> +		if (ecode)
> +			ret = ecode;	/* Save the last error code */
> +		else
> +			enabled = true;

So, if we have some enabled but return an error code, what should a
caller think of that? Wouldn't it be an inconsistent state?

-- Steve


> +	}
> +
> +	if (!enabled) {
> +		/* No probe is enabled. Roll back */
>  		if (file)
> -			trace_probe_remove_file(&tk->tp, file);
> +			trace_probe_remove_file(tp, file);
>  		else
> -			trace_probe_clear_flag(&tk->tp, TP_FLAG_PROFILE);
> +			trace_probe_clear_flag(tp, TP_FLAG_PROFILE);
>  	}
>  
>


> +static inline struct trace_probe_event *
> +trace_probe_event_from_call(struct trace_event_call *event_call)
> +{
> +	return container_of(event_call, struct trace_probe_event, call);
> +}
> +
> +static inline struct trace_probe *
> +trace_probe_primary_from_call(struct trace_event_call *call)
> +{
> +	struct trace_probe_event *tpe = trace_probe_event_from_call(call);
> +
> +	return list_first_entry(&tpe->probes, struct trace_probe, list);
> +}
> +
> +static inline struct list_head *trace_probe_probe_list(struct trace_probe *tp)
> +{
> +	return &tp->event->probes;
>  }
>  

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

* Re: [PATCH 16/21] tracing/uprobe: Add per-probe delete from event
  2019-05-31 15:19 ` [PATCH 16/21] tracing/uprobe: " Masami Hiramatsu
@ 2019-06-18  2:16   ` Steven Rostedt
  2019-06-18 16:18     ` Masami Hiramatsu
  0 siblings, 1 reply; 31+ messages in thread
From: Steven Rostedt @ 2019-06-18  2:16 UTC (permalink / raw)
  To: Masami Hiramatsu
  Cc: Ingo Molnar, linux-kernel, Tom Zanussi, Ravi Bangoria,
	Namhyung Kim, Arnaldo Carvalho de Melo

On Sat,  1 Jun 2019 00:19:17 +0900
Masami Hiramatsu <mhiramat@kernel.org> wrote:

> +static bool trace_uprobe_match_command_head(struct trace_uprobe *tu,
> +					    int argc, const char **argv)
> +{
> +	char buf[MAX_ARGSTR_LEN + 1];
> +	int len;
> +
> +	if (!argc)
> +		return true;
> +
> +	len = strlen(tu->filename);
> +	if (argv[0][len] != ':' || strncmp(tu->filename, argv[0], len))

Hmm, isn't it possible that 'len' can be greater than whatever argv[0] is?

The argv[0][len] looks very dangerous to me.

Perhaps that should be changed to:

	if (!(!strncmp(tu->filename, argv[0], len) && argv[0][len] == ':'))

That way, the test of argv[0][len] will only happen if argv[0] is of length len.

-- Steve


> +		return false;
> +
> +	if (tu->ref_ctr_offset == 0)
> +		snprintf(buf, sizeof(buf), "0x%0*lx",
> +				(int)(sizeof(void *) * 2), tu->offset);
> +	else
> +		snprintf(buf, sizeof(buf), "0x%0*lx(0x%lx)",
> +				(int)(sizeof(void *) * 2), tu->offset,
> +				tu->ref_ctr_offset);
> +	if (strcmp(buf, &argv[0][len + 1]))
> +		return false;
> +
> +	argc--; argv++;
> +
> +	return trace_probe_match_command_args(&tu->tp, argc, argv);
> +}
> +

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

* Re: [PATCH 10/21] tracing/probe: Split trace_event related data from trace_probe
  2019-06-18  1:56   ` Steven Rostedt
@ 2019-06-18 16:14     ` Masami Hiramatsu
  2019-06-18 16:23       ` Steven Rostedt
  0 siblings, 1 reply; 31+ messages in thread
From: Masami Hiramatsu @ 2019-06-18 16:14 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: Ingo Molnar, linux-kernel, Tom Zanussi, Ravi Bangoria,
	Namhyung Kim, Arnaldo Carvalho de Melo

On Mon, 17 Jun 2019 21:56:43 -0400
Steven Rostedt <rostedt@goodmis.org> wrote:

> On Sat,  1 Jun 2019 00:18:16 +0900
> Masami Hiramatsu <mhiramat@kernel.org> wrote:
> 
> > Split the trace_event related data from trace_probe data structure
> > and introduce trace_probe_event data structure for its folder.
> > This trace_probe_event data structure can have multiple trace_probe.
> > 
> > Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
> > ---
> >  kernel/trace/trace_kprobe.c |   99 ++++++++++++++++++++++-------------
> >  kernel/trace/trace_probe.c  |   53 +++++++++++++------
> >  kernel/trace/trace_probe.h  |   48 +++++++++++++----
> >  kernel/trace/trace_uprobe.c |  123 +++++++++++++++++++++++++++++--------------
> >  4 files changed, 221 insertions(+), 102 deletions(-)
> > 
> > diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c
> > index 9d483ad9bb6c..633edb88cd0e 100644
> > --- a/kernel/trace/trace_kprobe.c
> > +++ b/kernel/trace/trace_kprobe.c
> > @@ -180,9 +180,17 @@ unsigned long trace_kprobe_address(struct trace_kprobe *tk)
> >  	return addr;
> >  }
> >  
> > +static nokprobe_inline struct trace_kprobe *
> > +trace_kprobe_primary_from_call(struct trace_event_call *call)
> > +{
> > +	struct trace_probe *tp = trace_probe_primary_from_call(call);
> > +
> > +	return container_of(tp, struct trace_kprobe, tp);
> 
> 
> Hmm, is there a possibility that trace_probe_primary_from_call() may
> not have a primary?

Good question! Of course if given event_call is not a kprobe event,
it doesn't have primary (or any) trace_probe. But that must not happen
unless user misuses it.
And that list never be the empty, when the last trace probe is released,
the event_call also unregistered and released. See unregister_trace_kprobe()
for details. If there is no siblings on the list, the event_call is also
unregistered before unregistering kprobes, and after unregistering kprobes
the list is unlinked.
 (Note that unregister_kprobe() will wait a quiescence period
before return. This means all probe handlers are done before that.)

> > +}
> > +
> >  bool trace_kprobe_on_func_entry(struct trace_event_call *call)
> >  {
> > -	struct trace_kprobe *tk = (struct trace_kprobe *)call->data;
> > +	struct trace_kprobe *tk = trace_kprobe_primary_from_call(call);
> >  
> >  	return kprobe_on_func_entry(tk->rp.kp.addr,
> >  			tk->rp.kp.addr ? NULL : tk->rp.kp.symbol_name,
> > @@ -191,7 +199,7 @@ bool trace_kprobe_on_func_entry(struct trace_event_call *call)
> >  
> >  bool trace_kprobe_error_injectable(struct trace_event_call *call)
> >  {
> > -	struct trace_kprobe *tk = (struct trace_kprobe *)call->data;
> > +	struct trace_kprobe *tk = trace_kprobe_primary_from_call(call);
> >  
> >  	return within_error_injection_list(trace_kprobe_address(tk));
> >  }
> > @@ -295,28 +303,40 @@ static inline int __enable_trace_kprobe(struct trace_kprobe *tk)
> >   * Enable trace_probe
> >   * if the file is NULL, enable "perf" handler, or enable "trace" handler.
> >   */
> > -static int
> > -enable_trace_kprobe(struct trace_kprobe *tk, struct trace_event_file *file)
> > +static int enable_trace_kprobe(struct trace_event_call *call,
> > +				struct trace_event_file *file)
> >  {
> > -	bool enabled = trace_probe_is_enabled(&tk->tp);
> > -	int ret = 0;
> > +	struct trace_probe *pos, *tp = trace_probe_primary_from_call(call);
> > +	struct trace_kprobe *tk;
> > +	bool enabled = trace_probe_is_enabled(tp);
> > +	int ret = 0, ecode;
> >  
> >  	if (file) {
> > -		ret = trace_probe_add_file(&tk->tp, file);
> > +		ret = trace_probe_add_file(tp, file);
> >  		if (ret)
> >  			return ret;
> >  	} else
> > -		trace_probe_set_flag(&tk->tp, TP_FLAG_PROFILE);
> > +		trace_probe_set_flag(tp, TP_FLAG_PROFILE);
> >  
> >  	if (enabled)
> >  		return 0;
> >  
> > -	ret = __enable_trace_kprobe(tk);
> > -	if (ret) {
> > +	enabled = false;
> > +	list_for_each_entry(pos, trace_probe_probe_list(tp), list) {
> > +		tk = container_of(pos, struct trace_kprobe, tp);
> > +		ecode = __enable_trace_kprobe(tk);
> > +		if (ecode)
> > +			ret = ecode;	/* Save the last error code */
> > +		else
> > +			enabled = true;
> 
> So, if we have some enabled but return an error code, what should a
> caller think of that? Wouldn't it be an inconsistent state?

Oops, good catch!
This part is related to caller (ftrace/perf) so should be more careful.
Usually, kprobe enablement should not fail. If one of them has
gone (like a probe on unloaded module), it can be fail but that
should be ignored. I would like to add some additional check so that
- If all kprobes are on the module which is unloaded, enablement
  must be failed and return error.
- If any kprobe is enabled, and others are on non-exist modules,
  it should succeeded and return OK.
- If any kprobe caused an error not because of unloaded module,
  all other enablement should be canceled and return error.

Is that OK for you?

Thank you,

> 
> -- Steve
> 
> 
> > +	}
> > +
> > +	if (!enabled) {
> > +		/* No probe is enabled. Roll back */
> >  		if (file)
> > -			trace_probe_remove_file(&tk->tp, file);
> > +			trace_probe_remove_file(tp, file);
> >  		else
> > -			trace_probe_clear_flag(&tk->tp, TP_FLAG_PROFILE);
> > +			trace_probe_clear_flag(tp, TP_FLAG_PROFILE);
> >  	}
> >  
> >
> 
> 
> > +static inline struct trace_probe_event *
> > +trace_probe_event_from_call(struct trace_event_call *event_call)
> > +{
> > +	return container_of(event_call, struct trace_probe_event, call);
> > +}
> > +
> > +static inline struct trace_probe *
> > +trace_probe_primary_from_call(struct trace_event_call *call)
> > +{
> > +	struct trace_probe_event *tpe = trace_probe_event_from_call(call);
> > +
> > +	return list_first_entry(&tpe->probes, struct trace_probe, list);
> > +}
> > +
> > +static inline struct list_head *trace_probe_probe_list(struct trace_probe *tp)
> > +{
> > +	return &tp->event->probes;
> >  }
> >  


-- 
Masami Hiramatsu <mhiramat@kernel.org>

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

* Re: [PATCH 16/21] tracing/uprobe: Add per-probe delete from event
  2019-06-18  2:16   ` Steven Rostedt
@ 2019-06-18 16:18     ` Masami Hiramatsu
  0 siblings, 0 replies; 31+ messages in thread
From: Masami Hiramatsu @ 2019-06-18 16:18 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: Ingo Molnar, linux-kernel, Tom Zanussi, Ravi Bangoria,
	Namhyung Kim, Arnaldo Carvalho de Melo

On Mon, 17 Jun 2019 22:16:46 -0400
Steven Rostedt <rostedt@goodmis.org> wrote:

> On Sat,  1 Jun 2019 00:19:17 +0900
> Masami Hiramatsu <mhiramat@kernel.org> wrote:
> 
> > +static bool trace_uprobe_match_command_head(struct trace_uprobe *tu,
> > +					    int argc, const char **argv)
> > +{
> > +	char buf[MAX_ARGSTR_LEN + 1];
> > +	int len;
> > +
> > +	if (!argc)
> > +		return true;
> > +
> > +	len = strlen(tu->filename);
> > +	if (argv[0][len] != ':' || strncmp(tu->filename, argv[0], len))
> 
> Hmm, isn't it possible that 'len' can be greater than whatever argv[0] is?
> 
> The argv[0][len] looks very dangerous to me.

Ah, right! it can lead an unexpected memory access! 

> 
> Perhaps that should be changed to:
> 
> 	if (!(!strncmp(tu->filename, argv[0], len) && argv[0][len] == ':'))
> 
> That way, the test of argv[0][len] will only happen if argv[0] is of length len.

OK, I'll take it! Thank you!

> 
> -- Steve
> 
> 
> > +		return false;
> > +
> > +	if (tu->ref_ctr_offset == 0)
> > +		snprintf(buf, sizeof(buf), "0x%0*lx",
> > +				(int)(sizeof(void *) * 2), tu->offset);
> > +	else
> > +		snprintf(buf, sizeof(buf), "0x%0*lx(0x%lx)",
> > +				(int)(sizeof(void *) * 2), tu->offset,
> > +				tu->ref_ctr_offset);
> > +	if (strcmp(buf, &argv[0][len + 1]))
> > +		return false;
> > +
> > +	argc--; argv++;
> > +
> > +	return trace_probe_match_command_args(&tu->tp, argc, argv);
> > +}
> > +


-- 
Masami Hiramatsu <mhiramat@kernel.org>

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

* Re: [PATCH 10/21] tracing/probe: Split trace_event related data from trace_probe
  2019-06-18 16:14     ` Masami Hiramatsu
@ 2019-06-18 16:23       ` Steven Rostedt
  2019-06-18 21:11         ` Steven Rostedt
  2019-06-19  1:11         ` Masami Hiramatsu
  0 siblings, 2 replies; 31+ messages in thread
From: Steven Rostedt @ 2019-06-18 16:23 UTC (permalink / raw)
  To: Masami Hiramatsu
  Cc: Ingo Molnar, linux-kernel, Tom Zanussi, Ravi Bangoria,
	Namhyung Kim, Arnaldo Carvalho de Melo

On Wed, 19 Jun 2019 01:14:09 +0900
Masami Hiramatsu <mhiramat@kernel.org> wrote:

> On Mon, 17 Jun 2019 21:56:43 -0400
> Steven Rostedt <rostedt@goodmis.org> wrote:
> 

> > > +static nokprobe_inline struct trace_kprobe *
> > > +trace_kprobe_primary_from_call(struct trace_event_call *call)
> > > +{
> > > +	struct trace_probe *tp = trace_probe_primary_from_call(call);
> > > +
> > > +	return container_of(tp, struct trace_kprobe, tp);  
> > 
> > 
> > Hmm, is there a possibility that trace_probe_primary_from_call() may
> > not have a primary?  
> 
> Good question! Of course if given event_call is not a kprobe event,
> it doesn't have primary (or any) trace_probe. But that must not happen
> unless user misuses it.
> And that list never be the empty, when the last trace probe is released,
> the event_call also unregistered and released. See unregister_trace_kprobe()
> for details. If there is no siblings on the list, the event_call is also
> unregistered before unregistering kprobes, and after unregistering kprobes
> the list is unlinked.
>  (Note that unregister_kprobe() will wait a quiescence period
> before return. This means all probe handlers are done before that.)

Yeah, I thought something like that. But perhaps the
trace_probe_primary_from_call() code should add a WARN_ON() is the list
is empty.

> 


> > >  
> > > -	ret = __enable_trace_kprobe(tk);
> > > -	if (ret) {
> > > +	enabled = false;
> > > +	list_for_each_entry(pos, trace_probe_probe_list(tp), list) {
> > > +		tk = container_of(pos, struct trace_kprobe, tp);
> > > +		ecode = __enable_trace_kprobe(tk);
> > > +		if (ecode)
> > > +			ret = ecode;	/* Save the last error code */
> > > +		else
> > > +			enabled = true;  
> > 
> > So, if we have some enabled but return an error code, what should a
> > caller think of that? Wouldn't it be an inconsistent state?  
> 
> Oops, good catch!
> This part is related to caller (ftrace/perf) so should be more careful.
> Usually, kprobe enablement should not fail. If one of them has
> gone (like a probe on unloaded module), it can be fail but that
> should be ignored. I would like to add some additional check so that
> - If all kprobes are on the module which is unloaded, enablement
>   must be failed and return error.
> - If any kprobe is enabled, and others are on non-exist modules,
>   it should succeeded and return OK.
> - If any kprobe caused an error not because of unloaded module,
>   all other enablement should be canceled and return error.
> 
> Is that OK for you?
> 

Sounds good to me.

-- Steve

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

* Re: [PATCH 10/21] tracing/probe: Split trace_event related data from trace_probe
  2019-06-18 16:23       ` Steven Rostedt
@ 2019-06-18 21:11         ` Steven Rostedt
  2019-06-19  2:28           ` Masami Hiramatsu
  2019-06-19  1:11         ` Masami Hiramatsu
  1 sibling, 1 reply; 31+ messages in thread
From: Steven Rostedt @ 2019-06-18 21:11 UTC (permalink / raw)
  To: Masami Hiramatsu
  Cc: Ingo Molnar, linux-kernel, Tom Zanussi, Ravi Bangoria,
	Namhyung Kim, Arnaldo Carvalho de Melo

On Tue, 18 Jun 2019 12:23:22 -0400
Steven Rostedt <rostedt@goodmis.org> wrote:

> > Oops, good catch!
> > This part is related to caller (ftrace/perf) so should be more careful.
> > Usually, kprobe enablement should not fail. If one of them has
> > gone (like a probe on unloaded module), it can be fail but that
> > should be ignored. I would like to add some additional check so that
> > - If all kprobes are on the module which is unloaded, enablement
> >   must be failed and return error.
> > - If any kprobe is enabled, and others are on non-exist modules,
> >   it should succeeded and return OK.
> > - If any kprobe caused an error not because of unloaded module,
> >   all other enablement should be canceled and return error.
> > 
> > Is that OK for you?
> >   
> 
> Sounds good to me.

BTW,

I pulled in patches 1-9 and I'm starting to test them now.

-- Steve

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

* Re: [PATCH 10/21] tracing/probe: Split trace_event related data from trace_probe
  2019-06-18 16:23       ` Steven Rostedt
  2019-06-18 21:11         ` Steven Rostedt
@ 2019-06-19  1:11         ` Masami Hiramatsu
  1 sibling, 0 replies; 31+ messages in thread
From: Masami Hiramatsu @ 2019-06-19  1:11 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: Ingo Molnar, linux-kernel, Tom Zanussi, Ravi Bangoria,
	Namhyung Kim, Arnaldo Carvalho de Melo

On Tue, 18 Jun 2019 12:23:22 -0400
Steven Rostedt <rostedt@goodmis.org> wrote:

> On Wed, 19 Jun 2019 01:14:09 +0900
> Masami Hiramatsu <mhiramat@kernel.org> wrote:
> 
> > On Mon, 17 Jun 2019 21:56:43 -0400
> > Steven Rostedt <rostedt@goodmis.org> wrote:
> > 
> 
> > > > +static nokprobe_inline struct trace_kprobe *
> > > > +trace_kprobe_primary_from_call(struct trace_event_call *call)
> > > > +{
> > > > +	struct trace_probe *tp = trace_probe_primary_from_call(call);
> > > > +
> > > > +	return container_of(tp, struct trace_kprobe, tp);  
> > > 
> > > 
> > > Hmm, is there a possibility that trace_probe_primary_from_call() may
> > > not have a primary?  
> > 
> > Good question! Of course if given event_call is not a kprobe event,
> > it doesn't have primary (or any) trace_probe. But that must not happen
> > unless user misuses it.
> > And that list never be the empty, when the last trace probe is released,
> > the event_call also unregistered and released. See unregister_trace_kprobe()
> > for details. If there is no siblings on the list, the event_call is also
> > unregistered before unregistering kprobes, and after unregistering kprobes
> > the list is unlinked.
> >  (Note that unregister_kprobe() will wait a quiescence period
> > before return. This means all probe handlers are done before that.)
> 
> Yeah, I thought something like that. But perhaps the
> trace_probe_primary_from_call() code should add a WARN_ON() is the list
> is empty.

OK, I'll add that, and check in all callers.

> > > >  
> > > > -	ret = __enable_trace_kprobe(tk);
> > > > -	if (ret) {
> > > > +	enabled = false;
> > > > +	list_for_each_entry(pos, trace_probe_probe_list(tp), list) {
> > > > +		tk = container_of(pos, struct trace_kprobe, tp);
> > > > +		ecode = __enable_trace_kprobe(tk);
> > > > +		if (ecode)
> > > > +			ret = ecode;	/* Save the last error code */
> > > > +		else
> > > > +			enabled = true;  
> > > 
> > > So, if we have some enabled but return an error code, what should a
> > > caller think of that? Wouldn't it be an inconsistent state?  
> > 
> > Oops, good catch!
> > This part is related to caller (ftrace/perf) so should be more careful.
> > Usually, kprobe enablement should not fail. If one of them has
> > gone (like a probe on unloaded module), it can be fail but that
> > should be ignored. I would like to add some additional check so that
> > - If all kprobes are on the module which is unloaded, enablement
> >   must be failed and return error.
> > - If any kprobe is enabled, and others are on non-exist modules,
> >   it should succeeded and return OK.
> > - If any kprobe caused an error not because of unloaded module,
> >   all other enablement should be canceled and return error.
> > 
> > Is that OK for you?
> > 
> 
> Sounds good to me.

Thank you!


-- 
Masami Hiramatsu <mhiramat@kernel.org>

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

* Re: [PATCH 10/21] tracing/probe: Split trace_event related data from trace_probe
  2019-06-18 21:11         ` Steven Rostedt
@ 2019-06-19  2:28           ` Masami Hiramatsu
  2019-06-19  9:19             ` Steven Rostedt
  0 siblings, 1 reply; 31+ messages in thread
From: Masami Hiramatsu @ 2019-06-19  2:28 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: Ingo Molnar, linux-kernel, Tom Zanussi, Ravi Bangoria,
	Namhyung Kim, Arnaldo Carvalho de Melo

On Tue, 18 Jun 2019 17:11:15 -0400
Steven Rostedt <rostedt@goodmis.org> wrote:

> On Tue, 18 Jun 2019 12:23:22 -0400
> Steven Rostedt <rostedt@goodmis.org> wrote:
> 
> > > Oops, good catch!
> > > This part is related to caller (ftrace/perf) so should be more careful.
> > > Usually, kprobe enablement should not fail. If one of them has
> > > gone (like a probe on unloaded module), it can be fail but that
> > > should be ignored. I would like to add some additional check so that
> > > - If all kprobes are on the module which is unloaded, enablement
> > >   must be failed and return error.
> > > - If any kprobe is enabled, and others are on non-exist modules,
> > >   it should succeeded and return OK.
> > > - If any kprobe caused an error not because of unloaded module,
> > >   all other enablement should be canceled and return error.
> > > 
> > > Is that OK for you?
> > >   
> > 
> > Sounds good to me.
> 
> BTW,
> 
> I pulled in patches 1-9 and I'm starting to test them now.

Thanks! Should I send 10-21 patches in v2?

Thank you,




-- 
Masami Hiramatsu <mhiramat@kernel.org>

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

* Re: [PATCH 10/21] tracing/probe: Split trace_event related data from trace_probe
  2019-06-19  2:28           ` Masami Hiramatsu
@ 2019-06-19  9:19             ` Steven Rostedt
  0 siblings, 0 replies; 31+ messages in thread
From: Steven Rostedt @ 2019-06-19  9:19 UTC (permalink / raw)
  To: Masami Hiramatsu
  Cc: Ingo Molnar, linux-kernel, Tom Zanussi, Ravi Bangoria,
	Namhyung Kim, Arnaldo Carvalho de Melo

On Wed, 19 Jun 2019 11:28:22 +0900
Masami Hiramatsu <mhiramat@kernel.org> wrote:

> > BTW,
> > 
> > I pulled in patches 1-9 and I'm starting to test them now.  
> 
> Thanks! Should I send 10-21 patches in v2?

Yes please.

The tests have passed, and I will be pushing them to linux-next soon.
But as I'm currently traveling, I can't give an exact time I will do that.

-- Steve

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

end of thread, other threads:[~2019-06-19  9:19 UTC | newest]

Thread overview: 31+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-05-31 15:16 [PATCH 00/21] tracing/probe: Add multi-probes per event support Masami Hiramatsu
2019-05-31 15:16 ` [PATCH 01/21] tracing/kprobe: Set print format right after parsed command Masami Hiramatsu
2019-05-31 15:16 ` [PATCH 02/21] tracing/uprobe: Set print format when parsing command Masami Hiramatsu
2019-05-31 15:17 ` [PATCH 03/21] tracing/probe: Add trace_probe init and free functions Masami Hiramatsu
2019-05-31 15:17 ` [PATCH 04/21] tracing/probe: Add trace_event_call register API for trace_probe Masami Hiramatsu
2019-05-31 15:17 ` [PATCH 05/21] tracing/probe: Add trace_event_file access APIs " Masami Hiramatsu
2019-05-31 15:17 ` [PATCH 06/21] tracing/probe: Add trace flag " Masami Hiramatsu
2019-05-31 15:17 ` [PATCH 07/21] tracing/probe: Add probe event name and group name accesses APIs Masami Hiramatsu
2019-05-31 15:17 ` [PATCH 08/21] tracing/probe: Add trace_event_call " Masami Hiramatsu
2019-05-31 15:18 ` [PATCH 09/21] tracing/kprobe: Check registered state using kprobe Masami Hiramatsu
2019-05-31 15:18 ` [PATCH 10/21] tracing/probe: Split trace_event related data from trace_probe Masami Hiramatsu
2019-06-18  1:56   ` Steven Rostedt
2019-06-18 16:14     ` Masami Hiramatsu
2019-06-18 16:23       ` Steven Rostedt
2019-06-18 21:11         ` Steven Rostedt
2019-06-19  2:28           ` Masami Hiramatsu
2019-06-19  9:19             ` Steven Rostedt
2019-06-19  1:11         ` Masami Hiramatsu
2019-05-31 15:18 ` [PATCH 11/21] tracing/dynevent: Delete all matched events Masami Hiramatsu
2019-05-31 15:18 ` [PATCH 12/21] tracing/dynevent: Pass extra arguments to match operation Masami Hiramatsu
2019-05-31 15:18 ` [PATCH 13/21] tracing/kprobe: Add multi-probe per event support Masami Hiramatsu
2019-05-31 15:18 ` [PATCH 14/21] tracing/uprobe: Add multi-probe per uprobe " Masami Hiramatsu
2019-05-31 15:19 ` [PATCH 15/21] tracing/kprobe: Add per-probe delete from event Masami Hiramatsu
2019-05-31 15:19 ` [PATCH 16/21] tracing/uprobe: " Masami Hiramatsu
2019-06-18  2:16   ` Steven Rostedt
2019-06-18 16:18     ` Masami Hiramatsu
2019-05-31 15:19 ` [PATCH 17/21] tracing/probe: Add immediate parameter support Masami Hiramatsu
2019-05-31 15:19 ` [PATCH 18/21] tracing/probe: Add immediate string " Masami Hiramatsu
2019-05-31 15:19 ` [PATCH 19/21] selftests/ftrace: Add a testcase for kprobe multiprobe event Masami Hiramatsu
2019-05-31 15:19 ` [PATCH 20/21] selftests/ftrace: Add syntax error test for immediates Masami Hiramatsu
2019-05-31 15:20 ` [PATCH 21/21] selftests/ftrace: Add syntax error test for multiprobe Masami Hiramatsu

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.