printk: Don't take console semaphore in atomic context
The CPU HOTPLUG take_cpu_down path is invokved with preemption disabled via stop_machine. This causes a "Scheduling while atomic" BUG when there is contention for the console semaphore. The solution is to defer the console flush until it's not in scheduling violation. Change-Id: I2d0d58576a4db308ee40850a18a6bb9784ca4e4b Signed-off-by: Michael Bohan <mbohan@codeaurora.org> (cherry picked from commit f6d11b2eb9c110d0801aa40b1bfdb8194a5e3e3a)
This commit is contained in:
committed by
Rohit Vaswani
parent
8041e1099b
commit
82d5b8dc2a
@@ -1144,6 +1144,14 @@ void resume_console(void)
|
||||
console_unlock();
|
||||
}
|
||||
|
||||
static void __cpuinit console_flush(struct work_struct *work)
|
||||
{
|
||||
console_lock();
|
||||
console_unlock();
|
||||
}
|
||||
|
||||
static __cpuinitdata DECLARE_WORK(console_cpu_notify_work, console_flush);
|
||||
|
||||
/**
|
||||
* console_cpu_notify - print deferred console messages after CPU hotplug
|
||||
* @self: notifier struct
|
||||
@@ -1154,6 +1162,9 @@ void resume_console(void)
|
||||
* will be spooled but will not show up on the console. This function is
|
||||
* called when a new CPU comes online (or fails to come up), and ensures
|
||||
* that any such output gets printed.
|
||||
*
|
||||
* Special handling must be done for cases invoked from an atomic context,
|
||||
* as we can't be taking the console semaphore here.
|
||||
*/
|
||||
static int __cpuinit console_cpu_notify(struct notifier_block *self,
|
||||
unsigned long action, void *hcpu)
|
||||
@@ -1161,11 +1172,16 @@ static int __cpuinit console_cpu_notify(struct notifier_block *self,
|
||||
switch (action) {
|
||||
case CPU_ONLINE:
|
||||
case CPU_DEAD:
|
||||
case CPU_DYING:
|
||||
case CPU_DOWN_FAILED:
|
||||
case CPU_UP_CANCELED:
|
||||
console_lock();
|
||||
console_unlock();
|
||||
/* invoked with preemption disabled, so defer */
|
||||
case CPU_DYING:
|
||||
if (!console_trylock())
|
||||
schedule_work(&console_cpu_notify_work);
|
||||
else
|
||||
console_unlock();
|
||||
}
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user