aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorSteven Rostedt (Red Hat) <rostedt@goodmis.org>2015-01-13 11:20:43 -0500
committerSteven Rostedt <rostedt@goodmis.org>2015-01-15 09:37:07 -0500
commit8f86f83709c585742dea5dd7f0d2b79c43f992ec (patch)
tree75b0f8121268778bc9a0092e3f11a37b541b6edb /kernel
parentb1940cd21c0f4abdce101253e860feff547291b0 (diff)
ftrace: Fix updating of filters for shared global_ops filters
As the set_ftrace_filter affects both the function tracer as well as the function graph tracer, the ops that represent each have a shared ftrace_ops_hash structure. This allows both to be updated when the filter files are updated. But if function graph is enabled and the global_ops (function tracing) ops is not, then it is possible that the filter could be changed without the update happening for the function graph ops. This will cause the changes to not take place and may even cause a ftrace_bug to occur as it could mess with the trampoline accounting. The solution is to check if the ops uses the shared global_ops filter and if the ops itself is not enabled, to check if there's another ops that is enabled and also shares the global_ops filter. In that case, the modification still needs to be executed. Link: http://lkml.kernel.org/r/20150114154329.055980438@goodmis.org Cc: stable@vger.kernel.org # 3.17+ Reviewed-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/trace/ftrace.c26
1 files changed, 25 insertions, 1 deletions
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index 929a733d302e..2b35d0ba578d 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -4008,8 +4008,32 @@ ftrace_match_addr(struct ftrace_hash *hash, unsigned long ip, int remove)
4008static void ftrace_ops_update_code(struct ftrace_ops *ops, 4008static void ftrace_ops_update_code(struct ftrace_ops *ops,
4009 struct ftrace_hash *old_hash) 4009 struct ftrace_hash *old_hash)
4010{ 4010{
4011 if (ops->flags & FTRACE_OPS_FL_ENABLED && ftrace_enabled) 4011 struct ftrace_ops *op;
4012
4013 if (!ftrace_enabled)
4014 return;
4015
4016 if (ops->flags & FTRACE_OPS_FL_ENABLED) {
4012 ftrace_run_modify_code(ops, FTRACE_UPDATE_CALLS, old_hash); 4017 ftrace_run_modify_code(ops, FTRACE_UPDATE_CALLS, old_hash);
4018 return;
4019 }
4020
4021 /*
4022 * If this is the shared global_ops filter, then we need to
4023 * check if there is another ops that shares it, is enabled.
4024 * If so, we still need to run the modify code.
4025 */
4026 if (ops->func_hash != &global_ops.local_hash)
4027 return;
4028
4029 do_for_each_ftrace_op(op, ftrace_ops_list) {
4030 if (op->func_hash == &global_ops.local_hash &&
4031 op->flags & FTRACE_OPS_FL_ENABLED) {
4032 ftrace_run_modify_code(op, FTRACE_UPDATE_CALLS, old_hash);
4033 /* Only need to do this once */
4034 return;
4035 }
4036 } while_for_each_ftrace_op(op);
4013} 4037}
4014 4038
4015static int 4039static int