diff options
author | Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> | 2013-05-09 01:44:21 -0400 |
---|---|---|
committer | Steven Rostedt <rostedt@goodmis.org> | 2013-05-09 20:11:48 -0400 |
commit | 3f2367ba7cbf13ec0f3f1e93b833a7eacd1ab4b8 (patch) | |
tree | 81bac89b0b20458cb8505a3bdef4b9189ff4057e /kernel/trace | |
parent | f04f24fb7e48d446bd89a01c6056571f25972511 (diff) |
ftrace: Cleanup regex_lock and ftrace_lock around hash updating
Cleanup regex_lock and ftrace_lock locking points around
ftrace_ops hash update code.
The new rule is that regex_lock protects ops->*_hash
read-update-write code for each ftrace_ops. Usually,
hash update is done by following sequence.
1. allocate a new local hash and copy the original hash.
2. update the local hash.
3. move(actually, copy) back the local hash to ftrace_ops.
4. update ftrace entries if needed.
5. release the local hash.
This makes regex_lock protect #1-#4, and ftrace_lock
to protect #3, #4 and adding and removing ftrace_ops from the
ftrace_ops_list. The ftrace_lock protects #3 as well because
the move functions update the entries too.
Link: http://lkml.kernel.org/r/20130509054421.30398.83411.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>
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
Diffstat (limited to 'kernel/trace')
-rw-r--r-- | kernel/trace/ftrace.c | 59 |
1 files changed, 32 insertions, 27 deletions
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 827f2fe7bc3f..cacf0856191e 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c | |||
@@ -2656,28 +2656,26 @@ ftrace_regex_open(struct ftrace_ops *ops, int flag, | |||
2656 | return -ENOMEM; | 2656 | return -ENOMEM; |
2657 | } | 2657 | } |
2658 | 2658 | ||
2659 | iter->ops = ops; | ||
2660 | iter->flags = flag; | ||
2661 | |||
2662 | mutex_lock(&ops->regex_lock); | ||
2663 | |||
2659 | if (flag & FTRACE_ITER_NOTRACE) | 2664 | if (flag & FTRACE_ITER_NOTRACE) |
2660 | hash = ops->notrace_hash; | 2665 | hash = ops->notrace_hash; |
2661 | else | 2666 | else |
2662 | hash = ops->filter_hash; | 2667 | hash = ops->filter_hash; |
2663 | 2668 | ||
2664 | iter->ops = ops; | ||
2665 | iter->flags = flag; | ||
2666 | |||
2667 | if (file->f_mode & FMODE_WRITE) { | 2669 | if (file->f_mode & FMODE_WRITE) { |
2668 | mutex_lock(&ftrace_lock); | ||
2669 | iter->hash = alloc_and_copy_ftrace_hash(FTRACE_HASH_DEFAULT_BITS, hash); | 2670 | iter->hash = alloc_and_copy_ftrace_hash(FTRACE_HASH_DEFAULT_BITS, hash); |
2670 | mutex_unlock(&ftrace_lock); | ||
2671 | |||
2672 | if (!iter->hash) { | 2671 | if (!iter->hash) { |
2673 | trace_parser_put(&iter->parser); | 2672 | trace_parser_put(&iter->parser); |
2674 | kfree(iter); | 2673 | kfree(iter); |
2675 | return -ENOMEM; | 2674 | ret = -ENOMEM; |
2675 | goto out_unlock; | ||
2676 | } | 2676 | } |
2677 | } | 2677 | } |
2678 | 2678 | ||
2679 | mutex_lock(&ops->regex_lock); | ||
2680 | |||
2681 | if ((file->f_mode & FMODE_WRITE) && | 2679 | if ((file->f_mode & FMODE_WRITE) && |
2682 | (file->f_flags & O_TRUNC)) | 2680 | (file->f_flags & O_TRUNC)) |
2683 | ftrace_filter_reset(iter->hash); | 2681 | ftrace_filter_reset(iter->hash); |
@@ -2697,6 +2695,8 @@ ftrace_regex_open(struct ftrace_ops *ops, int flag, | |||
2697 | } | 2695 | } |
2698 | } else | 2696 | } else |
2699 | file->private_data = iter; | 2697 | file->private_data = iter; |
2698 | |||
2699 | out_unlock: | ||
2700 | mutex_unlock(&ops->regex_lock); | 2700 | mutex_unlock(&ops->regex_lock); |
2701 | 2701 | ||
2702 | return ret; | 2702 | return ret; |
@@ -3012,7 +3012,7 @@ register_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops, | |||
3012 | if (WARN_ON(not)) | 3012 | if (WARN_ON(not)) |
3013 | return -EINVAL; | 3013 | return -EINVAL; |
3014 | 3014 | ||
3015 | mutex_lock(&ftrace_lock); | 3015 | mutex_lock(&trace_probe_ops.regex_lock); |
3016 | 3016 | ||
3017 | hash = alloc_and_copy_ftrace_hash(FTRACE_HASH_DEFAULT_BITS, *orig_hash); | 3017 | hash = alloc_and_copy_ftrace_hash(FTRACE_HASH_DEFAULT_BITS, *orig_hash); |
3018 | if (!hash) { | 3018 | if (!hash) { |
@@ -3070,14 +3070,16 @@ register_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops, | |||
3070 | 3070 | ||
3071 | } while_for_each_ftrace_rec(); | 3071 | } while_for_each_ftrace_rec(); |
3072 | 3072 | ||
3073 | mutex_lock(&ftrace_lock); | ||
3073 | ret = ftrace_hash_move(&trace_probe_ops, 1, orig_hash, hash); | 3074 | ret = ftrace_hash_move(&trace_probe_ops, 1, orig_hash, hash); |
3074 | if (ret < 0) | 3075 | if (ret < 0) |
3075 | count = ret; | 3076 | count = ret; |
3076 | 3077 | ||
3077 | __enable_ftrace_function_probe(); | 3078 | __enable_ftrace_function_probe(); |
3079 | mutex_unlock(&ftrace_lock); | ||
3078 | 3080 | ||
3079 | out_unlock: | 3081 | out_unlock: |
3080 | mutex_unlock(&ftrace_lock); | 3082 | mutex_unlock(&trace_probe_ops.regex_lock); |
3081 | free_ftrace_hash(hash); | 3083 | free_ftrace_hash(hash); |
3082 | 3084 | ||
3083 | return count; | 3085 | return count; |
@@ -3117,7 +3119,7 @@ __unregister_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops, | |||
3117 | return; | 3119 | return; |
3118 | } | 3120 | } |
3119 | 3121 | ||
3120 | mutex_lock(&ftrace_lock); | 3122 | mutex_lock(&trace_probe_ops.regex_lock); |
3121 | 3123 | ||
3122 | hash = alloc_and_copy_ftrace_hash(FTRACE_HASH_DEFAULT_BITS, *orig_hash); | 3124 | hash = alloc_and_copy_ftrace_hash(FTRACE_HASH_DEFAULT_BITS, *orig_hash); |
3123 | if (!hash) | 3125 | if (!hash) |
@@ -3155,6 +3157,7 @@ __unregister_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops, | |||
3155 | list_add(&entry->free_list, &free_list); | 3157 | list_add(&entry->free_list, &free_list); |
3156 | } | 3158 | } |
3157 | } | 3159 | } |
3160 | mutex_lock(&ftrace_lock); | ||
3158 | __disable_ftrace_function_probe(); | 3161 | __disable_ftrace_function_probe(); |
3159 | /* | 3162 | /* |
3160 | * Remove after the disable is called. Otherwise, if the last | 3163 | * Remove after the disable is called. Otherwise, if the last |
@@ -3166,9 +3169,10 @@ __unregister_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops, | |||
3166 | list_del(&entry->free_list); | 3169 | list_del(&entry->free_list); |
3167 | ftrace_free_entry(entry); | 3170 | ftrace_free_entry(entry); |
3168 | } | 3171 | } |
3172 | mutex_unlock(&ftrace_lock); | ||
3169 | 3173 | ||
3170 | out_unlock: | 3174 | out_unlock: |
3171 | mutex_unlock(&ftrace_lock); | 3175 | mutex_unlock(&trace_probe_ops.regex_lock); |
3172 | free_ftrace_hash(hash); | 3176 | free_ftrace_hash(hash); |
3173 | } | 3177 | } |
3174 | 3178 | ||
@@ -3284,11 +3288,10 @@ ftrace_regex_write(struct file *file, const char __user *ubuf, | |||
3284 | } else | 3288 | } else |
3285 | iter = file->private_data; | 3289 | iter = file->private_data; |
3286 | 3290 | ||
3287 | mutex_lock(&iter->ops->regex_lock); | ||
3288 | |||
3289 | ret = -ENODEV; | ||
3290 | if (unlikely(ftrace_disabled)) | 3291 | if (unlikely(ftrace_disabled)) |
3291 | goto out_unlock; | 3292 | return -ENODEV; |
3293 | |||
3294 | /* iter->hash is a local copy, so we don't need regex_lock */ | ||
3292 | 3295 | ||
3293 | parser = &iter->parser; | 3296 | parser = &iter->parser; |
3294 | read = trace_get_user(parser, ubuf, cnt, ppos); | 3297 | read = trace_get_user(parser, ubuf, cnt, ppos); |
@@ -3299,13 +3302,11 @@ ftrace_regex_write(struct file *file, const char __user *ubuf, | |||
3299 | parser->idx, enable); | 3302 | parser->idx, enable); |
3300 | trace_parser_clear(parser); | 3303 | trace_parser_clear(parser); |
3301 | if (ret < 0) | 3304 | if (ret < 0) |
3302 | goto out_unlock; | 3305 | goto out; |
3303 | } | 3306 | } |
3304 | 3307 | ||
3305 | ret = read; | 3308 | ret = read; |
3306 | out_unlock: | 3309 | out: |
3307 | mutex_unlock(&iter->ops->regex_lock); | ||
3308 | |||
3309 | return ret; | 3310 | return ret; |
3310 | } | 3311 | } |
3311 | 3312 | ||
@@ -3357,16 +3358,19 @@ ftrace_set_hash(struct ftrace_ops *ops, unsigned char *buf, int len, | |||
3357 | if (unlikely(ftrace_disabled)) | 3358 | if (unlikely(ftrace_disabled)) |
3358 | return -ENODEV; | 3359 | return -ENODEV; |
3359 | 3360 | ||
3361 | mutex_lock(&ops->regex_lock); | ||
3362 | |||
3360 | if (enable) | 3363 | if (enable) |
3361 | orig_hash = &ops->filter_hash; | 3364 | orig_hash = &ops->filter_hash; |
3362 | else | 3365 | else |
3363 | orig_hash = &ops->notrace_hash; | 3366 | orig_hash = &ops->notrace_hash; |
3364 | 3367 | ||
3365 | hash = alloc_and_copy_ftrace_hash(FTRACE_HASH_DEFAULT_BITS, *orig_hash); | 3368 | hash = alloc_and_copy_ftrace_hash(FTRACE_HASH_DEFAULT_BITS, *orig_hash); |
3366 | if (!hash) | 3369 | if (!hash) { |
3367 | return -ENOMEM; | 3370 | ret = -ENOMEM; |
3371 | goto out_regex_unlock; | ||
3372 | } | ||
3368 | 3373 | ||
3369 | mutex_lock(&ops->regex_lock); | ||
3370 | if (reset) | 3374 | if (reset) |
3371 | ftrace_filter_reset(hash); | 3375 | ftrace_filter_reset(hash); |
3372 | if (buf && !ftrace_match_records(hash, buf, len)) { | 3376 | if (buf && !ftrace_match_records(hash, buf, len)) { |
@@ -3584,8 +3588,6 @@ int ftrace_regex_release(struct inode *inode, struct file *file) | |||
3584 | } else | 3588 | } else |
3585 | iter = file->private_data; | 3589 | iter = file->private_data; |
3586 | 3590 | ||
3587 | mutex_lock(&iter->ops->regex_lock); | ||
3588 | |||
3589 | parser = &iter->parser; | 3591 | parser = &iter->parser; |
3590 | if (trace_parser_loaded(parser)) { | 3592 | if (trace_parser_loaded(parser)) { |
3591 | parser->buffer[parser->idx] = 0; | 3593 | parser->buffer[parser->idx] = 0; |
@@ -3594,6 +3596,8 @@ int ftrace_regex_release(struct inode *inode, struct file *file) | |||
3594 | 3596 | ||
3595 | trace_parser_put(parser); | 3597 | trace_parser_put(parser); |
3596 | 3598 | ||
3599 | mutex_lock(&iter->ops->regex_lock); | ||
3600 | |||
3597 | if (file->f_mode & FMODE_WRITE) { | 3601 | if (file->f_mode & FMODE_WRITE) { |
3598 | filter_hash = !!(iter->flags & FTRACE_ITER_FILTER); | 3602 | filter_hash = !!(iter->flags & FTRACE_ITER_FILTER); |
3599 | 3603 | ||
@@ -3611,10 +3615,11 @@ int ftrace_regex_release(struct inode *inode, struct file *file) | |||
3611 | 3615 | ||
3612 | mutex_unlock(&ftrace_lock); | 3616 | mutex_unlock(&ftrace_lock); |
3613 | } | 3617 | } |
3618 | |||
3619 | mutex_unlock(&iter->ops->regex_lock); | ||
3614 | free_ftrace_hash(iter->hash); | 3620 | free_ftrace_hash(iter->hash); |
3615 | kfree(iter); | 3621 | kfree(iter); |
3616 | 3622 | ||
3617 | mutex_unlock(&iter->ops->regex_lock); | ||
3618 | return 0; | 3623 | return 0; |
3619 | } | 3624 | } |
3620 | 3625 | ||