Merge tag 'trace-v4.14-rc1-2' of git://git.kernel.org/pub/scm/linux/kernel/git/rosted...
authorLinus Torvalds <torvalds@linux-foundation.org>
Mon, 25 Sep 2017 22:22:31 +0000 (15:22 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Mon, 25 Sep 2017 22:22:31 +0000 (15:22 -0700)
Pull tracing fixes from Steven Rostedt:
 "Stack tracing and RCU has been having issues with each other and
  lockdep has been pointing out constant problems.

  The changes have been going into the stack tracer, but it has been
  discovered that the problem isn't with the stack tracer itself, but it
  is with calling save_stack_trace() from within the internals of RCU.

  The stack tracer is the one that can trigger the issue the easiest,
  but examining the problem further, it could also happen from a WARN()
  in the wrong place, or even if an NMI happened in this area and it did
  an rcu_read_lock().

  The critical area is where RCU is not watching. Which can happen while
  going to and from idle, or bringing up or taking down a CPU.

  The final fix was to put the protection in kernel_text_address() as it
  is the one that requires RCU to be watching while doing the stack
  trace.

  To make this work properly, Paul had to allow rcu_irq_enter() happen
  after rcu_nmi_enter(). This should have been done anyway, since an NMI
  can page fault (reading vmalloc area), and a page fault triggers
  rcu_irq_enter().

  One patch is just a consolidation of code so that the fix only needed
  to be done in one location"

* tag 'trace-v4.14-rc1-2' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-trace:
  tracing: Remove RCU work arounds from stack tracer
  extable: Enable RCU if it is not watching in kernel_text_address()
  extable: Consolidate *kernel_text_address() functions
  rcu: Allow for page faults in NMI handlers

kernel/extable.c
kernel/rcu/tree.c
kernel/trace/trace_stack.c

index 38c2412401a1b118d53d3cff92eba24753134aed..9aa1cc41ecf79c8c2cc5fb9dbd3fbd418025c0dd 100644 (file)
@@ -102,15 +102,7 @@ int core_kernel_data(unsigned long addr)
 
 int __kernel_text_address(unsigned long addr)
 {
-       if (core_kernel_text(addr))
-               return 1;
-       if (is_module_text_address(addr))
-               return 1;
-       if (is_ftrace_trampoline(addr))
-               return 1;
-       if (is_kprobe_optinsn_slot(addr) || is_kprobe_insn_slot(addr))
-               return 1;
-       if (is_bpf_text_address(addr))
+       if (kernel_text_address(addr))
                return 1;
        /*
         * There might be init symbols in saved stacktraces.
@@ -127,17 +119,42 @@ int __kernel_text_address(unsigned long addr)
 
 int kernel_text_address(unsigned long addr)
 {
+       bool no_rcu;
+       int ret = 1;
+
        if (core_kernel_text(addr))
                return 1;
+
+       /*
+        * If a stack dump happens while RCU is not watching, then
+        * RCU needs to be notified that it requires to start
+        * watching again. This can happen either by tracing that
+        * triggers a stack trace, or a WARN() that happens during
+        * coming back from idle, or cpu on or offlining.
+        *
+        * is_module_text_address() as well as the kprobe slots
+        * and is_bpf_text_address() require RCU to be watching.
+        */
+       no_rcu = !rcu_is_watching();
+
+       /* Treat this like an NMI as it can happen anywhere */
+       if (no_rcu)
+               rcu_nmi_enter();
+
        if (is_module_text_address(addr))
-               return 1;
+               goto out;
        if (is_ftrace_trampoline(addr))
-               return 1;
+               goto out;
        if (is_kprobe_optinsn_slot(addr) || is_kprobe_insn_slot(addr))
-               return 1;
+               goto out;
        if (is_bpf_text_address(addr))
-               return 1;
-       return 0;
+               goto out;
+       ret = 0;
+out:
+       if (no_rcu)
+               rcu_nmi_exit();
+
+       return ret;
 }
 
 /*
index 1250e4bd4b85e690c7db2b061a87599e8651a606..0c44c7b42e6d50bbb67ae47cbe257a734020b16c 100644 (file)
@@ -882,6 +882,11 @@ void rcu_irq_exit(void)
 
        RCU_LOCKDEP_WARN(!irqs_disabled(), "rcu_irq_exit() invoked with irqs enabled!!!");
        rdtp = this_cpu_ptr(&rcu_dynticks);
+
+       /* Page faults can happen in NMI handlers, so check... */
+       if (READ_ONCE(rdtp->dynticks_nmi_nesting))
+               return;
+
        WARN_ON_ONCE(IS_ENABLED(CONFIG_RCU_EQS_DEBUG) &&
                     rdtp->dynticks_nesting < 1);
        if (rdtp->dynticks_nesting <= 1) {
@@ -1015,6 +1020,11 @@ void rcu_irq_enter(void)
 
        RCU_LOCKDEP_WARN(!irqs_disabled(), "rcu_irq_enter() invoked with irqs enabled!!!");
        rdtp = this_cpu_ptr(&rcu_dynticks);
+
+       /* Page faults can happen in NMI handlers, so check... */
+       if (READ_ONCE(rdtp->dynticks_nmi_nesting))
+               return;
+
        oldval = rdtp->dynticks_nesting;
        rdtp->dynticks_nesting++;
        WARN_ON_ONCE(IS_ENABLED(CONFIG_RCU_EQS_DEBUG) &&
index a4df67cbc711459df2aa8b4a313eb449a472ee45..49cb41412eece8bb7dff9bedf5fd7991ade07b76 100644 (file)
@@ -96,23 +96,9 @@ check_stack(unsigned long ip, unsigned long *stack)
        if (in_nmi())
                return;
 
-       /*
-        * There's a slight chance that we are tracing inside the
-        * RCU infrastructure, and rcu_irq_enter() will not work
-        * as expected.
-        */
-       if (unlikely(rcu_irq_enter_disabled()))
-               return;
-
        local_irq_save(flags);
        arch_spin_lock(&stack_trace_max_lock);
 
-       /*
-        * RCU may not be watching, make it see us.
-        * The stack trace code uses rcu_sched.
-        */
-       rcu_irq_enter();
-
        /* In case another CPU set the tracer_frame on us */
        if (unlikely(!frame_size))
                this_size -= tracer_frame;
@@ -205,7 +191,6 @@ check_stack(unsigned long ip, unsigned long *stack)
        }
 
  out:
-       rcu_irq_exit();
        arch_spin_unlock(&stack_trace_max_lock);
        local_irq_restore(flags);
 }