From nobody Mon Apr 6 03:09:13 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id D7DCFC6FA82 for ; Sat, 10 Sep 2022 22:27:52 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229925AbiIJW1l (ORCPT ); Sat, 10 Sep 2022 18:27:41 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45714 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229547AbiIJW1i (ORCPT ); Sat, 10 Sep 2022 18:27:38 -0400 Received: from galois.linutronix.de (Galois.linutronix.de [IPv6:2a0a:51c0:0:12e:550::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id A353D3334D for ; Sat, 10 Sep 2022 15:27:36 -0700 (PDT) Message-ID: <20220910222300.406755505@linutronix.de> DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020; t=1662848853; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: references:references; bh=90zm53gNGsnNrRXGITrlxBi4gXs52pVv+A6dByA1a7E=; b=LUm4KwKOHcvSdINElyUi1bpztxeBJog1m8l1KW0VZgfQSM8hL6o/6ktMkegvRNVms9H3wB 0cNNrVHYiAd/C/p4shxFEO+9U8JOdCtEoeMGV8iRxCFrs5tOpX5meHtl9jvn+mP5L45oGR aISnt3GExDGxpW2pZPYY/lJdXcezftKo49UY0+ypQXJdxzhxIXlQ+nkuEk4CRr3y9MYC7A W0xLoVM7gCbXiAfNhv7vKDiDHeV8fcw75O3DW181504gYFVEeBjbv73lIG5wXZqi/GFISo SAzfqNG1kLqdI4VB1w8PrKW9/oVgvxrCzliJVuI0NzlO6HUWqKF9Dt8MpyMHAg== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020e; t=1662848853; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: references:references; bh=90zm53gNGsnNrRXGITrlxBi4gXs52pVv+A6dByA1a7E=; b=zJ4Y1gLCnVFMZG4UOQ73lwl7QCHFVYxY/eM7m9SFRoZ2gIfxrrGGY3GcXpp/53LDP+sFae W2MwGaeIevR/GsBg== From: Thomas Gleixner To: LKML Cc: John Ogness , Petr Mladek , Sergey Senozhatsky , Steven Rostedt , Linus Torvalds , Peter Zijlstra , "Paul E. McKenney" , Daniel Vetter , Greg Kroah-Hartman , Helge Deller , Jason Wessel , Daniel Thompson Subject: [patch RFC 01/29] printk: Make pr_flush() static References: <20220910221947.171557773@linutronix.de> MIME-Version: 1.0 Date: Sun, 11 Sep 2022 00:27:33 +0200 (CEST) Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" No user outside the printk code and no reason to export this. Signed-off-by: Thomas Gleixner Reviewed-by: Sergey Senozhatsky --- include/linux/printk.h | 7 ------- kernel/printk/printk.c | 5 +++-- 2 files changed, 3 insertions(+), 9 deletions(-) --- a/include/linux/printk.h +++ b/include/linux/printk.h @@ -169,8 +169,6 @@ extern void __printk_safe_exit(void); #define printk_deferred_enter __printk_safe_enter #define printk_deferred_exit __printk_safe_exit =20 -extern bool pr_flush(int timeout_ms, bool reset_on_progress); - /* * Please don't use printk_ratelimit(), because it shares ratelimiting sta= te * with all other unrelated printk_ratelimit() callsites. Instead use @@ -221,11 +219,6 @@ static inline void printk_deferred_exit( { } =20 -static inline bool pr_flush(int timeout_ms, bool reset_on_progress) -{ - return true; -} - static inline int printk_ratelimit(void) { return 0; --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -2296,6 +2296,7 @@ asmlinkage __visible int _printk(const c } EXPORT_SYMBOL(_printk); =20 +static bool pr_flush(int timeout_ms, bool reset_on_progress); static bool __pr_flush(struct console *con, int timeout_ms, bool reset_on_= progress); =20 #else /* CONFIG_PRINTK */ @@ -2330,6 +2331,7 @@ static void call_console_driver(struct c { } static bool suppress_message_printing(int level) { return false; } +static bool pr_flush(int timeout_ms, bool reset_on_progress) { return true= ; } static bool __pr_flush(struct console *con, int timeout_ms, bool reset_on_= progress) { return true; } =20 #endif /* CONFIG_PRINTK */ @@ -3438,11 +3440,10 @@ static bool __pr_flush(struct console *c * Context: Process context. May sleep while acquiring console lock. * Return: true if all enabled printers are caught up. */ -bool pr_flush(int timeout_ms, bool reset_on_progress) +static bool pr_flush(int timeout_ms, bool reset_on_progress) { return __pr_flush(NULL, timeout_ms, reset_on_progress); } -EXPORT_SYMBOL(pr_flush); =20 /* * Delayed printk version, for scheduler-internal messages: From nobody Mon Apr 6 03:09:13 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id E98A7C6FA89 for ; Sat, 10 Sep 2022 22:27:52 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230008AbiIJW1t (ORCPT ); Sat, 10 Sep 2022 18:27:49 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45718 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229640AbiIJW1i (ORCPT ); Sat, 10 Sep 2022 18:27:38 -0400 Received: from galois.linutronix.de (Galois.linutronix.de [IPv6:2a0a:51c0:0:12e:550::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 9323738474 for ; Sat, 10 Sep 2022 15:27:37 -0700 (PDT) Message-ID: <20220910222300.466273303@linutronix.de> DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020; t=1662848855; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: references:references; bh=E5VNsdhocstLmuIwTiCMPIibe4zDdVnAf/ePac5FTrs=; b=Zy3HnUi2VBS5ut9uhR/yxiVuE5M61YjpLA/xPSpsVmYTNqV9p1HHw6cB+/BmwvbvS24vk9 IXDNJmqT1Xe0owRlb//4pc09RTWehYtFXH1BrH2NPDemslzdvI6AeOTfzT1MgCokpYDKXu ijPjGyH+G2WfmZ7QX2ggS/onqNdrBwKvMxjI36H1TZNVjj6UOIkpHSBRhpN5AR5XzAiOBi TqCMSn9Qh4VYejlys4zK5yhUO5ia1wMOUTFQSWtvkmN0pJVBxGEEYfXFbEBOiT01lJMIoN ZdMFegZcBoiBeIbeKQ8qllxcTH6MuyVadZ9fcei/utfLciJhmnFdGH6+4cCKtQ== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020e; t=1662848855; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: references:references; bh=E5VNsdhocstLmuIwTiCMPIibe4zDdVnAf/ePac5FTrs=; b=FW65dlnuCZ6asy8+cb0W/jTJqUbzHFWiipkPt5DjzbMJfAqlNSVG5p7HeFUfebCJj9UYNm VrtaqLn3el0Lq/CQ== From: Thomas Gleixner To: LKML Cc: John Ogness , Petr Mladek , Sergey Senozhatsky , Steven Rostedt , Linus Torvalds , Peter Zijlstra , "Paul E. McKenney" , Daniel Vetter , Greg Kroah-Hartman , Helge Deller , Jason Wessel , Daniel Thompson Subject: [patch RFC 02/29] printk: Declare log_wait properly References: <20220910221947.171557773@linutronix.de> MIME-Version: 1.0 Date: Sun, 11 Sep 2022 00:27:34 +0200 (CEST) Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" kernel/printk/printk.c:365:1: warning: symbol 'log_wait' was not declared. = Should it be static? Signed-off-by: Thomas Gleixner Reviewed-by: Sergey Senozhatsky --- fs/proc/kmsg.c | 2 -- include/linux/syslog.h | 3 +++ 2 files changed, 3 insertions(+), 2 deletions(-) --- a/fs/proc/kmsg.c +++ b/fs/proc/kmsg.c @@ -17,8 +17,6 @@ =20 #include =20 -extern wait_queue_head_t log_wait; - static int kmsg_open(struct inode * inode, struct file * file) { return do_syslog(SYSLOG_ACTION_OPEN, NULL, 0, SYSLOG_FROM_PROC); --- a/include/linux/syslog.h +++ b/include/linux/syslog.h @@ -8,6 +8,8 @@ #ifndef _LINUX_SYSLOG_H #define _LINUX_SYSLOG_H =20 +#include + /* Close the log. Currently a NOP. */ #define SYSLOG_ACTION_CLOSE 0 /* Open the log. Currently a NOP. */ @@ -35,5 +37,6 @@ #define SYSLOG_FROM_PROC 1 =20 int do_syslog(int type, char __user *buf, int count, int source); +extern wait_queue_head_t log_wait; =20 #endif /* _LINUX_SYSLOG_H */ From nobody Mon Apr 6 03:09:13 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id C53F7ECAAD3 for ; Sat, 10 Sep 2022 22:28:01 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229965AbiIJW17 (ORCPT ); Sat, 10 Sep 2022 18:27:59 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45724 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229744AbiIJW1j (ORCPT ); Sat, 10 Sep 2022 18:27:39 -0400 Received: from galois.linutronix.de (Galois.linutronix.de [193.142.43.55]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id D088638454 for ; Sat, 10 Sep 2022 15:27:38 -0700 (PDT) Message-ID: <20220910222300.524466942@linutronix.de> DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020; t=1662848857; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: references:references; bh=LscXlV1rkfiGC1iyhRF8H7x4yCrolRpccYbWcMWLptc=; b=2nOZDMNEQCdfpEbpssXSxl/1NxSLAxk9cE2s/LMpzA6P7inlIJV9Bm+gYBM1ko/cn2AEXJ H54xOqeXV5EKksTluT+KQv2Q6+eia6bqZIKj4c53mQws/3Q76cYab6UQ+d3X7QwNa1r9kq O3OWn6YxT59J89uNmG3nIg79xaIgx8Hh2wlOrfTpASFb8U9MUITu8DfxSVOTGCz1oOM/iU XmoI6D1ja3tTp+ppLwi0RKZrofTNiFWuYoCeGLMBMB8KB4tInmFiugcpiOC3XjMonbXcva Lux42ac/A0bRBJZI4KDd3OjF2r9uv/SwQFSgzOsjvgX7/pRo5Xv2b4SLS8p5aw== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020e; t=1662848857; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: references:references; bh=LscXlV1rkfiGC1iyhRF8H7x4yCrolRpccYbWcMWLptc=; b=ej4Id8FFr5usQbn+Iedp/mRjjlbohRQD3qzmoGgBw5CqirPF8W3Kk80tOxPC1JbmD3dAz2 mbTh8mVJ+eZ3mVCw== From: Thomas Gleixner To: LKML Cc: John Ogness , Petr Mladek , Sergey Senozhatsky , Steven Rostedt , Linus Torvalds , Peter Zijlstra , "Paul E. McKenney" , Daniel Vetter , Greg Kroah-Hartman , Helge Deller , Jason Wessel , Daniel Thompson Subject: [patch RFC 03/29] printk: Remove write only variable nr_ext_console_drivers References: <20220910221947.171557773@linutronix.de> MIME-Version: 1.0 Date: Sun, 11 Sep 2022 00:27:36 +0200 (CEST) Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Signed-off-by: Thomas Gleixner Reviewed-by: Sergey Senozhatsky --- kernel/printk/printk.c | 9 --------- 1 file changed, 9 deletions(-) --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -220,9 +220,6 @@ int devkmsg_sysctl_set_loglvl(struct ctl } #endif /* CONFIG_PRINTK && CONFIG_SYSCTL */ =20 -/* Number of registered extended console drivers. */ -static int nr_ext_console_drivers; - /* * Helper macros to handle lockdep when locking/unlocking console_sem. We = use * macros instead of functions so that _RET_IP_ contains useful informatio= n. @@ -3188,9 +3185,6 @@ void register_console(struct console *ne console_drivers->next =3D newcon; } =20 - if (newcon->flags & CON_EXTENDED) - nr_ext_console_drivers++; - newcon->dropped =3D 0; if (newcon->flags & CON_PRINTBUFFER) { /* Get a consistent copy of @syslog_seq. */ @@ -3256,9 +3250,6 @@ int unregister_console(struct console *c if (res) goto out_disable_unlock; =20 - if (console->flags & CON_EXTENDED) - nr_ext_console_drivers--; - /* * If this isn't the last console and it has CON_CONSDEV set, we * need to set it on the next preferred console. From nobody Mon Apr 6 03:09:13 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 49929C6FA82 for ; Sat, 10 Sep 2022 22:28:08 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230232AbiIJW2E (ORCPT ); Sat, 10 Sep 2022 18:28:04 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45730 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229502AbiIJW1k (ORCPT ); Sat, 10 Sep 2022 18:27:40 -0400 Received: from galois.linutronix.de (Galois.linutronix.de [IPv6:2a0a:51c0:0:12e:550::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 316E229813 for ; Sat, 10 Sep 2022 15:27:40 -0700 (PDT) Message-ID: <20220910222300.582492276@linutronix.de> DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020; t=1662848858; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: references:references; bh=Qm8taPkDgEoKYe5N6xRe6zt5ZBhN+tYNXGldQ0AU8dU=; b=DAOnF5V7GsRIYCsAWcMF1QYSh3uPjaAT/M8bbYwUZXXXMRZDKJgK0w72mJK7/5itjSBpwX LHxmMSiK+Vj4pLeTMTdiMo2YnfUa9JGpXmd3wc2vPtLKEFjem3bdOU1deHANaWTiuIUYOM 7rxUPlwWwpe8EDpMUtb6V7VI5NdAe+GPHLhDHcGqK74otmGuQAlnuVgl+hBKZpFMQb/ZTM Gm18WpBDcQtg8Tb5WfoVHX1f3Y3a+4lXPO4PbgUgfX2zu0EFe4rrVcsc+EAIZ7Kc+a+Me1 V8s20L7mQjgMTKg+rJxc6e4sk8lPeh5i7EQ9o7l4miUeYuROMI1o8OUa0B4bSg== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020e; t=1662848858; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: references:references; bh=Qm8taPkDgEoKYe5N6xRe6zt5ZBhN+tYNXGldQ0AU8dU=; b=0LrrLymEtqK9JVYyAU5j/AMdhRbGsZJsreYsPz22AEviwF+82xS47W9nlG+WytpvcO4txs OR5KLGnMAZLm0GCA== From: Thomas Gleixner To: LKML Cc: John Ogness , Petr Mladek , Sergey Senozhatsky , Steven Rostedt , Linus Torvalds , Peter Zijlstra , "Paul E. McKenney" , Daniel Vetter , Greg Kroah-Hartman , Helge Deller , Jason Wessel , Daniel Thompson Subject: [patch RFC 04/29] printk: Remove bogus comment vs. boot consoles References: <20220910221947.171557773@linutronix.de> MIME-Version: 1.0 Date: Sun, 11 Sep 2022 00:27:38 +0200 (CEST) Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" The comment about unregistering boot consoles is just not matching the reality. Remove it. Signed-off-by: Thomas Gleixner Reviewed-by: Sergey Senozhatsky --- kernel/printk/printk.c | 3 --- 1 file changed, 3 deletions(-) --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -3213,9 +3213,6 @@ void register_console(struct console *ne if (bootcon_enabled && ((newcon->flags & (CON_CONSDEV | CON_BOOT)) =3D=3D CON_CONSDEV) && !keep_bootcon) { - /* We need to iterate through all boot consoles, to make - * sure we print everything out, before we unregister them. - */ for_each_console(con) if (con->flags & CON_BOOT) unregister_console(con); From nobody Mon Apr 6 03:09:13 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id C5A42C6FA82 for ; Sat, 10 Sep 2022 22:28:16 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230094AbiIJW2O (ORCPT ); Sat, 10 Sep 2022 18:28:14 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45750 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229929AbiIJW1m (ORCPT ); Sat, 10 Sep 2022 18:27:42 -0400 Received: from galois.linutronix.de (Galois.linutronix.de [193.142.43.55]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id C27CB38454 for ; Sat, 10 Sep 2022 15:27:41 -0700 (PDT) Message-ID: <20220910222300.641069948@linutronix.de> DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020; t=1662848860; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: references:references; bh=Op91FjKbY7zuuyXzPveWYDshKfFSBgIymEIf7Nbwy78=; b=p3epJnlAok0bykrF/9hop/Y4Gc4YEycgVLrQfbxVRktkx0Zy+r+bknnbQeso6VCN+Jh87E np1+sMZajRr5bqSCzDAwof2POu5DN0TGAFy40z8uOxXeGgPpDIcQojCrkxvhGLrOAXmzJV nXgzqfGcvSAmomI4qgGpShpkPWjp6D66Dp+0RDIfWGbS6Z2BglDUY3ev+18yseWdd9AZ88 DSTmxslCMEUXLrjciMj45ZyMoMNTIDBxVAlacl4GAyYPYit227inbiIyDpWfmONX9GAZlD 6cMYszFbguLcbs1CG0UPrT+4+PC2jK4or7HhMmHhlashOWRxhgdUVRxapZ7cDw== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020e; t=1662848860; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: references:references; bh=Op91FjKbY7zuuyXzPveWYDshKfFSBgIymEIf7Nbwy78=; b=7LIdKBipkXx6981nWNV+4x5sokZ3n0m+LQsMZCqVNXTlsqk/miZwa3CcgaI2vkYA9rKBTM VidiF4MGpgNQD/Bw== From: Thomas Gleixner To: LKML Cc: John Ogness , Petr Mladek , Sergey Senozhatsky , Steven Rostedt , Linus Torvalds , Peter Zijlstra , "Paul E. McKenney" , Daniel Vetter , Greg Kroah-Hartman , Helge Deller , Jason Wessel , Daniel Thompson Subject: [patch RFC 05/29] printk: Mark __printk percpu data ready __ro_after_init References: <20220910221947.171557773@linutronix.de> MIME-Version: 1.0 Date: Sun, 11 Sep 2022 00:27:39 +0200 (CEST) Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" This variable cannot change post boot. Signed-off-by: Thomas Gleixner Reviewed-by: Sergey Senozhatsky --- kernel/printk/printk.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -430,7 +430,7 @@ static struct printk_ringbuffer *prb =3D & * per_cpu_areas are initialised. This variable is set to true when * it's safe to access per-CPU data. */ -static bool __printk_percpu_data_ready __read_mostly; +static bool __printk_percpu_data_ready __ro_after_init; =20 bool printk_percpu_data_ready(void) { From nobody Mon Apr 6 03:09:13 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id CFC33C6FA82 for ; Sat, 10 Sep 2022 22:28:21 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230274AbiIJW2S (ORCPT ); Sat, 10 Sep 2022 18:28:18 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45770 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229982AbiIJW1o (ORCPT ); Sat, 10 Sep 2022 18:27:44 -0400 Received: from galois.linutronix.de (Galois.linutronix.de [193.142.43.55]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 7AE703D5A0 for ; Sat, 10 Sep 2022 15:27:43 -0700 (PDT) Message-ID: <20220910222300.712668210@linutronix.de> DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020; t=1662848861; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: references:references; bh=o5EroeZfB4NRvl63EpSxfqZIvT4RtM7/V27p+d+Wyos=; b=Lq9KRRbRCX0Ak4qz8PNcmnbY1qO4QNuFUisqEyBcaC5V2qUJOYoGBlTG0ZgaRxHg4CRI78 G323bD21b5keHOyH+Je+VPkSF2+aXuajMFh8PlD4ejaIig7y9+BGqkcmuxmUMxLLk/ZJlG JS6hS0K9YILffaYp7z/VAm6Obqb3AkoU73qZcUAiAWbTV1m2enP0INBpikmYVyMVaQezS2 PfYjSVb4htLORkATadQbQAyA2evBdVOlOuDBZBLlSPgMEz2RTZ7fxXbAEbdtjPBSniWcni 9NnwSLKJaRWNi5Gt/y1iGVoJi5hOiwjcbTtph597AlCSKOiKvrVU/Cam5ML3jA== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020e; t=1662848861; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: references:references; bh=o5EroeZfB4NRvl63EpSxfqZIvT4RtM7/V27p+d+Wyos=; b=sYK6VGhDAuF/Gqfwp7U/eUg7y/W1Byds18bfIvK6JOlosn9b09WsD0fVaMKF95jHZnCAym IpH7WSzU4DPAXiAQ== From: Thomas Gleixner To: LKML Cc: John Ogness , Petr Mladek , Sergey Senozhatsky , Steven Rostedt , Linus Torvalds , Peter Zijlstra , "Paul E. McKenney" , Daniel Vetter , Greg Kroah-Hartman , Helge Deller , Jason Wessel , Daniel Thompson Subject: [patch RFC 06/29] printk: Protect [un]register_console() with a mutex References: <20220910221947.171557773@linutronix.de> MIME-Version: 1.0 Date: Sun, 11 Sep 2022 00:27:41 +0200 (CEST) Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Unprotected list walks are a brilliant idea. Especially in the context of hotpluggable consoles. Signed-off-by: Thomas Gleixner --- include/linux/console.h | 30 ++++++++++++++++-- kernel/printk/printk.c | 79 ++++++++++++++++++++++++++++++++++++++++---= ----- 2 files changed, 93 insertions(+), 16 deletions(-) --- a/include/linux/console.h +++ b/include/linux/console.h @@ -157,10 +157,34 @@ struct console { struct console *next; }; =20 -/* - * for_each_console() allows you to iterate on each console +#ifdef CONFIG_LOCKDEP +extern void lockdep_assert_console_list_lock_held(void); +#else +static inline void lockdep_assert_console_list_lock_held(void) { } +#endif + +extern void console_list_lock(void) __acquires(console_mutex); +extern void console_list_unlock(void) __releases(console_mutex); + +/** + * for_each_registered_console() - Iterator over registered consoles + * @con: struct console pointer used as loop cursor + * + * Requires console_list_lock to be held. Can only be invoked from + * preemptible context. + */ +#define for_each_registered_console(con) \ + lockdep_assert_console_list_lock_held(); \ + for (con =3D console_drivers; con !=3D NULL; con =3D con->next) + +/** + * for_each_console() - Iterator over registered consoles + * @con: struct console pointer used as loop cursor + * + * Requires console_lock to be held which guarantees that the + * list is immutable. */ -#define for_each_console(con) \ +#define for_each_console(con) \ for (con =3D console_drivers; con !=3D NULL; con =3D con->next) =20 extern int console_set_on_cmdline; --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -79,10 +79,14 @@ int oops_in_progress; EXPORT_SYMBOL(oops_in_progress); =20 /* - * console_sem protects the console_drivers list, and also - * provides serialisation for access to the entire console - * driver system. + * console_sem protects the console_drivers list, and also provides + * serialization for access to the entire console driver system. + * + * console_mutex serializes register/unregister. console_sem has to be + * taken for any list manipulation inside the console_mutex locked + * section to keep the console BKL machinery happy. */ +static DEFINE_MUTEX(console_mutex); static DEFINE_SEMAPHORE(console_sem); struct console *console_drivers; EXPORT_SYMBOL_GPL(console_drivers); @@ -103,6 +107,12 @@ static int __read_mostly suppress_panic_ static struct lockdep_map console_lock_dep_map =3D { .name =3D "console_lock" }; + +void lockdep_assert_console_list_lock_held(void) +{ + lockdep_assert_held(&console_mutex); +} + #endif =20 enum devkmsg_log_bits { @@ -220,6 +230,26 @@ int devkmsg_sysctl_set_loglvl(struct ctl } #endif /* CONFIG_PRINTK && CONFIG_SYSCTL */ =20 +/** + * console_list_lock - Lock the console list + * + * For non-console related list walks, e.g. procfs, sysfs... + */ +void console_list_lock(void) +{ + mutex_lock(&console_mutex); +} + +/** + * console_list_unlock - Unlock the console list + * + * Counterpart to console_list_lock() + */ +void console_list_unlock(void) +{ + mutex_unlock(&console_mutex); +} + /* * Helper macros to handle lockdep when locking/unlocking console_sem. We = use * macros instead of functions so that _RET_IP_ contains useful informatio= n. @@ -2978,17 +3008,21 @@ struct tty_driver *console_device(int *i void console_stop(struct console *console) { __pr_flush(console, 1000, true); + console_list_lock(); console_lock(); console->flags &=3D ~CON_ENABLED; console_unlock(); + console_list_unlock(); } EXPORT_SYMBOL(console_stop); =20 void console_start(struct console *console) { + console_list_lock(); console_lock(); console->flags |=3D CON_ENABLED; console_unlock(); + console_list_unlock(); __pr_flush(console, 1000, true); } EXPORT_SYMBOL(console_start); @@ -3081,6 +3115,8 @@ static void try_enable_default_console(s (con->flags & CON_BOOT) ? "boot" : "", \ con->name, con->index, ##__VA_ARGS__) =20 +static int console_unregister_locked(struct console *console); + /* * The console driver calls this routine during kernel initialization * to register the console printing procedure with printk() and to @@ -3107,13 +3143,14 @@ void register_console(struct console *ne bool realcon_enabled =3D false; int err; =20 - for_each_console(con) { + console_list_lock(); + for_each_registered_console(con) { if (WARN(con =3D=3D newcon, "console '%s%d' already registered\n", con->name, con->index)) - return; + goto unlock; } =20 - for_each_console(con) { + for_each_registered_console(con) { if (con->flags & CON_BOOT) bootcon_enabled =3D true; else @@ -3124,7 +3161,7 @@ void register_console(struct console *ne if (newcon->flags & CON_BOOT && realcon_enabled) { pr_info("Too late to register bootconsole %s%d\n", newcon->name, newcon->index); - return; + goto unlock; } =20 /* @@ -3155,7 +3192,7 @@ void register_console(struct console *ne =20 /* printk() messages are not printed to the Braille console. */ if (err || newcon->flags & CON_BRL) - return; + goto unlock; =20 /* * If we have a bootconsole, and are switching to a real console, @@ -3209,14 +3246,17 @@ void register_console(struct console *ne if (bootcon_enabled && ((newcon->flags & (CON_CONSDEV | CON_BOOT)) =3D=3D CON_CONSDEV) && !keep_bootcon) { - for_each_console(con) + for_each_console(con) { if (con->flags & CON_BOOT) - unregister_console(con); + console_unregister_locked(con); + } } +unlock: + console_list_unlock(); } EXPORT_SYMBOL(register_console); =20 -int unregister_console(struct console *console) +static int console_unregister_locked(struct console *console) { struct console *con; int res; @@ -3269,6 +3309,16 @@ int unregister_console(struct console *c =20 return res; } + +int unregister_console(struct console *console) +{ + int res; + + console_list_lock(); + res =3D console_unregister_locked(console); + console_list_unlock(); + return res; +} EXPORT_SYMBOL(unregister_console); =20 /* @@ -3320,7 +3370,8 @@ static int __init printk_late_init(void) struct console *con; int ret; =20 - for_each_console(con) { + console_list_lock(); + for_each_registered_console(con) { if (!(con->flags & CON_BOOT)) continue; =20 @@ -3337,9 +3388,11 @@ static int __init printk_late_init(void) */ pr_warn("bootconsole [%s%d] uses init memory and must be disabled even = before the real one is ready\n", con->name, con->index); - unregister_console(con); + console_unregister_locked(con); } } + console_list_unlock(); + ret =3D cpuhp_setup_state_nocalls(CPUHP_PRINTK_DEAD, "printk:dead", NULL, console_cpu_notify); WARN_ON(ret < 0); From nobody Mon Apr 6 03:09:13 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id E5274C6FA82 for ; Sat, 10 Sep 2022 22:28:25 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230300AbiIJW2X (ORCPT ); Sat, 10 Sep 2022 18:28:23 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45798 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230017AbiIJW1q (ORCPT ); Sat, 10 Sep 2022 18:27:46 -0400 Received: from galois.linutronix.de (Galois.linutronix.de [193.142.43.55]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 451CE386BB for ; Sat, 10 Sep 2022 15:27:45 -0700 (PDT) Message-ID: <20220910222300.783722057@linutronix.de> DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020; t=1662848863; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: references:references; bh=qpkzU9jb2bUdUHq2NpoLCHahRoEppPCszhdtWaetok8=; b=Q6FVsyN/aJPyaEMuDxaRx7BVOK/OdIH7OuX/5QVTCOaJweRNfq+PLpIlbtCYrmH8czzipW Ffe1xBqjVTt7jF7Jf69FyGvI6kcRZnwwlaxPrvZeFuMYx2F6HupmXkh87NEqnhZHETvAHD t1rrMhiMpsDfK2YCvBtJ6q55CboiRILNeovjxFswLgoxdGAGpl2JRNwfOS2+VadZcvHNJ1 ZSJgP4D9/PYfYhrX5GSm/qi/9+fm+6fbUTwKQ/CZNCbXfpnBLxLvkjNPUJIDzcrsLeimPL Fb+yjpvRYxBTnEsoWFS1zvb3Pt//tJdLoHmAxsF1QkdN5A8BeWACNdOI4TYmTg== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020e; t=1662848863; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: references:references; bh=qpkzU9jb2bUdUHq2NpoLCHahRoEppPCszhdtWaetok8=; b=3Op6elz2aAwBiSirIUTeSnN+bV+QJFO7RDUgLF/qUrjJvCbRTMmHxz8MjqUn7xw5sZOaPe LRgRKZoTruScC6Dw== From: Thomas Gleixner To: LKML Cc: John Ogness , Petr Mladek , Sergey Senozhatsky , Steven Rostedt , Linus Torvalds , Peter Zijlstra , "Paul E. McKenney" , Daniel Vetter , Greg Kroah-Hartman , Helge Deller , Jason Wessel , Daniel Thompson Subject: [patch RFC 07/29] printk: Convert console list walks for readers to list lock References: <20220910221947.171557773@linutronix.de> MIME-Version: 1.0 Date: Sun, 11 Sep 2022 00:27:42 +0200 (CEST) Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Facilities which expose console information to sysfs or procfs can use the new list protection to keep the list stable. No need to hold console lock. Signed-off-by: Thomas Gleixner Reviewed-by: Sergey Senozhatsky --- drivers/tty/tty_io.c | 6 +++--- fs/proc/consoles.c | 6 +++--- kernel/printk/printk.c | 8 ++++---- 3 files changed, 10 insertions(+), 10 deletions(-) --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -3535,8 +3535,8 @@ static ssize_t show_cons_active(struct d struct console *c; ssize_t count =3D 0; =20 - console_lock(); - for_each_console(c) { + console_list_lock(); + for_each_registered_console(c) { if (!c->device) continue; if (!c->write) @@ -3560,7 +3560,7 @@ static ssize_t show_cons_active(struct d =20 count +=3D sprintf(buf + count, "%c", i ? ' ':'\n'); } - console_unlock(); + console_list_unlock(); =20 return count; } --- a/fs/proc/consoles.c +++ b/fs/proc/consoles.c @@ -63,8 +63,8 @@ static void *c_start(struct seq_file *m, struct console *con; loff_t off =3D 0; =20 - console_lock(); - for_each_console(con) + console_list_lock(); + for_each_registered_console(con) if (off++ =3D=3D *pos) break; =20 @@ -80,7 +80,7 @@ static void *c_next(struct seq_file *m, =20 static void c_stop(struct seq_file *m, void *v) { - console_unlock(); + console_list_unlock(); } =20 static const struct seq_operations consoles_op =3D { --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -2985,18 +2985,18 @@ void console_flush_on_panic(enum con_flu */ struct tty_driver *console_device(int *index) { - struct console *c; struct tty_driver *driver =3D NULL; + struct console *c; =20 - console_lock(); - for_each_console(c) { + console_list_lock(); + for_each_registered_console(c) { if (!c->device) continue; driver =3D c->device(c, index); if (driver) break; } - console_unlock(); + console_list_unlock(); return driver; } From nobody Mon Apr 6 03:09:13 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id C4BEFC6FA82 for ; Sat, 10 Sep 2022 22:28:30 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229853AbiIJW22 (ORCPT ); Sat, 10 Sep 2022 18:28:28 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45854 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229956AbiIJW1r (ORCPT ); Sat, 10 Sep 2022 18:27:47 -0400 Received: from galois.linutronix.de (Galois.linutronix.de [IPv6:2a0a:51c0:0:12e:550::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id C52DC42AEA for ; Sat, 10 Sep 2022 15:27:46 -0700 (PDT) Message-ID: <20220910222300.846719466@linutronix.de> DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020; t=1662848864; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: references:references; bh=X8SnKPqrkzZxerHYD/XgQWDb+uIPlnpUZ5U4JX+DX7g=; b=LZ5nkwCtJWjVflIeFYrTasSpWud/BpdHRAi72VFZ1drIKC33ebH3yUYvADtdnsxyeIStvr X6l0Lvis9vT27ffdzjHJp8i4B4H1wYpvmyluQi7QrjWts4WS1E6Mst2WfJQaFKoBAVqocG yzkEODXKhiKrTGohXl4gqAuigLy7tl69FWfpcb1mcSo991AouxLIz5CNTtK95HgA9sQx+z guv3nIpejRXIDqXlau8ZDxdpa5w7O5TVs7UU/2BK4fFE3lkvK3fVYaYy6nAgpConyQIEga geL1fVn8+XRDYVI411rcZWhS+B6P3cTyUbxskWfSXOa3wIo8d0vWvEaFvmxNOg== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020e; t=1662848864; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: references:references; bh=X8SnKPqrkzZxerHYD/XgQWDb+uIPlnpUZ5U4JX+DX7g=; b=AD02eYayJvVJbovZD8OsuYXTQ5VxXSx1+bVaG8pzVH0y7R5UKcmm//5xwaS1etOSwjfJnu a4up3EGjggGV/hCw== From: Thomas Gleixner To: LKML Cc: John Ogness , Petr Mladek , Sergey Senozhatsky , Steven Rostedt , Linus Torvalds , Peter Zijlstra , "Paul E. McKenney" , Daniel Vetter , Greg Kroah-Hartman , Helge Deller , Jason Wessel , Daniel Thompson Subject: [patch RFC 08/29] parisc: Put console abuse into one place References: <20220910221947.171557773@linutronix.de> MIME-Version: 1.0 Date: Sun, 11 Sep 2022 00:27:44 +0200 (CEST) Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" PARISC has a hope based mechanism to restore consoles in case of a HPMC (machine check exception) which is scattered over several places. Move it into one place to make further changes simpler and add comments. Signed-off-by: Thomas Gleixner Reviewed-by: Sergey Senozhatsky --- arch/parisc/include/asm/pdc.h | 2 +- arch/parisc/kernel/pdc_cons.c | 38 +++++++++++++++++++++++++++++++------- arch/parisc/kernel/traps.c | 17 +++++------------ 3 files changed, 37 insertions(+), 20 deletions(-) --- a/arch/parisc/include/asm/pdc.h +++ b/arch/parisc/include/asm/pdc.h @@ -20,7 +20,7 @@ extern unsigned long parisc_pat_pdc_cap; #define PDC_TYPE_SNAKE 2 /* Doesn't support SYSTEM_MAP */ =20 void pdc_console_init(void); /* in pdc_console.c */ -void pdc_console_restart(void); +void pdc_console_restart(bool hpmc); =20 void setup_pdc(void); /* in inventory.c */ =20 --- a/arch/parisc/kernel/pdc_cons.c +++ b/arch/parisc/kernel/pdc_cons.c @@ -237,20 +237,44 @@ void __init pdc_console_init(void) =20 =20 /* - * Used for emergencies. Currently only used if an HPMC occurs. If an - * HPMC occurs, it is possible that the current console may not be - * properly initialised after the PDC IO reset. This routine unregisters - * all of the current consoles, reinitializes the pdc console and - * registers it. + * + * + * Used for emergencies. + * + * - If an HPMC occurs, it is possible that the current console may not be + * properly initialised after the PDC IO reset. This routine unregisters + * all of the current consoles, reinitializes the pdc console and regis= ters + * it. + * + * - Maybe the kernel hasn't booted very far yet and hasn't been able + * to initialize the serial or STI console. In that case we should + * re-enable the pdc console, so that the user will be able to + * identify the problem. + * + * + * + * The above is all wishful thinking: + * + * - Invoking [un]register_console() from exception contexts is obviously + * unsafe. + * + * - If the HPMC left the machine in unpleasant state and the pdc console + * was already initialized, but later removed due to CON_BOOT then this + * will do nothing. + * + * Pretend that any of the below works in the same way as we pretend that + * any of PARISC works. */ - -void pdc_console_restart(void) +void pdc_console_restart(bool hpmc) { struct console *console; =20 if (pdc_console_initialized) return; =20 + if (!hpmc && console_drivers) + return; + /* If we've already seen the output, don't bother to print it again */ if (console_drivers !=3D NULL) pdc_cons.flags &=3D ~CON_PRINTBUFFER; --- a/arch/parisc/kernel/traps.c +++ b/arch/parisc/kernel/traps.c @@ -235,17 +235,12 @@ void die_if_kernel(char *str, struct pt_ " (__)\\ )\\/\\\n" " U ||----w |\n" " || ||\n"); -=09 + /* unlock the pdc lock if necessary */ pdc_emergency_unlock(); =20 - /* maybe the kernel hasn't booted very far yet and hasn't been able=20 - * to initialize the serial or STI console. In that case we should=20 - * re-enable the pdc console, so that the user will be able to=20 - * identify the problem. */ - if (!console_drivers) - pdc_console_restart(); -=09 + pdc_console_restart(false); + if (err) printk(KERN_CRIT "%s (pid %d): %s (code %ld)\n", current->comm, task_pid_nr(current), str, err); @@ -429,9 +424,7 @@ void parisc_terminate(char *msg, struct /* unlock the pdc lock if necessary */ pdc_emergency_unlock(); =20 - /* restart pdc console if necessary */ - if (!console_drivers) - pdc_console_restart(); + pdc_console_restart(false); =20 /* Not all paths will gutter the processor... */ switch(code){ @@ -483,7 +476,7 @@ void notrace handle_interruption(int cod int si_code; =20 if (code =3D=3D 1) - pdc_console_restart(); /* switch back to pdc if HPMC */ + pdc_console_restart(true); /* switch back to pdc if HPMC */ else if (!irqs_disabled_flags(regs->gr[0])) local_irq_enable(); From nobody Mon Apr 6 03:09:13 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 1DF95C6FA82 for ; Sat, 10 Sep 2022 22:28:38 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230319AbiIJW2g (ORCPT ); Sat, 10 Sep 2022 18:28:36 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45968 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230057AbiIJW1w (ORCPT ); Sat, 10 Sep 2022 18:27:52 -0400 Received: from galois.linutronix.de (Galois.linutronix.de [193.142.43.55]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 5EFFA3DF2E for ; Sat, 10 Sep 2022 15:27:48 -0700 (PDT) Message-ID: <20220910222300.906633712@linutronix.de> DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020; t=1662848866; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: references:references; bh=rf4oVT0IACM5+HOOtRh8ktCU4mJox5gT3mFbY4X0ro4=; b=xtXfpQ6xb7JeebjIdPGSmF2S7V4YMW5PUyCRbpQ0AjBGRT7a1eyRCqZU8zY8pvGVlwzW+5 KoezmY0Btk93Trb9iWm3Agn5nLEbQn5g3XmuIjd0lOeYB/5P2UX61czgUd3Kvi3h7ZBWVJ Cj3/AOCXU4iesBaoy+fB0bxD8TsUJHkXeA8xxatSKxKi5DOlKV0kE0Fe/659drk7Z1L9K2 jYHhGdbT35Te3z6ESKqbZ/mYJHCNdRA7+acOLTPI514y1itsZlSys2SwtquG+niT0XMroF D9Pwl67aWngtgHgJXXw8gcJZYzg71y+S5JF2Sa5g5UlbvgGGH70v3NTVgkwW8w== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020e; t=1662848866; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: references:references; bh=rf4oVT0IACM5+HOOtRh8ktCU4mJox5gT3mFbY4X0ro4=; b=MlUd/ANlzRpMXw1CNhR9CQYjifzNbwfkl52XRDH07kXzghewtr+0JfNxo8jDgBhHgMHnGE +qYj4H//NJlD87Dw== From: Thomas Gleixner To: LKML Cc: John Ogness , Petr Mladek , Sergey Senozhatsky , Steven Rostedt , Linus Torvalds , Peter Zijlstra , "Paul E. McKenney" , Daniel Vetter , Greg Kroah-Hartman , Helge Deller , Jason Wessel , Daniel Thompson Subject: [patch RFC 09/29] serial: kgdboc: Lock consoles in probe function References: <20220910221947.171557773@linutronix.de> MIME-Version: 1.0 Date: Sun, 11 Sep 2022 00:27:45 +0200 (CEST) Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Unprotected list walks are not necessarily safe. Signed-off-by: Thomas Gleixner Reviewed-by: Sergey Senozhatsky --- drivers/tty/serial/kgdboc.c | 2 ++ 1 file changed, 2 insertions(+) --- a/drivers/tty/serial/kgdboc.c +++ b/drivers/tty/serial/kgdboc.c @@ -193,6 +193,7 @@ static int configure_kgdboc(void) if (!p) goto noconfig; =20 + console_lock(); for_each_console(cons) { int idx; if (cons->device && cons->device(cons, &idx) =3D=3D p && @@ -201,6 +202,7 @@ static int configure_kgdboc(void) break; } } + console_unlock(); =20 kgdb_tty_driver =3D p; kgdb_tty_line =3D tty_line; From nobody Mon Apr 6 03:09:13 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 4DBA2ECAAD3 for ; Sat, 10 Sep 2022 22:28:43 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230409AbiIJW2l (ORCPT ); Sat, 10 Sep 2022 18:28:41 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:46004 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230090AbiIJW1x (ORCPT ); Sat, 10 Sep 2022 18:27:53 -0400 Received: from galois.linutronix.de (Galois.linutronix.de [193.142.43.55]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 569C243311 for ; Sat, 10 Sep 2022 15:27:49 -0700 (PDT) Message-ID: <20220910222300.966724916@linutronix.de> DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020; t=1662848867; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: references:references; bh=dUt7YWFMhjrMP4Qpw0W8vZndSNzlNorKm2KfwhLmlGk=; b=ZpGAMzk+By9q2iPr47fY+/daL7Pha5lvv2nOYLh97IzQ9DzVrzYq3Lq+QdyQokBlPs3Yvd ImRl/mHBqiLHGEPYTId7/dj6oxqq7qpGD1g0uIUo6lTUhkAKPUjAHaHFfloPIskY07i7XW e3KAXvvfKkYpYyGQmhByzFg1TqejB2pOe+NrM88nR+xNoxxxVis9T2plynwWfrjpeP0BEy 4BSI6p4oKx4yjtUwnwj+EfONM1qq1v+pL899ch6yuTeEx51yiOFLIP1xGYl2F4lDBwtZyi YAFEiVdncj9YK5OAzqqZkJK2q41kU+mDey6Rk5Aky5dXzifGt4HfBx6mAVljaQ== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020e; t=1662848867; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: references:references; bh=dUt7YWFMhjrMP4Qpw0W8vZndSNzlNorKm2KfwhLmlGk=; b=JHvCvb5+eSydfHBwY6ELO4EIf6T3okWVuaIDiFOwC4ey9m1xP4iBb2VHfDiiKy6CEoOHN2 IdDp66ONAbAPoBAA== From: Thomas Gleixner To: LKML Cc: John Ogness , Petr Mladek , Sergey Senozhatsky , Steven Rostedt , Linus Torvalds , Peter Zijlstra , "Paul E. McKenney" , Daniel Vetter , Greg Kroah-Hartman , Helge Deller , Jason Wessel , Daniel Thompson Subject: [patch RFC 10/29] kgbd: Pretend that console list walk is safe References: <20220910221947.171557773@linutronix.de> MIME-Version: 1.0 Date: Sun, 11 Sep 2022 00:27:47 +0200 (CEST) Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Provide a special list iterator macro for KGDB to allow unprotected list walks and add a few comments to explain the hope based approach. Preperatory change for changing the console list to hlist and adding lockdep asserts to regular list walks. Signed-off-by: Thomas Gleixner Reviewed-by: Sergey Senozhatsky --- drivers/tty/serial/kgdboc.c | 5 ++++- include/linux/console.h | 12 +++++++++++- kernel/debug/kdb/kdb_io.c | 7 ++++++- 3 files changed, 21 insertions(+), 3 deletions(-) --- a/drivers/tty/serial/kgdboc.c +++ b/drivers/tty/serial/kgdboc.c @@ -462,10 +462,13 @@ static void kgdboc_earlycon_pre_exp_hand * we have no other choice so we keep using it. Since not all * serial drivers might be OK with this, print a warning once per * boot if we detect this case. + * + * Pretend that walking the console list is safe... */ - for_each_console(con) + for_each_console_kgdb(con) { if (con =3D=3D kgdboc_earlycon_io_ops.cons) return; + } =20 already_warned =3D true; pr_warn("kgdboc_earlycon is still using bootconsole\n"); --- a/include/linux/console.h +++ b/include/linux/console.h @@ -184,7 +184,17 @@ extern void console_list_unlock(void); * Requires console_lock to be held which guarantees that the * list is immutable. */ -#define for_each_console(con) \ +#define for_each_console(con) \ + for (con =3D console_drivers; con !=3D NULL; con =3D con->next) + +/** + * for_each_console_kgdb() - Iterator over registered consoles for KGDB + * @con: struct console pointer used as loop cursor + * + * Has no serialization requirements and KGDB pretends that this is safe. + * Don't use outside of the KGDB fairy tale land! + */ +#define for_each_console_kgdb(con) \ for (con =3D console_drivers; con !=3D NULL; con =3D con->next) =20 extern int console_set_on_cmdline; --- a/kernel/debug/kdb/kdb_io.c +++ b/kernel/debug/kdb/kdb_io.c @@ -558,7 +558,12 @@ static void kdb_msg_write(const char *ms cp++; } =20 - for_each_console(c) { + /* + * This is a completely unprotected list walk designed by the + * wishful thinking departement. See the oops_inprogress comment + * below - especially the encourage section... + */ + for_each_console_kgdb(c) { if (!(c->flags & CON_ENABLED)) continue; if (c =3D=3D dbg_io_ops->cons) From nobody Mon Apr 6 03:09:13 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 5CAE0ECAAD3 for ; Sat, 10 Sep 2022 22:28:48 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230162AbiIJW2p (ORCPT ); Sat, 10 Sep 2022 18:28:45 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45980 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230118AbiIJW1z (ORCPT ); Sat, 10 Sep 2022 18:27:55 -0400 Received: from galois.linutronix.de (Galois.linutronix.de [193.142.43.55]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id D0E5E43327 for ; Sat, 10 Sep 2022 15:27:50 -0700 (PDT) Message-ID: <20220910222301.026064288@linutronix.de> DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020; t=1662848869; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: references:references; bh=lpamWxeD7WXfacPVoNQg0Q6R4SqcQTvaVnGnp8PqLdM=; b=YmPFuIYQ+9V+opmDhlZv871qYOrvkfmjaaoinjHRpOO4MbDMcfvdRmThrwQkPPgcAoK6Se HnyGMCFsWA8MJfWoviDLEqQHOLy5Fzu1lf9wne0QsQNvpATkh+vT3Qt+NAOpnJDdIftbGJ aez2V18hlxCrw5CTkI6OUtjD+j4aCcDTu/l7/pXqnCmgsKXUbK639wj5xQh80g88/ujo2i NfBPnO26aco9HMtbvwgdD1+2Nl6IPmIGnWYQIvqhkxmJ1S3L0OUr0JLSKtXhlOPGzv+oeP 1UVbMfmgMXzKDZyhCbB2qo62hxlryR1hE+AcTnS6M1GjJ8dqgHEej0oU3ypbng== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020e; t=1662848869; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: references:references; bh=lpamWxeD7WXfacPVoNQg0Q6R4SqcQTvaVnGnp8PqLdM=; b=pdw/ixWADrwbJmqaSrRHP4ujDZNNf0Tt5fTGkbeNM1f5dFSeZs3czHaPDW8JzCvrL64lCQ 2w/r0ChClTo3n3AQ== From: Thomas Gleixner To: LKML Cc: John Ogness , Petr Mladek , Sergey Senozhatsky , Steven Rostedt , Linus Torvalds , Peter Zijlstra , "Paul E. McKenney" , Daniel Vetter , Greg Kroah-Hartman , Helge Deller , Jason Wessel , Daniel Thompson Subject: [patch RFC 11/29] printk: Convert console_drivers list to hlist References: <20220910221947.171557773@linutronix.de> MIME-Version: 1.0 Date: Sun, 11 Sep 2022 00:27:48 +0200 (CEST) Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Replace the open coded single linked list with a hlist so a conversion to SRCU protected list walks can reuse the existing primitives. Signed-off-by: Thomas Gleixner --- arch/parisc/kernel/pdc_cons.c | 17 ++----- fs/proc/consoles.c | 5 +- include/linux/console.h | 19 +++++--- kernel/printk/printk.c | 99 ++++++++++++++++++++++---------------= ----- 4 files changed, 75 insertions(+), 65 deletions(-) --- a/arch/parisc/kernel/pdc_cons.c +++ b/arch/parisc/kernel/pdc_cons.c @@ -147,13 +147,8 @@ static int __init pdc_console_tty_driver =20 struct console *tmp; =20 - console_lock(); - for_each_console(tmp) - if (tmp =3D=3D &pdc_cons) - break; - console_unlock(); - - if (!tmp) { + /* Pretend that this works as much as it pretended to work historically */ + if (hlist_unhashed_lockless(&pdc_cons.node)) { printk(KERN_INFO "PDC console driver not registered anymore, not creatin= g %s\n", pdc_cons.name); return -ENODEV; } @@ -272,15 +267,15 @@ void pdc_console_restart(bool hpmc) if (pdc_console_initialized) return; =20 - if (!hpmc && console_drivers) + if (!hpmc && !hlist_empty(&console_list)) return; =20 /* If we've already seen the output, don't bother to print it again */ - if (console_drivers !=3D NULL) + if (!hlist_empty(&console_list)) pdc_cons.flags &=3D ~CON_PRINTBUFFER; =20 - while ((console =3D console_drivers) !=3D NULL) - unregister_console(console_drivers); + while (!hlist_empty(&console_list)) + unregister_console(READ_ONCE(console_list.first)); =20 /* force registering the pdc console */ pdc_console_init_force(); --- a/fs/proc/consoles.c +++ b/fs/proc/consoles.c @@ -74,8 +74,11 @@ static void *c_start(struct seq_file *m, static void *c_next(struct seq_file *m, void *v, loff_t *pos) { struct console *con =3D v; + ++*pos; - return con->next; + hlist_for_each_entry_continue(con, node) + break; + return con; } =20 static void c_stop(struct seq_file *m, void *v) --- a/include/linux/console.h +++ b/include/linux/console.h @@ -15,6 +15,7 @@ #define _LINUX_CONSOLE_H_ 1 =20 #include +#include #include =20 struct vc_data; @@ -154,15 +155,19 @@ struct console { u64 seq; unsigned long dropped; void *data; - struct console *next; + struct hlist_node node; }; =20 #ifdef CONFIG_LOCKDEP +extern void lockdep_assert_console_lock_held(void); extern void lockdep_assert_console_list_lock_held(void); #else +static inline void lockdep_assert_console_lock_held(void) { } static inline void lockdep_assert_console_list_lock_held(void) { } #endif =20 +extern struct hlist_head console_list; + extern void console_list_lock(void) __acquires(console_mutex); extern void console_list_unlock(void) __releases(console_mutex); =20 @@ -175,7 +180,7 @@ extern void console_list_unlock(void) __ */ #define for_each_registered_console(con) \ lockdep_assert_console_list_lock_held(); \ - for (con =3D console_drivers; con !=3D NULL; con =3D con->next) + hlist_for_each_entry(con, &console_list, node) =20 /** * for_each_console() - Iterator over registered consoles @@ -184,8 +189,9 @@ extern void console_list_unlock(void) __ * Requires console_lock to be held which guarantees that the * list is immutable. */ -#define for_each_console(con) \ - for (con =3D console_drivers; con !=3D NULL; con =3D con->next) +#define for_each_console(con) \ + lockdep_assert_console_lock_held(); \ + hlist_for_each_entry(con, &console_list, node) =20 /** * for_each_console_kgdb() - Iterator over registered consoles for KGDB @@ -194,8 +200,8 @@ extern void console_list_unlock(void) __ * Has no serialization requirements and KGDB pretends that this is safe. * Don't use outside of the KGDB fairy tale land! */ -#define for_each_console_kgdb(con) \ - for (con =3D console_drivers; con !=3D NULL; con =3D con->next) +#define for_each_console_kgdb(con) \ + hlist_for_each_entry(con, &console_list, node) =20 extern int console_set_on_cmdline; extern struct console *early_console; @@ -208,7 +214,6 @@ enum con_flush_mode { extern int add_preferred_console(char *name, int idx, char *options); extern void register_console(struct console *); extern int unregister_console(struct console *); -extern struct console *console_drivers; extern void console_lock(void); extern int console_trylock(void); extern void console_unlock(void); --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -79,17 +79,17 @@ int oops_in_progress; EXPORT_SYMBOL(oops_in_progress); =20 /* - * console_sem protects the console_drivers list, and also provides - * serialization for access to the entire console driver system. + * console_sem protects onsole_list, and also provides serialization for + * access to the entire console driver system. * * console_mutex serializes register/unregister. console_sem has to be - * taken for any list manipulation inside the console_mutex locked + * taken for any console_list manipulation inside the console_mutex locked * section to keep the console BKL machinery happy. */ static DEFINE_MUTEX(console_mutex); static DEFINE_SEMAPHORE(console_sem); -struct console *console_drivers; -EXPORT_SYMBOL_GPL(console_drivers); +HLIST_HEAD(console_list); +EXPORT_SYMBOL_GPL(console_list); =20 /* * System may need to suppress printk message under certain @@ -108,6 +108,11 @@ static struct lockdep_map console_lock_d .name =3D "console_lock" }; =20 +void lockdep_assert_console_lock_held(void) +{ + lockdep_assert(lock_is_held(&console_lock_dep_map)); +} + void lockdep_assert_console_list_lock_held(void) { lockdep_assert_held(&console_mutex); @@ -2586,7 +2591,7 @@ static int console_cpu_notify(unsigned i * console_lock - lock the console system for exclusive use. * * Acquires a lock which guarantees that the caller has - * exclusive access to the console system and the console_drivers list. + * exclusive access to the console system and console_list. * * Can sleep, returns nothing. */ @@ -2606,7 +2611,7 @@ EXPORT_SYMBOL(console_lock); * console_trylock - try to lock the console system for exclusive use. * * Try to acquire a lock which guarantees that the caller has exclusive - * access to the console system and the console_drivers list. + * access to the console system and console_list. * * returns 1 on success, and 0 on failure to acquire the lock. */ @@ -2974,7 +2979,15 @@ void console_flush_on_panic(enum con_flu u64 seq; =20 seq =3D prb_first_valid_seq(prb); - for_each_console(c) + /* + * This cannot use for_each_console() because it's not established + * that the current context has console locked and neither there is + * a guarantee that there is no concurrency in that case. + * + * Open code it for documentation purposes and pretend that + * it works. + */ + hlist_for_each_entry(c, &console_list, node) c->seq =3D seq; } console_unlock(); @@ -3115,6 +3128,9 @@ static void try_enable_default_console(s (con->flags & CON_BOOT) ? "boot" : "", \ con->name, con->index, ##__VA_ARGS__) =20 +#define cons_first() \ + hlist_entry(console_list.first, struct console, node) + static int console_unregister_locked(struct console *console); =20 /* @@ -3177,8 +3193,8 @@ void register_console(struct console *ne * flag set and will be first in the list. */ if (preferred_console < 0) { - if (!console_drivers || !console_drivers->device || - console_drivers->flags & CON_BOOT) { + if (hlist_empty(&console_list) || !cons_first()->device || + cons_first()->flags & CON_BOOT) { try_enable_default_console(newcon); } } @@ -3206,21 +3222,17 @@ void register_console(struct console *ne } =20 /* - * Put this console in the list - keep the - * preferred driver at the head of the list. + * Put this console in the list and keep the referred driver at the + * head of the list. */ console_lock(); - if ((newcon->flags & CON_CONSDEV) || console_drivers =3D=3D NULL) { - newcon->next =3D console_drivers; - console_drivers =3D newcon; - if (newcon->next) - newcon->next->flags &=3D ~CON_CONSDEV; - /* Ensure this flag is always set for the head of the list */ - newcon->flags |=3D CON_CONSDEV; - } else { - newcon->next =3D console_drivers->next; - console_drivers->next =3D newcon; - } + if (newcon->flags & CON_CONSDEV || hlist_empty(&console_list)) + hlist_add_head(&newcon->node, &console_list); + else + hlist_add_behind(&newcon->node, console_list.first); + + /* Ensure this flag is always set for the head of the list */ + cons_first()->flags |=3D CON_CONSDEV; =20 newcon->dropped =3D 0; if (newcon->flags & CON_PRINTBUFFER) { @@ -3246,7 +3258,9 @@ void register_console(struct console *ne if (bootcon_enabled && ((newcon->flags & (CON_CONSDEV | CON_BOOT)) =3D=3D CON_CONSDEV) && !keep_bootcon) { - for_each_console(con) { + struct hlist_node *tmp; + + hlist_for_each_entry_safe(con, tmp, &console_list, node) { if (con->flags & CON_BOOT) console_unregister_locked(con); } @@ -3258,7 +3272,6 @@ EXPORT_SYMBOL(register_console); =20 static int console_unregister_locked(struct console *console) { - struct console *con; int res; =20 con_printk(KERN_INFO, console, "disabled\n"); @@ -3269,32 +3282,28 @@ static int console_unregister_locked(str if (res > 0) return 0; =20 - res =3D -ENODEV; console_lock(); - if (console_drivers =3D=3D console) { - console_drivers=3Dconsole->next; - res =3D 0; - } else { - for_each_console(con) { - if (con->next =3D=3D console) { - con->next =3D console->next; - res =3D 0; - break; - } - } - } =20 - if (res) - goto out_disable_unlock; + /* Disable it unconditionally */ + console->flags &=3D ~CON_ENABLED; + + if (hlist_unhashed(&console->node)) + goto out_unlock; + + hlist_del_init(&console->node); =20 /* + * * If this isn't the last console and it has CON_CONSDEV set, we * need to set it on the next preferred console. + * + * + * The above makes no sense as there is no guarantee that the next + * console has any device attached. Oh well.... */ - if (console_drivers !=3D NULL && console->flags & CON_CONSDEV) - console_drivers->flags |=3D CON_CONSDEV; + if (!hlist_empty(&console_list) && console->flags & CON_CONSDEV) + cons_first()->flags |=3D CON_CONSDEV; =20 - console->flags &=3D ~CON_ENABLED; console_unlock(); console_sysfs_notify(); =20 @@ -3303,10 +3312,8 @@ static int console_unregister_locked(str =20 return res; =20 -out_disable_unlock: - console->flags &=3D ~CON_ENABLED; +out_unlock: console_unlock(); - return res; } From nobody Mon Apr 6 03:09:13 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 8EC25ECAAD3 for ; Sat, 10 Sep 2022 22:28:53 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230128AbiIJW2w (ORCPT ); Sat, 10 Sep 2022 18:28:52 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:46232 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230135AbiIJW2B (ORCPT ); Sat, 10 Sep 2022 18:28:01 -0400 Received: from galois.linutronix.de (Galois.linutronix.de [193.142.43.55]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id D911D42AEA for ; Sat, 10 Sep 2022 15:27:53 -0700 (PDT) Message-ID: <20220910222301.084428332@linutronix.de> DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020; t=1662848871; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: references:references; bh=fGXSmzhEoK8b0GTobsLbcAxSd+NNxBh/Huh2f6MgBe8=; b=oEoG4XV/p63GR35K1PB67q56l0RUQRKw6YTPQ6y3RalqcnfpaMMmKI3NSxD0i0qIm2CMRm +ULaMQMVKoCodg2N6gDErwVLpyx9bw4pRcNB6PmFCxWzDxtTQUSGrgzbIBr0mtuvP0/Ozq 3BWp1QpP5x8fRcNkxC0H1XUrUCXlyVb2JsrxYUj/kYtZv7veSbGvCPE5c7mcylreff3Fjc g4Dh96r9+i819DPBNfIysF9G2EPbI3/QhaRs4pq0fn2o8ovOwH8uWFrIhFAAgj2KgsTpJE ZdCK1ora8+Iusf+S/+3rMd3ABaPewKlCSxtpsaLso2HxBxc2x8anqqDhSphYew== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020e; t=1662848871; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: references:references; bh=fGXSmzhEoK8b0GTobsLbcAxSd+NNxBh/Huh2f6MgBe8=; b=XNjATjL37sd9bZqMc50Uk1ZjkOB2XZLy9+WnHzUcStr8G587JSVK2QVuK/z+MfYlvEN3ta zTxv+K0dAQU52NAQ== From: Thomas Gleixner To: LKML Cc: John Ogness , Petr Mladek , Sergey Senozhatsky , Steven Rostedt , Linus Torvalds , Peter Zijlstra , "Paul E. McKenney" , Daniel Vetter , Greg Kroah-Hartman , Helge Deller , Jason Wessel , Daniel Thompson Subject: [patch RFC 12/29] printk: Prepare for SCRU console list protection References: <20220910221947.171557773@linutronix.de> MIME-Version: 1.0 Date: Sun, 11 Sep 2022 00:27:50 +0200 (CEST) Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Provide a SRCU protected variant to walk the console list. Preperatory change for a new console infrastructure which operates independent of console BKL. Signed-off-by: Thomas Gleixner --- include/linux/console.h | 14 +++++++++++++- kernel/printk/printk.c | 16 +++++++++++++--- 2 files changed, 26 insertions(+), 4 deletions(-) --- a/include/linux/console.h +++ b/include/linux/console.h @@ -15,7 +15,7 @@ #define _LINUX_CONSOLE_H_ 1 =20 #include -#include +#include #include =20 struct vc_data; @@ -161,6 +161,7 @@ struct console { #ifdef CONFIG_LOCKDEP extern void lockdep_assert_console_lock_held(void); extern void lockdep_assert_console_list_lock_held(void); +extern bool console_srcu_read_lock_is_held(void); #else static inline void lockdep_assert_console_lock_held(void) { } static inline void lockdep_assert_console_list_lock_held(void) { } @@ -172,6 +173,17 @@ extern void console_list_lock(void) __ac extern void console_list_unlock(void) __releases(console_mutex); =20 /** + * for_each_console_srcu() - Iterator over registered consoles + * @con: struct console pointer used as loop cursor + * + * Requires console_srcu_read_lock to be held. Can be invoked from + * any context. + */ +#define for_each_console_srcu(con) \ + hlist_for_each_entry_srcu(con, &console_list, node, \ + console_srcu_read_lock_is_held()) + +/** * for_each_registered_console() - Iterator over registered consoles * @con: struct console pointer used as loop cursor * --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -90,6 +90,7 @@ static DEFINE_MUTEX(console_mutex); static DEFINE_SEMAPHORE(console_sem); HLIST_HEAD(console_list); EXPORT_SYMBOL_GPL(console_list); +DEFINE_STATIC_SRCU(console_srcu); =20 /* * System may need to suppress printk message under certain @@ -118,6 +119,10 @@ void lockdep_assert_console_list_lock_he lockdep_assert_held(&console_mutex); } =20 +bool console_srcu_read_lock_is_held(void) +{ + return srcu_read_lock_held(&console_srcu); +} #endif =20 enum devkmsg_log_bits { @@ -3227,9 +3232,9 @@ void register_console(struct console *ne */ console_lock(); if (newcon->flags & CON_CONSDEV || hlist_empty(&console_list)) - hlist_add_head(&newcon->node, &console_list); + hlist_add_head_rcu(&newcon->node, &console_list); else - hlist_add_behind(&newcon->node, console_list.first); + hlist_add_behind_rcu(&newcon->node, console_list.first); =20 /* Ensure this flag is always set for the head of the list */ cons_first()->flags |=3D CON_CONSDEV; @@ -3245,6 +3250,7 @@ void register_console(struct console *ne newcon->seq =3D prb_next_seq(prb); } console_unlock(); + /* No need to synchronize SRCU here! */ console_sysfs_notify(); =20 /* @@ -3290,7 +3296,7 @@ static int console_unregister_locked(str if (hlist_unhashed(&console->node)) goto out_unlock; =20 - hlist_del_init(&console->node); + hlist_del_init_rcu(&console->node); =20 /* * @@ -3305,6 +3311,10 @@ static int console_unregister_locked(str cons_first()->flags |=3D CON_CONSDEV; =20 console_unlock(); + + /* Ensure that all SRCU list walks have completed */ + synchronize_srcu(&console_srcu); + console_sysfs_notify(); =20 if (console->exit) From nobody Mon Apr 6 03:09:13 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 1358AECAAD3 for ; Sat, 10 Sep 2022 22:28:57 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230447AbiIJW24 (ORCPT ); Sat, 10 Sep 2022 18:28:56 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:46244 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230153AbiIJW2B (ORCPT ); Sat, 10 Sep 2022 18:28:01 -0400 Received: from galois.linutronix.de (Galois.linutronix.de [193.142.43.55]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 305E74362D for ; Sat, 10 Sep 2022 15:27:55 -0700 (PDT) Message-ID: <20220910222301.141696132@linutronix.de> DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020; t=1662848872; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: references:references; bh=ucJCwIArz/Obdz0no/ZggjeV/meklOatxzaddZBmlzw=; b=Z+lN6QD2lalfKWyMMeV80c6lroOwf0YpggJVEVXBFRkop3lUHQNNQMPFQWidfh6xAdukWy BwW3sj9r0bPhXA095G3tuR1gKLsJWp8P3F21XmAAAdTJ+84z7C7Sc+sh313TLXDHyZfQL2 ekpwKrHqIN8O5kgmp6Fb9a8NZ1ibwCLD2/yDO5V7WS6EBJi2/ZYko/weq1+ozgKCweXHOT ImX2Bp96HLxU2OvIXEJISkpJu+N2fbt+IfXOPiMEYEKfb0RSJzUvET593kZjh9GGS8vIit JR+rONc0gnJINRl8IvzHikMafhfqSfhtiGlj91Mf5AKce/H6hJ3V6uXxKYpxRw== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020e; t=1662848872; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: references:references; bh=ucJCwIArz/Obdz0no/ZggjeV/meklOatxzaddZBmlzw=; b=uYSC3ZXu9l3Q0SYJXNB43seqCZIqWAwtL2eEHo4sVg9eKHX9S3rHW6oR9jb7jGloW7A3NE T0hbmxLva2VDv5Dg== From: Thomas Gleixner To: LKML Cc: John Ogness , Petr Mladek , Sergey Senozhatsky , Steven Rostedt , Linus Torvalds , Peter Zijlstra , "Paul E. McKenney" , Daniel Vetter , Greg Kroah-Hartman , Helge Deller , Jason Wessel , Daniel Thompson Subject: [patch RFC 13/29] printk: Move buffer size defines References: <20220910221947.171557773@linutronix.de> MIME-Version: 1.0 Date: Sun, 11 Sep 2022 00:27:52 +0200 (CEST) Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Move the buffer size defines to console.h in preperation of adding a buffer structure. Signed-off-by: Thomas Gleixner --- include/linux/console.h | 14 ++++++++++++++ include/linux/printk.h | 2 -- kernel/printk/printk.c | 8 -------- 3 files changed, 14 insertions(+), 10 deletions(-) --- a/include/linux/console.h +++ b/include/linux/console.h @@ -122,6 +122,20 @@ static inline int con_debug_leave(void) #define CM_ERASE (2) #define CM_MOVE (3) =20 +#ifdef CONFIG_PRINTK +/* The maximum size of a formatted record (i.e. with prefix added per line= ) */ +#define CONSOLE_LOG_MAX 1024 + +/* The maximum size for a dropped text message */ +#define DROPPED_TEXT_MAX 64 +#else +#define CONSOLE_LOG_MAX 0 +#define DROPPED_TEXT_MAX 0 +#endif + +/* The maximum size of an formatted extended record */ +#define CONSOLE_EXT_LOG_MAX 8192 + /* * The interface for a console, or any other device that wants to capture * console messages (printer driver?) --- a/include/linux/printk.h +++ b/include/linux/printk.h @@ -44,8 +44,6 @@ static inline const char *printk_skip_he return buffer; } =20 -#define CONSOLE_EXT_LOG_MAX 8192 - /* printk's without a loglevel use this.. */ #define MESSAGE_LOGLEVEL_DEFAULT CONFIG_MESSAGE_LOGLEVEL_DEFAULT =20 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -428,12 +428,6 @@ static struct latched_seq clear_seq =3D { #define PREFIX_MAX 32 #endif =20 -/* the maximum size of a formatted record (i.e. with prefix added per line= ) */ -#define CONSOLE_LOG_MAX 1024 - -/* the maximum size for a dropped text message */ -#define DROPPED_TEXT_MAX 64 - /* the maximum size allowed to be reserved for a record */ #define LOG_LINE_MAX (CONSOLE_LOG_MAX - PREFIX_MAX) =20 @@ -2338,8 +2332,6 @@ static bool __pr_flush(struct console *c =20 #else /* CONFIG_PRINTK */ =20 -#define CONSOLE_LOG_MAX 0 -#define DROPPED_TEXT_MAX 0 #define printk_time false =20 #define prb_read_valid(rb, seq, r) false From nobody Mon Apr 6 03:09:13 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 66BAEC6FA82 for ; Sat, 10 Sep 2022 22:29:00 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230453AbiIJW26 (ORCPT ); Sat, 10 Sep 2022 18:28:58 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45968 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230215AbiIJW2E (ORCPT ); Sat, 10 Sep 2022 18:28:04 -0400 Received: from galois.linutronix.de (Galois.linutronix.de [193.142.43.55]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 2F1BA43E43 for ; Sat, 10 Sep 2022 15:27:56 -0700 (PDT) Message-ID: <20220910222301.198303830@linutronix.de> DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020; t=1662848874; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: references:references; bh=OGECJYeezcNM6bctMFLtG7sTwDOnNte8eZxyEhnl5nM=; b=IuZNLSLWrfeHviHjBCswWUiLPjJFadWgbgopNg+pFLiSOex8+bMxyrgNnktQ7UJE5v1hcp TOrC3ymS+Q0JSjqxcm0YLsXRNeWd1gAtLs5VYgL9Lfr7Yb7dSsB9wcSLco5Q9Wq7P2FZjg UaHIB2NS3xgrDaC6GKKBOhcOEbUcd1NxStfD+vxTQWxa3G680gY4e6pMjboeFMAhm5fbYf mIZcGZyxrCk2jn82OvS1jgM2Du+GkcOpSSno3SSiIkAmZd+XlgiW3Ih7kgzUGro28FcCyN kRGoImK+ZOP4sD/GVt+WAqlbCIa+Qe/08QXTOd+BVqxGZ5YB/i8kFyX1pe+0Bw== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020e; t=1662848874; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: references:references; bh=OGECJYeezcNM6bctMFLtG7sTwDOnNte8eZxyEhnl5nM=; b=PKAdd0InIgltg78+kqH3kBPOYXjLT9jGUBShTCd3FLo95raEjRV00tE5D+dK7A2xBZMql5 Ux091lYUiBpbyuDQ== From: Thomas Gleixner To: LKML Cc: John Ogness , Petr Mladek , Sergey Senozhatsky , Steven Rostedt , Linus Torvalds , Peter Zijlstra , "Paul E. McKenney" , Daniel Vetter , Greg Kroah-Hartman , Helge Deller , Jason Wessel , Daniel Thompson Subject: [patch RFC 14/29] printk: Document struct console References: <20220910221947.171557773@linutronix.de> MIME-Version: 1.0 Date: Sun, 11 Sep 2022 00:27:53 +0200 (CEST) Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add docbook comments to struct console. Signed-off-by: Thomas Gleixner --- include/linux/console.h | 94 ++++++++++++++++++++++++++++++++++---------= ----- 1 file changed, 67 insertions(+), 27 deletions(-) --- a/include/linux/console.h +++ b/include/linux/console.h @@ -15,6 +15,7 @@ #define _LINUX_CONSOLE_H_ 1 =20 #include +#include #include #include =20 @@ -139,37 +140,76 @@ static inline int con_debug_leave(void) /* * The interface for a console, or any other device that wants to capture * console messages (printer driver?) - * - * If a console driver is marked CON_BOOT then it will be auto-unregistered - * when the first real console is registered. This is for early-printk dr= ivers. */ =20 -#define CON_PRINTBUFFER (1) -#define CON_CONSDEV (2) /* Preferred console, /dev/console */ -#define CON_ENABLED (4) -#define CON_BOOT (8) -#define CON_ANYTIME (16) /* Safe to call when cpu is offline */ -#define CON_BRL (32) /* Used for a braille device */ -#define CON_EXTENDED (64) /* Use the extended output format a la /dev/kmsg= */ +/** + * cons_flags - General console flags + * @CON_PRINTBUFFER: Print the complete dmesg backlog on register/enable + * @CON_CONSDEV: Questionable historical leftover to denote which console + * driver is the preferred console which is defining what + * backs up /dev/console + * @CON_ENABLED: General enable state subject to note #1 + * @CON_BOOT: Marks the console driver as early console driver which + * is used during boot before the real driver becomes available. + * It will be automatically unregistered unless the early console + * command line parameter for this console has the 'keep' option set. + * @CON_ANYTIME: A misnomed historical flag which tells the core code that= the + * legacy @console::write callback can be invoked on a CPU which + * is marked OFFLINE. That's misleading as it suggests that there + * is no contextual limit for invoking the callback. + * @CON_BRL: Indicates a braille device which is exempt from receiving the + * printk spam for obvious reasons + * @CON_EXTENDED: The console supports the extended output format of /dev/= kmesg + * which requires a larger output record buffer + */ +enum cons_flags { + CON_PRINTBUFFER =3D BIT(0), + CON_CONSDEV =3D BIT(1), + CON_ENABLED =3D BIT(2), + CON_BOOT =3D BIT(3), + CON_ANYTIME =3D BIT(4), + CON_BRL =3D BIT(5), + CON_EXTENDED =3D BIT(6), +}; =20 +/** + * struct console - The console descriptor structure + * @name: The name of the console driver + * @write: Write callback to output messages (Optional) + * @read: Read callback for console input (Optional) + * @device: The underlying TTY device driver (Optional) + * @unblank: Callback to unblank the console (Optional) + * @setup: Callback for initializing the console (Optional) + * @exit: Callback for teardown of the console (Optional) + * @match: Callback for matching a console (Optional) + * @flags: Console flags. See enum cons_flags + * @index: Console index, e.g. port number + * @cflag: TTY control mode flags + * @ispeed: TTY input speed + * @ospeed: TTY output speed + * @seq: Sequence number of the last ringbuffer record printed + * @dropped: Number of dropped ringbuffer records + * @data: Driver private data + * @node: hlist node for the console list + */ struct console { - char name[16]; - void (*write)(struct console *, const char *, unsigned); - int (*read)(struct console *, char *, unsigned); - struct tty_driver *(*device)(struct console *, int *); - void (*unblank)(void); - int (*setup)(struct console *, char *); - int (*exit)(struct console *); - int (*match)(struct console *, char *name, int idx, char *options); - short flags; - short index; - int cflag; - uint ispeed; - uint ospeed; - u64 seq; - unsigned long dropped; - void *data; - struct hlist_node node; + char name[16]; + void (*write)(struct console *, const char *, unsigned); + int (*read)(struct console *, char *, unsigned); + struct tty_driver *(*device)(struct console *, int *); + void (*unblank)(void); + int (*setup)(struct console *, char *); + int (*exit)(struct console *); + int (*match)(struct console *, char *name, int idx, char *options); + short flags; + short index; + int cflag; + uint ispeed; + uint ospeed; + u64 seq; + unsigned long dropped; + void *data; + struct hlist_node node; }; =20 #ifdef CONFIG_LOCKDEP From nobody Mon Apr 6 03:09:13 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 80F3DC6FA82 for ; Sat, 10 Sep 2022 22:29:09 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230473AbiIJW3G (ORCPT ); Sat, 10 Sep 2022 18:29:06 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:46778 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230165AbiIJW2S (ORCPT ); Sat, 10 Sep 2022 18:28:18 -0400 Received: from galois.linutronix.de (Galois.linutronix.de [IPv6:2a0a:51c0:0:12e:550::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id C423043E5D for ; Sat, 10 Sep 2022 15:27:58 -0700 (PDT) Message-ID: <20220910222301.253866623@linutronix.de> DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020; t=1662848875; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: references:references; bh=3xI7lyIQCW3w0/wiKpLxYgu3oHCXS+iYlZXHschZG0c=; b=sYky9NRuc6BaPd16D3VpHkXEq+HLtuTyCzTHXQ1X3nI69k4aLit51cJY8iZak4x+bR9r+f n5/GJg6eHCYi+NljLg4KBP8ZEuXY5wISyhsZM8HSDkyYpa6ZQYHa8fUrbk0caeFCWSp1bB jEe91ipWNorm1k6p49pdkpvKJAKTpUxSG4XD2PbV1G34R6+4lD9pp2vFtzA8nXZMCpLoSQ nG4AS+i4IAXFEERv3axXTNVpDM80DzTILAwePTDnjFCLBVEDiqZ+8x9P/anu8RqiIX308P tD6UNHIP4nhZ7U6bnuTySqaaobgyGej/bRd6MCwqKvBMFrtnZFN4CkI4FT5QvQ== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020e; t=1662848875; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: references:references; bh=3xI7lyIQCW3w0/wiKpLxYgu3oHCXS+iYlZXHschZG0c=; b=oYwgwlgFJkRM9mZRDrIGeoxKs0BKvIQPjFBSxnVsI6CKbrnSLZms1iG/b1MCI8yMbKKQMI 6OhyWfhaPGyskYBQ== From: Thomas Gleixner To: LKML Cc: John Ogness , Petr Mladek , Sergey Senozhatsky , Steven Rostedt , Linus Torvalds , Peter Zijlstra , "Paul E. McKenney" , Daniel Vetter , Greg Kroah-Hartman , Helge Deller , Jason Wessel , Daniel Thompson Subject: [patch RFC 15/29] printk: Add struct cons_text_buf References: <20220910221947.171557773@linutronix.de> MIME-Version: 1.0 Date: Sun, 11 Sep 2022 00:27:55 +0200 (CEST) Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Create a data structure to replace the open coded seperate buffers for regular and extended formatting. Signed-off-by: Thomas Gleixner --- include/linux/console.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) --- a/include/linux/console.h +++ b/include/linux/console.h @@ -173,6 +173,20 @@ enum cons_flags { }; =20 /** + * struct cons_text_buf - console output text buffer + * @ext_text: Buffer for extended log format text + * @dropped_text: Buffer for dropped text + * @text: Buffer for ringbuffer text + */ +struct cons_text_buf { + union { + char ext_text[CONSOLE_EXT_LOG_MAX]; + char dropped_text[DROPPED_TEXT_MAX]; + }; + char text[CONSOLE_LOG_MAX]; +}; + +/** * struct console - The console descriptor structure * @name: The name of the console driver * @write: Write callback to output messages (Optional) From nobody Mon Apr 6 03:09:13 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id B6297ECAAD3 for ; Sat, 10 Sep 2022 22:29:03 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230466AbiIJW3B (ORCPT ); Sat, 10 Sep 2022 18:29:01 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45978 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230137AbiIJW2Q (ORCPT ); Sat, 10 Sep 2022 18:28:16 -0400 Received: from galois.linutronix.de (Galois.linutronix.de [IPv6:2a0a:51c0:0:12e:550::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 43D5D43E7F for ; Sat, 10 Sep 2022 15:27:59 -0700 (PDT) Message-ID: <20220910222301.310153421@linutronix.de> DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020; t=1662848877; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: references:references; bh=Q4EKtLdKBpGBLYI/18LY67PpRmzH0E6rK3cfFzsdadQ=; b=NG4Uzw1YXjlcA334ks/2vKNcR5dhcaFrdgFDuMepIGsO38GRgb8G0ZXrWBYjwXCcjq+peY drotznovja8BcO1DvycSzG+KBNEtF6ujE7MBUvq/7skG1NViJI8dlg57khxTkL+WMfgqko unwT+nsTl5P8kiujhofC3s+MYjCSwmH8FYrN2DiIGmUFNwIt0KQcl1cFSXnEmilc2nvqxt vnzAEG6ht4EmSyDhdxWQ59/bkY/EUrspUoVX8dWxpZR4zWg3v/zLADAiVVR2C3LEOqZoqv 4zZfHQElfb+W2d2QcPC0cej6bKvQBHbYVeHw7J85zjGuxKEU376d8K9BL2ul+A== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020e; t=1662848877; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: references:references; bh=Q4EKtLdKBpGBLYI/18LY67PpRmzH0E6rK3cfFzsdadQ=; b=K43vbXpQMewswxlD0ROcI9fs5ZnsPtTRbWvgs3WG1ThyCcVXiwlvDDmwInsrUeMWv+YZWQ WRbG5KgbLTjtsxCg== From: Thomas Gleixner To: LKML Cc: John Ogness , Petr Mladek , Sergey Senozhatsky , Steven Rostedt , Linus Torvalds , Peter Zijlstra , "Paul E. McKenney" , Daniel Vetter , Greg Kroah-Hartman , Helge Deller , Jason Wessel , Daniel Thompson Subject: [patch RFC 16/29] printk: Use struct cons_text_buf References: <20220910221947.171557773@linutronix.de> MIME-Version: 1.0 Date: Sun, 11 Sep 2022 00:27:56 +0200 (CEST) Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Replace the seperately allocated output buffers with a single instance of struct cons_text_buf. Signed-off-by: Thomas Gleixner --- kernel/printk/printk.c | 50 ++++++++++++++++++++------------------------= ----- 1 file changed, 21 insertions(+), 29 deletions(-) --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -666,11 +666,9 @@ struct devkmsg_user { atomic64_t seq; struct ratelimit_state rs; struct mutex lock; - char buf[CONSOLE_EXT_LOG_MAX]; - struct printk_info info; - char text_buf[CONSOLE_EXT_LOG_MAX]; struct printk_record record; + struct cons_text_buf txtbuf; }; =20 static __printf(3, 4) __cold @@ -753,6 +751,8 @@ static ssize_t devkmsg_read(struct file { struct devkmsg_user *user =3D file->private_data; struct printk_record *r =3D &user->record; + char *outbuf =3D user->txtbuf.ext_text; + const int maxlen =3D sizeof(user->txtbuf.ext_text); size_t len; ssize_t ret; =20 @@ -793,8 +793,8 @@ static ssize_t devkmsg_read(struct file goto out; } =20 - len =3D info_print_ext_header(user->buf, sizeof(user->buf), r->info); - len +=3D msg_print_ext_body(user->buf + len, sizeof(user->buf) - len, + len =3D info_print_ext_header(outbuf, maxlen, r->info); + len +=3D msg_print_ext_body(outbuf + len, maxlen - len, &r->text_buf[0], r->info->text_len, &r->info->dev_info); =20 @@ -805,7 +805,7 @@ static ssize_t devkmsg_read(struct file goto out; } =20 - if (copy_to_user(buf, user->buf, len)) { + if (copy_to_user(buf, outbuf, len)) { ret =3D -EFAULT; goto out; } @@ -904,7 +904,8 @@ static int devkmsg_open(struct inode *in mutex_init(&user->lock); =20 prb_rec_init_rd(&user->record, &user->info, - &user->text_buf[0], sizeof(user->text_buf)); + user->txtbuf.text, + sizeof(user->txtbuf.text)); =20 atomic64_set(&user->seq, prb_first_valid_seq(prb)); =20 @@ -2704,8 +2705,8 @@ static void __console_unlock(void) * * Requires the console_lock. */ -static bool console_emit_next_record(struct console *con, char *text, char= *ext_text, - char *dropped_text, bool *handover) +static bool console_emit_next_record(struct console *con, struct cons_text= _buf *txtbuf, + bool *handover, bool extmsg) { static int panic_console_dropped; struct printk_info info; @@ -2714,7 +2715,7 @@ static bool console_emit_next_record(str char *write_text; size_t len; =20 - prb_rec_init_rd(&r, &info, text, CONSOLE_LOG_MAX); + prb_rec_init_rd(&r, &info, txtbuf->text, CONSOLE_LOG_MAX); =20 *handover =3D false; =20 @@ -2736,13 +2737,13 @@ static bool console_emit_next_record(str goto skip; } =20 - if (ext_text) { - write_text =3D ext_text; - len =3D info_print_ext_header(ext_text, CONSOLE_EXT_LOG_MAX, r.info); - len +=3D msg_print_ext_body(ext_text + len, CONSOLE_EXT_LOG_MAX - len, + if (extmsg) { + write_text =3D txtbuf->ext_text; + len =3D info_print_ext_header(write_text, CONSOLE_EXT_LOG_MAX, r.info); + len +=3D msg_print_ext_body(write_text + len, CONSOLE_EXT_LOG_MAX - len, &r.text_buf[0], r.info->text_len, &r.info->dev_info); } else { - write_text =3D text; + write_text =3D txtbuf->text; len =3D record_print_text(&r, console_msg_format & MSG_FORMAT_SYSLOG, pr= intk_time); } =20 @@ -2760,7 +2761,7 @@ static bool console_emit_next_record(str console_lock_spinning_enable(); =20 stop_critical_timings(); /* don't trace print latency */ - call_console_driver(con, write_text, len, dropped_text); + call_console_driver(con, write_text, len, extmsg ? NULL : txtbuf->dropped= _text); start_critical_timings(); =20 con->seq++; @@ -2796,9 +2797,7 @@ static bool console_emit_next_record(str */ static bool console_flush_all(bool do_cond_resched, u64 *next_seq, bool *h= andover) { - static char dropped_text[DROPPED_TEXT_MAX]; - static char ext_text[CONSOLE_EXT_LOG_MAX]; - static char text[CONSOLE_LOG_MAX]; + static struct cons_text_buf txtbuf; bool any_usable =3D false; struct console *con; bool any_progress; @@ -2816,16 +2815,9 @@ static bool console_flush_all(bool do_co continue; any_usable =3D true; =20 - if (con->flags & CON_EXTENDED) { - /* Extended consoles do not print "dropped messages". */ - progress =3D console_emit_next_record(con, &text[0], - &ext_text[0], NULL, - handover); - } else { - progress =3D console_emit_next_record(con, &text[0], - NULL, &dropped_text[0], - handover); - } + progress =3D console_emit_next_record(con, &txtbuf, handover, + con->flags & CON_EXTENDED); + if (*handover) return false; From nobody Mon Apr 6 03:09:13 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id A2002ECAAD3 for ; Sat, 10 Sep 2022 22:29:13 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229535AbiIJW3M (ORCPT ); Sat, 10 Sep 2022 18:29:12 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:46058 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230037AbiIJW2S (ORCPT ); Sat, 10 Sep 2022 18:28:18 -0400 Received: from galois.linutronix.de (Galois.linutronix.de [193.142.43.55]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 1317944562 for ; Sat, 10 Sep 2022 15:28:01 -0700 (PDT) Message-ID: <20220910222301.366236279@linutronix.de> DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020; t=1662848878; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: references:references; bh=7h7DFq7DlMY8WzXRmdGz2plVQFhZnaozFR9FGyxDljo=; b=x/3ERXFx93KQf63lpOzkDVa73BmTwMDTxjJ6zoimc5QsGGE8W89awKZ6Qc0a/ubYEwpaBO IBoj40/rUogU28+Uhvy5ca40+ssoiBWqNyBgjRCxl4do/8nUOPE7aFJHNW9kCj8xRoJr++ GoocjZLn6Rb8vWZC2pRtWG/zKx2UqDXperdBQ/zOxvJbGySrWVZUVA4TtxH0uS1pVNBqb2 JXNvg60Mrnj0EBqC4eRxnulF9yHRR94vWr5wpbBAEATIXlb9hG3iyiuimOJQ0JxYXPZxEG KwCueJ33yS5MEZMM1BPZbqX952NfGjgQV2TV1McDELBWieUb19gmxZkxRU+U6g== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020e; t=1662848878; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: references:references; bh=7h7DFq7DlMY8WzXRmdGz2plVQFhZnaozFR9FGyxDljo=; b=aY+++WRDc0UvwblV/17pD6tW6n1oN4ouvFQPQ3gKvM1VX7+Q6QLqQtl911Re1hGCgqBUlz 1MZV+l5Q5goUaUCQ== From: Thomas Gleixner To: LKML Cc: John Ogness , Petr Mladek , Sergey Senozhatsky , Steven Rostedt , Linus Torvalds , Peter Zijlstra , "Paul E. McKenney" , Daniel Vetter , Greg Kroah-Hartman , Helge Deller , Jason Wessel , Daniel Thompson Subject: [patch RFC 17/29] printk: Use an output descriptor struct for emit References: <20220910221947.171557773@linutronix.de> MIME-Version: 1.0 Date: Sun, 11 Sep 2022 00:27:58 +0200 (CEST) Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" To prepare for a new console infrastructure which is independent of the console BKL wrap the output mode into a descriptor struct so the new infrastrucure can share the emit code which dumps the ringbuffer record into the output text buffers. Signed-off-by: Thomas Gleixner --- include/linux/console.h | 15 +++++++ kernel/printk/printk.c | 94 ++++++++++++++++++++++++++++++++++---------= ----- 2 files changed, 82 insertions(+), 27 deletions(-) --- a/include/linux/console.h +++ b/include/linux/console.h @@ -187,6 +187,21 @@ struct cons_text_buf { }; =20 /** + * struct cons_outbuf_desc - console output buffer descriptor + * @txtbuf: Pointer to buffer for storing the text + * @outbuf: Pointer to the position in @buffer for + * writing it out to the device + * @len: Message length + * @extmsg: Select extended format printing + */ +struct cons_outbuf_desc { + struct cons_text_buf *txtbuf; + char *outbuf; + unsigned int len; + bool extmsg; +}; + +/** * struct console - The console descriptor structure * @name: The name of the console driver * @write: Write callback to output messages (Optional) --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -2684,40 +2684,39 @@ static void __console_unlock(void) up_console_sem(); } =20 -/* - * Print one record for the given console. The record printed is whatever - * record is the next available record for the given console. - * - * @text is a buffer of size CONSOLE_LOG_MAX. - * - * If extended messages should be printed, @ext_text is a buffer of size - * CONSOLE_EXT_LOG_MAX. Otherwise @ext_text must be NULL. - * - * If dropped messages should be printed, @dropped_text is a buffer of size - * DROPPED_TEXT_MAX. Otherwise @dropped_text must be NULL. - * - * @handover will be set to true if a printk waiter has taken over the - * console_lock, in which case the caller is no longer holding the - * console_lock. Otherwise it is set to false. - * - * Returns false if the given console has no next record to print, otherwi= se - * true. + +/** + * cons_fill_outbuf - Fill the output buffer with the next record + * @con: The console to print on + * @desc: Pointer to the output descriptor + * + * The output descriptor contains all information which is necessary + * to print (buffer pointer, extended format selector...). + * + * Returns: False if there is no pending record in the ringbuffer + * True if there is a pending record in the ringbuffer. + * + * When the return value is true, then the caller has to check + * @desc->outbuf. If not NULL it points to the first character to write to + * the device and @desc->len contains the length of the message. * - * Requires the console_lock. + * If it is NULL then records have been dropped or skipped and con->seq + * has been forwarded so the caller can try to print the next record. */ -static bool console_emit_next_record(struct console *con, struct cons_text= _buf *txtbuf, - bool *handover, bool extmsg) +static bool cons_fill_outbuf(struct console *con, struct cons_outbuf_desc = *desc) { static int panic_console_dropped; + + struct cons_text_buf *txtbuf =3D desc->txtbuf; struct printk_info info; struct printk_record r; - unsigned long flags; char *write_text; size_t len; =20 - prb_rec_init_rd(&r, &info, txtbuf->text, CONSOLE_LOG_MAX); + desc->outbuf =3D NULL; + desc->len =3D 0; =20 - *handover =3D false; + prb_rec_init_rd(&r, &info, txtbuf->text, CONSOLE_LOG_MAX); =20 if (!prb_read_valid(prb, con->seq, &r)) return false; @@ -2734,10 +2733,10 @@ static bool console_emit_next_record(str /* Skip record that has level above the console loglevel. */ if (suppress_message_printing(r.info->level)) { con->seq++; - goto skip; + return true; } =20 - if (extmsg) { + if (desc->extmsg) { write_text =3D txtbuf->ext_text; len =3D info_print_ext_header(write_text, CONSOLE_EXT_LOG_MAX, r.info); len +=3D msg_print_ext_body(write_text + len, CONSOLE_EXT_LOG_MAX - len, @@ -2747,6 +2746,47 @@ static bool console_emit_next_record(str len =3D record_print_text(&r, console_msg_format & MSG_FORMAT_SYSLOG, pr= intk_time); } =20 + desc->len =3D len; + desc->outbuf =3D write_text; + return true; +} + +/** + * console_emit_next_record - Print one record for the given console + * @con: The console to print on + * @txtbuf: Pointer to the output buffer + * @handover: Pointer to Handover handshake storage + * @extmsg: Selects extended message format + * + * The record printed is whatever record is the next available record for + * the given console. + * + * @handover will be set to true if a printk waiter has taken over the + * console_lock, in which case the caller is no longer holding the + * console_lock. Otherwise it is set to false. + * + * Returns false if the given console has no next record to print, otherwi= se + * true. + * + * Requires the console_lock. + */ +static bool console_emit_next_record(struct console *con, struct cons_text= _buf *txtbuf, + bool *handover, bool extmsg) +{ + struct cons_outbuf_desc desc =3D { + .txtbuf =3D txtbuf, + .extmsg =3D extmsg, + }; + unsigned long flags; + + *handover =3D false; + + if (!cons_fill_outbuf(con, &desc)) + return false; + + if (!desc.outbuf) + goto skip; + /* * While actively printing out messages, if another printk() * were to occur on another CPU, it may wait for this one to @@ -2761,7 +2801,7 @@ static bool console_emit_next_record(str console_lock_spinning_enable(); =20 stop_critical_timings(); /* don't trace print latency */ - call_console_driver(con, write_text, len, extmsg ? NULL : txtbuf->dropped= _text); + call_console_driver(con, desc.outbuf, desc.len, extmsg ? NULL : txtbuf->d= ropped_text); start_critical_timings(); =20 con->seq++; From nobody Mon Apr 6 03:09:13 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 52EB6C6FA82 for ; Sat, 10 Sep 2022 22:29:22 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230212AbiIJW3T (ORCPT ); Sat, 10 Sep 2022 18:29:19 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:47170 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230314AbiIJW2a (ORCPT ); Sat, 10 Sep 2022 18:28:30 -0400 Received: from galois.linutronix.de (Galois.linutronix.de [193.142.43.55]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 61E5F43333 for ; Sat, 10 Sep 2022 15:28:02 -0700 (PDT) Message-ID: <20220910222301.422514421@linutronix.de> DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020; t=1662848880; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: references:references; bh=GORp14X0ZPsta6IucVBlmsXp9iduDN+zPIQ5DiLrn3I=; b=iMQNCn8ruP6Jx1Gh4WzWgOGiyi+3IGoUmLYw4P1Z5niRDBN4m60017dC1LeiV8lbh9N6pS V6I1RzY3iRGq/U/UwagFgVk+SI3pYhLPRkmVl3qkBrofWfVG63ydgghR1Qw1WM5CXfawxh MkN/CUdMlVmbnadOJz7UyEbHE6ZkmQLCFGO8lQ0AG0GrgRCe2mySkHFHn5z0Y5MMLBwgEn b/gIGoP5Zte0QjN0jSN0tzgzsx/PHMY61suwONVe7uRehoIK2i7YRNHwwjP4VTtmDd0lfE W/Q3hy8YqoLrtzvehknIHVpvx8YqD0yR9oiRVEdniup4gNeQuCGvzq51ijuLdw== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020e; t=1662848880; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: references:references; bh=GORp14X0ZPsta6IucVBlmsXp9iduDN+zPIQ5DiLrn3I=; b=59bMwLuHY15oRwAWgcslNBmblSP4msdmhJTJnuUN6FzYZmokzKg6IUwUuaL4qA/e+i8XcH R9XwkH0jsSjGhABA== From: Thomas Gleixner To: LKML Cc: John Ogness , Petr Mladek , Sergey Senozhatsky , Steven Rostedt , Linus Torvalds , Peter Zijlstra , "Paul E. McKenney" , Daniel Vetter , Greg Kroah-Hartman , Helge Deller , Jason Wessel , Daniel Thompson Subject: [patch RFC 18/29] printk: Handle dropped message smarter References: <20220910221947.171557773@linutronix.de> MIME-Version: 1.0 Date: Sun, 11 Sep 2022 00:27:59 +0200 (CEST) Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" No need for an extra buffer type. Regular formatting which needs the '$N messages dropped' printout can sprintf() it into the unused extended text buffer. As a further simplification move the 'dropped' message right in front of the actual record text and let the write function output it in one go. Signed-off-by: Thomas Gleixner --- include/linux/console.h | 12 ++---- kernel/printk/printk.c | 86 +++++++++++++++++++++++++++++++------------= ----- 2 files changed, 61 insertions(+), 37 deletions(-) --- a/include/linux/console.h +++ b/include/linux/console.h @@ -175,28 +175,26 @@ enum cons_flags { /** * struct cons_text_buf - console output text buffer * @ext_text: Buffer for extended log format text - * @dropped_text: Buffer for dropped text * @text: Buffer for ringbuffer text */ struct cons_text_buf { - union { - char ext_text[CONSOLE_EXT_LOG_MAX]; - char dropped_text[DROPPED_TEXT_MAX]; - }; - char text[CONSOLE_LOG_MAX]; -}; + char ext_text[CONSOLE_EXT_LOG_MAX]; + char text[CONSOLE_LOG_MAX]; +} __no_randomize_layout; =20 /** * struct cons_outbuf_desc - console output buffer descriptor * @txtbuf: Pointer to buffer for storing the text * @outbuf: Pointer to the position in @buffer for * writing it out to the device + * @dropped: The dropped count * @len: Message length * @extmsg: Select extended format printing */ struct cons_outbuf_desc { struct cons_text_buf *txtbuf; char *outbuf; + unsigned long dropped; unsigned int len; bool extmsg; }; --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -1957,27 +1957,6 @@ static int console_trylock_spinning(void } =20 /* - * Call the specified console driver, asking it to write out the specified - * text and length. If @dropped_text is non-NULL and any records have been - * dropped, a dropped message will be written out first. - */ -static void call_console_driver(struct console *con, const char *text, siz= e_t len, - char *dropped_text) -{ - size_t dropped_len; - - if (con->dropped && dropped_text) { - dropped_len =3D snprintf(dropped_text, DROPPED_TEXT_MAX, - "** %lu printk messages dropped **\n", - con->dropped); - con->dropped =3D 0; - con->write(con, dropped_text, dropped_len); - } - - con->write(con, text, len); -} - -/* * Recursion is tracked separately on each CPU. If NMIs are supported, an * additional NMI context per CPU is also separately tracked. Until per-CPU * is available, a separate "early tracking" is performed. @@ -2356,10 +2335,6 @@ static ssize_t msg_print_ext_body(char * struct dev_printk_info *dev_info) { return 0; } static void console_lock_spinning_enable(void) { } static int console_lock_spinning_disable_and_check(void) { return 0; } -static void call_console_driver(struct console *con, const char *text, siz= e_t len, - char *dropped_text) -{ -} static bool suppress_message_printing(int level) { return false; } static bool pr_flush(int timeout_ms, bool reset_on_progress) { return true= ; } static bool __pr_flush(struct console *con, int timeout_ms, bool reset_on_= progress) { return true; } @@ -2684,6 +2659,46 @@ static void __console_unlock(void) up_console_sem(); } =20 +/** + * cons_print_dropped - Print 'dropped' message if required + * @desc: Pointer to the output descriptor + * + * Prints the 'dropped' message info the output buffer if @desc->dropped is + * not 0 and the regular format is requested. Extended format does not + * need this message because it prints the sequence numbers. + * + * In regular format the extended message buffer is not in use. + * So print into it at the beginning and move the resulting string + * just in front of the regular text buffer so that the message can + * be printed in one go. + * + * In case of a message this returns with @desc->outbuf and @desc->len + * updated. If no message is required then @desc is not modified. + */ +static void cons_print_dropped(struct cons_outbuf_desc *desc) +{ + struct cons_text_buf *txtbuf =3D desc->txtbuf; + size_t len; + + if (!desc->dropped || desc->extmsg) + return; + + if (WARN_ON_ONCE(desc->outbuf !=3D txtbuf->text)) + return; + + /* Print it into ext_text which is unused */ + len =3D snprintf(txtbuf->ext_text, DROPPED_TEXT_MAX, + "** %lu printk messages dropped **\n", desc->dropped); + desc->dropped =3D 0; + + /* Copy it just below text so it goes out with one write */ + memcpy(txtbuf->text - len, txtbuf->ext_text, len); + + /* Update the descriptor */ + desc->len +=3D len; + desc->outbuf -=3D len; +} + =20 /** * cons_fill_outbuf - Fill the output buffer with the next record @@ -2737,17 +2752,26 @@ static bool cons_fill_outbuf(struct cons } =20 if (desc->extmsg) { + /* + * Extended messages do not require "dropped" message + * as that can be seen from the sequence number + */ write_text =3D txtbuf->ext_text; len =3D info_print_ext_header(write_text, CONSOLE_EXT_LOG_MAX, r.info); len +=3D msg_print_ext_body(write_text + len, CONSOLE_EXT_LOG_MAX - len, &r.text_buf[0], r.info->text_len, &r.info->dev_info); + desc->len =3D len; + desc->outbuf =3D write_text; } else { - write_text =3D txtbuf->text; len =3D record_print_text(&r, console_msg_format & MSG_FORMAT_SYSLOG, pr= intk_time); + + desc->len =3D len; + desc->outbuf =3D txtbuf->text; + desc->dropped =3D con->dropped; + cons_print_dropped(desc); + con->dropped =3D desc->dropped; } =20 - desc->len =3D len; - desc->outbuf =3D write_text; return true; } =20 @@ -2800,8 +2824,10 @@ static bool console_emit_next_record(str printk_safe_enter_irqsave(flags); console_lock_spinning_enable(); =20 - stop_critical_timings(); /* don't trace print latency */ - call_console_driver(con, desc.outbuf, desc.len, extmsg ? NULL : txtbuf->d= ropped_text); + /* don't trace print latency */ + stop_critical_timings(); + /* Write everything out to the hardware */ + con->write(con, desc.outbuf, desc.len); start_critical_timings(); =20 con->seq++; From nobody Mon Apr 6 03:09:13 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 67258C6FA82 for ; Sat, 10 Sep 2022 22:29:27 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229514AbiIJW30 (ORCPT ); Sat, 10 Sep 2022 18:29:26 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45980 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230315AbiIJW2b (ORCPT ); Sat, 10 Sep 2022 18:28:31 -0400 Received: from galois.linutronix.de (Galois.linutronix.de [193.142.43.55]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id CEA3C43327 for ; Sat, 10 Sep 2022 15:28:04 -0700 (PDT) Message-ID: <20220910222301.479172669@linutronix.de> DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020; t=1662848881; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: references:references; bh=eW1Uv7VcznaWz1WCA/sCs2A1xXkZMV/Q/SbEfreVnsg=; b=nLhzR3/u5SeUMOBnmpTsUUhNpI+Wypi0sJNm5i86qygBtQAKb9ssAryYUyTMEgUvyN2sm+ T3g0QiyYz9+Ea7hVrcv6Pkxyqa3+HL/QGNaJSDpz3XGqayGF34dmoyquEHn+L9T+6grkJt F2slE8RdopxrJEPgYHt3m0lg9H1FYcYlPleVrpy9L6UoxddnhfrBaZtDEhoFssa+6rM5Lh 8jvEkY9UWfBA5ozQy0/kLfEmw9Ji+ahwC/GrKyy9D2geGcVIrvp6uu7ID/24/9XStw2ZBM 63Cao8aZjbAWdpKX4EYHyR1Ti3lj9N2ZfapqIb/6ZuEVrx+WLCEsEXBSg4F+UA== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020e; t=1662848881; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: references:references; bh=eW1Uv7VcznaWz1WCA/sCs2A1xXkZMV/Q/SbEfreVnsg=; b=5OF6Nei9RtmlJEXDfoL0aeOUY4u9J9+nvcw0wzr7WTHIOvLIb2o7+CQuymymjOM0H3zvVD GWCFFecB8fyPk4Bw== From: Thomas Gleixner To: LKML Cc: John Ogness , Petr Mladek , Sergey Senozhatsky , Steven Rostedt , Linus Torvalds , Peter Zijlstra , "Paul E. McKenney" , Daniel Vetter , Greg Kroah-Hartman , Helge Deller , Jason Wessel , Daniel Thompson , John Ogness Subject: [patch RFC 19/29] printk: Add basic infrastructure for non-BKL consoles References: <20220910221947.171557773@linutronix.de> MIME-Version: 1.0 Date: Sun, 11 Sep 2022 00:28:01 +0200 (CEST) Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" The current console/printk subsystem is protected by a Big Kernel Lock, aka. console_lock which has has ill defined semantics and is more or less stateless. This puts severe limitations on the console subsystem and makes forced takeover and output in emergency and panic situations a fragile endavour which is based on try and pray. The goal of non-BKL consoles is to break out of the console lock jail and to provide a new infrastructure which avoids the pitfalls and allows console drivers to be gradually converted over. The proposed infrastructure aims for the following properties: - Lockless (SCRU protected) console list walk - Per console locking instead of global locking - Per console state which allows to make informed decisions - Stateful handover and takeover As a first step this adds state to struct console. The per console state is a atomic_long_t with a 32bit bit field and on 64bit a 32bit sequence for tracking the last printed ringbuffer sequence number. On 32bit the sequence is seperate from state for obvious reasons which requires to handle a few extra race conditions. Add the initial state with the most basic 'alive' and 'enabled' bits and wire it up into the console register/unregister functionality and exclude such consoles from being handled in the console BKL mechanisms. The decision to use a bitfield was made as using a plain u32 and mask/shift operations turned out to result in uncomprehensible code. Co-Developed-by: John Ogness Signed-off-by: John Ogness Signed-off-by: Thomas Gleixner (Intel) --- fs/proc/consoles.c | 1=20 include/linux/console.h | 38 +++++++++ kernel/printk/printk.c | 21 ++++- kernel/printk/printk_nobkl.c | 176 ++++++++++++++++++++++++++++++++++++++= +++++ 4 files changed, 235 insertions(+), 1 deletion(-) --- a/fs/proc/consoles.c +++ b/fs/proc/consoles.c @@ -21,6 +21,7 @@ static int show_console_dev(struct seq_f { CON_ENABLED, 'E' }, { CON_CONSDEV, 'C' }, { CON_BOOT, 'B' }, + { CON_NO_BKL, 'N' }, { CON_PRINTBUFFER, 'p' }, { CON_BRL, 'b' }, { CON_ANYTIME, 'a' }, --- a/include/linux/console.h +++ b/include/linux/console.h @@ -161,6 +161,8 @@ static inline int con_debug_leave(void) * printk spam for obvious reasons * @CON_EXTENDED: The console supports the extended output format of /dev/= kmesg * which requires a larger output record buffer + * @CON_NO_BKL: Console can operate outside of the BKL style console_lock + * constraints. */ enum cons_flags { CON_PRINTBUFFER =3D BIT(0), @@ -170,6 +172,37 @@ enum cons_flags { CON_ANYTIME =3D BIT(4), CON_BRL =3D BIT(5), CON_EXTENDED =3D BIT(6), + CON_NO_BKL =3D BIT(7), +}; + +/** + * struct cons_state - console state for NOBKL consoles + * @atom: Compound of the state fields for atomic operations + * @seq: Sequence for record tracking (64bit only) + * @bits: Compound of the state bits below + * + * @alive: Console is alive. Required for teardown + * @enabled: Console is enabled. If 0, do not use + * + * To be used for state read and preparation of atomic_long_cmpxchg() + * operations. + */ +struct cons_state { + union { + unsigned long atom; + struct { +#ifdef CONFIG_64BIT + u32 seq; +#endif + union { + u32 bits; + struct { + u32 alive : 1; + u32 enabled : 1; + }; + }; + }; + }; }; =20 /** @@ -218,6 +251,8 @@ struct cons_outbuf_desc { * @dropped: Number of dropped ringbuffer records * @data: Driver private data * @node: hlist node for the console list + * + * @atomic_state: State array for non-BKL consoles. Real and handover */ struct console { char name[16]; @@ -237,6 +272,9 @@ struct console { unsigned long dropped; void *data; struct hlist_node node; + + /* NOBKL console specific members */ + atomic_long_t __private atomic_state[2]; }; =20 #ifdef CONFIG_LOCKDEP --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -2339,7 +2339,9 @@ static bool suppress_message_printing(in static bool pr_flush(int timeout_ms, bool reset_on_progress) { return true= ; } static bool __pr_flush(struct console *con, int timeout_ms, bool reset_on_= progress) { return true; } =20 -#endif /* CONFIG_PRINTK */ +#endif /* !CONFIG_PRINTK */ + +#include "printk_nobkl.c" =20 #ifdef CONFIG_EARLY_PRINTK struct console *early_console; @@ -2635,6 +2637,13 @@ static bool abandon_console_lock_in_pani */ static inline bool console_is_usable(struct console *con) { + /* + * Exclude the NOBKL consoles. They are handled seperately + * as they do not require the console BKL + */ + if ((con->flags & CON_NO_BKL)) + return false; + if (!(con->flags & CON_ENABLED)) return false; =20 @@ -3079,7 +3088,10 @@ void console_stop(struct console *consol console_list_lock(); console_lock(); console->flags &=3D ~CON_ENABLED; + cons_state_disable(console); console_unlock(); + /* Ensure that all SRCU list walks have completed */ + synchronize_srcu(&console_srcu); console_list_unlock(); } EXPORT_SYMBOL(console_stop); @@ -3089,6 +3101,7 @@ void console_start(struct console *conso console_list_lock(); console_lock(); console->flags |=3D CON_ENABLED; + cons_state_enable(console); console_unlock(); console_list_unlock(); __pr_flush(console, 1000, true); @@ -3276,6 +3289,9 @@ void register_console(struct console *ne newcon->flags &=3D ~CON_PRINTBUFFER; } =20 + /* Initialize the nobkl data in @newcon */ + cons_nobkl_init(newcon); + /* * Put this console in the list and keep the referred driver at the * head of the list. @@ -3342,6 +3358,7 @@ static int console_unregister_locked(str =20 /* Disable it unconditionally */ console->flags &=3D ~CON_ENABLED; + cons_state_disable(console); =20 if (hlist_unhashed(&console->node)) goto out_unlock; @@ -3365,6 +3382,8 @@ static int console_unregister_locked(str /* Ensure that all SRCU list walks have completed */ synchronize_srcu(&console_srcu); =20 + cons_nobkl_cleanup(console); + console_sysfs_notify(); =20 if (console->exit) --- /dev/null +++ b/kernel/printk/printk_nobkl.c @@ -0,0 +1,176 @@ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (C) 2022 Linutronix GmbH, John Ogness +// Copyright (C) 2022 Intel, Thomas Gleixner + +/* + * Printk implementation for consoles which do not depend on the BKL style + * console_lock() mechanism. + * + * Console is locked on a CPU when state::locked is set and state:cpu =3D= =3D + * current CPU. This is valid for the current execution context. + * + * Nesting execution contexts on the same CPU can carefully take over + * if the driver allows reentrancy via state::unsafe =3D false. When the + * interrupted context resumes it checks the state before entering + * a unsafe region and aborts the operation it it detects the takeover. + * + * In case of panic or emergency the nesting context can take over the + * console forcefully. The write callback is then invoked with the unsafe + * flag set in the write context data which allows the driver side to avoid + * locks and to evaluate the driver state so it can use an emergency path = or + * repair the state instead of blindly assuming that it works. + * + * If the interrupted context touches the assigned record buffer after + * takeover that does not cause harm because at the same execution level + * there is no concurrency on the same CPU. A threaded printer has always + * its own record buffer so it can never interfere with any of the per CPU + * record buffers. + * + * A concurrent writer on a different CPU can request to take over the + * console by: + * + * 1) Carefully writing the desired state into state[HANDOVER] + * if there is no same or higher priority request pending + * This locks state[HANDOVER] except for higher priority + * waiters. + * + * 2) Setting state[REAL].req_prio unless a higher priority + * waiter won the race. + * + * 3) Carefully spin on state[REAL] until that is locked with the + * expected state. When the state is not the expected one then it + * has to verify that state[HANDOVER] is still the same and that + * state[REAL] has not been taken over or marked dead. + * + * The unlocker hands over to state[HANDOVER], but only if state[REAL] + * matches. + * + * In case that the owner does not react on the request and does not make + * observable progress, the caller can decide to do a hostile take over. + */ + +#ifdef CONFIG_PRINTK + +#define copy_full_state(_dst, _src) do { _dst =3D _src; } while(0) +#define copy_bit_state(_dst, _src) do { _dst.bits =3D _src.bits; } while(0) + +#ifdef CONFIG_64BIT +#define copy_seq_state64(_dst, _src) do { _dst.seq =3D _src.seq; } while(0) +#else +#define copy_seq_state64(_dst, _src) do { } while(0) +#endif + +enum state_selector { + STATE_REAL, + STATE_HANDOVER, +}; + +/** + * cons_state_set - Helper function to set the console state + * @con: Console to update + * @which: Selects real state or handover state + * @new: The new state to write + * + * Only to be used when the console is not yet or not longer visible in the + * system. + */ +static inline void cons_state_set(struct console *con, enum state_selector= which, + struct cons_state *new) +{ + atomic_long_set(&ACCESS_PRIVATE(con, atomic_state[which]), new->atom); +} + +/** + * cons_state_read - Helper function to read the console state + * @con: Console to update + * @which: Selects real state or handover state + * @state: The state to store the result + */ +static inline void cons_state_read(struct console *con, enum state_selecto= r which, + struct cons_state *state) +{ + state->atom =3D atomic_long_read(&ACCESS_PRIVATE(con, atomic_state[which]= )); +} + +/** + * cons_state_try_cmpxchg() - Helper function for atomic_long_try_cmpxchg(= ) on console state + * @con: Console to update + * @which: Selects real state or handover state + * @old: Old state + * @new: New state + * + * Returns: True on success, false on fail + */ +static inline bool cons_state_try_cmpxchg(struct console *con, + enum state_selector which, + struct cons_state *old, + struct cons_state *new) +{ + return atomic_long_try_cmpxchg(&ACCESS_PRIVATE(con, atomic_state[which]), + &old->atom, new->atom); +} + +/** + * cons_state_mod_enabled - Helper function to en/disable a console + * @con: Console to modify + */ +static void cons_state_mod_enabled(struct console *con, bool enable) +{ + struct cons_state old, new; + + cons_state_read(con, STATE_REAL, &old); + do { + copy_full_state(new, old); + new.enabled =3D enable; + } while (!cons_state_try_cmpxchg(con, STATE_REAL, &old, &new)); +} + +/** + * cons_state_disable - Helper function to disable a console + * @con: Console to disable + */ +static void cons_state_disable(struct console *con) +{ + cons_state_mod_enabled(con, false); +} + +/** + * cons_state_enable - Helper function to enable a console + * @con: Console to enable + */ +static void cons_state_enable(struct console *con) +{ + cons_state_mod_enabled(con, true); +} + +/** + * cons_nobkl_init - Initialize the NOBKL console state + * @con: Console to initialize + */ +static void cons_nobkl_init(struct console *con) +{ + struct cons_state state =3D { + .alive =3D 1, + .enabled =3D !!(con->flags & CON_ENABLED), + }; + + cons_state_set(con, STATE_REAL, &state); +} + +/** + * cons_nobkl_cleanup - Cleanup the NOBKL console state + * @con: Console to cleanup + */ +static void cons_nobkl_cleanup(struct console *con) +{ + struct cons_state state =3D { }; + + cons_state_set(con, STATE_REAL, &state); +} + +#else /* CONFIG_PRINTK */ +static inline void cons_nobkl_init(struct console *con) { } +static inline void cons_nobkl_cleanup(struct console *con) { } +static inline void cons_state_disable(struct console *con) { } +static inline void cons_state_enable(struct console *con) { } +#endif /* !CONFIG_PRINTK */ From nobody Mon Apr 6 03:09:13 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id C99A5C6FA82 for ; Sat, 10 Sep 2022 22:29:44 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230391AbiIJW3m (ORCPT ); Sat, 10 Sep 2022 18:29:42 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:47482 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230236AbiIJW2i (ORCPT ); Sat, 10 Sep 2022 18:28:38 -0400 Received: from galois.linutronix.de (Galois.linutronix.de [193.142.43.55]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 1772243606 for ; Sat, 10 Sep 2022 15:28:05 -0700 (PDT) Message-ID: <20220910222301.539158418@linutronix.de> DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020; t=1662848883; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: references:references; bh=+saMLYDsS/m2enf6TfMEaB5aiB2N6jXCMDiRdRXMaJ0=; b=YiwMm7paqOmXf2P471+wibGaaUi7aDiCXQW7wzvpdOsuKaeYPuESnTMrngiRXaSwjQpQHi WylGAfHPApkK9UbhOlixf/PoNnUqD8LSN7ZjVmju1tMwoS8Xk45QgskWz5PNlD64gBE2zE Ni5aX1hPTVcrvRylir67jf77v3pB5j3UwXHUBw3wimm0haE27z/aRryJYzlItH2vg0JIj7 klP11t+KG/ArL5Ws2Hn5qrw6OdbbFdpso2YNMXIaoAs+he1jszEBCmiRkNio8cIcyTTFcm skxgdO49YrGCy0RAhOXyFNDspPnO7xBizh7oiFryjUUnVHpPEWZNdYKaOY/SQw== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020e; t=1662848883; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: references:references; bh=+saMLYDsS/m2enf6TfMEaB5aiB2N6jXCMDiRdRXMaJ0=; b=FJvMaosjU7/7c8GrFhD/LHeklWdNpKdGzZK1VtNt7TtwUEGgJxmYcGLqiWjzI5v6ouF8Et Oy88M1S89YDkRLDw== From: Thomas Gleixner To: LKML Cc: John Ogness , Petr Mladek , Sergey Senozhatsky , Steven Rostedt , Linus Torvalds , Peter Zijlstra , "Paul E. McKenney" , Daniel Vetter , Greg Kroah-Hartman , Helge Deller , Jason Wessel , Daniel Thompson , John Ogness Subject: [patch RFC 20/29] printk: Add non-BKL console acquire/release logic References: <20220910221947.171557773@linutronix.de> MIME-Version: 1.0 Date: Sun, 11 Sep 2022 00:28:02 +0200 (CEST) Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add per console acquire/release functionality. The console 'locked' state is a combination of several state fields: - The 'locked' bit - The 'cpu' field which denotes on which CPU the console is locked =20 - The 'cur_prio' field which contains the severity of the printk context which owns the console. This field is used for decisions whether to attempt friendly handovers and also prevents takeovers from a less severe context, e.g. to protect the panic CPU. The acquire mechanism comes with several flavours: - Straight forward acquire when the console is not contended - Friendly handover mechanism based on a request/grant handshake The requesting context: 1) puts the desired handover state (CPU nr, prio) into a seperate handover state 2) sets the 'req_prio' field in the real console state 3) Waits for the owning context to handover with a timeout The owning context: 1) Observes the 'req_prio' field set 2) Hands the console over to the requesting context by switching the console state to the handover state which the requester provided =20 - Hostile takeover The new owner takes the console over without handshake This is required when friendly handovers are not possible, i.e. the higher priority context interrupted the owning context on the same CPU or the owning context is not able to make progress on a remote CPU. The release is the counterpart which either releases the console directly or hands it gracefully over to a requester. All operations on console::atomic_state[REAL|HANDOVER} are atomic cmpxchg based to handle concurrency. The acquire/release functions implement only minimal policies: - Preference for higher priority contexts - Protection of the panic CPU All other policy decisions have to be made at the call sites. The design allows to implement the well known: acquire() output_one_line() release() algorithm, but also allows to avoid the per line acquire/release for e.g. panic situations by doing the acquire once and then relying on the panic CPU protection for the rest. Co-Developed-by: John Ogness Signed-off-by: John Ogness Signed-off-by: Thomas Gleixner --- include/linux/console.h | 63 +++++ kernel/printk/printk_nobkl.c | 466 ++++++++++++++++++++++++++++++++++++++= +++++ 2 files changed, 529 insertions(+) --- a/include/linux/console.h +++ b/include/linux/console.h @@ -183,6 +183,12 @@ enum cons_flags { * * @alive: Console is alive. Required for teardown * @enabled: Console is enabled. If 0, do not use + * @locked: Console is locked by a writer + * @unsafe: Console is busy in a non takeover region + * @thread: Current owner is the printk thread + * @cur_prio: The priority of the current output + * @req_prio: The priority of a handover request + * @cpu: The CPU on which the writer runs * * To be used for state read and preparation of atomic_long_cmpxchg() * operations. @@ -199,6 +205,12 @@ struct cons_state { struct { u32 alive : 1; u32 enabled : 1; + u32 locked : 1; + u32 unsafe : 1; + u32 thread : 1; + u32 cur_prio : 2; + u32 req_prio : 2; + u32 cpu : 18; }; }; }; @@ -233,6 +245,56 @@ struct cons_outbuf_desc { }; =20 /** + * cons_prio - console writer priority for NOBKL consoles + * @CONS_PRIO_NONE: Unused + * @CONS_PRIO_NORMAL: Regular printk + * @CONS_PRIO_EMERGENCY: Emergency output (WARN/OOPS...) + * @CONS_PRIO_PANIC: Panic output + * + * Emergency output can carefully takeover the console even without consent + * of the owner, ideally only when @cons_state::unsafe is not set. Panic + * output can ignore the unsafe flag as a last resort. If panic output is + * active no takeover is possible until the panic output releases the + * console. + */ +enum cons_prio { + CONS_PRIO_NONE =3D 0, + CONS_PRIO_NORMAL, + CONS_PRIO_EMERGENCY, + CONS_PRIO_PANIC, +}; + +struct console; + +/** + * struct cons_context - Context for console acquire/release + * @console: The associated console + * @state: The state at acquire time + * @old_state: The old state when try_acquire() failed for analyis + * by the caller + * @hov_state: The handover state for spin and cleanup + * @req_state: The request state for spin and cleanup + * @spinwait_max_us: Limit for spinwait acquire + * @prio: Priority of the context + * @thread: The acquire is printk thread context + * @hostile: Hostile takeover requested. Cleared on normal + * acquire or friendly handover + * @spinwait: Spinwait on acquire if possible + */ +struct cons_context { + struct console *console; + struct cons_state state; + struct cons_state old_state; + struct cons_state hov_state; + struct cons_state req_state; + unsigned int spinwait_max_us; + enum cons_prio prio; + unsigned int thread : 1; + unsigned int hostile : 1; + unsigned int spinwait : 1; +}; + +/** * struct console - The console descriptor structure * @name: The name of the console driver * @write: Write callback to output messages (Optional) @@ -275,6 +337,7 @@ struct console { =20 /* NOBKL console specific members */ atomic_long_t __private atomic_state[2]; + }; =20 #ifdef CONFIG_LOCKDEP --- a/kernel/printk/printk_nobkl.c +++ b/kernel/printk/printk_nobkl.c @@ -144,6 +144,472 @@ static void cons_state_enable(struct con } =20 /** + * cons_state_ok - Check whether state is ok for usage + * @state: The state to check + * + * Returns: True if usable, false otherwise. + */ +static inline bool cons_state_ok(struct cons_state state) +{ + return state.alive && state.enabled; +} + +/** + * cons_state_full_match - Check whether the full state matches + * @cur: The state to check + * @prev: The previous state + * + * Returns: True if matching, false otherwise. + * + * Check the full state including state::seq on 64bit. For take over + * detection. + */ +static inline bool cons_state_full_match(struct cons_state cur, + struct cons_state prev) +{ + /* + * req_prio can be set by a concurrent writer for friendly + * handover. Ignore it in the comparison. + */ + cur.req_prio =3D prev.req_prio; + return cur.atom =3D=3D prev.atom; +} + +/** + * cons_state_bits_match - Check for matching state bits + * @cur: The state to check + * @prev: The previous state + * + * Returns: True if state matches, false otherwise. + * + * Contrary to cons_state_full_match this checks only the bits and ignores + * a sequence change on 64bits. On 32bit the two functions are identical. + */ +static inline bool cons_state_bits_match(struct cons_state cur, + struct cons_state prev) +{ + /* + * req_prio can be set by a concurrent writer for friendly + * handover. Ignore it in the comparison. + */ + cur.req_prio =3D prev.req_prio; + return cur.bits =3D=3D prev.bits; +} + +/** + * cons_check_panic - Check whether a remote CPU paniced + */ +static inline bool cons_check_panic(void) +{ + unsigned int pcpu =3D atomic_read(&panic_cpu); + + return pcpu !=3D PANIC_CPU_INVALID && pcpu !=3D smp_processor_id(); +} + +/** + * cons_cleanup_handover - Cleanup a handover request + * @ctxt: Pointer to acquire context + * + * @ctxt->hov_state contains the state to clean up + */ +static void cons_cleanup_handover(struct cons_context *ctxt) +{ + struct console *con =3D ctxt->console; + struct cons_state new; + + /* + * No loop required. Either hov_state is still the same or + * not. + */ + new.atom =3D 0; + cons_state_try_cmpxchg(con, STATE_HANDOVER, &ctxt->hov_state, &new); +} + +/** + * cons_setup_handover - Setup a handover request + * @ctxt: Pointer to acquire context + * + * On success @ctxt->hov_state contains the requested handover state + */ +static bool cons_setup_handover(struct cons_context *ctxt) +{ + unsigned int cpu =3D smp_processor_id(); + struct console *con =3D ctxt->console; + struct cons_state old; + struct cons_state hstate =3D { + .alive =3D 1, + .enabled =3D 1, + .locked =3D 1, + .cur_prio =3D ctxt->prio, + .cpu =3D cpu, + }; + + /* + * Try to store hstate in @con->atomic_state[HANDOVER]. This might + * race with a higher priority waiter. + */ + cons_state_read(con, STATE_HANDOVER, &old); + do { + if (cons_check_panic()) + return false; + + /* Same or higher priority waiter exists? */ + if (old.cur_prio >=3D ctxt->prio) + return false; + + } while (!cons_state_try_cmpxchg(con, STATE_HANDOVER, &old, &hstate)); + + copy_full_state(ctxt->hov_state, hstate); + return true; +} + +/** + * cons_setup_request - Setup a handover request in state[REAL] + * @ctxt: Pointer to acquire context + * @old: The state which was used to make the decision to spin wait + * + * @ctxt->hov_state contains the handover state which was set in + * state[HANDOVER] + */ +static bool cons_setup_request(struct cons_context *ctxt, struct cons_stat= e old) +{ + struct console *con =3D ctxt->console; + struct cons_state cur, new; + + /* Now set the request in state[REAL] */ + cons_state_read(con, STATE_REAL, &cur); + do { + if (cons_check_panic()) + goto cleanup; + + /* Bit state changed vs. the decision to spinwait? */ + if (!cons_state_bits_match(cur, old)) + goto cleanup; + + /* Setup a request for handover. */ + copy_full_state(new, cur); + new.req_prio =3D ctxt->prio; + } while (!cons_state_try_cmpxchg(con, STATE_REAL, &cur, &new)); + + /* Safe that state for comparision in spinwait */ + copy_bit_state(ctxt->req_state, new); + return true; + +cleanup: + cons_cleanup_handover(ctxt); + return false; +} + +/** + * cons_try_acquire_spin - Complete the spinwait attempt + * @ctxt: Pointer to an aquire context which contains + * all information about the acquire mode + * + * @ctxt->hov_state contains the handover state which was set in + * state[HANDOVER] + * @ctxt->req_state contains the request state which was set in + * state[REAL] + * + * Returns: True if locked. False otherwise + */ +static bool cons_try_acquire_spin(struct cons_context *ctxt) +{ + struct console *con =3D ctxt->console; + struct cons_state cur, new; + bool ret =3D false; + int timeout; + + /* Now wait for the other side to hand over */ + for (timeout =3D ctxt->spinwait_max_us; timeout >=3D 0; timeout--) { + if (cons_check_panic()) + goto cleanup; + + cons_state_read(con, STATE_REAL, &cur); + /* + * This might have raced with a new requester coming in + * after the lock was handed over. So the request pends now + * for the current context with higher priority. + */ + if (cons_state_bits_match(cur, ctxt->hov_state)) + goto success; + + /* + * When state changed since the request was made give up as + * it is not longer consistent. This must include + * state::req_prio. + */ + if (cur.bits !=3D ctxt->req_state.bits) + goto cleanup; + + /* + * Finally check whether the handover state is still + * the same. + */ + cons_state_read(con, STATE_HANDOVER, &cur); + if (cur.atom !=3D ctxt->hov_state.atom) + goto cleanup; + + /* Account time */ + udelay(1); + } + + /* + * Timeout. Cleanup the handover state and carefully try to undo + * req_prio in real state. + */ + cons_cleanup_handover(ctxt); + + cons_state_read(con, STATE_REAL, &cur); + do { + /* + * The timeout might have raced with the owner coming late + * and handing it over gracefully. + */ + if (cur.bits =3D=3D ctxt->hov_state.bits) + goto success; + /* + * Validate that the state matches with the state at + * request time. + */ + if (cur.bits !=3D ctxt->req_state.bits) + return false; + + copy_full_state(new, cur); + new.req_prio =3D 0; + } while (!cons_state_try_cmpxchg(con, STATE_REAL, &cur, &new)); + /* Reset worked */ + return false; + +success: + /* Store the real state */ + copy_full_state(ctxt->state, cur); + ctxt->hostile =3D false; + ret =3D true; + +cleanup: + cons_cleanup_handover(ctxt); + return ret; +} + +/** + * __cons_try_acquire - Try to acquire the console for printk output + * @ctxt: Pointer to an aquire context which contains + * all information about the acquire mode + * + * Returns: True if the acquire was successful. False on fail. + * + * In case of success @ctxt->state contains the acquisition + * state. + * + * In case of fail @ctxt->old_state contains the state + * which was read from @con->state for analysis by the caller. + */ +static bool __cons_try_acquire(struct cons_context *ctxt) +{ + struct console *con =3D ctxt->console; + unsigned int cpu =3D smp_processor_id(); + struct cons_state old, new; + + if (WARN_ON_ONCE(!(con->flags & CON_NO_BKL))) + return false; + + cons_state_read(con, STATE_REAL, &old); + +again: + if (cons_check_panic()) + return false; + + /* Preserve it for the caller and for spinwait */ + copy_full_state(ctxt->old_state, old); + + if (!cons_state_ok(old)) + return false; + + /* Set up the new state for takeover */ + copy_full_state(new, old); + new.locked =3D 1; + new.thread =3D ctxt->thread; + new.cur_prio =3D ctxt->prio; + new.req_prio =3D CONS_PRIO_NONE; + new.cpu =3D cpu; + + /* Attempt to acquire it directly if unlocked */ + if (!old.locked) { + if (!cons_state_try_cmpxchg(con, STATE_REAL, &old, &new)) + goto again; + + ctxt->hostile =3D false; + copy_full_state(ctxt->state, new); + goto success; + } + + /* + * Give up if the calling context is the printk thread. The + * atomic writer will wake the thread when it is done with + * the important output. + */ + if (ctxt->thread) + return false; + + /* + * If the active context is on the same CPU then there is + * obviously no handshake possible. + */ + if (old.cpu =3D=3D cpu) + goto check_hostile; + + /* + * If the caller did not request spin-waiting or a request with the + * same or higher priority is pending then check whether a hostile + * takeover is due. + */ + if (!ctxt->spinwait || old.req_prio >=3D ctxt->prio) + goto check_hostile; + + /* Proceed further with spin acquire */ + if (!cons_setup_handover(ctxt)) + return false; + + /* + * Setup the request in state[REAL]. Hand in the state, which was + * used to make the decision to spinwait above, for comparison. + */ + if (!cons_setup_request(ctxt, old)) + return false; + + /* Now spin on it */ + if (!cons_try_acquire_spin(ctxt)) + return false; +success: + /* Common updates on success */ + return true; + +check_hostile: + if (!ctxt->hostile) + return false; + + if (!cons_state_try_cmpxchg(con, STATE_REAL, &old, &new)) + goto again; + + ctxt->hostile =3D true; + copy_full_state(ctxt->state, new); + goto success; +} + +/** + * cons_try_acquire - Try to acquire the console for printk output + * @ctxt: Pointer to an aquire context which contains + * all information about the acquire mode + * + * Returns: True if the acquire was successful. False on fail. + * + * In case of success @ctxt->state contains the acquisition + * state. + * + * In case of fail @ctxt->old_state contains the state + * which was read from @con->state for analysis by the caller. + */ +static bool __maybe_unused cons_try_acquire(struct cons_context *ctxt) +{ + if (__cons_try_acquire(ctxt)) + return true; + + ctxt->state.atom =3D 0; + return false; +} + +/** + * __cons_release - Release the console after output is done + * @ctxt: The acquire context which contains the state + * at cons_try_acquire() + * + * Returns: True if the release was regular + * + * False if the console is in unusable state or was handed over + * with handshake or taken over hostile without handshake. + * + * The return value tells the caller whether it needs to evaluate further + * printing. + */ +static bool __cons_release(struct cons_context *ctxt) +{ + struct console *con =3D ctxt->console; + struct cons_state old, new, hstate; + + if (WARN_ON_ONCE(!(con->flags & CON_NO_BKL))) + return false; + + cons_state_read(con, STATE_REAL, &old); + +again: + if (!cons_state_full_match(old, ctxt->state)) + return false; + + /* + * Release it directly when: + * - the console has been disabled + * - no handover request is pending + */ + if (!cons_state_ok(old) || !old.req_prio) + goto unlock; + + /* Read the handover target state */ + cons_state_read(con, STATE_HANDOVER, &hstate); + + /* If the waiter gave up hstate is 0 */ + if (!hstate.atom) + goto unlock; + + /* + * If a higher priority waiter raced against a lower priority + * waiter then wait for it to update the real state. + */ + if (hstate.cur_prio !=3D old.req_prio) + goto again; + + /* Switch the state and preserve the sequence on 64bit */ + copy_bit_state(new, hstate); + copy_seq_state64(new, old); + if (!cons_state_try_cmpxchg(con, STATE_REAL, &old, &new)) + goto again; + + return true; + +unlock: + copy_full_state(new, old); + new.locked =3D 0; + new.thread =3D 0; + new.cur_prio =3D CONS_PRIO_NONE; + new.req_prio =3D CONS_PRIO_NONE; + + if (!cons_state_try_cmpxchg(con, STATE_REAL, &old, &new)) + goto again; + + return true; +} + +/** + * cons_release - Release the console after output is done + * @ctxt: The acquire context which contains the state + * at cons_try_acquire() + * + * Returns: True if the release was regular + * + * False if the console is in unusable state or was handed over + * with handshake or taken over hostile without handshake. + * + * The return value tells the caller whether it needs to evaluate further + * printing. + */ +static bool __maybe_unused cons_release(struct cons_context *ctxt) +{ + bool ret =3D __cons_release(ctxt); + + ctxt->state.atom =3D 0; + return ret; +} + +/** * cons_nobkl_init - Initialize the NOBKL console state * @con: Console to initialize */ From nobody Mon Apr 6 03:09:13 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id DA743ECAAD3 for ; Sat, 10 Sep 2022 22:29:52 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230414AbiIJW3v (ORCPT ); Sat, 10 Sep 2022 18:29:51 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:46698 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230395AbiIJW2l (ORCPT ); Sat, 10 Sep 2022 18:28:41 -0400 Received: from galois.linutronix.de (Galois.linutronix.de [193.142.43.55]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 4B8C945040 for ; Sat, 10 Sep 2022 15:28:07 -0700 (PDT) Message-ID: <20220910222301.597440803@linutronix.de> DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020; t=1662848885; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: references:references; bh=yRyMpUYT+kmNyPrU5TuOkxnIPqW5hmLjaAM5Dx5YUoo=; b=1A7aaJDo5ez7UQG931AM8p7H8p6BWjG63SKE1+1TPnXaVDmopf1Esy9YgKCz9z7VQ2KHu/ w9Wctya/3qu04CV3Y/iPRYP9JGm+1hkaTUItnJfB7gUrChLs9TU5+is8FhwZ5SGAtcD1Wo L3aqmnQa5uy+FuHnc4mhLsBV2nialmlPvXnddzylyWy5JAcwRyC/p8rYptlRL+BGnDBn6u Qk1h+dmGIMVQJysK6VcJDUmLxbSRWV9yJvyQtZQIAfbR3beT0cvCzek/Dgjte5IDAdzt/J E3hry0isBo7OT+0tP+wM8/wI6oFV4kLcSUHIXyPGuv9HKse+UsdvM8Lpyvwd9g== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020e; t=1662848885; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: references:references; bh=yRyMpUYT+kmNyPrU5TuOkxnIPqW5hmLjaAM5Dx5YUoo=; b=J6KUbzvZVvtdwgZ9oumV19NJwy3XtkgtPj+dhTtWS+2XytNviPsASH/b9X/AaSxZWx6yEf N0mJYDKrvnmoTQCQ== From: Thomas Gleixner To: LKML Cc: John Ogness , Petr Mladek , Sergey Senozhatsky , Steven Rostedt , Linus Torvalds , Peter Zijlstra , "Paul E. McKenney" , Daniel Vetter , Greg Kroah-Hartman , Helge Deller , Jason Wessel , Daniel Thompson , John Ogness Subject: [patch RFC 21/29] printk: Add buffer management for noBKL consoles References: <20220910221947.171557773@linutronix.de> MIME-Version: 1.0 Date: Sun, 11 Sep 2022 00:28:04 +0200 (CEST) Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" In case of hostile takeovers it must be ensured that the previous owner cannot scribble over the output buffer of the emergency/panic context. This is achieved by: - Allocating per CPU output buffers per console and add the required handl= ing into the acquire/release functions. - Adding a single instance to struct console for early boot (pre per CPU data being available). The builtin instance is also used for threaded printing once printer threads become available. Wrapped into a seperate data structure so other context related fields can be added in later steps. Co-Developed-by: John Ogness Signed-off-by: John Ogness Signed-off-by: Thomas Gleixner --- include/linux/console.h | 21 ++++++++++++- kernel/printk/printk.c | 18 ++++++++--- kernel/printk/printk_nobkl.c | 69 ++++++++++++++++++++++++++++++++++++++= +++++ 3 files changed, 102 insertions(+), 6 deletions(-) --- a/include/linux/console.h +++ b/include/linux/console.h @@ -276,6 +276,7 @@ struct console; * @req_state: The request state for spin and cleanup * @spinwait_max_us: Limit for spinwait acquire * @prio: Priority of the context + * @txtbuf: Pointer to the text buffer for this context * @thread: The acquire is printk thread context * @hostile: Hostile takeover requested. Cleared on normal * acquire or friendly handover @@ -289,11 +290,25 @@ struct cons_context { struct cons_state req_state; unsigned int spinwait_max_us; enum cons_prio prio; + struct cons_text_buf *txtbuf; unsigned int thread : 1; unsigned int hostile : 1; unsigned int spinwait : 1; }; =20 +#define CONS_MAX_NEST_LVL 8 + +/** + * struct cons_context_data - console context data + * @txtbuf: Buffer for storing the text + * + * Used for early boot embedded into struct console and for + * per CPU data. + */ +struct cons_context_data { + struct cons_text_buf txtbuf; +}; + /** * struct console - The console descriptor structure * @name: The name of the console driver @@ -315,6 +330,8 @@ struct cons_context { * @node: hlist node for the console list * * @atomic_state: State array for non-BKL consoles. Real and handover + * @pcpu_data: Pointer to percpu context data + * @ctxt_data: Builtin context data for early boot and threaded printing */ struct console { char name[16]; @@ -336,8 +353,10 @@ struct console { struct hlist_node node; =20 /* NOBKL console specific members */ - atomic_long_t __private atomic_state[2]; + atomic_long_t __private atomic_state[2]; =20 + struct cons_context_data __percpu *pcpu_data; + struct cons_context_data ctxt_data; }; =20 #ifdef CONFIG_LOCKDEP --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -1071,9 +1071,17 @@ static void __init log_buf_add_cpu(void) static inline void log_buf_add_cpu(void) {} #endif /* CONFIG_SMP */ =20 +static void cons_alloc_percpu_data(struct console *con); + static void __init set_percpu_data_ready(void) { + struct console *con; + + console_list_lock(); + for_each_registered_console(con) + cons_alloc_percpu_data(con); __printk_percpu_data_ready =3D true; + console_list_unlock(); } =20 static unsigned int __init add_to_rb(struct printk_ringbuffer *rb, @@ -2341,6 +2349,11 @@ static bool __pr_flush(struct console *c =20 #endif /* !CONFIG_PRINTK */ =20 +#define con_printk(lvl, con, fmt, ...) \ + printk(lvl pr_fmt("%sconsole [%s%d] " fmt), \ + (con->flags & CON_BOOT) ? "boot" : "", \ + con->name, con->index, ##__VA_ARGS__) + #include "printk_nobkl.c" =20 #ifdef CONFIG_EARLY_PRINTK @@ -3191,11 +3204,6 @@ static void try_enable_default_console(s newcon->flags |=3D CON_CONSDEV; } =20 -#define con_printk(lvl, con, fmt, ...) \ - printk(lvl pr_fmt("%sconsole [%s%d] " fmt), \ - (con->flags & CON_BOOT) ? "boot" : "", \ - con->name, con->index, ##__VA_ARGS__) - #define cons_first() \ hlist_entry(console_list.first, struct console, node) =20 --- a/kernel/printk/printk_nobkl.c +++ b/kernel/printk/printk_nobkl.c @@ -207,6 +207,43 @@ static inline bool cons_check_panic(void } =20 /** + * cons_context_set_text_buf - Set the output text buffer for the current = context + * @ctxt: Pointer to the aquire context + * + * Buffer selection: + * 1) Early boot uses the console builtin buffer + * 2) Threads use the console builtin buffer + * 3) All other context use the per CPU buffers + * + * This guarantees that there is no concurrency on the output records + * ever. Per CPU nesting is not a problem at all. The takeover logic + * tells the interrupted context that the buffer has been overwritten. + * + * There are two critical regions which matter: + * + * 1) Context is filling the buffer with a record. After interruption + * it continues to sprintf() the record and before it goes to + * write it out, it checks the state, notices the takeover, discards + * the content and backs out. + * + * 2) Context is in a unsafe critical region in the driver. After + * interruption it might read overwritten data from the output + * buffer. When it leaves the critical region it notices and backs + * out. Hostile takeovers in driver critical regions are best effort + * and there is not much which can be done about that. + */ +static void cons_context_set_text_buf(struct cons_context *ctxt) +{ + struct console *con =3D ctxt->console; + + /* Early boot or allocation fail? */ + if (!con->pcpu_data) + ctxt->txtbuf =3D &con->ctxt_data.txtbuf; + else + ctxt->txtbuf =3D &(this_cpu_ptr(con->pcpu_data)->txtbuf); +} + +/** * cons_cleanup_handover - Cleanup a handover request * @ctxt: Pointer to acquire context * @@ -482,6 +519,7 @@ static bool __cons_try_acquire(struct co return false; success: /* Common updates on success */ + cons_context_set_text_buf(ctxt); return true; =20 check_hostile: @@ -610,6 +648,35 @@ static bool __maybe_unused cons_release( } =20 /** + * cons_alloc_percpu_data - Allocate percpu data for a console + * @con: Console to allocate for + */ +static void cons_alloc_percpu_data(struct console *con) +{ + if (!printk_percpu_data_ready()) + return; + + con->pcpu_data =3D alloc_percpu(typeof(*con->pcpu_data)); + if (con->pcpu_data) + return; + + con_printk(KERN_WARNING, con, "Failed to allocate percpu buffers\n"); +} + +/** + * cons_free_percpu_data - Free percpu data of a console on unregister + * @con: Console to clean up + */ +static void cons_free_percpu_data(struct console *con) +{ + if (!con->pcpu_data) + return; + + free_percpu(con->pcpu_data); + con->pcpu_data =3D NULL; +} + +/** * cons_nobkl_init - Initialize the NOBKL console state * @con: Console to initialize */ @@ -620,6 +687,7 @@ static void cons_nobkl_init(struct conso .enabled =3D !!(con->flags & CON_ENABLED), }; =20 + cons_alloc_percpu_data(con); cons_state_set(con, STATE_REAL, &state); } =20 @@ -632,6 +700,7 @@ static void cons_nobkl_cleanup(struct co struct cons_state state =3D { }; =20 cons_state_set(con, STATE_REAL, &state); + cons_free_percpu_data(con); } =20 #else /* CONFIG_PRINTK */ From nobody Mon Apr 6 03:09:13 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 79880C6FA82 for ; Sat, 10 Sep 2022 22:30:03 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230102AbiIJWaB (ORCPT ); Sat, 10 Sep 2022 18:30:01 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:46736 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230410AbiIJW2l (ORCPT ); Sat, 10 Sep 2022 18:28:41 -0400 Received: from galois.linutronix.de (Galois.linutronix.de [193.142.43.55]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 9F4FB45060 for ; Sat, 10 Sep 2022 15:28:09 -0700 (PDT) Message-ID: <20220910222301.654817026@linutronix.de> DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020; t=1662848886; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: references:references; bh=V3nslHeiY7vWR7aBqi9IfKVmvqX1b3nre7PznFTjP54=; b=zqvAM8a9TzTOkfp4BhhnkkB0U0BnK8o+ThtyYJXwrCKV4bF963O+463y9zW4X1kDD8piWo kzjEznuNrUsehJ7+RWMMir6ne7agCdu9FNFPcceIR8QdgYn11KbRY0gcjmwXePDZ2YXGTS W/dkY3OAk0R9eeYVbF2bhoc47dPm57m/R7o1fcb3XgUrSVX4xx55KBjoK1NsLlx33WX8l5 wibpW4M4JeX9QKyfemK486O5y3PUV8NEODDLS9V7InTrzrwOW8U2fqqx7kT3SDpoRyfkCJ Kq4xvOArAUEJrZ7mfBp0GOO7BE/af+y9Pm40WrV0fhDXGLxyGCVMSLmjcIXzyw== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020e; t=1662848886; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: references:references; bh=V3nslHeiY7vWR7aBqi9IfKVmvqX1b3nre7PznFTjP54=; b=B4+MUerbxLxDsVOn+jgpVITvcY8hQaT4GUc+ZkKfcqUCj9ZvmuV6tZbevKaQFjIo6U4vm4 uKQkM+qIxZTOqJCQ== From: Thomas Gleixner To: LKML Cc: John Ogness , Petr Mladek , Sergey Senozhatsky , Steven Rostedt , Linus Torvalds , Peter Zijlstra , "Paul E. McKenney" , Daniel Vetter , Greg Kroah-Hartman , Helge Deller , Jason Wessel , Daniel Thompson , John Ogness Subject: [patch RFC 22/29] printk: Add sequence handling for non-BKL consoles References: <20220910221947.171557773@linutronix.de> MIME-Version: 1.0 Date: Sun, 11 Sep 2022 00:28:06 +0200 (CEST) Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" On 64bit systems the sequence tracking is embedded into the atomic console state, on 32bit it has to be stored in a seperate atomic member. The latter needs to handle the non-atomicity in hostile takeover cases, while 64bit can completely rely on the state atomicity. The ringbuffer sequence number is 64bit, but having a 32bit representation in the console is sufficient. If a console ever gets more than 2^31 records behind the ringbuffer then this is the least of the problems. On acquire() the stomic 32bit sequence number is expanded to 64 bit by folding the ringbuffers sequence into it carefully. Co-Developed-by: John Ogness Signed-off-by: John Ogness Signed-off-by: Thomas Gleixner --- include/linux/console.h | 11 +- kernel/printk/printk_nobkl.c | 204 ++++++++++++++++++++++++++++++++++++++= ++++- 2 files changed, 212 insertions(+), 3 deletions(-) --- a/include/linux/console.h +++ b/include/linux/console.h @@ -275,6 +275,8 @@ struct console; * @hov_state: The handover state for spin and cleanup * @req_state: The request state for spin and cleanup * @spinwait_max_us: Limit for spinwait acquire + * @oldseq: The sequence number at acquire() + * @newseq: The sequence number for progress * @prio: Priority of the context * @txtbuf: Pointer to the text buffer for this context * @thread: The acquire is printk thread context @@ -288,6 +290,8 @@ struct cons_context { struct cons_state old_state; struct cons_state hov_state; struct cons_state req_state; + u64 oldseq; + u64 newseq; unsigned int spinwait_max_us; enum cons_prio prio; struct cons_text_buf *txtbuf; @@ -330,6 +334,7 @@ struct cons_context_data { * @node: hlist node for the console list * * @atomic_state: State array for non-BKL consoles. Real and handover + * @atomic_seq: Sequence for record tracking (32bit only) * @pcpu_data: Pointer to percpu context data * @ctxt_data: Builtin context data for early boot and threaded printing */ @@ -353,8 +358,10 @@ struct console { struct hlist_node node; =20 /* NOBKL console specific members */ - atomic_long_t __private atomic_state[2]; - + atomic_long_t __private atomic_state[2]; +#ifndef CONFIG_64BIT + atomic_t __private atomic_seq; +#endif struct cons_context_data __percpu *pcpu_data; struct cons_context_data ctxt_data; }; --- a/kernel/printk/printk_nobkl.c +++ b/kernel/printk/printk_nobkl.c @@ -51,6 +51,8 @@ =20 #ifdef CONFIG_PRINTK =20 +static bool cons_release(struct cons_context *ctxt); + #define copy_full_state(_dst, _src) do { _dst =3D _src; } while(0) #define copy_bit_state(_dst, _src) do { _dst.bits =3D _src.bits; } while(0) =20 @@ -244,6 +246,205 @@ static void cons_context_set_text_buf(st } =20 /** + * cons_forward_sequence - Helper function forward the sequence + * @con: Console to work on + * + * Forward @con->atomic_seq to the oldest available record. For init + * only. Do not use for runtime updates. + */ +static void cons_forward_sequence(struct console *con) +{ + u32 seq =3D (u32)prb_first_valid_seq(prb); +#ifdef CONFIG_64BIT + struct cons_state state; + + cons_state_read(con, STATE_REAL, &state); + state.seq =3D seq; + cons_state_set(con, STATE_REAL, &state); +#else + atomic_set(&ACCESS_PRIVATE(con, atomic_seq), seq); +#endif +} + +/** + * cons_context_sequence_init - Retrieve the last printed sequence number + * @ctxt: Pointer to an aquire context which contains + * all information about the acquire mode + * + * On return the retrieved sequence number is stored in ctxt->oldseq. + * + * The sequence number is safe in forceful takeover situations. + * + * Either the writer succeded to update before it got interrupted + * or it failed. In the latter case the takeover will print the + * same line again. + * + * The sequence is only the lower 32bits of the ringbuffer sequence. The + * ringbuffer must be 2^31 records ahead to get out of sync. This needs + * some care when starting a console, i.e setting the sequence to 0 is + * wrong. It has to be set to the oldest valid sequence in the ringbuffer + * as that cannot be more than 2^31 records away + * + * On 64bit the 32bit sequence is part of console::state which is saved + * in @ctxt->state. This prevents the 32bit update race. + */ +static void cons_context_sequence_init(struct cons_context *ctxt) +{ + u64 rbseq; + +#ifdef CONFIG_64BIT + ctxt->oldseq =3D ctxt->state.seq; +#else + ctxt->oldseq =3D atomic_read(&ACCESS_PRIVATE(ctxt->console, atomic_seq)); +#endif + + /* + * The sequence is only the lower 32bits of the ringbuffer + * sequence. So it needs to be expanded to 64bit. Get the next + * sequence number from the ringbuffer and fold it. + */ + rbseq =3D prb_next_seq(prb); + ctxt->oldseq =3D rbseq - ((u32)rbseq - (u32)ctxt->oldseq); + ctxt->newseq =3D ctxt->oldseq; +} + +/** + * cons_sequence_try_update - Try to update the sequence number + * @ctxt: Pointer to an aquire context which contains + * all information about the acquire mode + * + * Returns: True on success + * False on fail. + * + * Internal helper as the logic is different on 32bit and 64bit. + * + * On 32 bit the sequence is seperate from state and therefore + * subject to a subtle race in the case of hostile takeovers. + * + * On 64 bit the sequence is part of the state and therefore safe + * vs. hostile takeovers. + * + * In case of fail the console has been taken over and @ctxt is + * invalid. Caller has to reacquire the console. + */ +#ifdef CONFIG_64BIT +static bool __maybe_unused cons_sequence_try_update(struct cons_context *c= txt) +{ + struct console *con =3D ctxt->console; + struct cons_state old, new; + + cons_state_read(con, STATE_REAL, &old); + do { + /* Full state compare including sequence */ + if (!cons_state_full_match(old, ctxt->state)) + return false; + + /* Preserve bit state */ + copy_bit_state(new, old); + new.seq =3D ctxt->newseq; + + /* + * Can race with hostile takeover or with a handover + * request. + */ + } while (!cons_state_try_cmpxchg(con, STATE_REAL, &old, &new)); + + copy_full_state(ctxt->state, new); + ctxt->oldseq =3D ctxt->newseq; + + return true; +} +#else +static bool __maybe_unused cons_sequence_try_update(struct cons_context *c= txt) +{ + struct console *con =3D ctxt->console; + unsigned long old, new, cur; + struct cons_state state; + int pcpu; + + /* + * There is a corner case which needs to be considered here: + * + * CPU0 CPU1 + * printk() + * acquire() -> emergency + * write() acquire() + * update_seq() + * state =3D=3D OK + * --> NMI + * takeover() + * <--- write() + * cmpxchg() succeeds update_seq() + * cmpxchg() fails + * + * There is nothing which can be done about this other than having + * yet another state bit which needs to be tracked and analyzed, + * but fails to cover the problem completely. + * + * No other scenarios expose such a problem. On same CPU takeovers + * the cmpxchg() always fails on the interrupted context after the + * interrupting context finished printing, but that's fine as it + * does not own the console anymore. The state check after the + * failed cmpxchg prevents that. + */ + cons_state_read(con, STATE_REAL, &state); + /* Sequence is not part of cons_state on 32bit */ + if (!cons_state_bits_match(state, ctxt->state)) + return false; + + /* + * Get the original sequence number which was retrieved + * from @con->atomic_seq. @con->atomic_seq should be still + * the same. 32bit truncates. See cons_context_set_sequence(). + */ + old =3D (unsigned long)ctxt->oldseq; + new =3D (unsigned long)ctxt->newseq; + cur =3D atomic_cmpxchg(&ACCESS_PRIVATE(con, atomic_seq), old, new); + if (cur =3D=3D old) { + ctxt->oldseq =3D ctxt->newseq; + return true; + } + + /* + * Reread the state. If the state does not own the console anymore + * then it cannot touch the sequence again. + */ + cons_state_read(con, STATE_REAL, &state); + /* Sequence is not part of cons_state on 32bit */ + if (!cons_state_bits_match(state, ctxt->state)) + return false; + + /* If panic and not on the panic CPU, drop the lock */ + pcpu =3D atomic_read(&panic_cpu); + if (pcpu !=3D PANIC_CPU_INVALID && pcpu !=3D smp_processor_id()) + goto unlock; + + if (pcpu =3D=3D smp_processor_id()) { + /* + * This is the panic CPU. Emitting a warning here does not + * help at all. The callchain is clear and the priority is + * to get the messages out. In the worst case duplicated + * ones. That's a job for postprocessing. + */ + atomic_set(&ACCESS_PRIVATE(con, atomic_seq), new); + ctxt->oldseq =3D ctxt->newseq; + return true; + } + + /* + * Only emit a warning when this happens outside of a panic + * situation as on panic it's neither useful nor helping to let the + * panic CPU get the important stuff out. + */ + WARN_ON_ONCE(pcpu =3D=3D PANIC_CPU_INVALID); + +unlock: + cons_release(ctxt); + return false; +} +#endif + +/** * cons_cleanup_handover - Cleanup a handover request * @ctxt: Pointer to acquire context * @@ -519,6 +720,7 @@ static bool __cons_try_acquire(struct co return false; success: /* Common updates on success */ + cons_context_sequence_init(ctxt); cons_context_set_text_buf(ctxt); return true; =20 @@ -529,7 +731,6 @@ static bool __cons_try_acquire(struct co if (!cons_state_try_cmpxchg(con, STATE_REAL, &old, &new)) goto again; =20 - ctxt->hostile =3D true; copy_full_state(ctxt->state, new); goto success; } @@ -688,6 +889,7 @@ static void cons_nobkl_init(struct conso }; =20 cons_alloc_percpu_data(con); + cons_forward_sequence(con); cons_state_set(con, STATE_REAL, &state); } From nobody Mon Apr 6 03:09:13 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 9D7A7C6FA82 for ; Sat, 10 Sep 2022 22:30:12 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230288AbiIJWaH (ORCPT ); Sat, 10 Sep 2022 18:30:07 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:46758 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230415AbiIJW2m (ORCPT ); Sat, 10 Sep 2022 18:28:42 -0400 Received: from galois.linutronix.de (Galois.linutronix.de [193.142.43.55]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 9D8EE4506B for ; Sat, 10 Sep 2022 15:28:10 -0700 (PDT) Message-ID: <20220910222301.710939648@linutronix.de> DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020; t=1662848888; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: references:references; bh=NoR5hNciBAMmxWbbiSpzU3uPg8Vew2ti+A3f4lzSUQ0=; b=yNNXbj8a/j3A9TY1ZHo2z5SgqvWreIKreHIaMzHIe2PvsxuYEFagUD3rNVp/9RfqUskxex a3ud3ZiZnKpHt0Zaos5RRB9nPHCemBvchJ6ATLPYUIcZvDAtGfi3cCiIu5RKtOdYHee8U0 LFnJ+LNXeQ/7/K9LR9impGjmX6pQ53XHkiUqDPuSasAr22g/ADp8YwgtAGzlZ6/YDyMNyG aKxhst2iWR9OaFic4M1YZTWBzt8qHNe5PM5sb/4RWieBLn61BOTa6OnkV5EMSXDHKNq/5k fkYGaFSK6ECCdToUK6NY8aTLS+Z5f2nrMHtL/BCIDihy94a5f9yZmMfwTZOuRA== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020e; t=1662848888; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: references:references; bh=NoR5hNciBAMmxWbbiSpzU3uPg8Vew2ti+A3f4lzSUQ0=; b=DlTb6LDsL6x3MKInZGhzoseEIEsULkMOi1PDfI8o49hVdTECfkOsJ7EGgj23aBoF+ZyO+6 5QctIlp+4Da7xyBw== From: Thomas Gleixner To: LKML Cc: John Ogness , Petr Mladek , Sergey Senozhatsky , Steven Rostedt , Linus Torvalds , Peter Zijlstra , "Paul E. McKenney" , Daniel Vetter , Greg Kroah-Hartman , Helge Deller , Jason Wessel , Daniel Thompson , John Ogness Subject: [patch RFC 23/29] printk: Add non-BKL console print state functions References: <20220910221947.171557773@linutronix.de> MIME-Version: 1.0 Date: Sun, 11 Sep 2022 00:28:07 +0200 (CEST) Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Provide three functions which are related to the safe handover mechanism and allow console drivers to denote takeover unsafe sections: - console_can_proceed() Invoked by a console driver to check whether a handover request is pendi= ng or whether the console was taken over in a hostile fashion. - console_enter/exit_unsafe() Invoked by a console driver to reflect that the driver output function is about to enter or to leave an critical region where a hostile take over is unsafe. These functions are also cancelation points. The unsafe state is reflected in the console state and allows a takeover attempt to make informed decisions whether to take over and/or output on such console at all. The unsafe state is also reflected on output to the driver in the write context to the atomic_write() output function so the driver can make informed decisions about the required actions or take an special emergency path. Co-Developed-by: John Ogness Signed-off-by: John Ogness Signed-off-by: Thomas Gleixner --- include/linux/console.h | 20 ++++++ kernel/printk/printk_nobkl.c | 134 ++++++++++++++++++++++++++++++++++++++= +++++ 2 files changed, 154 insertions(+) --- a/include/linux/console.h +++ b/include/linux/console.h @@ -300,6 +300,22 @@ struct cons_context { unsigned int spinwait : 1; }; =20 +/** + * struct cons_write_context - Context handed to the write callbacks + * @ctxt: The core console context + * @outbuf: Pointer to the text buffer for output + * @len: Length to write + * @pos: Current write position in @outbuf + * @unsafe: Invoked in unsafe state due to force takeover + */ +struct cons_write_context { + struct cons_context __private ctxt; + char *outbuf; + unsigned int len; + unsigned int pos; + bool unsafe; +}; + #define CONS_MAX_NEST_LVL 8 =20 /** @@ -423,6 +439,10 @@ extern void console_list_unlock(void) __ #define for_each_console_kgdb(con) \ hlist_for_each_entry(con, &console_list, node) =20 +extern bool console_can_proceed(struct cons_write_context *wctxt); +extern bool console_enter_unsafe(struct cons_write_context *wctxt); +extern bool console_exit_unsafe(struct cons_write_context *wctxt); + extern int console_set_on_cmdline; extern struct console *early_console; =20 --- a/kernel/printk/printk_nobkl.c +++ b/kernel/printk/printk_nobkl.c @@ -874,6 +874,140 @@ static void cons_free_percpu_data(struct } =20 /** + * console_can_proceed - Check whether printing can proceed + * @wctxt: The write context which was handed to the write function + * + * Returns: True if the state is correct. False if a handover + * has been requested or if the console was taken + * over. + * + * Must be invoked after the record was dumped into the assigned record + * buffer and at appropriate safe places in the driver. For unsafe driver + * sections see console_enter_unsafe(). + * + * When this function returns false then the calling context is not allowed + * to go forward and has to back out immediately and carefully. The buffer + * content is not longer trusted either and the console lock is not longer + * held. + */ +bool console_can_proceed(struct cons_write_context *wctxt) +{ + struct cons_context *ctxt =3D &ACCESS_PRIVATE(wctxt, ctxt); + struct console *con =3D ctxt->console; + struct cons_state state; + + cons_state_read(con, STATE_REAL, &state); + /* Store it for analyis or reuse */ + copy_full_state(ctxt->old_state, state); + + /* + * If the state aside of req_prio is not longer matching, console + * was taken over. + */ + if (!cons_state_full_match(state, ctxt->state)) + return false; + + /* + * Having a safe point for take over and eventually a few + * duplicated characters or a full line is way better than a + * hostile takeover. Post processing can take care of the garbage. + * Continue if the requested priority is not sufficient. + */ + if (state.req_prio <=3D state.cur_prio) + return true; + + /* Release and hand over */ + cons_release(ctxt); + /* + * This does not check whether the handover succeeded. The + * outermost callsite has to do the final check whether printing + * should continue or not. The console is unlocked already so go + * back all the way instead of trying to implement heuristics in + * tons of places. + */ + return false; +} + +/** + * __console_update_unsafe - Update the unsafe bit in @con->atomic_state + * @wctxt: The write context which was handed to the write function + * + * Returns: True if the state is correct. False if a handover + * has been requested or if the console was taken + * over. + * + * Must be invoked before a unsafe driver section is entered. + * + * When this function returns false then the calling context is not allowed + * to go forward and has to back out immediately and carefully. The buffer + * content is not longer trusted either and the console lock is not longer + * held. + * + * Internal helper to avoid duplicated code + */ +static bool __console_update_unsafe(struct cons_write_context *wctxt, bool= unsafe) +{ + struct cons_context *ctxt =3D &ACCESS_PRIVATE(wctxt, ctxt); + struct console *con =3D ctxt->console; + struct cons_state new; + + do { + if (!console_can_proceed(wctxt)) + return false; + /* + * console_can_proceed() saved the real state in + * ctxt->old_state + */ + copy_full_state(new, ctxt->old_state); + new.unsafe =3D unsafe; + + } while (!cons_state_try_cmpxchg(con, STATE_REAL, &ctxt->old_state, &new)= ); + + copy_full_state(ctxt->state, new); + return true; +} + +/** + * console_enter_unsafe - Enter an unsafe region in the driver + * @wctxt: The write context which was handed to the write function + * + * Returns: True if the state is correct. False if a handover + * has been requested or if the console was taken + * over. + * + * Must be invoked before a unsafe driver section is entered. + * + * When this function returns false then the calling context is not allowed + * to go forward and has to back out immediately and carefully. The buffer + * content is not longer trusted either and the console lock is not longer + * held. + */ +bool console_enter_unsafe(struct cons_write_context *wctxt) +{ + return __console_update_unsafe(wctxt, true); +} + +/** + * console_exit_unsafe - Exit an unsafe region in the driver + * @wctxt: The write context which was handed to the write function + * + * Returns: True if the state is correct. False if a handover + * has been requested or if the console was taken + * over. + * + * Must be invoked before a unsafe driver section is exited. + * + * When this function returns false then the calling context is not allowed + * to go forward and has to back out immediately and carefully. The buffer + * content is not longer trusted either and the console lock is not longer + * held. + */ +bool console_exit_unsafe(struct cons_write_context *wctxt) +{ + return __console_update_unsafe(wctxt, false); +} + +/** * cons_nobkl_init - Initialize the NOBKL console state * @con: Console to initialize */ From nobody Mon Apr 6 03:09:13 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id B88A8ECAAD3 for ; Sat, 10 Sep 2022 22:29:58 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230256AbiIJW3z (ORCPT ); Sat, 10 Sep 2022 18:29:55 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:46274 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230140AbiIJW2l (ORCPT ); Sat, 10 Sep 2022 18:28:41 -0400 Received: from galois.linutronix.de (Galois.linutronix.de [193.142.43.55]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id A1B3245073 for ; Sat, 10 Sep 2022 15:28:11 -0700 (PDT) Message-ID: <20220910222301.768132577@linutronix.de> DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020; t=1662848889; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: references:references; bh=JqcsLWC6gxaWGeg5CMWoSHMARcCM/7NtJ9JVFHbkB74=; b=P/dWLzqGeqQY8S/RnzXbC64UH3URSghq7Y3ZVCkGkIhqwzTzwlbwkt0JeqazXgDZY0rjX8 31Gp6Z08fdIK08gkRvoIi4ETjETtkV6z0C0NmKkMHogpMeJy2vYxGoRH/KWs3wHpbq7a1Y S0GZMVJrPYc5vUEmcuwp6HmizXwx1pW8GHol6JGwagjAhF7fKgWMNXz9Xnm9UN9o8HfLJa LNUdr6nGGhIFAB9uPuLS1H+3Fb0WCUEGNrjC0H/ii4ia6MREYdRuQf3O1o6XAPlGpx86s5 uFui+Be2sWuoM+2Et5FSBRY8FikYmu8SbPejkvnO1u1rSAdBQF1a01Q/79rGww== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020e; t=1662848889; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: references:references; bh=JqcsLWC6gxaWGeg5CMWoSHMARcCM/7NtJ9JVFHbkB74=; b=YHdw8QBVrwHqZWy1VBRJddoteQPTLQPLoE6jmf31gvgUazLp6T4f+B103nzG08ihPvh3Qw KbcfTZ52sA2hlwDA== From: Thomas Gleixner To: LKML Cc: John Ogness , Petr Mladek , Sergey Senozhatsky , Steven Rostedt , Linus Torvalds , Peter Zijlstra , "Paul E. McKenney" , Daniel Vetter , Greg Kroah-Hartman , Helge Deller , Jason Wessel , Daniel Thompson , John Ogness Subject: [patch RFC 24/29] printk: Put seq and dropped into cons_text_desc References: <20220910221947.171557773@linutronix.de> MIME-Version: 1.0 Date: Sun, 11 Sep 2022 00:28:09 +0200 (CEST) Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Non-BKL consoles have atomic sequence tracking which is not compatible with the legacy consoles. Put sequence and dropped message count into struct cons_text_desc, let cons_fill_outbuf() operate on the seq/dropped fields and let the call sites handle the update to the corresponding fields in struct console. This allows sharing cons_fill_outbuf() between the two worlds. For the legacy consoles this is not more or less racy than the existing code. Co-Developed-by: John Ogness Signed-off-by: John Ogness Signed-off-by: Thomas Gleixner --- include/linux/console.h | 2 ++ kernel/printk/printk.c | 25 ++++++++++++++----------- 2 files changed, 16 insertions(+), 11 deletions(-) --- a/include/linux/console.h +++ b/include/linux/console.h @@ -232,6 +232,7 @@ struct cons_text_buf { * @txtbuf: Pointer to buffer for storing the text * @outbuf: Pointer to the position in @buffer for * writing it out to the device + * @seq: The sequence requested * @dropped: The dropped count * @len: Message length * @extmsg: Select extended format printing @@ -239,6 +240,7 @@ struct cons_text_buf { struct cons_outbuf_desc { struct cons_text_buf *txtbuf; char *outbuf; + u64 seq; unsigned long dropped; unsigned int len; bool extmsg; --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -2740,7 +2740,7 @@ static void cons_print_dropped(struct co * If it is NULL then records have been dropped or skipped and con->seq * has been forwarded so the caller can try to print the next record. */ -static bool cons_fill_outbuf(struct console *con, struct cons_outbuf_desc = *desc) +static bool cons_fill_outbuf(struct cons_outbuf_desc *desc) { static int panic_console_dropped; =20 @@ -2755,12 +2755,12 @@ static bool cons_fill_outbuf(struct cons =20 prb_rec_init_rd(&r, &info, txtbuf->text, CONSOLE_LOG_MAX); =20 - if (!prb_read_valid(prb, con->seq, &r)) + if (!prb_read_valid(prb, desc->seq, &r)) return false; =20 - if (con->seq !=3D r.info->seq) { - con->dropped +=3D r.info->seq - con->seq; - con->seq =3D r.info->seq; + if (desc->seq !=3D r.info->seq) { + desc->dropped +=3D r.info->seq - desc->seq; + desc->seq =3D r.info->seq; if (panic_in_progress() && panic_console_dropped++ > 10) { suppress_panic_printk =3D 1; pr_warn_once("Too many dropped messages. Suppress messages on non-panic= CPUs to prevent livelock.\n"); @@ -2769,7 +2769,7 @@ static bool cons_fill_outbuf(struct cons =20 /* Skip record that has level above the console loglevel. */ if (suppress_message_printing(r.info->level)) { - con->seq++; + desc->seq++; return true; } =20 @@ -2789,9 +2789,7 @@ static bool cons_fill_outbuf(struct cons =20 desc->len =3D len; desc->outbuf =3D txtbuf->text; - desc->dropped =3D con->dropped; cons_print_dropped(desc); - con->dropped =3D desc->dropped; } =20 return true; @@ -2820,16 +2818,21 @@ static bool console_emit_next_record(str bool *handover, bool extmsg) { struct cons_outbuf_desc desc =3D { - .txtbuf =3D txtbuf, - .extmsg =3D extmsg, + .txtbuf =3D txtbuf, + .extmsg =3D extmsg, + .seq =3D con->seq, + .dropped =3D con->dropped, }; unsigned long flags; =20 *handover =3D false; =20 - if (!cons_fill_outbuf(con, &desc)) + if (!cons_fill_outbuf(&desc)) return false; =20 + con->seq =3D desc.seq; + con->dropped =3D desc.dropped; + if (!desc.outbuf) goto skip; From nobody Mon Apr 6 03:09:13 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 8D13EC6FA82 for ; Sat, 10 Sep 2022 22:30:22 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229534AbiIJWaU (ORCPT ); Sat, 10 Sep 2022 18:30:20 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:47700 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230421AbiIJW2o (ORCPT ); Sat, 10 Sep 2022 18:28:44 -0400 Received: from galois.linutronix.de (Galois.linutronix.de [IPv6:2a0a:51c0:0:12e:550::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id BC6E3459A7 for ; Sat, 10 Sep 2022 15:28:13 -0700 (PDT) Message-ID: <20220910222301.824778546@linutronix.de> DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020; t=1662848891; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: references:references; bh=1nKppJo7BxmMJFXIfi8EoIqbK71Dxa8Haxjpt9z15Tk=; b=g5J80fbLvcjgxTYMH/kc3+rSHiZf9tIk3s1vdHkcLgJfjdFUugd9s6TV48/9SOtc9JpDkt JH9SnrWIBdUlbFCU8akBmSuSm+UVdI2Ilcj3RR6Quevp2Y0s+e5R64MlVFaliyhsySXYn3 UAOCpzcmYFLYcCZYZTI2nah7UYOqhi8j2t7JtKoa2ZGm59htiRxPx+eXccSdCY0TiViJLm TaFChIZ+cm5SKeb0vCA2yuOG1WQYx4uYVFbFAadgDMQKu3Wyz3vOm74/TSErGk0Xa0klF8 9SR5MwBtyqSJXVYrAgzTBsrD82FZoGKnXqQgAvVpL526/XnSOU45qrfcctQApg== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020e; t=1662848891; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: references:references; bh=1nKppJo7BxmMJFXIfi8EoIqbK71Dxa8Haxjpt9z15Tk=; b=MCwdSrA92NhXmAsBZe8KYswZIlVESP+CVhdL4sdzlA3yE2+ZjhM71Dlvjcj5X2Kxip1pqr Kwv8Zv3ZsX3pnhAg== From: Thomas Gleixner To: LKML Cc: John Ogness , Petr Mladek , Sergey Senozhatsky , Steven Rostedt , Linus Torvalds , Peter Zijlstra , "Paul E. McKenney" , Daniel Vetter , Greg Kroah-Hartman , Helge Deller , Jason Wessel , Daniel Thompson , John Ogness Subject: [patch RFC 25/29] printk: Provide functions to emit a ringbuffer record on non-BKL consoles References: <20220910221947.171557773@linutronix.de> MIME-Version: 1.0 Date: Sun, 11 Sep 2022 00:28:10 +0200 (CEST) Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Utilize the shared fill function and add the required safety points to check for handover/takeover and invoke the atomic write function of the console driver. Add the proper handling for updating the sequence number. Co-Developed-by: John Ogness Signed-off-by: John Ogness Signed-off-by: Thomas Gleixner --- include/linux/console.h | 7 ++ kernel/printk/printk_nobkl.c | 107 ++++++++++++++++++++++++++++++++++++++= ++++- 2 files changed, 112 insertions(+), 2 deletions(-) --- a/include/linux/console.h +++ b/include/linux/console.h @@ -281,10 +281,12 @@ struct console; * @newseq: The sequence number for progress * @prio: Priority of the context * @txtbuf: Pointer to the text buffer for this context + * @dropped: Dropped counter for the current context * @thread: The acquire is printk thread context * @hostile: Hostile takeover requested. Cleared on normal * acquire or friendly handover * @spinwait: Spinwait on acquire if possible + * @backlog: Ringbuffer has pending records */ struct cons_context { struct console *console; @@ -297,9 +299,11 @@ struct cons_context { unsigned int spinwait_max_us; enum cons_prio prio; struct cons_text_buf *txtbuf; + unsigned long dropped; unsigned int thread : 1; unsigned int hostile : 1; unsigned int spinwait : 1; + unsigned int backlog : 1; }; =20 /** @@ -380,6 +384,9 @@ struct console { #ifndef CONFIG_64BIT atomic_t __private atomic_seq; #endif + + bool (*write_atomic)(struct console *con, struct cons_write_context *wctx= t); + struct cons_context_data __percpu *pcpu_data; struct cons_context_data ctxt_data; }; --- a/kernel/printk/printk_nobkl.c +++ b/kernel/printk/printk_nobkl.c @@ -328,7 +328,7 @@ static void cons_context_sequence_init(s * invalid. Caller has to reacquire the console. */ #ifdef CONFIG_64BIT -static bool __maybe_unused cons_sequence_try_update(struct cons_context *c= txt) +static bool cons_sequence_try_update(struct cons_context *ctxt) { struct console *con =3D ctxt->console; struct cons_state old, new; @@ -354,7 +354,7 @@ static bool __maybe_unused cons_sequence return true; } #else -static bool __maybe_unused cons_sequence_try_update(struct cons_context *c= txt) +static bool cons_sequence_try_update(struct cons_context *ctxt) { struct console *con =3D ctxt->console; unsigned long old, new, cur; @@ -1006,6 +1006,109 @@ bool console_exit_unsafe(struct cons_wri return __console_update_unsafe(wctxt, false); } =20 +static bool cons_fill_outbuf(struct cons_outbuf_desc *desc); + +/** + * cons_get_record - Fill the buffer with the next pending ringbuffer reco= rd + * @wctxt: The write context which will be handed to the write function + * + * Returns: True if there are records to print. If the output buffer is + * filled @wctxt->outbuf points to the text, otherwise it is NULL. + * + * False signals that there are no pending records anymore and + * the printing can stop. + */ +static bool cons_get_record(struct cons_write_context *wctxt) +{ + struct cons_context *ctxt =3D &ACCESS_PRIVATE(wctxt, ctxt); + struct console *con =3D ctxt->console; + struct cons_outbuf_desc desc =3D { + .txtbuf =3D ctxt->txtbuf, + .extmsg =3D con->flags & CON_EXTENDED, + .seq =3D ctxt->newseq, + .dropped =3D ctxt->dropped, + }; + bool progress =3D cons_fill_outbuf(&desc); + + ctxt->newseq =3D desc.seq; + ctxt->dropped =3D desc.dropped; + + wctxt->pos =3D 0; + wctxt->len =3D desc.len; + wctxt->outbuf =3D desc.outbuf; + return progress; +} + +/** + * cons_emit_record - Emit record in the acquired context + * @wctxt: The write context which will be handed to the write function + * + * Returns: False if the operation was aborted (takeover) + * True otherwise + * + * In case of takeover the caller is not allowed to touch console state. + * The console is owned by someone else. If the caller wants to print + * more it has to reacquire the console first. + * + * If it returns true @wctxt->ctxt.backlog indicates whether there are + * still records pending in the ringbuffer, + */ +static int __maybe_unused cons_emit_record(struct cons_write_context *wctx= t) +{ + struct cons_context *ctxt =3D &ACCESS_PRIVATE(wctxt, ctxt); + struct console *con =3D ctxt->console; + bool done =3D false; + + /* + * @con->dropped is not protected in case of hostile takeovers so + * the update below is racy. Annotate it accordingly. + */ + ctxt->dropped =3D data_race(READ_ONCE(con->dropped)); + + /* Fill the output buffer with the next record */ + ctxt->backlog =3D cons_get_record(wctxt); + if (!ctxt->backlog) + return true; + + /* Safety point. Don't touch state in case of takeover */ + if (!console_can_proceed(wctxt)) + return false; + + /* Counterpart to the read above */ + WRITE_ONCE(con->dropped, ctxt->dropped); + + /* + * In case of skipped records, Update sequence state in @con. + */ + if (!wctxt->outbuf) + goto update; + + /* Tell the driver about potential unsafe state */ + wctxt->unsafe =3D ctxt->state.unsafe; + + if (!ctxt->thread && con->write_atomic) { + done =3D con->write_atomic(con, wctxt); + } else { + cons_release(ctxt); + WARN_ON_ONCE(1); + return false; + } + + /* If not done, the write was aborted due to takeover */ + if (!done) + return false; + + ctxt->newseq++; +update: + /* + * The sequence update attempt is not part of console_release() + * because in panic situations the console is not released by + * the panic CPU until all records are written. On 32bit the + * sequence is seperate from state anyway. + */ + return cons_sequence_try_update(ctxt); +} + /** * cons_nobkl_init - Initialize the NOBKL console state * @con: Console to initialize From nobody Mon Apr 6 03:09:13 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id D2B14ECAAD3 for ; Sat, 10 Sep 2022 22:30:40 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230032AbiIJWag (ORCPT ); Sat, 10 Sep 2022 18:30:36 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:46066 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230317AbiIJW3R (ORCPT ); Sat, 10 Sep 2022 18:29:17 -0400 Received: from galois.linutronix.de (Galois.linutronix.de [193.142.43.55]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id E5877459B3 for ; Sat, 10 Sep 2022 15:28:15 -0700 (PDT) Message-ID: <20220910222301.881787284@linutronix.de> DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020; t=1662848892; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: references:references; bh=ITvwnhbMRopkU0uxXaBKIS73OwMZbbp3Ns73njgnTns=; b=XQ6dwSdqrlUVAuW3dX/LuWdVHeZpXNuW3M3+eyEcQZdTBGwFiooRC8wSHLNwFpOv+L/ARH k58mDsb4ZRQsfEdfEA1L4xjPT0+WEClV3odQlhH7DxneySw58JPc4hjhIJfT45sFZ2F5gG +0KZHXokixbeDTskHf7UbF73+nTQY81EDmiqJqlzn2lUmEKHlDwy5GKahwxAL3qzZbugww 9TUaw6X6BXjKOyQODIa+M9XS5QqrJdwn14WjAprE/g5RLVLLTriqR4Ql7gzM5U6aZ0eoF4 rrLlX0dOjJNg+QviT12lCampD9AoI0OgSQnqAHdNyuZCY3qsQG1z6XRsu2hfdg== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020e; t=1662848892; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: references:references; bh=ITvwnhbMRopkU0uxXaBKIS73OwMZbbp3Ns73njgnTns=; b=v8KQzrfnlvNiRc91Fuxuq5tIQO3uH/GaInbYC1wywePeZeEix9WhTTbTfYFQL32ZzxigNg GUF9GXZn1tJrjADw== From: Thomas Gleixner To: LKML Cc: John Ogness , Petr Mladek , Sergey Senozhatsky , Steven Rostedt , Linus Torvalds , Peter Zijlstra , "Paul E. McKenney" , Daniel Vetter , Greg Kroah-Hartman , Helge Deller , Jason Wessel , Daniel Thompson , John Ogness Subject: [patch RFC 26/29] printk: Add threaded printing support References: <20220910221947.171557773@linutronix.de> MIME-Version: 1.0 Date: Sun, 11 Sep 2022 00:28:12 +0200 (CEST) Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: John Ogness Add the infrastructure to create a printer thread per console along with the required thread function which is takeover/handover aware. Signed-off-by: John Ogness Signed-off-by: Thomas Gleixner --- include/linux/console.h | 12 ++ kernel/printk/printk_nobkl.c | 207 ++++++++++++++++++++++++++++++++++++++= +++-- 2 files changed, 214 insertions(+), 5 deletions(-) --- a/include/linux/console.h +++ b/include/linux/console.h @@ -17,6 +17,7 @@ #include #include #include +#include #include =20 struct vc_data; @@ -357,6 +358,12 @@ struct cons_context_data { * * @atomic_state: State array for non-BKL consoles. Real and handover * @atomic_seq: Sequence for record tracking (32bit only) + * @kthread: Pointer to kernel thread + * @rcuwait: RCU wait for the kernel thread + * @kthread_running: Indicator whether the kthread is running + * @thread_txtbuf: Pointer to thread private buffer + * @write_atomic: Write callback for atomic context + * @write_thread: Write callback for threaded printing * @pcpu_data: Pointer to percpu context data * @ctxt_data: Builtin context data for early boot and threaded printing */ @@ -384,8 +391,13 @@ struct console { #ifndef CONFIG_64BIT atomic_t __private atomic_seq; #endif + struct task_struct *kthread; + struct rcuwait rcuwait; + atomic_t kthread_running; + struct cons_text_buf *thread_txtbuf; =20 bool (*write_atomic)(struct console *con, struct cons_write_context *wctx= t); + bool (*write_thread)(struct console *con, struct cons_write_context *wctx= t); =20 struct cons_context_data __percpu *pcpu_data; struct cons_context_data ctxt_data; --- a/kernel/printk/printk_nobkl.c +++ b/kernel/printk/printk_nobkl.c @@ -50,6 +50,8 @@ */ =20 #ifdef CONFIG_PRINTK +static bool printk_threads_enabled __ro_after_init; +static bool printk_force_atomic __initdata; =20 static bool cons_release(struct cons_context *ctxt); =20 @@ -238,8 +240,8 @@ static void cons_context_set_text_buf(st { struct console *con =3D ctxt->console; =20 - /* Early boot or allocation fail? */ - if (!con->pcpu_data) + /* Early boot, allocation fail or thread context? */ + if (!con->pcpu_data || ctxt->thread) ctxt->txtbuf =3D &con->ctxt_data.txtbuf; else ctxt->txtbuf =3D &(this_cpu_ptr(con->pcpu_data)->txtbuf); @@ -840,6 +842,8 @@ static bool __maybe_unused cons_release( { bool ret =3D __cons_release(ctxt); =20 + /* Invalidate the record pointer. It's not longer valid */ + ctxt->txtbuf =3D NULL; ctxt->state.atom =3D 0; return ret; } @@ -1022,10 +1026,9 @@ static bool cons_fill_outbuf(struct cons static bool cons_get_record(struct cons_write_context *wctxt) { struct cons_context *ctxt =3D &ACCESS_PRIVATE(wctxt, ctxt); - struct console *con =3D ctxt->console; struct cons_outbuf_desc desc =3D { .txtbuf =3D ctxt->txtbuf, - .extmsg =3D con->flags & CON_EXTENDED, + .extmsg =3D ctxt->console->flags & CON_EXTENDED, .seq =3D ctxt->newseq, .dropped =3D ctxt->dropped, }; @@ -1054,7 +1057,7 @@ static bool cons_get_record(struct cons_ * If it returns true @wctxt->ctxt.backlog indicates whether there are * still records pending in the ringbuffer, */ -static int __maybe_unused cons_emit_record(struct cons_write_context *wctx= t) +static bool cons_emit_record(struct cons_write_context *wctxt) { struct cons_context *ctxt =3D &ACCESS_PRIVATE(wctxt, ctxt); struct console *con =3D ctxt->console; @@ -1089,6 +1092,8 @@ static int __maybe_unused cons_emit_reco =20 if (!ctxt->thread && con->write_atomic) { done =3D con->write_atomic(con, wctxt); + } else if (ctxt->thread && con->write_thread) { + done =3D con->write_thread(con, wctxt); } else { cons_release(ctxt); WARN_ON_ONCE(1); @@ -1111,6 +1116,194 @@ static int __maybe_unused cons_emit_reco } =20 /** + * cons_kthread_should_run - Check whether the printk thread should run + * @con: Console to operate on + * @ctxt: The acquire context which contains the state + * at console_acquire() + */ +static bool cons_kthread_should_run(struct console *con, struct cons_conte= xt *ctxt) +{ + if (kthread_should_stop()) + return true; + + /* This reads state and sequence on 64bit. On 32bit only state */ + cons_state_read(con, STATE_REAL, &ctxt->state); + /* Bring the sequence in @ctxt up to date */ + cons_context_sequence_init(ctxt); + + if (!cons_state_ok(ctxt->state)) + return false; + + /* + * Atomic printing is running on some other CPU. The owner + * will wake the console thread on unlock if necessary. + */ + if (ctxt->state.locked) + return false; + + return prb_read_valid(prb, ctxt->oldseq, NULL); +} + +/** + * cons_kthread_func - The printk thread function + * @__console: Console to operate on + */ +static int cons_kthread_func(void *__console) +{ + struct console *con =3D __console; + struct cons_write_context wctxt =3D { + .ctxt.console =3D con, + .ctxt.prio =3D CONS_PRIO_NORMAL, + .ctxt.thread =3D 1, + }; + struct cons_context *ctxt =3D &ACCESS_PRIVATE(&wctxt, ctxt); + int ret; + + atomic_set(&con->kthread_running, 1); + + for (;;) { + atomic_dec(&con->kthread_running); + /* + * Provides a full memory barrier vs. cons_kthread_wake(). + */ + ret =3D rcuwait_wait_event(&con->rcuwait, cons_kthread_should_run(con, c= txt), + TASK_INTERRUPTIBLE); + + if (kthread_should_stop()) + break; + + atomic_inc(&con->kthread_running); + + /* Wait was interrupted by a spurious signal, go back to sleep */ + if (ret) + continue; + + for (;;) { + bool backlog; + + /* + * Ensure this stays on the CPU to make handover and + * takeover possible. + */ + migrate_disable(); + + /* + * Try to acquire the console without attempting to + * take over. If an atomic printer wants to hand + * back to the thread it simply wakes it up. + */ + if (!cons_try_acquire(ctxt)) + break; + + /* Stop when the console was handed/taken over */ + if (!cons_emit_record(&wctxt)) + break; + + backlog =3D ctxt->backlog; + + /* Stop when the console was handed/taken over */ + if (!cons_release(ctxt)) + break; + + /* Backlog done? */ + if (!backlog) + break; + + migrate_enable(); + cond_resched(); + } + migrate_enable(); + } + return 0; +} + +/** + * cons_kthread_wake - Wake up a printk thread + * @con: Console to operate on + */ +static inline void cons_kthread_wake(struct console *con) +{ + rcuwait_wake_up(&con->rcuwait); +} + +/** + * cons_kthread_stop - Stop a printk thread + * @con: Console to operate on + */ +static void cons_kthread_stop(struct console *con) +{ + struct task_struct *kt; + + lockdep_assert_held(&console_mutex); + + if (!con->kthread) + return; + + /* + * Nothing else than the thread itself can see @con->kthread + * anymore. @con is unhashed and all list walkers are synchronized. + */ + kt =3D con->kthread; + con->kthread =3D NULL; + kthread_stop(kt); + + kfree(con->thread_txtbuf); + con->thread_txtbuf =3D NULL; +} + +/** + * cons_kthread_create - Create a printk thread + * @con: Console to operate on + * + * If it fails, let the console proceed. The atomic part might + * be usable and useful. + */ +static void cons_kthread_create(struct console *con) +{ + struct task_struct *kt; + + lockdep_assert_held(&console_mutex); + + if (!(con->flags & CON_NO_BKL) || !con->write_thread) + return; + + if (!printk_threads_enabled || con->kthread) + return; + + con->thread_txtbuf =3D kmalloc(sizeof(*con->thread_txtbuf), GFP_KERNEL); + if (!con->thread_txtbuf) { + con_printk(KERN_ERR, con, "unable to allocate memory for printing thread= \n"); + return; + } + + kt =3D kthread_run(cons_kthread_func, con, "pr/%s%d", con->name, con->ind= ex); + if (IS_ERR(kt)) { + con_printk(KERN_ERR, con, "unable to start printing thread\n"); + kfree(con->thread_txtbuf); + con->thread_txtbuf =3D NULL; + return; + } + + con->kthread =3D kt; +} + +static int __init printk_setup_threads(void) +{ + struct console *con; + + if (printk_force_atomic) + return 0; + + console_list_lock(); + printk_threads_enabled =3D true; + for_each_registered_console(con) + cons_kthread_create(con); + console_list_unlock(); + return 0; +} +early_initcall(printk_setup_threads); + +/** * cons_nobkl_init - Initialize the NOBKL console state * @con: Console to initialize */ @@ -1123,7 +1316,10 @@ static void cons_nobkl_init(struct conso =20 cons_alloc_percpu_data(con); cons_forward_sequence(con); + rcuwait_init(&con->rcuwait); + cons_kthread_create(con); cons_state_set(con, STATE_REAL, &state); + cons_kthread_wake(con); } =20 /** @@ -1134,6 +1330,7 @@ static void cons_nobkl_cleanup(struct co { struct cons_state state =3D { }; =20 + cons_kthread_stop(con); cons_state_set(con, STATE_REAL, &state); cons_free_percpu_data(con); } From nobody Mon Apr 6 03:09:13 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 81CFCECAAD3 for ; Sat, 10 Sep 2022 22:30:31 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230484AbiIJWa3 (ORCPT ); Sat, 10 Sep 2022 18:30:29 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45966 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230470AbiIJW3G (ORCPT ); Sat, 10 Sep 2022 18:29:06 -0400 Received: from galois.linutronix.de (Galois.linutronix.de [193.142.43.55]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id AF1284362D for ; Sat, 10 Sep 2022 15:28:16 -0700 (PDT) Message-ID: <20220910222301.939249419@linutronix.de> DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020; t=1662848894; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: references:references; bh=1gLj17SVnYEqJIpQXxtTYqtNvfOkCPZwAPnJd+DRrik=; b=eEVBRaEBQWd/tHXCwHaKJwdtLXqBe1gkIMqlIfFXi/TOnbKB6kpVOYZmWDZvB/fhRTVwSm UqhqOwvxvakJv1KsCkZG5qUq35E8kPz5Htuo0dFY8AVvIATpufeqxac/KfAT3ay8v9udmC W6ulZcXKomKLQrQTnf2iWT44OAhbLoTC6tsYZKiGNyfcq7yEQJlFuWQ7ulbib6R2AYU/la O4LLXGimYc4qowbG9KDPpFJ0UuJQNqfIwRCGfzynW9jvAb8DvghDLRxkG98YDF0lQIf1y6 8ugoonVE6y6Fywz0SV5r+//r2Y1PiGpBHvygvgn9qhFzDeXcYtwBfQobuR9kjw== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020e; t=1662848894; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: references:references; bh=1gLj17SVnYEqJIpQXxtTYqtNvfOkCPZwAPnJd+DRrik=; b=npjxPp0NuVdubxR6QH6WlgL8ozDbJVxX7Sr4Lxr7gb1jAaYUjKSfONfYaDEwkstcLjN4t8 1v7MnWA0br5mUCAA== From: Thomas Gleixner To: LKML Cc: John Ogness , Petr Mladek , Sergey Senozhatsky , Steven Rostedt , Linus Torvalds , Peter Zijlstra , "Paul E. McKenney" , Daniel Vetter , Greg Kroah-Hartman , Helge Deller , Jason Wessel , Daniel Thompson , John Ogness Subject: [patch RFC 27/29] printk: Add write context storage for atomic writes References: <20220910221947.171557773@linutronix.de> MIME-Version: 1.0 Date: Sun, 11 Sep 2022 00:28:13 +0200 (CEST) Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: John Ogness The number of consoles is unknown at compile time and allocating write contexts on stack in emergency/panic situations is not desired either. Allocate a write context array (one for each priority level) along with the per CPU output buffers. Signed-off-by: John Ogness Signed-off-by: Thomas Gleixner --- include/linux/console.h | 7 +++++++ 1 file changed, 7 insertions(+) --- a/include/linux/console.h +++ b/include/linux/console.h @@ -253,6 +253,7 @@ struct cons_outbuf_desc { * @CONS_PRIO_NORMAL: Regular printk * @CONS_PRIO_EMERGENCY: Emergency output (WARN/OOPS...) * @CONS_PRIO_PANIC: Panic output + * @CONS_PRIO_MAX: The number of priority levels * * Emergency output can carefully takeover the console even without consent * of the owner, ideally only when @cons_state::unsafe is not set. Panic @@ -265,6 +266,7 @@ enum cons_prio { CONS_PRIO_NORMAL, CONS_PRIO_EMERGENCY, CONS_PRIO_PANIC, + CONS_PRIO_MAX, }; =20 struct console; @@ -327,12 +329,17 @@ struct cons_write_context { =20 /** * struct cons_context_data - console context data + * @wctxt: Write context per priority level * @txtbuf: Buffer for storing the text * * Used for early boot embedded into struct console and for * per CPU data. + * + * The write contexts are allocated to avoid having them on stack, e.g. in + * warn() or panic(). */ struct cons_context_data { + struct cons_write_context wctxt[CONS_PRIO_MAX]; struct cons_text_buf txtbuf; }; From nobody Mon Apr 6 03:09:13 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 5D068C6FA82 for ; Sat, 10 Sep 2022 22:30:51 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229905AbiIJWas (ORCPT ); Sat, 10 Sep 2022 18:30:48 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:46688 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230365AbiIJW3g (ORCPT ); Sat, 10 Sep 2022 18:29:36 -0400 Received: from galois.linutronix.de (Galois.linutronix.de [IPv6:2a0a:51c0:0:12e:550::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 7E6594362F for ; Sat, 10 Sep 2022 15:28:18 -0700 (PDT) Message-ID: <20220910222301.995758602@linutronix.de> DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020; t=1662848896; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: references:references; bh=VZUWuBMYzpylNgKty5AYXdXV5NIO5g3BN7mnRpIJyQI=; b=miw4BK4yfyLsSznSNCFH+QPZZMkQf8sjXxAwQ94j2ePBjarXEkM1RQThIWzU5MSy8/6zUc Lk9YlEBAv1GPsVH3BKu1lpl6WvOvzYCGbfh5e+krS63cSdRZjkC/GxoDaaCBNcPC4xIYkL 9DXq+h+GdrJxDH7nH66hUPfJbRfKPWrHvM78bjgLWT3TTAvfJxpl82cYzBq0OGqUHuF27F QBJ3iNP70MbXaqz4cLtjcC+jsaGAve3QbaIT9G+ef5kwOOHK96TDeJRHgeWxJ+do+YSACJ UdNjn5J9rdWoHQUSS2kBKP58jn1nlVZyMZaW4lmgI2FETKlCvEDz4XBZwrmY1w== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020e; t=1662848896; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: references:references; bh=VZUWuBMYzpylNgKty5AYXdXV5NIO5g3BN7mnRpIJyQI=; b=xk8vHRV0cwsYr2A7RNo8WDo0uuPCKYJ/VlyOBa7ShHBh9M3st77fC2XOs2XgqUbud2I33p xNZHXkM52nwFHXCQ== From: Thomas Gleixner To: LKML Cc: John Ogness , Petr Mladek , Sergey Senozhatsky , Steven Rostedt , Linus Torvalds , Peter Zijlstra , "Paul E. McKenney" , Daniel Vetter , Greg Kroah-Hartman , Helge Deller , Jason Wessel , Daniel Thompson , John Ogness Subject: [patch RFC 28/29] printk: Provide functions for atomic write enforcement References: <20220910221947.171557773@linutronix.de> MIME-Version: 1.0 Date: Sun, 11 Sep 2022 00:28:15 +0200 (CEST) Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: John Ogness Threaded printk is the preferred mechanism to tame the noisyness of printk, but WARN/OOPS/PANIC require to print out immediately as the printer threads might not be able to run. Add per CPU state which denotes the priority/urgency of the output and provide functions which flush the printk backlog during early boot and in priority elevated contexts. Signed-off-by: John Ogness Signed-off-by: Thomas Gleixner --- include/linux/console.h | 6 + kernel/printk/printk.c | 26 +++-- kernel/printk/printk_nobkl.c | 217 ++++++++++++++++++++++++++++++++++++++= +++++ 3 files changed, 240 insertions(+), 9 deletions(-) --- a/include/linux/console.h +++ b/include/linux/console.h @@ -16,6 +16,7 @@ =20 #include #include +#include #include #include #include @@ -367,6 +368,7 @@ struct cons_context_data { * @atomic_seq: Sequence for record tracking (32bit only) * @kthread: Pointer to kernel thread * @rcuwait: RCU wait for the kernel thread + * @irq_work: IRQ work for thread wakeup * @kthread_running: Indicator whether the kthread is running * @thread_txtbuf: Pointer to thread private buffer * @write_atomic: Write callback for atomic context @@ -400,6 +402,7 @@ struct console { #endif struct task_struct *kthread; struct rcuwait rcuwait; + struct irq_work irq_work; atomic_t kthread_running; struct cons_text_buf *thread_txtbuf; =20 @@ -471,6 +474,9 @@ extern bool console_can_proceed(struct c extern bool console_enter_unsafe(struct cons_write_context *wctxt); extern bool console_exit_unsafe(struct cons_write_context *wctxt); =20 +extern enum cons_prio cons_atomic_enter(enum cons_prio prio); +extern void cons_atomic_exit(enum cons_prio prio, enum cons_prio prev_prio= ); + extern int console_set_on_cmdline; extern struct console *early_console; =20 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -1072,6 +1072,8 @@ static inline void log_buf_add_cpu(void) #endif /* CONFIG_SMP */ =20 static void cons_alloc_percpu_data(struct console *con); +static void cons_atomic_flush(void); +static void cons_wake_threads(void); =20 static void __init set_percpu_data_ready(void) { @@ -2270,17 +2272,21 @@ asmlinkage int vprintk_emit(int facility =20 printed_len =3D vprintk_store(facility, level, dev_info, fmt, args); =20 + /* + * The caller may be holding system-critical or + * timing-sensitive locks. Disable preemption during + * printing of all remaining records to all consoles so that + * this context can return as soon as possible. Hopefully + * another printk() caller will take over the printing. + */ + preempt_disable(); + + /* Flush the non-BKL consoles if required */ + cons_atomic_flush(); + /* If called from the scheduler, we can not call up(). */ if (!in_sched) { /* - * The caller may be holding system-critical or - * timing-sensitive locks. Disable preemption during - * printing of all remaining records to all consoles so that - * this context can return as soon as possible. Hopefully - * another printk() caller will take over the printing. - */ - preempt_disable(); - /* * Try to acquire and then immediately release the console * semaphore. The release will print out buffers. With the * spinning variant, this context tries to take over the @@ -2288,9 +2294,11 @@ asmlinkage int vprintk_emit(int facility */ if (console_trylock_spinning()) console_unlock(); - preempt_enable(); } =20 + preempt_enable(); + + cons_wake_threads(); wake_up_klogd(); return printed_len; } --- a/kernel/printk/printk_nobkl.c +++ b/kernel/printk/printk_nobkl.c @@ -1231,6 +1231,222 @@ static inline void cons_kthread_wake(str } =20 /** + * cons_irq_work - irq work to wake printk thread + * @irq_work: The irq work to operate on + */ +static void cons_irq_work(struct irq_work *irq_work) +{ + struct console *con =3D container_of(irq_work, struct console, irq_work); + + cons_kthread_wake(con); +} + +/** + * cons_wake_threads - Wake up printing threads + */ +static void cons_wake_threads(void) +{ + struct console *con; + int cookie; + + cookie =3D srcu_read_lock(&console_srcu); + for_each_console_srcu(con) { + if (con->kthread && !atomic_read(&con->kthread_running)) + irq_work_queue(&con->irq_work); + } + srcu_read_unlock(&console_srcu, cookie); +} + +/** + * struct cons_cpu_state - Per CPU printk context state + * @prio: The current context priority level + * @nesting: Per priority nest counter + */ +struct cons_cpu_state { + enum cons_prio prio; + int nesting[CONS_PRIO_MAX]; +}; + +static DEFINE_PER_CPU(struct cons_cpu_state, cons_pcpu_state); +static struct cons_cpu_state early_cons_pcpu_state __initdata; + +/** + * cons_get_cpu_state - Get the per CPU console state pointer + * + * Returns either a pointer to the per CPU state of the current CPU or to + * the init data state during early boot. + */ +static __ref struct cons_cpu_state *cons_get_cpu_state(void) +{ + if (!printk_percpu_data_ready()) + return &early_cons_pcpu_state; + else + return this_cpu_ptr(&cons_pcpu_state); +} + +/** + * cons_get_wctxt - Get the write context for atomic printing + * @con: Console to operate on + * @prio: Priority of the context + * + * Returns either the per CPU context or the builtin context for + * early boot. + */ +static struct cons_write_context *cons_get_wctxt(struct console *con, + enum cons_prio prio) +{ + if (!con->pcpu_data) + return &con->ctxt_data.wctxt[prio]; + + return &this_cpu_ptr(con->pcpu_data)->wctxt[prio]; +} + +/** + * cons_atomic_try_acquire - Try to acquire the console for atomic printing + * @con: The console to acquire + * @ctxt: The console context instance to work on + * @prio: The priority of the current context + */ +static bool cons_atomic_try_acquire(struct console *con, struct cons_conte= xt *ctxt, + enum cons_prio prio) +{ + memset(ctxt, 0, sizeof(*ctxt)); + ctxt->console =3D con; + ctxt->spinwait_max_us =3D 2000; + ctxt->prio =3D prio; + ctxt->spinwait =3D 1; + + /* Try to acquire it directly or via a friendly handover */ + if (cons_try_acquire(ctxt)) + return true; + + /* Investigate whether a hostile takeover is due */ + if (ctxt->old_state.cur_prio >=3D prio) + return false; + + ctxt->hostile =3D 1; + return cons_try_acquire(ctxt); +} + +/** + * cons_atomic_flush_one - Flush one console in atomic mode + * @con: The console to flush + * @prio: The priority of the current context + */ +static void cons_atomic_flush_one(struct console *con, enum cons_prio prio) +{ + struct cons_write_context *wctxt =3D cons_get_wctxt(con, prio); + struct cons_context *ctxt =3D &ACCESS_PRIVATE(wctxt, ctxt); + + if (!cons_atomic_try_acquire(con, ctxt, prio)) + return; + + do { + /* + * cons_emit_record() returns false when the console was + * handed over or taken over. In both cases the context is + * not longer valid. + */ + if (!cons_emit_record(wctxt)) + return; + } while (ctxt->backlog); + + cons_release(ctxt); +} + +/** + * cons_atomic_flush - Flush consoles in atomic mode if required + */ +static void cons_atomic_flush(void) +{ + struct cons_cpu_state *cpu_state; + struct console *con; + int cookie; + + cpu_state =3D cons_get_cpu_state(); + + /* + * Let the outermost write of this priority print. This avoids + * nasty hackery for nested WARN() where the printing itself + * generates one. + * + * cpu_state->prio <=3D CONS_PRIO_NORMAL is not subject to nesting + * and it can fall through for early boot and for consoles which do + * not have a kthread (yet). For simplicity sake just fall through. + */ + if (cpu_state->prio > CONS_PRIO_NORMAL && + cpu_state->nesting[cpu_state->prio] !=3D 1) + return; + + cookie =3D srcu_read_lock(&console_srcu); + for_each_console_srcu(con) { + if (!con->write_atomic) + continue; + + if (cpu_state->prio > CONS_PRIO_NORMAL || !con->kthread) + cons_atomic_flush_one(con, cpu_state->prio); + } + srcu_read_unlock(&console_srcu, cookie); +} + +/** + * cons_atomic_enter - Enter a context which enforces atomic printing + * @prio: Priority of the context + * + * Returns: The previous priority which needs to be fed into + * the corresponding cons_atomic_exit() + */ +enum cons_prio cons_atomic_enter(enum cons_prio prio) +{ + struct cons_cpu_state *cpu_state; + enum cons_prio prev_prio; + + migrate_disable(); + cpu_state =3D cons_get_cpu_state(); + + prev_prio =3D cpu_state->prio; + if (prev_prio < prio) + cpu_state->prio =3D prio; + + /* + * Increment the nesting on @cpu_state->prio so a WARN() + * nested into a panic printout does not attempt to + * scribble state. + */ + cpu_state->nesting[cpu_state->prio]++; + + return prev_prio; +} + +/** + * cons_atomic_exit - Exit a context which enforces atomic printing + * @prio: Priority of the context to leave + * @prev_prio: Priority of the previous context for restore + * + * @prev_prio is the priority returned by the corresponding cons_atomic_en= ter(). + */ +void cons_atomic_exit(enum cons_prio prio, enum cons_prio prev_prio) +{ + struct cons_cpu_state *cpu_state; + + cpu_state =3D cons_get_cpu_state(); + + /* + * Undo the nesting of cons_atomic_enter() at the CPU state + * priority. + */ + cpu_state->nesting[cpu_state->prio]--; + + /* + * Restore the previous priority which was returned by + * cons_atomic_enter(). + */ + cpu_state->prio =3D prev_prio; + + migrate_enable(); +} + +/** * cons_kthread_stop - Stop a printk thread * @con: Console to operate on */ @@ -1321,6 +1537,7 @@ static void cons_nobkl_init(struct conso cons_alloc_percpu_data(con); cons_forward_sequence(con); rcuwait_init(&con->rcuwait); + init_irq_work(&con->irq_work, cons_irq_work); cons_kthread_create(con); cons_state_set(con, STATE_REAL, &state); cons_kthread_wake(con); From nobody Mon Apr 6 03:09:13 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id AC155C6FA82 for ; Sat, 10 Sep 2022 22:30:59 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229787AbiIJWa6 (ORCPT ); Sat, 10 Sep 2022 18:30:58 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45978 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230385AbiIJW3k (ORCPT ); Sat, 10 Sep 2022 18:29:40 -0400 Received: from galois.linutronix.de (Galois.linutronix.de [193.142.43.55]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 5C61145F6B for ; Sat, 10 Sep 2022 15:28:19 -0700 (PDT) Message-ID: <20220910222302.052398226@linutronix.de> DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020; t=1662848897; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: references:references; bh=PfOqpESp8tLtZDC+o8o6mnQEU5nU5UN8jXbbOmj7yS4=; b=m6Abpy6h1kF4rVeB+tpgtOq5St2HvOoeyZmg3+oUoEtc765WcnPNdjjdDskblrqvvh5HNk KiRC42PRB7VaAGyui0U3PPmaJ2HA4GU41PDgVaIDtcov1VV3AfkKdlLog5LOMIinhHX0jQ QzXs+yLhpaAHDcVD7saCgOBVUKYcjwAgW9Jt3p/yX2MuRk2oM7hRX4+sDJsxzVP1Og4wFG LGm+QnND9C0++XeX14/sd8bJqLKt1FbOmKPMGoqBXo3ZpqRWoPrRf/FTmo4N1so5lSKl8E yvQQq1ppEUsHjPnfshWShiM/PP40N03NHcxpGJW/C3jDOtofdbkHIzVEvj+CfA== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020e; t=1662848897; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: references:references; bh=PfOqpESp8tLtZDC+o8o6mnQEU5nU5UN8jXbbOmj7yS4=; b=XSgI0HWlYJEj+zBs/+PztE9DWGK8iwwPJ6EA+zl/UFDLvCDcC9P9LSHOe29UE+vTNZxvAz 2L3mmKMAyxEIB+CA== From: Thomas Gleixner To: LKML Cc: John Ogness , Petr Mladek , Sergey Senozhatsky , Steven Rostedt , Linus Torvalds , Peter Zijlstra , "Paul E. McKenney" , Daniel Vetter , Greg Kroah-Hartman , Helge Deller , Jason Wessel , Daniel Thompson , John Ogness Subject: [patch RFC 29/29] printk: Add atomic write enforcement to warn/panic... References: <20220910221947.171557773@linutronix.de> MIME-Version: 1.0 Date: Sun, 11 Sep 2022 00:28:17 +0200 (CEST) Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Signed-off-by: John Ogness Invoke the atomic write enforcement functions for warn/panic to ensure that the information gets out to the consoles. This is not yet a final solution as this still unlocks consoles and depends on the "reliablity" of legacy consoles which are invoked during printk(). Once the legacy is converted over this can be changed to lock consoles on entry, print undisturbed and release them on exit. Signed-off-by: John Ogness Signed-off-by: Thomas Gleixner --- kernel/panic.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) --- a/kernel/panic.c +++ b/kernel/panic.c @@ -256,6 +256,12 @@ void panic(const char *fmt, ...) if (old_cpu !=3D PANIC_CPU_INVALID && old_cpu !=3D this_cpu) panic_smp_self_stop(); =20 + /* + * No point in saving the previous printk severity level + * here. Panic won't come back + */ + cons_atomic_enter(CONS_PRIO_PANIC); + console_verbose(); bust_spinlocks(1); va_start(args, fmt); @@ -602,6 +608,10 @@ struct warn_args { void __warn(const char *file, int line, void *caller, unsigned taint, struct pt_regs *regs, struct warn_args *args) { + enum cons_prio prev_prio; + + prev_prio =3D cons_atomic_enter(CONS_PRIO_EMERGENCY); + disable_trace_on_warning(); =20 if (file) @@ -633,6 +643,8 @@ void __warn(const char *file, int line, =20 /* Just a warning, don't kill lockdep. */ add_taint(taint, LOCKDEP_STILL_OK); + + cons_atomic_exit(CONS_PRIO_EMERGENCY, prev_prio); } =20 #ifndef __WARN_FLAGS