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();
|
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
|
* console_cpu_notify - print deferred console messages after CPU hotplug
|
||||||
* @self: notifier struct
|
* @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
|
* 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
|
* called when a new CPU comes online (or fails to come up), and ensures
|
||||||
* that any such output gets printed.
|
* 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,
|
static int __cpuinit console_cpu_notify(struct notifier_block *self,
|
||||||
unsigned long action, void *hcpu)
|
unsigned long action, void *hcpu)
|
||||||
@@ -1161,11 +1172,16 @@ static int __cpuinit console_cpu_notify(struct notifier_block *self,
|
|||||||
switch (action) {
|
switch (action) {
|
||||||
case CPU_ONLINE:
|
case CPU_ONLINE:
|
||||||
case CPU_DEAD:
|
case CPU_DEAD:
|
||||||
case CPU_DYING:
|
|
||||||
case CPU_DOWN_FAILED:
|
case CPU_DOWN_FAILED:
|
||||||
case CPU_UP_CANCELED:
|
case CPU_UP_CANCELED:
|
||||||
console_lock();
|
console_lock();
|
||||||
console_unlock();
|
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;
|
return NOTIFY_OK;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user