diff --git a/include/linux/console.h b/include/linux/console.h index 7571a16bd653..c61c169f85b3 100644 --- a/include/linux/console.h +++ b/include/linux/console.h @@ -150,6 +150,7 @@ extern int console_trylock(void); extern void console_unlock(void); extern void console_conditional_schedule(void); extern void console_unblank(void); +extern void console_flush(void); extern struct tty_driver *console_device(int *); extern void console_stop(struct console *); extern void console_start(struct console *); diff --git a/kernel/printk.c b/kernel/printk.c index 8d981b2b5bb1..1c0577383af5 100644 --- a/kernel/printk.c +++ b/kernel/printk.c @@ -2306,6 +2306,28 @@ struct tty_driver *console_device(int *index) } /* + * Wait until all messages accumulated in the printk buffer are printed to + * console. Note that as soon as this function returns, new messages may be + * added to the printk buffer by other CPUs. + */ +void console_flush(void) +{ + bool retry; + unsigned long flags; + + while (1) { + raw_spin_lock_irqsave(&logbuf_lock, flags); + retry = console_seq != log_next_seq; + raw_spin_unlock_irqrestore(&logbuf_lock, flags); + if (!retry || console_suspended) + break; + /* Cycle console_sem to wait for outstanding printing */ + console_lock(); + console_unlock(); + } +} + +/* * Prevent further output on the passed console device so that (for example) * serial drivers can disable console output before suspending a port, and can * re-enable output afterwards. diff --git a/kernel/stop_machine.c b/kernel/stop_machine.c index 84571e09c907..14ac740e0c7f 100644 --- a/kernel/stop_machine.c +++ b/kernel/stop_machine.c @@ -21,5 +21,6 @@ #include #include +#include /* * Structure to determine completion condition and record errors. May @@ -574,6 +575,14 @@ int __stop_machine(int (*fn)(void *), void *data, const struct cpumask *cpus) return ret; } + /* + * If there are lots of outstanding messages, printing them can take a + * long time and all cpus would be spinning waiting for the printing to + * finish thus triggering NMI watchdog, RCU lockups etc. Wait for the + * printing here to avoid these. + */ + console_flush(); + /* Set the initial state and stop all online cpus. */ set_state(&msdata, MULTI_STOP_PREPARE); return stop_cpus(cpu_online_mask, multi_cpu_stop, &msdata); -- 1.8.1.4