Commit 7e49fcce authored by Steven Rostedt's avatar Steven Rostedt Committed by Ingo Molnar

trace, lockdep: manual preempt count adding for local_bh_disable

Impact: fix to preempt trace triggering lockdep check_flag failure

In local_bh_disable, the use of add_preempt_count causes the
preempt tracer to start recording the time preemption is off.
But because it already modified the preempt_count to show
softirqs disabled, and before it called the lockdep code to
handle this, it causes a state that lockdep can not handle.

The preempt tracer will reset the ring buffer on start of a trace,
and the ring buffer reset code does a spin_lock_irqsave. This
calls into lockdep and lockdep will fail when it detects the
invalid state of having softirqs disabled but the internal
current->softirqs_enabled is still set.

The fix is to manually add the SOFTIRQ_OFFSET to preempt count
and call the preempt tracer code outside the lockdep critical
area.

Thanks to Peter Zijlstra for suggesting this solution.
Signed-off-by: default avatarSteven Rostedt <srostedt@redhat.com>
Signed-off-by: default avatarIngo Molnar <mingo@elte.hu>
parent b06a8301
...@@ -137,6 +137,8 @@ extern unsigned long nr_uninterruptible(void); ...@@ -137,6 +137,8 @@ extern unsigned long nr_uninterruptible(void);
extern unsigned long nr_active(void); extern unsigned long nr_active(void);
extern unsigned long nr_iowait(void); extern unsigned long nr_iowait(void);
extern unsigned long get_parent_ip(unsigned long addr);
struct seq_file; struct seq_file;
struct cfs_rq; struct cfs_rq;
struct task_group; struct task_group;
......
...@@ -4399,10 +4399,7 @@ void scheduler_tick(void) ...@@ -4399,10 +4399,7 @@ void scheduler_tick(void)
#endif #endif
} }
#if defined(CONFIG_PREEMPT) && (defined(CONFIG_DEBUG_PREEMPT) || \ unsigned long get_parent_ip(unsigned long addr)
defined(CONFIG_PREEMPT_TRACER))
static inline unsigned long get_parent_ip(unsigned long addr)
{ {
if (in_lock_functions(addr)) { if (in_lock_functions(addr)) {
addr = CALLER_ADDR2; addr = CALLER_ADDR2;
...@@ -4412,6 +4409,9 @@ static inline unsigned long get_parent_ip(unsigned long addr) ...@@ -4412,6 +4409,9 @@ static inline unsigned long get_parent_ip(unsigned long addr)
return addr; return addr;
} }
#if defined(CONFIG_PREEMPT) && (defined(CONFIG_DEBUG_PREEMPT) || \
defined(CONFIG_PREEMPT_TRACER))
void __kprobes add_preempt_count(int val) void __kprobes add_preempt_count(int val)
{ {
#ifdef CONFIG_DEBUG_PREEMPT #ifdef CONFIG_DEBUG_PREEMPT
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include <linux/freezer.h> #include <linux/freezer.h>
#include <linux/kthread.h> #include <linux/kthread.h>
#include <linux/rcupdate.h> #include <linux/rcupdate.h>
#include <linux/ftrace.h>
#include <linux/smp.h> #include <linux/smp.h>
#include <linux/tick.h> #include <linux/tick.h>
...@@ -79,13 +80,23 @@ static void __local_bh_disable(unsigned long ip) ...@@ -79,13 +80,23 @@ static void __local_bh_disable(unsigned long ip)
WARN_ON_ONCE(in_irq()); WARN_ON_ONCE(in_irq());
raw_local_irq_save(flags); raw_local_irq_save(flags);
add_preempt_count(SOFTIRQ_OFFSET); /*
* The preempt tracer hooks into add_preempt_count and will break
* lockdep because it calls back into lockdep after SOFTIRQ_OFFSET
* is set and before current->softirq_enabled is cleared.
* We must manually increment preempt_count here and manually
* call the trace_preempt_off later.
*/
preempt_count() += SOFTIRQ_OFFSET;
/* /*
* Were softirqs turned off above: * Were softirqs turned off above:
*/ */
if (softirq_count() == SOFTIRQ_OFFSET) if (softirq_count() == SOFTIRQ_OFFSET)
trace_softirqs_off(ip); trace_softirqs_off(ip);
raw_local_irq_restore(flags); raw_local_irq_restore(flags);
if (preempt_count() == SOFTIRQ_OFFSET)
trace_preempt_off(CALLER_ADDR0, get_parent_ip(CALLER_ADDR1));
} }
#else /* !CONFIG_TRACE_IRQFLAGS */ #else /* !CONFIG_TRACE_IRQFLAGS */
static inline void __local_bh_disable(unsigned long ip) static inline void __local_bh_disable(unsigned long ip)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment