lkml.org 
[lkml]   [2015]   [Jun]   [16]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 3.4 087/172] ftrace: Fix en(dis)able graph caller when en(dis)abling record via sysctl
    Date
    From: Pratyush Anand <panand@redhat.com>

    3.4.108-rc1 review patch. If anyone has any objections, please let me know.

    ------------------


    commit 1619dc3f8f555ee1cdd3c75db3885d5715442b12 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.com

    Signed-off-by: Pratyush 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: Steven Rostedt <rostedt@goodmis.org>
    [lizf: Backported to 3.4: adjust context]
    Signed-off-by: Zefan Li <lizefan@huawei.com>
    ---
    kernel/trace/ftrace.c | 27 ++++++++++++++++++++++-----
    1 file changed, 22 insertions(+), 5 deletions(-)

    diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
    index 5b6bd45..d73d0b7 100644
    --- a/kernel/trace/ftrace.c
    +++ b/kernel/trace/ftrace.c
    @@ -1014,6 +1014,12 @@ ftrace_filter_lseek(struct file *file, loff_t offset, int whence)
    return ret;
    }

    +#ifdef CONFIG_FUNCTION_GRAPH_TRACER
    +static int ftrace_graph_active;
    +#else
    +# define ftrace_graph_active 0
    +#endif
    +
    #ifdef CONFIG_DYNAMIC_FTRACE

    #ifndef CONFIG_FTRACE_MCOUNT_RECORD
    @@ -2056,24 +2062,36 @@ static int ftrace_shutdown(struct ftrace_ops *ops, int command)

    static void ftrace_startup_sysctl(void)
    {
    + int command;
    +
    if (unlikely(ftrace_disabled))
    return;

    /* Force update next time */
    saved_ftrace_func = NULL;
    /* ftrace_start_up is true if we want ftrace running */
    - if (ftrace_start_up)
    - ftrace_run_update_code(FTRACE_UPDATE_CALLS);
    + if (ftrace_start_up) {
    + command = FTRACE_UPDATE_CALLS;
    + if (ftrace_graph_active)
    + command |= FTRACE_START_FUNC_RET;
    + ftrace_run_update_code(command);
    + }
    }

    static void ftrace_shutdown_sysctl(void)
    {
    + int command;
    +
    if (unlikely(ftrace_disabled))
    return;

    /* ftrace_start_up is true if ftrace is running */
    - if (ftrace_start_up)
    - ftrace_run_update_code(FTRACE_DISABLE_CALLS);
    + if (ftrace_start_up) {
    + command = FTRACE_DISABLE_CALLS;
    + if (ftrace_graph_active)
    + command |= FTRACE_STOP_FUNC_RET;
    + ftrace_run_update_code(command);
    + }
    }

    static cycle_t ftrace_update_time;
    @@ -4465,7 +4483,6 @@ ftrace_enable_sysctl(struct ctl_table *table, int write,

    #ifdef CONFIG_FUNCTION_GRAPH_TRACER

    -static int ftrace_graph_active;
    static struct notifier_block ftrace_suspend_notifier;

    int ftrace_graph_entry_stub(struct ftrace_graph_ent *trace)
    --
    1.9.1


    \
     
     \ /
      Last update: 2015-06-16 11:41    [W:4.098 / U:0.676 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site