diff options
Diffstat (limited to 'kernel/printk')
-rw-r--r-- | kernel/printk/printk.c | 23 |
1 files changed, 14 insertions, 9 deletions
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c index 2523332bd998..a6d023c3b852 100644 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -1758,20 +1758,12 @@ asmlinkage int vprintk_emit(int facility, int level, if (!in_sched) { lockdep_off(); /* - * Disable preemption to avoid being preempted while holding - * console_sem which would prevent anyone from printing to - * console - */ - preempt_disable(); - - /* * Try to acquire and then immediately release the console * semaphore. The release will print out buffers and wake up * /dev/kmsg and syslog() users. */ if (console_trylock()) console_unlock(); - preempt_enable(); lockdep_on(); } @@ -2122,7 +2114,20 @@ int console_trylock(void) return 0; } console_locked = 1; - console_may_schedule = 0; + /* + * When PREEMPT_COUNT disabled we can't reliably detect if it's + * safe to schedule (e.g. calling printk while holding a spin_lock), + * because preempt_disable()/preempt_enable() are just barriers there + * and preempt_count() is always 0. + * + * RCU read sections have a separate preemption counter when + * PREEMPT_RCU enabled thus we must take extra care and check + * rcu_preempt_depth(), otherwise RCU read sections modify + * preempt_count(). + */ + console_may_schedule = !oops_in_progress && + preemptible() && + !rcu_preempt_depth(); return 1; } EXPORT_SYMBOL(console_trylock); |