History

workqueue: fix state-dump console deadlock

Console drivers often queue work while holding locks also taken in their console write paths, something which can lead to deadlocks on SMP when dumping workqueue state (e.g. sysrq-t or on suspend failures). For serial console drivers this could look like: CPU0 CPU1 ---- ---- show_workqueue_state(); lock(&pool->lock); <IRQ> lock(&port->lock); schedule_work(); lock(&pool->lock); printk(); lock(console_owner); lock(&port->lock); where workqueues are, for example, used to push data to the line discipline, process break signals and handle modem-status changes. Line disciplines and serdev drivers can also queue work on write-wakeup notifications, etc. Reworking every console driver to avoid queuing work while holding locks also taken in their write paths would complicate drivers and is neither desirable or feasible. Instead use the deferred-printk mechanism to avoid printing while holding pool locks when dumping workqueue state. Note that there are a few WARN_ON() assertions in the workqueue code which could potentially also trigger a deadlock. Hopefully the ongoing printk rework will provide a general solution for this eventually. This was originally reported after a lockdep splat when executing sysrq-t with the imx serial driver.

Johan Hovold committed 5 years ago

Commit 57116ce1 parent 80f0a1f1 file · +16 −2Browse files

Showing the changes to kernel/workqueue.c (1 of 1 file). Show all

Unified · Split

kernel/workqueue.c+16−2
@@ -4830,8 +4830,16 @@ void show_workqueue_state(void) · 4829 unmodified lines
4830 4830
4831 for_each_pwq(pwq, wq) {4831 for_each_pwq(pwq, wq) {
4832 raw_spin_lock_irqsave(&pwq->pool->lock, flags);4832 raw_spin_lock_irqsave(&pwq->pool->lock, flags);
4833 if (pwq->nr_active || !list_empty(&pwq->inactive_works))4833 if (pwq->nr_active || !list_empty(&pwq->inactive_works)) {
4834 /*
4835 * Defer printing to avoid deadlocks in console
4836 * drivers that queue work while holding locks
4837 * also taken in their write paths.
4838 */
4839 printk_deferred_enter();
4834 show_pwq(pwq);4840 show_pwq(pwq);
4841 printk_deferred_exit();
4842 }
4835 raw_spin_unlock_irqrestore(&pwq->pool->lock, flags);4843 raw_spin_unlock_irqrestore(&pwq->pool->lock, flags);
4836 /*4844 /*
4837 * We could be printing a lot from atomic context, e.g.4845 * We could be printing a lot from atomic context, e.g.
@@ -4849,7 +4857,12 @@ void show_workqueue_state(void) · 11 unmodified lines
4849 raw_spin_lock_irqsave(&pool->lock, flags);4857 raw_spin_lock_irqsave(&pool->lock, flags);
4850 if (pool->nr_workers == pool->nr_idle)4858 if (pool->nr_workers == pool->nr_idle)
4851 goto next_pool;4859 goto next_pool;
4852 4860 /*
4861 * Defer printing to avoid deadlocks in console drivers that
4862 * queue work while holding locks also taken in their write
4863 * paths.
4864 */
4865 printk_deferred_enter();
4853 pr_info("pool %d:", pool->id);4866 pr_info("pool %d:", pool->id);
4854 pr_cont_pool_info(pool);4867 pr_cont_pool_info(pool);
4855 pr_cont(" hung=%us workers=%d",4868 pr_cont(" hung=%us workers=%d",
@@ -4864,6 +4877,7 @@ void show_workqueue_state(void) · 8 unmodified lines
4864 first = false;4877 first = false;
4865 }4878 }
4866 pr_cont("\n");4879 pr_cont("\n");
4880 printk_deferred_exit();
4867 next_pool:4881 next_pool:
4868 raw_spin_unlock_irqrestore(&pool->lock, flags);4882 raw_spin_unlock_irqrestore(&pool->lock, flags);
4869 /*4883 /*

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t