]> git.baikalelectronics.ru Git - kernel.git/commitdiff
ftrace: disable preemption when recursion locked
author王贇 <yun.wang@linux.alibaba.com>
Wed, 27 Oct 2021 03:14:44 +0000 (11:14 +0800)
committerSteven Rostedt (VMware) <rostedt@goodmis.org>
Wed, 27 Oct 2021 15:21:49 +0000 (11:21 -0400)
As the documentation explained, ftrace_test_recursion_trylock()
and ftrace_test_recursion_unlock() were supposed to disable and
enable preemption properly, however currently this work is done
outside of the function, which could be missing by mistake.

And since the internal using of trace_test_and_set_recursion()
and trace_clear_recursion() also require preemption disabled, we
can just merge the logical.

This patch will make sure the preemption has been disabled when
trace_test_and_set_recursion() return bit >= 0, and
trace_clear_recursion() will enable the preemption if previously
enabled.

Link: https://lkml.kernel.org/r/13bde807-779c-aa4c-0672-20515ae365ea@linux.alibaba.com
CC: Petr Mladek <pmladek@suse.com>
Cc: Guo Ren <guoren@kernel.org>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: "James E.J. Bottomley" <James.Bottomley@HansenPartnership.com>
Cc: Helge Deller <deller@gmx.de>
Cc: Michael Ellerman <mpe@ellerman.id.au>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Paul Walmsley <paul.walmsley@sifive.com>
Cc: Palmer Dabbelt <palmer@dabbelt.com>
Cc: Albert Ou <aou@eecs.berkeley.edu>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Borislav Petkov <bp@alien8.de>
Cc: "H. Peter Anvin" <hpa@zytor.com>
Cc: Josh Poimboeuf <jpoimboe@redhat.com>
Cc: Jiri Kosina <jikos@kernel.org>
Cc: Joe Lawrence <joe.lawrence@redhat.com>
Cc: Masami Hiramatsu <mhiramat@kernel.org>
Cc: Nicholas Piggin <npiggin@gmail.com>
Cc: Jisheng Zhang <jszhang@kernel.org>
CC: Steven Rostedt <rostedt@goodmis.org>
CC: Miroslav Benes <mbenes@suse.cz>
Reported-by: Abaci <abaci@linux.alibaba.com>
Suggested-by: Peter Zijlstra <peterz@infradead.org>
Signed-off-by: Michael Wang <yun.wang@linux.alibaba.com>
[ Removed extra line in comment - SDR ]
Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
arch/csky/kernel/probes/ftrace.c
arch/parisc/kernel/ftrace.c
arch/powerpc/kernel/kprobes-ftrace.c
arch/riscv/kernel/probes/ftrace.c
arch/x86/kernel/kprobes/ftrace.c
include/linux/trace_recursion.h
kernel/livepatch/patch.c
kernel/trace/ftrace.c
kernel/trace/trace_functions.c

index b388228abbf267543f91f2c2e613ac6b27b24f4e..834cffcfbce32039a18301de4424c58812b814ae 100644 (file)
@@ -17,7 +17,6 @@ void kprobe_ftrace_handler(unsigned long ip, unsigned long parent_ip,
                return;
 
        regs = ftrace_get_regs(fregs);
-       preempt_disable_notrace();
        p = get_kprobe((kprobe_opcode_t *)ip);
        if (!p) {
                p = get_kprobe((kprobe_opcode_t *)(ip - MCOUNT_INSN_SIZE));
@@ -57,7 +56,6 @@ void kprobe_ftrace_handler(unsigned long ip, unsigned long parent_ip,
                __this_cpu_write(current_kprobe, NULL);
        }
 out:
-       preempt_enable_notrace();
        ftrace_test_recursion_unlock(bit);
 }
 NOKPROBE_SYMBOL(kprobe_ftrace_handler);
index 01581f715737f43ab17a26220ca1aeaec83a8447..b14011d3c2f104f16be02c0d8c55ca16587e860e 100644 (file)
@@ -211,7 +211,6 @@ void kprobe_ftrace_handler(unsigned long ip, unsigned long parent_ip,
                return;
 
        regs = ftrace_get_regs(fregs);
-       preempt_disable_notrace();
        p = get_kprobe((kprobe_opcode_t *)ip);
        if (unlikely(!p) || kprobe_disabled(p))
                goto out;
@@ -240,7 +239,6 @@ void kprobe_ftrace_handler(unsigned long ip, unsigned long parent_ip,
        }
        __this_cpu_write(current_kprobe, NULL);
 out:
-       preempt_enable_notrace();
        ftrace_test_recursion_unlock(bit);
 }
 NOKPROBE_SYMBOL(kprobe_ftrace_handler);
index 7154d58338cc29314b13afe0c14d3cb5e0ff9e40..072ebe7f290ba77b5e40a2303e0f856edfa5660f 100644 (file)
@@ -26,7 +26,6 @@ void kprobe_ftrace_handler(unsigned long nip, unsigned long parent_nip,
                return;
 
        regs = ftrace_get_regs(fregs);
-       preempt_disable_notrace();
        p = get_kprobe((kprobe_opcode_t *)nip);
        if (unlikely(!p) || kprobe_disabled(p))
                goto out;
@@ -61,7 +60,6 @@ void kprobe_ftrace_handler(unsigned long nip, unsigned long parent_nip,
                __this_cpu_write(current_kprobe, NULL);
        }
 out:
-       preempt_enable_notrace();
        ftrace_test_recursion_unlock(bit);
 }
 NOKPROBE_SYMBOL(kprobe_ftrace_handler);
index aab85a82f4199da898e841f23c7df8fbe499dbaf..7142ec42e889f996fd2d0b0eb32a54fba1a89128 100644 (file)
@@ -15,7 +15,6 @@ void kprobe_ftrace_handler(unsigned long ip, unsigned long parent_ip,
        if (bit < 0)
                return;
 
-       preempt_disable_notrace();
        p = get_kprobe((kprobe_opcode_t *)ip);
        if (unlikely(!p) || kprobe_disabled(p))
                goto out;
@@ -52,7 +51,6 @@ void kprobe_ftrace_handler(unsigned long ip, unsigned long parent_ip,
                __this_cpu_write(current_kprobe, NULL);
        }
 out:
-       preempt_enable_notrace();
        ftrace_test_recursion_unlock(bit);
 }
 NOKPROBE_SYMBOL(kprobe_ftrace_handler);
index 596de2f6d3a57f522f1fa30496a5ec75977e63a7..dd2ec14adb77ba97b22e8c849681f4f1ae133c59 100644 (file)
@@ -25,7 +25,6 @@ void kprobe_ftrace_handler(unsigned long ip, unsigned long parent_ip,
        if (bit < 0)
                return;
 
-       preempt_disable_notrace();
        p = get_kprobe((kprobe_opcode_t *)ip);
        if (unlikely(!p) || kprobe_disabled(p))
                goto out;
@@ -59,7 +58,6 @@ void kprobe_ftrace_handler(unsigned long ip, unsigned long parent_ip,
                __this_cpu_write(current_kprobe, NULL);
        }
 out:
-       preempt_enable_notrace();
        ftrace_test_recursion_unlock(bit);
 }
 NOKPROBE_SYMBOL(kprobe_ftrace_handler);
index 24f284eb55a748ae1ddae8e731fa5a21e6846ca5..a13f23b04d739c200f4122f198979f7781caf2bf 100644 (file)
@@ -155,6 +155,9 @@ extern void ftrace_record_recursion(unsigned long ip, unsigned long parent_ip);
 # define do_ftrace_record_recursion(ip, pip)   do { } while (0)
 #endif
 
+/*
+ * Preemption is promised to be disabled when return bit >= 0.
+ */
 static __always_inline int trace_test_and_set_recursion(unsigned long ip, unsigned long pip,
                                                        int start, int max)
 {
@@ -189,14 +192,20 @@ static __always_inline int trace_test_and_set_recursion(unsigned long ip, unsign
        current->trace_recursion = val;
        barrier();
 
+       preempt_disable_notrace();
+
        return bit + 1;
 }
 
+/*
+ * Preemption will be enabled (if it was previously enabled).
+ */
 static __always_inline void trace_clear_recursion(int bit)
 {
        if (!bit)
                return;
 
+       preempt_enable_notrace();
        barrier();
        bit--;
        trace_recursion_clear(bit);
@@ -209,7 +218,7 @@ static __always_inline void trace_clear_recursion(int bit)
  * tracing recursed in the same context (normal vs interrupt),
  *
  * Returns: -1 if a recursion happened.
- *           >= 0 if no recursion
+ *           >= 0 if no recursion.
  */
 static __always_inline int ftrace_test_recursion_trylock(unsigned long ip,
                                                         unsigned long parent_ip)
index e8029aea67f1d80f7bf488b85e0a1df1e5a75437..fe316c021d73dd7556b44ecc0bac802d78df6d21 100644 (file)
@@ -49,14 +49,15 @@ static void notrace klp_ftrace_handler(unsigned long ip,
 
        ops = container_of(fops, struct klp_ops, fops);
 
+       /*
+        * The ftrace_test_recursion_trylock() will disable preemption,
+        * which is required for the variant of synchronize_rcu() that is
+        * used to allow patching functions where RCU is not watching.
+        * See klp_synchronize_transition() for more details.
+        */
        bit = ftrace_test_recursion_trylock(ip, parent_ip);
        if (WARN_ON_ONCE(bit < 0))
                return;
-       /*
-        * A variant of synchronize_rcu() is used to allow patching functions
-        * where RCU is not watching, see klp_synchronize_transition().
-        */
-       preempt_disable_notrace();
 
        func = list_first_or_null_rcu(&ops->func_stack, struct klp_func,
                                      stack_node);
@@ -120,7 +121,6 @@ static void notrace klp_ftrace_handler(unsigned long ip,
        klp_arch_set_pc(fregs, (unsigned long)func->new_func);
 
 unlock:
-       preempt_enable_notrace();
        ftrace_test_recursion_unlock(bit);
 }
 
index 2057ad363772079cec03049148e1b3dced1feccb..b4ed1a301232aaa8b8307b8b763d310b819470c9 100644 (file)
@@ -7198,16 +7198,15 @@ __ftrace_ops_list_func(unsigned long ip, unsigned long parent_ip,
        struct ftrace_ops *op;
        int bit;
 
+       /*
+        * The ftrace_test_and_set_recursion() will disable preemption,
+        * which is required since some of the ops may be dynamically
+        * allocated, they must be freed after a synchronize_rcu().
+        */
        bit = trace_test_and_set_recursion(ip, parent_ip, TRACE_LIST_START, TRACE_LIST_MAX);
        if (bit < 0)
                return;
 
-       /*
-        * Some of the ops may be dynamically allocated,
-        * they must be freed after a synchronize_rcu().
-        */
-       preempt_disable_notrace();
-
        do_for_each_ftrace_op(op, ftrace_ops_list) {
                /* Stub functions don't need to be called nor tested */
                if (op->flags & FTRACE_OPS_FL_STUB)
@@ -7231,7 +7230,6 @@ __ftrace_ops_list_func(unsigned long ip, unsigned long parent_ip,
                }
        } while_for_each_ftrace_op(op);
 out:
-       preempt_enable_notrace();
        trace_clear_recursion(bit);
 }
 
@@ -7279,12 +7277,9 @@ static void ftrace_ops_assist_func(unsigned long ip, unsigned long parent_ip,
        if (bit < 0)
                return;
 
-       preempt_disable_notrace();
-
        if (!(op->flags & FTRACE_OPS_FL_RCU) || rcu_is_watching())
                op->func(ip, parent_ip, op, fregs);
 
-       preempt_enable_notrace();
        trace_clear_recursion(bit);
 }
 NOKPROBE_SYMBOL(ftrace_ops_assist_func);
index 1f0e63f5d1f9838e52b086fa9e6d9f15f2f04e6d..9f1bfbe105e8d9213e6134992341135724bac843 100644 (file)
@@ -186,7 +186,6 @@ function_trace_call(unsigned long ip, unsigned long parent_ip,
                return;
 
        trace_ctx = tracing_gen_ctx();
-       preempt_disable_notrace();
 
        cpu = smp_processor_id();
        data = per_cpu_ptr(tr->array_buffer.data, cpu);
@@ -194,7 +193,6 @@ function_trace_call(unsigned long ip, unsigned long parent_ip,
                trace_function(tr, ip, parent_ip, trace_ctx);
 
        ftrace_test_recursion_unlock(bit);
-       preempt_enable_notrace();
 }
 
 #ifdef CONFIG_UNWINDER_ORC
@@ -298,8 +296,6 @@ function_no_repeats_trace_call(unsigned long ip, unsigned long parent_ip,
        if (bit < 0)
                return;
 
-       preempt_disable_notrace();
-
        cpu = smp_processor_id();
        data = per_cpu_ptr(tr->array_buffer.data, cpu);
        if (atomic_read(&data->disabled))
@@ -324,7 +320,6 @@ function_no_repeats_trace_call(unsigned long ip, unsigned long parent_ip,
 
 out:
        ftrace_test_recursion_unlock(bit);
-       preempt_enable_notrace();
 }
 
 static void