Re: [PATCH 1/3] printk: Fix kdb_trap_printk placement

From: Peter Zijlstra
Date: Wed Oct 19 2016 - 11:18:58 EST


On Wed, Oct 19, 2016 at 04:41:40PM +0200, Petr Mladek wrote:
> On Tue 2016-10-18 19:08:31, Peter Zijlstra wrote:
> > Some people figured vprintk_emit() makes for a nice API and exported
> > it, bypassing the kdb trap.
> >
> > This still leaves vprintk_nmi() outside of the kbd reach, should that
> > be fixed too?
>
> Good question! vkdb_printf() tries to avoid a deadlock but the code is racy:
>
> int vkdb_printf(enum kdb_msgsrc src, const char *fmt, va_list ap)
> {
> [...]
> /* Serialize kdb_printf if multiple cpus try to write at once.
> * But if any cpu goes recursive in kdb, just print the output,
> * even if it is interleaved with any other text.
> */
> if (!KDB_STATE(PRINTF_LOCK)) {
> KDB_STATE_SET(PRINTF_LOCK);
> spin_lock_irqsave(&kdb_printf_lock, flags);
> got_printf_lock = 1;
> atomic_inc(&kdb_event);
> } else {
> __acquire(kdb_printf_lock);
> }
>
>
> Let's have the following situation:
>
> CPU1 CPU2
>
> if (!KDB_STATE(PRINTF_LOCK)) {
> KDB_STATE_SET(PRINTF_LOCK);
>
> if (!KDB_STATE(PRINTF_LOCK)) {
> } else {
> __acquire(kdb_printf_lock);
> }
>
> Now, both CPUs are in the critical section and happily writing over each
> other, e.g. in
>
> vsnprintf(next_avail, size_avail, fmt, ap);
>
> I quess that we want to fix this race. But I am not sure if it will
> be done an NMI-safe way. I am going to send a patch for this.

Something like patch 3 in this series should do I suppose. But the
vkdb_printf() thing using spin_lock_irqsave() seems to suggest it was
never meant to be used from NMI context.