• Pratyush Anand's avatar
    ftrace: Fix en(dis)able graph caller when en(dis)abling record via sysctl · 3f4f900f
    Pratyush Anand authored
    commit 1619dc3f upstream.
    
    When ftrace is enabled globally through the proc interface, we must check if
    ftrace_graph_active is set. If it is set, then we should also pass the
    FTRACE_START_FUNC_RET command to ftrace_run_update_code(). Similarly, when
    ftrace is disabled globally through the proc interface, we must check if
    ftrace_graph_active is set. If it is set, then we should also pass the
    FTRACE_STOP_FUNC_RET command to ftrace_run_update_code().
    
    Consider the following situation.
    
     # echo 0 > /proc/sys/kernel/ftrace_enabled
    
    After this ftrace_enabled = 0.
    
     # echo function_graph > /sys/kernel/debug/tracing/current_tracer
    
    Since ftrace_enabled = 0, ftrace_enable_ftrace_graph_caller() is never
    called.
    
     # echo 1 > /proc/sys/kernel/ftrace_enabled
    
    Now ftrace_enabled will be set to true, but still
    ftrace_enable_ftrace_graph_caller() will not be called, which is not
    desired.
    
    Further if we execute the following after this:
      # echo nop > /sys/kernel/debug/tracing/current_tracer
    
    Now since ftrace_enabled is set it will call
    ftrace_disable_ftrace_graph_caller(), which causes a kernel warning on
    the ARM platform.
    
    On the ARM platform, when ftrace_enable_ftrace_graph_caller() is called,
    it checks whether the old instruction is a nop or not. If it's not a nop,
    then it returns an error. If it is a nop then it replaces instruction at
    that address with a branch to ftrace_graph_caller.
    ftrace_disable_ftrace_graph_caller() behaves just the opposite. Therefore,
    if generic ftrace code ever calls either ftrace_enable_ftrace_graph_caller()
    or ftrace_disable_ftrace_graph_caller() consecutively two times in a row,
    then it will return an error, which will cause the generic ftrace code to
    raise a warning.
    
    Note, x86 does not have an issue with this because the architecture
    specific code for ftrace_enable_ftrace_graph_caller() and
    ftrace_disable_ftrace_graph_caller() does not check the previous state,
    and calling either of these functions twice in a row has no ill effect.
    
    Link: http://lkml.kernel.org/r/e4fbe64cdac0dd0e86a3bf914b0f83c0b419f146.1425666454.git.panand@redhat.comSigned-off-by: default avatarPratyush Anand <panand@redhat.com>
    [
      removed extra if (ftrace_start_up) and defined ftrace_graph_active as 0
      if CONFIG_FUNCTION_GRAPH_TRACER is not set.
    ]
    Signed-off-by: default avatarSteven Rostedt <rostedt@goodmis.org>
    [bwh: Backported to 3.2: adjust context]
    Signed-off-by: default avatarBen Hutchings <ben@decadent.org.uk>
    3f4f900f
ftrace.c 93.6 KB