aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorMasami Hiramatsu <masami.hiramatsu.pt@hitachi.com>2013-05-09 01:44:17 -0400
committerSteven Rostedt <rostedt@goodmis.org>2013-05-09 20:10:22 -0400
commitf04f24fb7e48d446bd89a01c6056571f25972511 (patch)
treeb1d1ecbe88df0eee0309970fd07dc37fb375a440 /kernel
parent7c088b5120ffef017e2ddc38f992277e96436ef6 (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 'kernel')
-rw-r--r--kernel/trace/ftrace.c73
1 files changed, 52 insertions, 21 deletions
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index d85a0ad81a67..827f2fe7bc3f 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -64,6 +64,13 @@
64 64
65#define FL_GLOBAL_CONTROL_MASK (FTRACE_OPS_FL_GLOBAL | FTRACE_OPS_FL_CONTROL) 65#define FL_GLOBAL_CONTROL_MASK (FTRACE_OPS_FL_GLOBAL | FTRACE_OPS_FL_CONTROL)
66 66
67#ifdef CONFIG_DYNAMIC_FTRACE
68#define INIT_REGEX_LOCK(opsname) \
69 .regex_lock = __MUTEX_INITIALIZER(opsname.regex_lock),
70#else
71#define INIT_REGEX_LOCK(opsname)
72#endif
73
67static struct ftrace_ops ftrace_list_end __read_mostly = { 74static struct ftrace_ops ftrace_list_end __read_mostly = {
68 .func = ftrace_stub, 75 .func = ftrace_stub,
69 .flags = FTRACE_OPS_FL_RECURSION_SAFE | FTRACE_OPS_FL_STUB, 76 .flags = FTRACE_OPS_FL_RECURSION_SAFE | FTRACE_OPS_FL_STUB,
@@ -131,6 +138,16 @@ static void ftrace_ops_no_ops(unsigned long ip, unsigned long parent_ip);
131 while (likely(op = rcu_dereference_raw((op)->next)) && \ 138 while (likely(op = rcu_dereference_raw((op)->next)) && \
132 unlikely((op) != &ftrace_list_end)) 139 unlikely((op) != &ftrace_list_end))
133 140
141static inline void ftrace_ops_init(struct ftrace_ops *ops)
142{
143#ifdef CONFIG_DYNAMIC_FTRACE
144 if (!(ops->flags & FTRACE_OPS_FL_INITIALIZED)) {
145 mutex_init(&ops->regex_lock);
146 ops->flags |= FTRACE_OPS_FL_INITIALIZED;
147 }
148#endif
149}
150
134/** 151/**
135 * ftrace_nr_registered_ops - return number of ops registered 152 * ftrace_nr_registered_ops - return number of ops registered
136 * 153 *
@@ -907,7 +924,8 @@ static void unregister_ftrace_profiler(void)
907#else 924#else
908static struct ftrace_ops ftrace_profile_ops __read_mostly = { 925static struct ftrace_ops ftrace_profile_ops __read_mostly = {
909 .func = function_profile_call, 926 .func = function_profile_call,
910 .flags = FTRACE_OPS_FL_RECURSION_SAFE, 927 .flags = FTRACE_OPS_FL_RECURSION_SAFE | FTRACE_OPS_FL_INITIALIZED,
928 INIT_REGEX_LOCK(ftrace_profile_ops)
911}; 929};
912 930
913static int register_ftrace_profiler(void) 931static int register_ftrace_profiler(void)
@@ -1103,11 +1121,10 @@ static struct ftrace_ops global_ops = {
1103 .func = ftrace_stub, 1121 .func = ftrace_stub,
1104 .notrace_hash = EMPTY_HASH, 1122 .notrace_hash = EMPTY_HASH,
1105 .filter_hash = EMPTY_HASH, 1123 .filter_hash = EMPTY_HASH,
1106 .flags = FTRACE_OPS_FL_RECURSION_SAFE, 1124 .flags = FTRACE_OPS_FL_RECURSION_SAFE | FTRACE_OPS_FL_INITIALIZED,
1125 INIT_REGEX_LOCK(global_ops)
1107}; 1126};
1108 1127
1109static DEFINE_MUTEX(ftrace_regex_lock);
1110
1111struct ftrace_page { 1128struct ftrace_page {
1112 struct ftrace_page *next; 1129 struct ftrace_page *next;
1113 struct dyn_ftrace *records; 1130 struct dyn_ftrace *records;
@@ -1247,6 +1264,7 @@ static void free_ftrace_hash_rcu(struct ftrace_hash *hash)
1247 1264
1248void ftrace_free_filter(struct ftrace_ops *ops) 1265void ftrace_free_filter(struct ftrace_ops *ops)
1249{ 1266{
1267 ftrace_ops_init(ops);
1250 free_ftrace_hash(ops->filter_hash); 1268 free_ftrace_hash(ops->filter_hash);
1251 free_ftrace_hash(ops->notrace_hash); 1269 free_ftrace_hash(ops->notrace_hash);
1252} 1270}
@@ -2624,6 +2642,8 @@ ftrace_regex_open(struct ftrace_ops *ops, int flag,
2624 struct ftrace_hash *hash; 2642 struct ftrace_hash *hash;
2625 int ret = 0; 2643 int ret = 0;
2626 2644
2645 ftrace_ops_init(ops);
2646
2627 if (unlikely(ftrace_disabled)) 2647 if (unlikely(ftrace_disabled))
2628 return -ENODEV; 2648 return -ENODEV;
2629 2649
@@ -2656,7 +2676,7 @@ ftrace_regex_open(struct ftrace_ops *ops, int flag,
2656 } 2676 }
2657 } 2677 }
2658 2678
2659 mutex_lock(&ftrace_regex_lock); 2679 mutex_lock(&ops->regex_lock);
2660 2680
2661 if ((file->f_mode & FMODE_WRITE) && 2681 if ((file->f_mode & FMODE_WRITE) &&
2662 (file->f_flags & O_TRUNC)) 2682 (file->f_flags & O_TRUNC))
@@ -2677,7 +2697,7 @@ ftrace_regex_open(struct ftrace_ops *ops, int flag,
2677 } 2697 }
2678 } else 2698 } else
2679 file->private_data = iter; 2699 file->private_data = iter;
2680 mutex_unlock(&ftrace_regex_lock); 2700 mutex_unlock(&ops->regex_lock);
2681 2701
2682 return ret; 2702 return ret;
2683} 2703}
@@ -2910,6 +2930,8 @@ static void function_trace_probe_call(unsigned long ip, unsigned long parent_ip,
2910static struct ftrace_ops trace_probe_ops __read_mostly = 2930static struct ftrace_ops trace_probe_ops __read_mostly =
2911{ 2931{
2912 .func = function_trace_probe_call, 2932 .func = function_trace_probe_call,
2933 .flags = FTRACE_OPS_FL_INITIALIZED,
2934 INIT_REGEX_LOCK(trace_probe_ops)
2913}; 2935};
2914 2936
2915static int ftrace_probe_registered; 2937static int ftrace_probe_registered;
@@ -3256,18 +3278,18 @@ ftrace_regex_write(struct file *file, const char __user *ubuf,
3256 if (!cnt) 3278 if (!cnt)
3257 return 0; 3279 return 0;
3258 3280
3259 mutex_lock(&ftrace_regex_lock);
3260
3261 ret = -ENODEV;
3262 if (unlikely(ftrace_disabled))
3263 goto out_unlock;
3264
3265 if (file->f_mode & FMODE_READ) { 3281 if (file->f_mode & FMODE_READ) {
3266 struct seq_file *m = file->private_data; 3282 struct seq_file *m = file->private_data;
3267 iter = m->private; 3283 iter = m->private;
3268 } else 3284 } else
3269 iter = file->private_data; 3285 iter = file->private_data;
3270 3286
3287 mutex_lock(&iter->ops->regex_lock);
3288
3289 ret = -ENODEV;
3290 if (unlikely(ftrace_disabled))
3291 goto out_unlock;
3292
3271 parser = &iter->parser; 3293 parser = &iter->parser;
3272 read = trace_get_user(parser, ubuf, cnt, ppos); 3294 read = trace_get_user(parser, ubuf, cnt, ppos);
3273 3295
@@ -3282,7 +3304,7 @@ ftrace_regex_write(struct file *file, const char __user *ubuf,
3282 3304
3283 ret = read; 3305 ret = read;
3284out_unlock: 3306out_unlock:
3285 mutex_unlock(&ftrace_regex_lock); 3307 mutex_unlock(&iter->ops->regex_lock);
3286 3308
3287 return ret; 3309 return ret;
3288} 3310}
@@ -3344,7 +3366,7 @@ ftrace_set_hash(struct ftrace_ops *ops, unsigned char *buf, int len,
3344 if (!hash) 3366 if (!hash)
3345 return -ENOMEM; 3367 return -ENOMEM;
3346 3368
3347 mutex_lock(&ftrace_regex_lock); 3369 mutex_lock(&ops->regex_lock);
3348 if (reset) 3370 if (reset)
3349 ftrace_filter_reset(hash); 3371 ftrace_filter_reset(hash);
3350 if (buf && !ftrace_match_records(hash, buf, len)) { 3372 if (buf && !ftrace_match_records(hash, buf, len)) {
@@ -3366,7 +3388,7 @@ ftrace_set_hash(struct ftrace_ops *ops, unsigned char *buf, int len,
3366 mutex_unlock(&ftrace_lock); 3388 mutex_unlock(&ftrace_lock);
3367 3389
3368 out_regex_unlock: 3390 out_regex_unlock:
3369 mutex_unlock(&ftrace_regex_lock); 3391 mutex_unlock(&ops->regex_lock);
3370 3392
3371 free_ftrace_hash(hash); 3393 free_ftrace_hash(hash);
3372 return ret; 3394 return ret;
@@ -3392,6 +3414,7 @@ ftrace_set_addr(struct ftrace_ops *ops, unsigned long ip, int remove,
3392int ftrace_set_filter_ip(struct ftrace_ops *ops, unsigned long ip, 3414int ftrace_set_filter_ip(struct ftrace_ops *ops, unsigned long ip,
3393 int remove, int reset) 3415 int remove, int reset)
3394{ 3416{
3417 ftrace_ops_init(ops);
3395 return ftrace_set_addr(ops, ip, remove, reset, 1); 3418 return ftrace_set_addr(ops, ip, remove, reset, 1);
3396} 3419}
3397EXPORT_SYMBOL_GPL(ftrace_set_filter_ip); 3420EXPORT_SYMBOL_GPL(ftrace_set_filter_ip);
@@ -3416,6 +3439,7 @@ ftrace_set_regex(struct ftrace_ops *ops, unsigned char *buf, int len,
3416int ftrace_set_filter(struct ftrace_ops *ops, unsigned char *buf, 3439int ftrace_set_filter(struct ftrace_ops *ops, unsigned char *buf,
3417 int len, int reset) 3440 int len, int reset)
3418{ 3441{
3442 ftrace_ops_init(ops);
3419 return ftrace_set_regex(ops, buf, len, reset, 1); 3443 return ftrace_set_regex(ops, buf, len, reset, 1);
3420} 3444}
3421EXPORT_SYMBOL_GPL(ftrace_set_filter); 3445EXPORT_SYMBOL_GPL(ftrace_set_filter);
@@ -3434,6 +3458,7 @@ EXPORT_SYMBOL_GPL(ftrace_set_filter);
3434int ftrace_set_notrace(struct ftrace_ops *ops, unsigned char *buf, 3458int ftrace_set_notrace(struct ftrace_ops *ops, unsigned char *buf,
3435 int len, int reset) 3459 int len, int reset)
3436{ 3460{
3461 ftrace_ops_init(ops);
3437 return ftrace_set_regex(ops, buf, len, reset, 0); 3462 return ftrace_set_regex(ops, buf, len, reset, 0);
3438} 3463}
3439EXPORT_SYMBOL_GPL(ftrace_set_notrace); 3464EXPORT_SYMBOL_GPL(ftrace_set_notrace);
@@ -3524,6 +3549,8 @@ ftrace_set_early_filter(struct ftrace_ops *ops, char *buf, int enable)
3524{ 3549{
3525 char *func; 3550 char *func;
3526 3551
3552 ftrace_ops_init(ops);
3553
3527 while (buf) { 3554 while (buf) {
3528 func = strsep(&buf, ","); 3555 func = strsep(&buf, ",");
3529 ftrace_set_regex(ops, func, strlen(func), 0, enable); 3556 ftrace_set_regex(ops, func, strlen(func), 0, enable);
@@ -3551,14 +3578,14 @@ int ftrace_regex_release(struct inode *inode, struct file *file)
3551 int filter_hash; 3578 int filter_hash;
3552 int ret; 3579 int ret;
3553 3580
3554 mutex_lock(&ftrace_regex_lock);
3555 if (file->f_mode & FMODE_READ) { 3581 if (file->f_mode & FMODE_READ) {
3556 iter = m->private; 3582 iter = m->private;
3557
3558 seq_release(inode, file); 3583 seq_release(inode, file);
3559 } else 3584 } else
3560 iter = file->private_data; 3585 iter = file->private_data;
3561 3586
3587 mutex_lock(&iter->ops->regex_lock);
3588
3562 parser = &iter->parser; 3589 parser = &iter->parser;
3563 if (trace_parser_loaded(parser)) { 3590 if (trace_parser_loaded(parser)) {
3564 parser->buffer[parser->idx] = 0; 3591 parser->buffer[parser->idx] = 0;
@@ -3587,7 +3614,7 @@ int ftrace_regex_release(struct inode *inode, struct file *file)
3587 free_ftrace_hash(iter->hash); 3614 free_ftrace_hash(iter->hash);
3588 kfree(iter); 3615 kfree(iter);
3589 3616
3590 mutex_unlock(&ftrace_regex_lock); 3617 mutex_unlock(&iter->ops->regex_lock);
3591 return 0; 3618 return 0;
3592} 3619}
3593 3620
@@ -4126,7 +4153,8 @@ void __init ftrace_init(void)
4126 4153
4127static struct ftrace_ops global_ops = { 4154static struct ftrace_ops global_ops = {
4128 .func = ftrace_stub, 4155 .func = ftrace_stub,
4129 .flags = FTRACE_OPS_FL_RECURSION_SAFE, 4156 .flags = FTRACE_OPS_FL_RECURSION_SAFE | FTRACE_OPS_FL_INITIALIZED,
4157 INIT_REGEX_LOCK(global_ops)
4130}; 4158};
4131 4159
4132static int __init ftrace_nodyn_init(void) 4160static int __init ftrace_nodyn_init(void)
@@ -4180,8 +4208,9 @@ ftrace_ops_control_func(unsigned long ip, unsigned long parent_ip,
4180} 4208}
4181 4209
4182static struct ftrace_ops control_ops = { 4210static struct ftrace_ops control_ops = {
4183 .func = ftrace_ops_control_func, 4211 .func = ftrace_ops_control_func,
4184 .flags = FTRACE_OPS_FL_RECURSION_SAFE, 4212 .flags = FTRACE_OPS_FL_RECURSION_SAFE | FTRACE_OPS_FL_INITIALIZED,
4213 INIT_REGEX_LOCK(control_ops)
4185}; 4214};
4186 4215
4187static inline void 4216static inline void
@@ -4539,6 +4568,8 @@ int register_ftrace_function(struct ftrace_ops *ops)
4539{ 4568{
4540 int ret = -1; 4569 int ret = -1;
4541 4570
4571 ftrace_ops_init(ops);
4572
4542 mutex_lock(&ftrace_lock); 4573 mutex_lock(&ftrace_lock);
4543 4574
4544 ret = __register_ftrace_function(ops); 4575 ret = __register_ftrace_function(ops);