diff options
Diffstat (limited to 'kernel/trace/ftrace.c')
| -rw-r--r-- | kernel/trace/ftrace.c | 55 |
1 files changed, 46 insertions, 9 deletions
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 929a733d302e..45e5cb143d17 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c | |||
| @@ -2497,12 +2497,14 @@ static void ftrace_run_update_code(int command) | |||
| 2497 | } | 2497 | } |
| 2498 | 2498 | ||
| 2499 | static void ftrace_run_modify_code(struct ftrace_ops *ops, int command, | 2499 | static void ftrace_run_modify_code(struct ftrace_ops *ops, int command, |
| 2500 | struct ftrace_hash *old_hash) | 2500 | struct ftrace_ops_hash *old_hash) |
| 2501 | { | 2501 | { |
| 2502 | ops->flags |= FTRACE_OPS_FL_MODIFYING; | 2502 | ops->flags |= FTRACE_OPS_FL_MODIFYING; |
| 2503 | ops->old_hash.filter_hash = old_hash; | 2503 | ops->old_hash.filter_hash = old_hash->filter_hash; |
| 2504 | ops->old_hash.notrace_hash = old_hash->notrace_hash; | ||
| 2504 | ftrace_run_update_code(command); | 2505 | ftrace_run_update_code(command); |
| 2505 | ops->old_hash.filter_hash = NULL; | 2506 | ops->old_hash.filter_hash = NULL; |
| 2507 | ops->old_hash.notrace_hash = NULL; | ||
| 2506 | ops->flags &= ~FTRACE_OPS_FL_MODIFYING; | 2508 | ops->flags &= ~FTRACE_OPS_FL_MODIFYING; |
| 2507 | } | 2509 | } |
| 2508 | 2510 | ||
| @@ -3579,7 +3581,7 @@ static struct ftrace_ops trace_probe_ops __read_mostly = | |||
| 3579 | 3581 | ||
| 3580 | static int ftrace_probe_registered; | 3582 | static int ftrace_probe_registered; |
| 3581 | 3583 | ||
| 3582 | static void __enable_ftrace_function_probe(struct ftrace_hash *old_hash) | 3584 | static void __enable_ftrace_function_probe(struct ftrace_ops_hash *old_hash) |
| 3583 | { | 3585 | { |
| 3584 | int ret; | 3586 | int ret; |
| 3585 | int i; | 3587 | int i; |
| @@ -3637,6 +3639,7 @@ int | |||
| 3637 | register_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops, | 3639 | register_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops, |
| 3638 | void *data) | 3640 | void *data) |
| 3639 | { | 3641 | { |
| 3642 | struct ftrace_ops_hash old_hash_ops; | ||
| 3640 | struct ftrace_func_probe *entry; | 3643 | struct ftrace_func_probe *entry; |
| 3641 | struct ftrace_hash **orig_hash = &trace_probe_ops.func_hash->filter_hash; | 3644 | struct ftrace_hash **orig_hash = &trace_probe_ops.func_hash->filter_hash; |
| 3642 | struct ftrace_hash *old_hash = *orig_hash; | 3645 | struct ftrace_hash *old_hash = *orig_hash; |
| @@ -3658,6 +3661,10 @@ register_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops, | |||
| 3658 | 3661 | ||
| 3659 | mutex_lock(&trace_probe_ops.func_hash->regex_lock); | 3662 | mutex_lock(&trace_probe_ops.func_hash->regex_lock); |
| 3660 | 3663 | ||
| 3664 | old_hash_ops.filter_hash = old_hash; | ||
| 3665 | /* Probes only have filters */ | ||
| 3666 | old_hash_ops.notrace_hash = NULL; | ||
| 3667 | |||
| 3661 | hash = alloc_and_copy_ftrace_hash(FTRACE_HASH_DEFAULT_BITS, old_hash); | 3668 | hash = alloc_and_copy_ftrace_hash(FTRACE_HASH_DEFAULT_BITS, old_hash); |
| 3662 | if (!hash) { | 3669 | if (!hash) { |
| 3663 | count = -ENOMEM; | 3670 | count = -ENOMEM; |
| @@ -3718,7 +3725,7 @@ register_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops, | |||
| 3718 | 3725 | ||
| 3719 | ret = ftrace_hash_move(&trace_probe_ops, 1, orig_hash, hash); | 3726 | ret = ftrace_hash_move(&trace_probe_ops, 1, orig_hash, hash); |
| 3720 | 3727 | ||
| 3721 | __enable_ftrace_function_probe(old_hash); | 3728 | __enable_ftrace_function_probe(&old_hash_ops); |
| 3722 | 3729 | ||
| 3723 | if (!ret) | 3730 | if (!ret) |
| 3724 | free_ftrace_hash_rcu(old_hash); | 3731 | free_ftrace_hash_rcu(old_hash); |
| @@ -4006,10 +4013,34 @@ ftrace_match_addr(struct ftrace_hash *hash, unsigned long ip, int remove) | |||
| 4006 | } | 4013 | } |
| 4007 | 4014 | ||
| 4008 | static void ftrace_ops_update_code(struct ftrace_ops *ops, | 4015 | static void ftrace_ops_update_code(struct ftrace_ops *ops, |
| 4009 | struct ftrace_hash *old_hash) | 4016 | struct ftrace_ops_hash *old_hash) |
| 4010 | { | 4017 | { |
| 4011 | if (ops->flags & FTRACE_OPS_FL_ENABLED && ftrace_enabled) | 4018 | struct ftrace_ops *op; |
| 4019 | |||
| 4020 | if (!ftrace_enabled) | ||
| 4021 | return; | ||
| 4022 | |||
| 4023 | if (ops->flags & FTRACE_OPS_FL_ENABLED) { | ||
| 4012 | ftrace_run_modify_code(ops, FTRACE_UPDATE_CALLS, old_hash); | 4024 | ftrace_run_modify_code(ops, FTRACE_UPDATE_CALLS, old_hash); |
| 4025 | return; | ||
| 4026 | } | ||
| 4027 | |||
| 4028 | /* | ||
| 4029 | * If this is the shared global_ops filter, then we need to | ||
| 4030 | * check if there is another ops that shares it, is enabled. | ||
| 4031 | * If so, we still need to run the modify code. | ||
| 4032 | */ | ||
| 4033 | if (ops->func_hash != &global_ops.local_hash) | ||
| 4034 | return; | ||
| 4035 | |||
| 4036 | do_for_each_ftrace_op(op, ftrace_ops_list) { | ||
| 4037 | if (op->func_hash == &global_ops.local_hash && | ||
| 4038 | op->flags & FTRACE_OPS_FL_ENABLED) { | ||
| 4039 | ftrace_run_modify_code(op, FTRACE_UPDATE_CALLS, old_hash); | ||
| 4040 | /* Only need to do this once */ | ||
| 4041 | return; | ||
| 4042 | } | ||
| 4043 | } while_for_each_ftrace_op(op); | ||
| 4013 | } | 4044 | } |
| 4014 | 4045 | ||
| 4015 | static int | 4046 | static int |
| @@ -4017,6 +4048,7 @@ ftrace_set_hash(struct ftrace_ops *ops, unsigned char *buf, int len, | |||
| 4017 | unsigned long ip, int remove, int reset, int enable) | 4048 | unsigned long ip, int remove, int reset, int enable) |
| 4018 | { | 4049 | { |
| 4019 | struct ftrace_hash **orig_hash; | 4050 | struct ftrace_hash **orig_hash; |
| 4051 | struct ftrace_ops_hash old_hash_ops; | ||
| 4020 | struct ftrace_hash *old_hash; | 4052 | struct ftrace_hash *old_hash; |
| 4021 | struct ftrace_hash *hash; | 4053 | struct ftrace_hash *hash; |
| 4022 | int ret; | 4054 | int ret; |
| @@ -4053,9 +4085,11 @@ ftrace_set_hash(struct ftrace_ops *ops, unsigned char *buf, int len, | |||
| 4053 | 4085 | ||
| 4054 | mutex_lock(&ftrace_lock); | 4086 | mutex_lock(&ftrace_lock); |
| 4055 | old_hash = *orig_hash; | 4087 | old_hash = *orig_hash; |
| 4088 | old_hash_ops.filter_hash = ops->func_hash->filter_hash; | ||
| 4089 | old_hash_ops.notrace_hash = ops->func_hash->notrace_hash; | ||
| 4056 | ret = ftrace_hash_move(ops, enable, orig_hash, hash); | 4090 | ret = ftrace_hash_move(ops, enable, orig_hash, hash); |
| 4057 | if (!ret) { | 4091 | if (!ret) { |
| 4058 | ftrace_ops_update_code(ops, old_hash); | 4092 | ftrace_ops_update_code(ops, &old_hash_ops); |
| 4059 | free_ftrace_hash_rcu(old_hash); | 4093 | free_ftrace_hash_rcu(old_hash); |
| 4060 | } | 4094 | } |
| 4061 | mutex_unlock(&ftrace_lock); | 4095 | mutex_unlock(&ftrace_lock); |
| @@ -4267,6 +4301,7 @@ static void __init set_ftrace_early_filters(void) | |||
| 4267 | int ftrace_regex_release(struct inode *inode, struct file *file) | 4301 | int ftrace_regex_release(struct inode *inode, struct file *file) |
| 4268 | { | 4302 | { |
| 4269 | struct seq_file *m = (struct seq_file *)file->private_data; | 4303 | struct seq_file *m = (struct seq_file *)file->private_data; |
| 4304 | struct ftrace_ops_hash old_hash_ops; | ||
| 4270 | struct ftrace_iterator *iter; | 4305 | struct ftrace_iterator *iter; |
| 4271 | struct ftrace_hash **orig_hash; | 4306 | struct ftrace_hash **orig_hash; |
| 4272 | struct ftrace_hash *old_hash; | 4307 | struct ftrace_hash *old_hash; |
| @@ -4300,10 +4335,12 @@ int ftrace_regex_release(struct inode *inode, struct file *file) | |||
| 4300 | 4335 | ||
| 4301 | mutex_lock(&ftrace_lock); | 4336 | mutex_lock(&ftrace_lock); |
| 4302 | old_hash = *orig_hash; | 4337 | old_hash = *orig_hash; |
| 4338 | old_hash_ops.filter_hash = iter->ops->func_hash->filter_hash; | ||
| 4339 | old_hash_ops.notrace_hash = iter->ops->func_hash->notrace_hash; | ||
| 4303 | ret = ftrace_hash_move(iter->ops, filter_hash, | 4340 | ret = ftrace_hash_move(iter->ops, filter_hash, |
| 4304 | orig_hash, iter->hash); | 4341 | orig_hash, iter->hash); |
| 4305 | if (!ret) { | 4342 | if (!ret) { |
| 4306 | ftrace_ops_update_code(iter->ops, old_hash); | 4343 | ftrace_ops_update_code(iter->ops, &old_hash_ops); |
| 4307 | free_ftrace_hash_rcu(old_hash); | 4344 | free_ftrace_hash_rcu(old_hash); |
| 4308 | } | 4345 | } |
| 4309 | mutex_unlock(&ftrace_lock); | 4346 | mutex_unlock(&ftrace_lock); |
| @@ -5419,7 +5456,7 @@ static __init int ftrace_init_debugfs(void) | |||
| 5419 | struct dentry *d_tracer; | 5456 | struct dentry *d_tracer; |
| 5420 | 5457 | ||
| 5421 | d_tracer = tracing_init_dentry(); | 5458 | d_tracer = tracing_init_dentry(); |
| 5422 | if (!d_tracer) | 5459 | if (IS_ERR(d_tracer)) |
| 5423 | return 0; | 5460 | return 0; |
| 5424 | 5461 | ||
| 5425 | ftrace_init_dyn_debugfs(d_tracer); | 5462 | ftrace_init_dyn_debugfs(d_tracer); |
