aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteven Rostedt (Red Hat) <rostedt@goodmis.org>2014-10-24 14:56:01 -0400
committerSteven Rostedt <rostedt@goodmis.org>2014-10-24 16:33:36 -0400
commit8252ecf346474cfe46315bd0a7ca655c293c34a9 (patch)
tree71a1ee72107c5907ea8bd898c536ad65b0367de3
parentf114040e3ea6e07372334ade75d1ee0775c355e1 (diff)
ftrace: Set ops->old_hash on modifying what an ops hooks to
The code that checks for trampolines when modifying function hooks tests against a modified ops "old_hash". But the ops old_hash pointer is not being updated before the changes are made, making it possible to not find the right hash to the callback and possibly causing ftrace to break in accounting and disable itself. Have the ops set its old_hash before the modifying takes place. Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
-rw-r--r--kernel/trace/ftrace.c24
1 files changed, 15 insertions, 9 deletions
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index fb186b9ddf51..483b8c1b1de0 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -2293,10 +2293,13 @@ static void ftrace_run_update_code(int command)
2293 FTRACE_WARN_ON(ret); 2293 FTRACE_WARN_ON(ret);
2294} 2294}
2295 2295
2296static void ftrace_run_modify_code(struct ftrace_ops *ops, int command) 2296static void ftrace_run_modify_code(struct ftrace_ops *ops, int command,
2297 struct ftrace_hash *old_hash)
2297{ 2298{
2298 ops->flags |= FTRACE_OPS_FL_MODIFYING; 2299 ops->flags |= FTRACE_OPS_FL_MODIFYING;
2300 ops->old_hash.filter_hash = old_hash;
2299 ftrace_run_update_code(command); 2301 ftrace_run_update_code(command);
2302 ops->old_hash.filter_hash = NULL;
2300 ops->flags &= ~FTRACE_OPS_FL_MODIFYING; 2303 ops->flags &= ~FTRACE_OPS_FL_MODIFYING;
2301} 2304}
2302 2305
@@ -3340,7 +3343,7 @@ static struct ftrace_ops trace_probe_ops __read_mostly =
3340 3343
3341static int ftrace_probe_registered; 3344static int ftrace_probe_registered;
3342 3345
3343static void __enable_ftrace_function_probe(void) 3346static void __enable_ftrace_function_probe(struct ftrace_hash *old_hash)
3344{ 3347{
3345 int ret; 3348 int ret;
3346 int i; 3349 int i;
@@ -3348,7 +3351,8 @@ static void __enable_ftrace_function_probe(void)
3348 if (ftrace_probe_registered) { 3351 if (ftrace_probe_registered) {
3349 /* still need to update the function call sites */ 3352 /* still need to update the function call sites */
3350 if (ftrace_enabled) 3353 if (ftrace_enabled)
3351 ftrace_run_modify_code(&trace_probe_ops, FTRACE_UPDATE_CALLS); 3354 ftrace_run_modify_code(&trace_probe_ops, FTRACE_UPDATE_CALLS,
3355 old_hash);
3352 return; 3356 return;
3353 } 3357 }
3354 3358
@@ -3477,13 +3481,14 @@ register_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
3477 } while_for_each_ftrace_rec(); 3481 } while_for_each_ftrace_rec();
3478 3482
3479 ret = ftrace_hash_move(&trace_probe_ops, 1, orig_hash, hash); 3483 ret = ftrace_hash_move(&trace_probe_ops, 1, orig_hash, hash);
3484
3485 __enable_ftrace_function_probe(old_hash);
3486
3480 if (!ret) 3487 if (!ret)
3481 free_ftrace_hash_rcu(old_hash); 3488 free_ftrace_hash_rcu(old_hash);
3482 else 3489 else
3483 count = ret; 3490 count = ret;
3484 3491
3485 __enable_ftrace_function_probe();
3486
3487 out_unlock: 3492 out_unlock:
3488 mutex_unlock(&ftrace_lock); 3493 mutex_unlock(&ftrace_lock);
3489 out: 3494 out:
@@ -3764,10 +3769,11 @@ ftrace_match_addr(struct ftrace_hash *hash, unsigned long ip, int remove)
3764 return add_hash_entry(hash, ip); 3769 return add_hash_entry(hash, ip);
3765} 3770}
3766 3771
3767static void ftrace_ops_update_code(struct ftrace_ops *ops) 3772static void ftrace_ops_update_code(struct ftrace_ops *ops,
3773 struct ftrace_hash *old_hash)
3768{ 3774{
3769 if (ops->flags & FTRACE_OPS_FL_ENABLED && ftrace_enabled) 3775 if (ops->flags & FTRACE_OPS_FL_ENABLED && ftrace_enabled)
3770 ftrace_run_modify_code(ops, FTRACE_UPDATE_CALLS); 3776 ftrace_run_modify_code(ops, FTRACE_UPDATE_CALLS, old_hash);
3771} 3777}
3772 3778
3773static int 3779static int
@@ -3813,7 +3819,7 @@ ftrace_set_hash(struct ftrace_ops *ops, unsigned char *buf, int len,
3813 old_hash = *orig_hash; 3819 old_hash = *orig_hash;
3814 ret = ftrace_hash_move(ops, enable, orig_hash, hash); 3820 ret = ftrace_hash_move(ops, enable, orig_hash, hash);
3815 if (!ret) { 3821 if (!ret) {
3816 ftrace_ops_update_code(ops); 3822 ftrace_ops_update_code(ops, old_hash);
3817 free_ftrace_hash_rcu(old_hash); 3823 free_ftrace_hash_rcu(old_hash);
3818 } 3824 }
3819 mutex_unlock(&ftrace_lock); 3825 mutex_unlock(&ftrace_lock);
@@ -4058,7 +4064,7 @@ int ftrace_regex_release(struct inode *inode, struct file *file)
4058 ret = ftrace_hash_move(iter->ops, filter_hash, 4064 ret = ftrace_hash_move(iter->ops, filter_hash,
4059 orig_hash, iter->hash); 4065 orig_hash, iter->hash);
4060 if (!ret) { 4066 if (!ret) {
4061 ftrace_ops_update_code(iter->ops); 4067 ftrace_ops_update_code(iter->ops, old_hash);
4062 free_ftrace_hash_rcu(old_hash); 4068 free_ftrace_hash_rcu(old_hash);
4063 } 4069 }
4064 mutex_unlock(&ftrace_lock); 4070 mutex_unlock(&ftrace_lock);