From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753127AbdI1M0L (ORCPT ); Thu, 28 Sep 2017 08:26:11 -0400 Received: from merlin.infradead.org ([205.233.59.134]:53302 "EHLO merlin.infradead.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752986AbdI1M0I (ORCPT ); Thu, 28 Sep 2017 08:26:08 -0400 Message-Id: <20170928122513.431444176@infradead.org> User-Agent: quilt/0.63-1 Date: Thu, 28 Sep 2017 14:18:26 +0200 From: Peter Zijlstra To: pmladek@suse.com, sergey.senozhatsky@gmail.com Cc: linux-kernel@vger.kernel.org, rostedt@goodmis.org, mingo@kernel.org, tglx@linutronix.de, peterz@infradead.org Subject: [PATCH 3/3] early_printk: Add simple serialization to early_vprintk() References: <20170928121823.430053219@infradead.org> MIME-Version: 1.0 Content-Type: text/plain; charset=ISO-8859-15 Content-Disposition: inline; filename=peterz-early_printk-serialize.patch Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org In order to avoid multiple CPUs banging on the serial port at the same time, add simple serialization. This explicitly deals with nested contexts (like IRQs etc.). Signed-off-by: Peter Zijlstra (Intel) --- kernel/printk/printk.c | 35 ++++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -378,14 +378,47 @@ static int __init force_early_printk_set } early_param("force_early_printk", force_early_printk_setup); +static int early_printk_cpu = -1; + static int early_vprintk(const char *fmt, va_list args) { + int n, cpu, old; char buf[512]; - int n; + + cpu = get_cpu(); + /* + * Test-and-Set inter-cpu spinlock with recursion. + */ + for (;;) { + /* + * c-cas to avoid the exclusive bouncing on spin. + * Depends on the memory barrier implied by cmpxchg + * for ACQUIRE semantics. + */ + old = READ_ONCE(early_printk_cpu); + if (old == -1) { + old = cmpxchg(&early_printk_cpu, -1, cpu); + if (old == -1) + break; + } + /* + * Allow recursion for interrupts and the like. + */ + if (old == cpu) + break; + + cpu_relax(); + } n = vscnprintf(buf, sizeof(buf), fmt, args); early_console->write(early_console, buf, n); + /* + * Unlock -- in case @old == @cpu, this is a no-op. + */ + smp_store_release(&early_printk_cpu, old); + put_cpu(); + return n; }