diff options
author | Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> | 2013-05-09 01:44:17 -0400 |
---|---|---|
committer | Steven Rostedt <rostedt@goodmis.org> | 2013-05-09 20:10:22 -0400 |
commit | f04f24fb7e48d446bd89a01c6056571f25972511 (patch) | |
tree | b1d1ecbe88df0eee0309970fd07dc37fb375a440 /include/linux/ftrace.h | |
parent | 7c088b5120ffef017e2ddc38f992277e96436ef6 (diff) |
ftrace, kprobes: Fix a deadlock on ftrace_regex_lock
Fix a deadlock on ftrace_regex_lock which happens when setting
an enable_event trigger on dynamic kprobe event as below.
----
sh-2.05b# echo p vfs_symlink > kprobe_events
sh-2.05b# echo vfs_symlink:enable_event:kprobes:p_vfs_symlink_0 > set_ftrace_filter
=============================================
[ INFO: possible recursive locking detected ]
3.9.0+ #35 Not tainted
---------------------------------------------
sh/72 is trying to acquire lock:
(ftrace_regex_lock){+.+.+.}, at: [<ffffffff810ba6c1>] ftrace_set_hash+0x81/0x1f0
but task is already holding lock:
(ftrace_regex_lock){+.+.+.}, at: [<ffffffff810b7cbd>] ftrace_regex_write.isra.29.part.30+0x3d/0x220
other info that might help us debug this:
Possible unsafe locking scenario:
CPU0
----
lock(ftrace_regex_lock);
lock(ftrace_regex_lock);
*** DEADLOCK ***
----
To fix that, this introduces a finer regex_lock for each ftrace_ops.
ftrace_regex_lock is too big of a lock which protects all
filter/notrace_hash operations, but it doesn't need to be a global
lock after supporting multiple ftrace_ops because each ftrace_ops
has its own filter/notrace_hash.
Link: http://lkml.kernel.org/r/20130509054417.30398.84254.stgit@mhiramat-M0-7522
Cc: Srikar Dronamraju <srikar@linux.vnet.ibm.com>
Cc: Oleg Nesterov <oleg@redhat.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Tom Zanussi <tom.zanussi@intel.com>
Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
[ Added initialization flag and automate mutex initialization for
non ftrace.c ftrace_probes. ]
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
Diffstat (limited to 'include/linux/ftrace.h')
-rw-r--r-- | include/linux/ftrace.h | 4 |
1 files changed, 4 insertions, 0 deletions
diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h index f83e17a40e8b..99d0fbcbaf79 100644 --- a/include/linux/ftrace.h +++ b/include/linux/ftrace.h | |||
@@ -90,6 +90,8 @@ typedef void (*ftrace_func_t)(unsigned long ip, unsigned long parent_ip, | |||
90 | * not set this, then the ftrace infrastructure will add recursion | 90 | * not set this, then the ftrace infrastructure will add recursion |
91 | * protection for the caller. | 91 | * protection for the caller. |
92 | * STUB - The ftrace_ops is just a place holder. | 92 | * STUB - The ftrace_ops is just a place holder. |
93 | * INITIALIZED - The ftrace_ops has already been initialized (first use time | ||
94 | * register_ftrace_function() is called, it will initialized the ops) | ||
93 | */ | 95 | */ |
94 | enum { | 96 | enum { |
95 | FTRACE_OPS_FL_ENABLED = 1 << 0, | 97 | FTRACE_OPS_FL_ENABLED = 1 << 0, |
@@ -100,6 +102,7 @@ enum { | |||
100 | FTRACE_OPS_FL_SAVE_REGS_IF_SUPPORTED = 1 << 5, | 102 | FTRACE_OPS_FL_SAVE_REGS_IF_SUPPORTED = 1 << 5, |
101 | FTRACE_OPS_FL_RECURSION_SAFE = 1 << 6, | 103 | FTRACE_OPS_FL_RECURSION_SAFE = 1 << 6, |
102 | FTRACE_OPS_FL_STUB = 1 << 7, | 104 | FTRACE_OPS_FL_STUB = 1 << 7, |
105 | FTRACE_OPS_FL_INITIALIZED = 1 << 8, | ||
103 | }; | 106 | }; |
104 | 107 | ||
105 | struct ftrace_ops { | 108 | struct ftrace_ops { |
@@ -110,6 +113,7 @@ struct ftrace_ops { | |||
110 | #ifdef CONFIG_DYNAMIC_FTRACE | 113 | #ifdef CONFIG_DYNAMIC_FTRACE |
111 | struct ftrace_hash *notrace_hash; | 114 | struct ftrace_hash *notrace_hash; |
112 | struct ftrace_hash *filter_hash; | 115 | struct ftrace_hash *filter_hash; |
116 | struct mutex regex_lock; | ||
113 | #endif | 117 | #endif |
114 | }; | 118 | }; |
115 | 119 | ||