lkml.org 
[lkml]   [2017]   [Apr]   [19]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 4.9 42/69] ftrace: Fix removing of second function probe
    Date
    4.9-stable review patch.  If anyone has any objections, please let me know.

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

    From: Steven Rostedt (VMware) <rostedt@goodmis.org>

    commit 82cc4fc2e70ec5baeff8f776f2773abc8b2cc0ae upstream.

    When two function probes are added to set_ftrace_filter, and then one of
    them is removed, the update to the function locations is not performed, and
    the record keeping of the function states are corrupted, and causes an
    ftrace_bug() to occur.

    This is easily reproducable by adding two probes, removing one, and then
    adding it back again.

    # cd /sys/kernel/debug/tracing
    # echo schedule:traceoff > set_ftrace_filter
    # echo do_IRQ:traceoff > set_ftrace_filter
    # echo \!do_IRQ:traceoff > /debug/tracing/set_ftrace_filter
    # echo do_IRQ:traceoff > set_ftrace_filter

    Causes:
    ------------[ cut here ]------------
    WARNING: CPU: 2 PID: 1098 at kernel/trace/ftrace.c:2369 ftrace_get_addr_curr+0x143/0x220
    Modules linked in: [...]
    CPU: 2 PID: 1098 Comm: bash Not tainted 4.10.0-test+ #405
    Hardware name: Hewlett-Packard HP Compaq Pro 6300 SFF/339A, BIOS K01 v02.05 05/07/2012
    Call Trace:
    dump_stack+0x68/0x9f
    __warn+0x111/0x130
    ? trace_irq_work_interrupt+0xa0/0xa0
    warn_slowpath_null+0x1d/0x20
    ftrace_get_addr_curr+0x143/0x220
    ? __fentry__+0x10/0x10
    ftrace_replace_code+0xe3/0x4f0
    ? ftrace_int3_handler+0x90/0x90
    ? printk+0x99/0xb5
    ? 0xffffffff81000000
    ftrace_modify_all_code+0x97/0x110
    arch_ftrace_update_code+0x10/0x20
    ftrace_run_update_code+0x1c/0x60
    ftrace_run_modify_code.isra.48.constprop.62+0x8e/0xd0
    register_ftrace_function_probe+0x4b6/0x590
    ? ftrace_startup+0x310/0x310
    ? debug_lockdep_rcu_enabled.part.4+0x1a/0x30
    ? update_stack_state+0x88/0x110
    ? ftrace_regex_write.isra.43.part.44+0x1d3/0x320
    ? preempt_count_sub+0x18/0xd0
    ? mutex_lock_nested+0x104/0x800
    ? ftrace_regex_write.isra.43.part.44+0x1d3/0x320
    ? __unwind_start+0x1c0/0x1c0
    ? _mutex_lock_nest_lock+0x800/0x800
    ftrace_trace_probe_callback.isra.3+0xc0/0x130
    ? func_set_flag+0xe0/0xe0
    ? __lock_acquire+0x642/0x1790
    ? __might_fault+0x1e/0x20
    ? trace_get_user+0x398/0x470
    ? strcmp+0x35/0x60
    ftrace_trace_onoff_callback+0x48/0x70
    ftrace_regex_write.isra.43.part.44+0x251/0x320
    ? match_records+0x420/0x420
    ftrace_filter_write+0x2b/0x30
    __vfs_write+0xd7/0x330
    ? do_loop_readv_writev+0x120/0x120
    ? locks_remove_posix+0x90/0x2f0
    ? do_lock_file_wait+0x160/0x160
    ? __lock_is_held+0x93/0x100
    ? rcu_read_lock_sched_held+0x5c/0xb0
    ? preempt_count_sub+0x18/0xd0
    ? __sb_start_write+0x10a/0x230
    ? vfs_write+0x222/0x240
    vfs_write+0xef/0x240
    SyS_write+0xab/0x130
    ? SyS_read+0x130/0x130
    ? trace_hardirqs_on_caller+0x182/0x280
    ? trace_hardirqs_on_thunk+0x1a/0x1c
    entry_SYSCALL_64_fastpath+0x18/0xad
    RIP: 0033:0x7fe61c157c30
    RSP: 002b:00007ffe87890258 EFLAGS: 00000246 ORIG_RAX: 0000000000000001
    RAX: ffffffffffffffda RBX: ffffffff8114a410 RCX: 00007fe61c157c30
    RDX: 0000000000000010 RSI: 000055814798f5e0 RDI: 0000000000000001
    RBP: ffff8800c9027f98 R08: 00007fe61c422740 R09: 00007fe61ca53700
    R10: 0000000000000073 R11: 0000000000000246 R12: 0000558147a36400
    R13: 00007ffe8788f160 R14: 0000000000000024 R15: 00007ffe8788f15c
    ? trace_hardirqs_off_caller+0xc0/0x110
    ---[ end trace 99fa09b3d9869c2c ]---
    Bad trampoline accounting at: ffffffff81cc3b00 (do_IRQ+0x0/0x150)

    Fixes: 59df055f1991 ("ftrace: trace different functions with a different tracer")
    Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

    ---
    kernel/trace/ftrace.c | 20 ++++++++++++++++----
    1 file changed, 16 insertions(+), 4 deletions(-)

    --- a/kernel/trace/ftrace.c
    +++ b/kernel/trace/ftrace.c
    @@ -3736,23 +3736,24 @@ static void __enable_ftrace_function_pro
    ftrace_probe_registered = 1;
    }

    -static void __disable_ftrace_function_probe(void)
    +static bool __disable_ftrace_function_probe(void)
    {
    int i;

    if (!ftrace_probe_registered)
    - return;
    + return false;

    for (i = 0; i < FTRACE_FUNC_HASHSIZE; i++) {
    struct hlist_head *hhd = &ftrace_func_hash[i];
    if (hhd->first)
    - return;
    + return false;
    }

    /* no more funcs left */
    ftrace_shutdown(&trace_probe_ops, 0);

    ftrace_probe_registered = 0;
    + return true;
    }


    @@ -3882,6 +3883,7 @@ static void
    __unregister_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
    void *data, int flags)
    {
    + struct ftrace_ops_hash old_hash_ops;
    struct ftrace_func_entry *rec_entry;
    struct ftrace_func_probe *entry;
    struct ftrace_func_probe *p;
    @@ -3893,6 +3895,7 @@ __unregister_ftrace_function_probe(char
    struct hlist_node *tmp;
    char str[KSYM_SYMBOL_LEN];
    int i, ret;
    + bool disabled;

    if (glob && (strcmp(glob, "*") == 0 || !strlen(glob)))
    func_g.search = NULL;
    @@ -3911,6 +3914,10 @@ __unregister_ftrace_function_probe(char

    mutex_lock(&trace_probe_ops.func_hash->regex_lock);

    + old_hash_ops.filter_hash = old_hash;
    + /* Probes only have filters */
    + old_hash_ops.notrace_hash = NULL;
    +
    hash = alloc_and_copy_ftrace_hash(FTRACE_HASH_DEFAULT_BITS, *orig_hash);
    if (!hash)
    /* Hmm, should report this somehow */
    @@ -3948,12 +3955,17 @@ __unregister_ftrace_function_probe(char
    }
    }
    mutex_lock(&ftrace_lock);
    - __disable_ftrace_function_probe();
    + disabled = __disable_ftrace_function_probe();
    /*
    * Remove after the disable is called. Otherwise, if the last
    * probe is removed, a null hash means *all enabled*.
    */
    ret = ftrace_hash_move(&trace_probe_ops, 1, orig_hash, hash);
    +
    + /* still need to update the function call sites */
    + if (ftrace_enabled && !disabled)
    + ftrace_run_modify_code(&trace_probe_ops, FTRACE_UPDATE_CALLS,
    + &old_hash_ops);
    synchronize_sched();
    if (!ret)
    free_ftrace_hash_rcu(old_hash);

    \
     
     \ /
      Last update: 2017-04-19 16:56    [W:4.325 / U:0.072 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site