]> git.baikalelectronics.ru Git - kernel.git/commit
workqueue: fix state-dump console deadlock
authorJohan Hovold <johan@kernel.org>
Wed, 6 Oct 2021 11:58:52 +0000 (13:58 +0200)
committerTejun Heo <tj@kernel.org>
Mon, 11 Oct 2021 16:50:28 +0000 (06:50 -1000)
commitbaddfe31ee3d96f380c4c6efb4c6144aaf6ad4fe
tree91726f6d2299e032f1cf07f381533f80db96dffa
parent2dd9445a939d13b8640bf23a4a15a1145bb51e02
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.

Fixes: b9ff3b79ad51 ("workqueue: dump workqueues on sysrq-t")
Cc: stable@vger.kernel.org # 4.0
Reported-by: Fabio Estevam <festevam@denx.de>
Tested-by: Fabio Estevam <festevam@denx.de>
Signed-off-by: Johan Hovold <johan@kernel.org>
Reviewed-by: John Ogness <john.ogness@linutronix.de>
Signed-off-by: Tejun Heo <tj@kernel.org>
kernel/workqueue.c