From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-pl0-f67.google.com ([209.85.160.67]:40850 "EHLO mail-pl0-f67.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751644AbeERCHK (ORCPT ); Thu, 17 May 2018 22:07:10 -0400 Date: Fri, 18 May 2018 11:07:05 +0900 From: Sergey Senozhatsky To: Petr Mladek Cc: Sergey Senozhatsky , Steven Rostedt , Peter Zijlstra , Tetsuo Handa , Sergey Senozhatsky , linux-kernel@vger.kernel.org, "4 . 13+" Subject: Re: [PATCH] printk/nmi: Prevent deadlock when serializing NMI backtraces Message-ID: <20180518020705.GB1160@jagdpanzerIV> References: <20180517143903.19339-1-pmladek@suse.com> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <20180517143903.19339-1-pmladek@suse.com> Sender: stable-owner@vger.kernel.org List-ID: On (05/17/18 16:39), Petr Mladek wrote: > > CPU0 CPU1 CPU2 > > printk() > vprintk_emit() > spin_lock(&logbuf_lock) > > trigger_all_cpu_backtrace() > raise() > > nmi_enter() > printk_nmi_enter() > if (this_cpu_read(printk_context) > & PRINTK_SAFE_CONTEXT_MASK) > // false > else > // looks safe to use printk_deferred() > this_cpu_or(printk_context, > PRINTK_NMI_DEFERRED_CONTEXT_MASK); > > nmi_cpu_backtrace() > arch_spin_lock(&lock); > show_regs() > > nmi_enter() > nmi_cpu_backtrace() > arch_spin_lock(&lock); > > printk() > vprintk_func() > vprintk_deferred() > vprintk_emit() > spin_lock(&logbuf_lock) > > DEADLOCK: between &logbuf_lock from vprintk_emit() and > &lock from nmi_cpu_backtrace(). > > CPU0 CPU1 > lock(logbuf_lock) lock(lock) > lock(lock) lock(logbuf_lock) > [..] > Signed-off-by: Petr Mladek This is a pretty cool find! Acked-by: Sergey Senozhatsky > - if ((this_cpu_read(printk_context) & PRINTK_SAFE_CONTEXT_MASK) && > - raw_spin_is_locked(&logbuf_lock)) { > + if (raw_spin_is_locked(&logbuf_lock)) > this_cpu_or(printk_context, PRINTK_NMI_CONTEXT_MASK); > - } else { > + else > this_cpu_or(printk_context, PRINTK_NMI_DEFERRED_CONTEXT_MASK); > - } A question - can we switch to a bitwise OR? if (this_cpu_read(printk_context) & PRINTK_SAFE_CONTEXT_MASK) || raw_spin_is_locked(&logbuf_lock) just to check per-CPU `printk_context' first and only afterwards access the global `logbuf_lock'. printk_nmi_enter() happens on every CPU, so maybe we can avoid some overhead by checking the local per-CPU data first. -ss