diff options
author | Steven Rostedt (VMware) <rostedt@goodmis.org> | 2017-04-04 14:46:56 -0400 |
---|---|---|
committer | Steven Rostedt (VMware) <rostedt@goodmis.org> | 2017-04-20 22:06:42 -0400 |
commit | e16b35ddb840788e023fac2482b61c0b6bf98057 (patch) | |
tree | 482b09e069be85d7f9adcea28b79e0ed3a18cd9e | |
parent | 1a48df0041c2756194e700affb0e2ff084092e28 (diff) |
ftrace: Add helper function ftrace_hash_move_and_update_ops()
The processes of updating a ops filter_hash is a bit complex, and requires
setting up an old hash to perform the update. This is done exactly the same
in two locations for the same reasons. Create a helper function that does it
in one place.
Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
-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 */ |