mirror of
https://github.com/FEX-Emu/linux.git
synced 2025-01-10 19:43:29 +00:00
sched/debug: Make the "Preemption disabled at ..." message more useful
This message is currently really useless since it always prints a value that comes from the printk() we just did, e.g.: BUG: sleeping function called from invalid context at mm/slab.h:388 in_atomic(): 0, irqs_disabled(): 0, pid: 31996, name: trinity-c1 Preemption disabled at:[<ffffffff8119db33>] down_trylock+0x13/0x80 BUG: sleeping function called from invalid context at include/linux/freezer.h:56 in_atomic(): 0, irqs_disabled(): 0, pid: 31996, name: trinity-c1 Preemption disabled at:[<ffffffff811aaa37>] console_unlock+0x2f7/0x930 Here, both down_trylock() and console_unlock() is somewhere in the printk() path. We should save the value before calling printk() and use the saved value instead. That immediately reveals the offending callsite: BUG: sleeping function called from invalid context at mm/slab.h:388 in_atomic(): 0, irqs_disabled(): 0, pid: 14971, name: trinity-c2 Preemption disabled at:[<ffffffff819bcd46>] rhashtable_walk_start+0x46/0x150 Bug report: http://marc.info/?l=linux-netdev&m=146925979821849&w=2 Signed-off-by: Vegard Nossum <vegard.nossum@oracle.com> Cc: Andrew Morton <akpm@linux-foundation.org> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Mike Galbraith <efault@gmx.de> Cc: Paul E. McKenney <paulmck@linux.vnet.ibm.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Rusty Russel <rusty@rustcorp.com.au> Cc: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: Ingo Molnar <mingo@kernel.org>
This commit is contained in:
parent
98b0a85780
commit
d1c6d149cf
@ -3236,6 +3236,15 @@ static inline void cond_resched_rcu(void)
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline unsigned long get_preempt_disable_ip(struct task_struct *p)
|
||||
{
|
||||
#ifdef CONFIG_DEBUG_PREEMPT
|
||||
return p->preempt_disable_ip;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Does a critical section need to be broken due to another
|
||||
* task waiting?: (technically does not depend on CONFIG_PREEMPT,
|
||||
|
@ -3171,6 +3171,9 @@ static inline void preempt_latency_stop(int val) { }
|
||||
*/
|
||||
static noinline void __schedule_bug(struct task_struct *prev)
|
||||
{
|
||||
/* Save this before calling printk(), since that will clobber it */
|
||||
unsigned long preempt_disable_ip = get_preempt_disable_ip(current);
|
||||
|
||||
if (oops_in_progress)
|
||||
return;
|
||||
|
||||
@ -3181,13 +3184,12 @@ static noinline void __schedule_bug(struct task_struct *prev)
|
||||
print_modules();
|
||||
if (irqs_disabled())
|
||||
print_irqtrace_events(prev);
|
||||
#ifdef CONFIG_DEBUG_PREEMPT
|
||||
if (in_atomic_preempt_off()) {
|
||||
if (IS_ENABLED(CONFIG_DEBUG_PREEMPT)
|
||||
&& in_atomic_preempt_off()) {
|
||||
pr_err("Preemption disabled at:");
|
||||
print_ip_sym(current->preempt_disable_ip);
|
||||
print_ip_sym(preempt_disable_ip);
|
||||
pr_cont("\n");
|
||||
}
|
||||
#endif
|
||||
if (panic_on_warn)
|
||||
panic("scheduling while atomic\n");
|
||||
|
||||
@ -7571,6 +7573,7 @@ EXPORT_SYMBOL(__might_sleep);
|
||||
void ___might_sleep(const char *file, int line, int preempt_offset)
|
||||
{
|
||||
static unsigned long prev_jiffy; /* ratelimiting */
|
||||
unsigned long preempt_disable_ip;
|
||||
|
||||
rcu_sleep_check(); /* WARN_ON_ONCE() by default, no rate limit reqd. */
|
||||
if ((preempt_count_equals(preempt_offset) && !irqs_disabled() &&
|
||||
@ -7581,6 +7584,9 @@ void ___might_sleep(const char *file, int line, int preempt_offset)
|
||||
return;
|
||||
prev_jiffy = jiffies;
|
||||
|
||||
/* Save this before calling printk(), since that will clobber it */
|
||||
preempt_disable_ip = get_preempt_disable_ip(current);
|
||||
|
||||
printk(KERN_ERR
|
||||
"BUG: sleeping function called from invalid context at %s:%d\n",
|
||||
file, line);
|
||||
@ -7595,13 +7601,12 @@ void ___might_sleep(const char *file, int line, int preempt_offset)
|
||||
debug_show_held_locks(current);
|
||||
if (irqs_disabled())
|
||||
print_irqtrace_events(current);
|
||||
#ifdef CONFIG_DEBUG_PREEMPT
|
||||
if (!preempt_count_equals(preempt_offset)) {
|
||||
if (IS_ENABLED(CONFIG_DEBUG_PREEMPT)
|
||||
&& !preempt_count_equals(preempt_offset)) {
|
||||
pr_err("Preemption disabled at:");
|
||||
print_ip_sym(current->preempt_disable_ip);
|
||||
print_ip_sym(preempt_disable_ip);
|
||||
pr_cont("\n");
|
||||
}
|
||||
#endif
|
||||
dump_stack();
|
||||
}
|
||||
EXPORT_SYMBOL(___might_sleep);
|
||||
|
Loading…
Reference in New Issue
Block a user