Re: [PATCH v2] mm/page_isolation: fix a deadlock with printk()

From: Petr Mladek
Date: Tue Oct 08 2019 - 04:15:15 EST


On Mon 2019-10-07 11:33:27, Qian Cai wrote:
> On Mon, 2019-10-07 at 17:12 +0200, Michal Hocko wrote:
> > On Mon 07-10-19 10:59:10, Qian Cai wrote:
> > [...]
> > > It is almost impossible to eliminate all the indirect call chains from
> > > console_sem/console_owner_lock to zone->lock because it is too normal that
> > > something later needs to allocate some memory dynamically, so as long as it
> > > directly call printk() with zone->lock held, it will be in trouble.
> >
> > Do you have any example where the console driver really _has_ to
> > allocate. Because I have hard time to believe this is going to work at
> > all as the atomic context doesn't allow to do any memory reclaim and
> > such an allocation would be too easy to fail so the allocation cannot
> > really rely on it.
>
> I don't know how to explain to you clearly, but let me repeat again one last
> time. There is no necessary for console driver directly to allocate considering
> this example,
>
> CPU0: CPU1: CPU2: CPU3:
> console_sem->lock zone->lock
> pi->lock
> pi->lock rq_lock
> rq->lock
> zone->lock
> console_sem->lock

I am curious about CPU2. Does scheduler need to allocate memory?

> Here it only need someone held the rq_lock and allocate some memory. There is
> also true for port_lock. Since the deadlock could involve a lot of CPUs and a
> longer lock chain, it is impossible to predict which one to allocate some memory
> while held a lock could end up with the same problematic lock chain.
>
> This is just a tip of iceberg to show the lock dependency,
>
> console_owner --> port_lock_key
>
> which could easily happen everywhere with a simple printk().

We have got several lockdep reports about possible deadlocks between
console_lock and port_lock caused by printk() called from console
code.

First note that they have been there for years. They were well hidden
until 4.11 released in April 2017. Where the commit
f975237b76827956fe13e ("printk: use printk_safe buffers in printk")
allowed recursive printk() and lockdep.

We believe that these deadlocks are really hard to hit. Console
drivers call printk() only in very critical and rare situations.
This is why nobody invested too much time into fixing these
so far.

There are basically three possibilities:

1. Do crazy exercises with locks all around the kernel to
avoid the deadlocks. It is usually not worth it. And
it is a "whack a mole" approach.

2. Use printk_deferred() in problematic code paths. It is
a "whack a mole" approach as well. And we would end up
with printk_deferred() used almost everywhere.

3. Always deffer the console handling in printk(). This would
help also to avoid soft lockups. Several people pushed
against this last few years because it might reduce
the chance to see the message in case of system crash.

As I said, there has finally been agreement to always do
the offload few weeks ago. John Ogness is working on it.
So we might have the systematic solution for these deadlocks
rather sooner than later.

Feel free to ask John to CC you on the patches if you want
to help with review.

Best Regards,
Petr