diff options
| -rw-r--r-- | kernel/trace/ftrace.c | 105 |
1 files changed, 53 insertions, 52 deletions
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index f7fcab8f3aa1..5c8d8eea9e7c 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c | |||
| @@ -3674,6 +3674,56 @@ ftrace_match_records(struct ftrace_hash *hash, char *buff, int len) | |||
| 3674 | return match_records(hash, buff, len, NULL); | 3674 | return match_records(hash, buff, len, NULL); |
| 3675 | } | 3675 | } |
| 3676 | 3676 | ||
| 3677 | static void ftrace_ops_update_code(struct ftrace_ops *ops, | ||
| 3678 | struct ftrace_ops_hash *old_hash) | ||
| 3679 | { | ||
| 3680 | struct ftrace_ops *op; | ||
| 3681 | |||
| 3682 | if (!ftrace_enabled) | ||
| 3683 | return; | ||
| 3684 | |||
| 3685 | if (ops->flags & FTRACE_OPS_FL_ENABLED) { | ||
| 3686 | ftrace_run_modify_code(ops, FTRACE_UPDATE_CALLS, old_hash); | ||
| 3687 | return; | ||
| 3688 | } | ||
| 3689 | |||
| 3690 | /* | ||
| 3691 | * If this is the shared global_ops filter, then we need to | ||
| 3692 | * check if there is another ops that shares it, is enabled. | ||
| 3693 | * If so, we still need to run the modify code. | ||
| 3694 | */ | ||
| 3695 | if (ops->func_hash != &global_ops.local_hash) | ||
| 3696 | return; | ||
| 3697 | |||
| 3698 | do_for_each_ftrace_op(op, ftrace_ops_list) { | ||
| 3699 | if (op->func_hash == &global_ops.local_hash && | ||
| 3700 | op->flags & FTRACE_OPS_FL_ENABLED) { | ||
| 3701 | ftrace_run_modify_code(op, FTRACE_UPDATE_CALLS, old_hash); | ||
| 3702 | /* Only need to do this once */ | ||
| 3703 | return; | ||
| 3704 | } | ||
| 3705 | } while_for_each_ftrace_op(op); | ||
| 3706 | } | ||
| 3707 | |||
| 3708 | static int ftrace_hash_move_and_update_ops(struct ftrace_ops *ops, | ||
| 3709 | struct ftrace_hash **orig_hash, | ||
| 3710 | struct ftrace_hash *hash, | ||
| 3711 | int enable) | ||
| 3712 | { | ||
| 3713 | struct ftrace_ops_hash old_hash_ops; | ||
| 3714 | struct ftrace_hash *old_hash; | ||
| 3715 | int ret; | ||
| 3716 | |||
| 3717 | old_hash = *orig_hash; | ||
| 3718 | old_hash_ops.filter_hash = ops->func_hash->filter_hash; | ||
| 3719 | old_hash_ops.notrace_hash = ops->func_hash->notrace_hash; | ||
| 3720 | ret = ftrace_hash_move(ops, enable, orig_hash, hash); | ||
| 3721 | if (!ret) { | ||
| 3722 | ftrace_ops_update_code(ops, &old_hash_ops); | ||
| 3723 | free_ftrace_hash_rcu(old_hash); | ||
| 3724 | } | ||
| 3725 | return ret; | ||
| 3726 | } | ||
| 3677 | 3727 | ||
| 3678 | /* | 3728 | /* |
| 3679 | * We register the module command as a template to show others how | 3729 | * We register the module command as a template to show others how |
| @@ -4306,44 +4356,11 @@ ftrace_match_addr(struct ftrace_hash *hash, unsigned long ip, int remove) | |||
| 4306 | return add_hash_entry(hash, ip); | 4356 | return add_hash_entry(hash, ip); |
| 4307 | } | 4357 | } |
| 4308 | 4358 | ||
| 4309 | static void ftrace_ops_update_code(struct ftrace_ops *ops, | ||
| 4310 | struct ftrace_ops_hash *old_hash) | ||
| 4311 | { | ||
| 4312 | struct ftrace_ops *op; | ||
| 4313 | |||
| 4314 | if (!ftrace_enabled) | ||
| 4315 | return; | ||
| 4316 | |||
| 4317 | if (ops->flags & FTRACE_OPS_FL_ENABLED) { | ||
| 4318 | ftrace_run_modify_code(ops, FTRACE_UPDATE_CALLS, old_hash); | ||
| 4319 | return; | ||
| 4320 | } | ||
| 4321 | |||
| 4322 | /* | ||
| 4323 | * If this is the shared global_ops filter, then we need to | ||
| 4324 | * check if there is another ops that shares it, is enabled. | ||
| 4325 | * If so, we still need to run the modify code. | ||
| 4326 | */ | ||
| 4327 | if (ops->func_hash != &global_ops.local_hash) | ||
| 4328 | return; | ||
| 4329 | |||
| 4330 | do_for_each_ftrace_op(op, ftrace_ops_list) { | ||
| 4331 | if (op->func_hash == &global_ops.local_hash && | ||
| 4332 | op->flags & FTRACE_OPS_FL_ENABLED) { | ||
| 4333 | ftrace_run_modify_code(op, FTRACE_UPDATE_CALLS, old_hash); | ||
| 4334 | /* Only need to do this once */ | ||
| 4335 | return; | ||
| 4336 | } | ||
| 4337 | } while_for_each_ftrace_op(op); | ||
| 4338 | } | ||
| 4339 | |||
| 4340 | static int | 4359 | static int |
| 4341 | ftrace_set_hash(struct ftrace_ops *ops, unsigned char *buf, int len, | 4360 | ftrace_set_hash(struct ftrace_ops *ops, unsigned char *buf, int len, |
| 4342 | unsigned long ip, int remove, int reset, int enable) | 4361 | unsigned long ip, int remove, int reset, int enable) |
| 4343 | { | 4362 | { |
| 4344 | struct ftrace_hash **orig_hash; | 4363 | struct ftrace_hash **orig_hash; |
| 4345 | struct ftrace_ops_hash old_hash_ops; | ||
| 4346 | struct ftrace_hash *old_hash; | ||
| 4347 | struct ftrace_hash *hash; | 4364 | struct ftrace_hash *hash; |
| 4348 | int ret; | 4365 | int ret; |
| 4349 | 4366 | ||
| @@ -4378,14 +4395,7 @@ ftrace_set_hash(struct ftrace_ops *ops, unsigned char *buf, int len, | |||
| 4378 | } | 4395 | } |
| 4379 | 4396 | ||
| 4380 | mutex_lock(&ftrace_lock); | 4397 | mutex_lock(&ftrace_lock); |
| 4381 | old_hash = *orig_hash; | 4398 | ret = ftrace_hash_move_and_update_ops(ops, orig_hash, hash, enable); |
| 4382 | old_hash_ops.filter_hash = ops->func_hash->filter_hash; | ||
| 4383 | old_hash_ops.notrace_hash = ops->func_hash->notrace_hash; | ||
| 4384 | ret = ftrace_hash_move(ops, enable, orig_hash, hash); | ||
| 4385 | if (!ret) { | ||
| 4386 | ftrace_ops_update_code(ops, &old_hash_ops); | ||
| 4387 | free_ftrace_hash_rcu(old_hash); | ||
| 4388 | } | ||
| 4389 | mutex_unlock(&ftrace_lock); | 4399 | mutex_unlock(&ftrace_lock); |
| 4390 | 4400 | ||
| 4391 | out_regex_unlock: | 4401 | out_regex_unlock: |
| @@ -4624,10 +4634,8 @@ static void __init set_ftrace_early_filters(void) | |||
| 4624 | int ftrace_regex_release(struct inode *inode, struct file *file) | 4634 | int ftrace_regex_release(struct inode *inode, struct file *file) |
| 4625 | { | 4635 | { |
| 4626 | struct seq_file *m = (struct seq_file *)file->private_data; | 4636 | struct seq_file *m = (struct seq_file *)file->private_data; |
| 4627 | struct ftrace_ops_hash old_hash_ops; | ||
| 4628 | struct ftrace_iterator *iter; | 4637 | struct ftrace_iterator *iter; |
| 4629 | struct ftrace_hash **orig_hash; | 4638 | struct ftrace_hash **orig_hash; |
| 4630 | struct ftrace_hash *old_hash; | ||
| 4631 | struct trace_parser *parser; | 4639 | struct trace_parser *parser; |
| 4632 | int filter_hash; | 4640 | int filter_hash; |
| 4633 | int ret; | 4641 | int ret; |
| @@ -4657,15 +4665,8 @@ int ftrace_regex_release(struct inode *inode, struct file *file) | |||
| 4657 | orig_hash = &iter->ops->func_hash->notrace_hash; | 4665 | orig_hash = &iter->ops->func_hash->notrace_hash; |
| 4658 | 4666 | ||
| 4659 | mutex_lock(&ftrace_lock); | 4667 | mutex_lock(&ftrace_lock); |
| 4660 | old_hash = *orig_hash; | 4668 | ret = ftrace_hash_move_and_update_ops(iter->ops, orig_hash, |
| 4661 | old_hash_ops.filter_hash = iter->ops->func_hash->filter_hash; | 4669 | iter->hash, filter_hash); |
| 4662 | old_hash_ops.notrace_hash = iter->ops->func_hash->notrace_hash; | ||
| 4663 | ret = ftrace_hash_move(iter->ops, filter_hash, | ||
| 4664 | orig_hash, iter->hash); | ||
| 4665 | if (!ret) { | ||
| 4666 | ftrace_ops_update_code(iter->ops, &old_hash_ops); | ||
| 4667 | free_ftrace_hash_rcu(old_hash); | ||
| 4668 | } | ||
| 4669 | mutex_unlock(&ftrace_lock); | 4670 | mutex_unlock(&ftrace_lock); |
| 4670 | } else { | 4671 | } else { |
| 4671 | /* For read only, the hash is the ops hash */ | 4672 | /* For read only, the hash is the ops hash */ |
