From nobody Thu Dec 18 19:05:48 2025 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 6EE79EEB560 for ; Fri, 8 Sep 2023 18:51:55 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S243399AbjIHSv5 (ORCPT ); Fri, 8 Sep 2023 14:51:57 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:57488 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S241747AbjIHSvz (ORCPT ); Fri, 8 Sep 2023 14:51:55 -0400 Received: from galois.linutronix.de (Galois.linutronix.de [IPv6:2a0a:51c0:0:12e:550::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 6F49B1BC1 for ; Fri, 8 Sep 2023 11:51:18 -0700 (PDT) From: John Ogness DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020; t=1694199011; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=cBog/17jG1mTArwU5kOIIQv+uQFxg8laxa+tevZYKXU=; b=RijY906TtiQUrkrUSSEkXYk3v0DEgFmGmwsJNiylvtABHHs6nzzmlZJTA0A8PnTreDksHJ HB8lzBQc2cA4ElCtz80bMCAbRUDaI6BsCqGeC6BYKau8nEaMIQNtweK6vQ1T+OfjKIIoe4 yv/IuiJ/kvhqLhcihqdknt1/2+4nDcqdHoZHhqsyfe+GeAj5/goWFNb0RHK2ujpZUQq053 DSqSqLRSnrn/LZlw3iCxCWKBciQZT53JwqMTpjwN0w5cOra25OlbkyzTkYsL5eqGp1Mb1s UtnLjX6hfohf+QSgkq7BoRzp9ib3rfg7yY3cwlkRRBpVJc3ZN07sGb32ps8yTg== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020e; t=1694199011; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=cBog/17jG1mTArwU5kOIIQv+uQFxg8laxa+tevZYKXU=; b=FP0ziImASuXGnDdmQ5oBsds9eXFeeq1dtsD+aOspXmpHxkvyBxj+fsBk+hNMPeAAzFPBXX BjXmEpKq7UrxNcAw== To: Petr Mladek Cc: Sergey Senozhatsky , Steven Rostedt , Thomas Gleixner , linux-kernel@vger.kernel.org, Greg Kroah-Hartman Subject: [PATCH printk v4 1/8] printk: Add non-BKL (nbcon) console basic infrastructure Date: Fri, 8 Sep 2023 20:56:01 +0206 Message-Id: <20230908185008.468566-2-john.ogness@linutronix.de> In-Reply-To: <20230908185008.468566-1-john.ogness@linutronix.de> References: <20230908185008.468566-1-john.ogness@linutronix.de> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" From: Thomas Gleixner The current console/printk subsystem is protected by a Big Kernel Lock, (aka console_lock) which 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 endeavour that is based on try and pray. The goal of non-BKL (nbcon) consoles is to break out of the console lock jail and to provide a new infrastructure that avoids the pitfalls and also allows console drivers to be gradually converted over. The proposed infrastructure aims for the following properties: - Per console locking instead of global locking - Per console state that allows to make informed decisions - Stateful handover and takeover As a first step, state is added to struct console. The per console state is an atomic_t using a 32bit bit field. Reserve state bits, which will be populated later in the series. Wire it up into the console register/unregister functionality. It was decided to use a bitfield because using a plain u32 with mask/shift operations resulted in uncomprehensible code. Co-developed-by: John Ogness Signed-off-by: John Ogness Signed-off-by: Thomas Gleixner (Intel) Reviewed-by: Petr Mladek --- include/linux/console.h | 31 ++++++++++++++++++ kernel/printk/Makefile | 2 +- kernel/printk/internal.h | 8 +++++ kernel/printk/nbcon.c | 70 ++++++++++++++++++++++++++++++++++++++++ kernel/printk/printk.c | 13 ++++++-- 5 files changed, 120 insertions(+), 4 deletions(-) create mode 100644 kernel/printk/nbcon.c diff --git a/include/linux/console.h b/include/linux/console.h index 7de11c763eb3..a2d37a7a98a8 100644 --- a/include/linux/console.h +++ b/include/linux/console.h @@ -156,6 +156,8 @@ static inline int con_debug_leave(void) * /dev/kmesg which requires a larger output buffer. * @CON_SUSPENDED: Indicates if a console is suspended. If true, the * printing callbacks must not be called. + * @CON_NBCON: Console can operate outside of the legacy style console_lo= ck + * constraints. */ enum cons_flags { CON_PRINTBUFFER =3D BIT(0), @@ -166,8 +168,32 @@ enum cons_flags { CON_BRL =3D BIT(5), CON_EXTENDED =3D BIT(6), CON_SUSPENDED =3D BIT(7), + CON_NBCON =3D BIT(8), }; =20 +/** + * struct nbcon_state - console state for nbcon consoles + * @atom: Compound of the state fields for atomic operations + * + * To be used for reading and preparing of the value stored in the nbcon + * state variable @console::nbcon_state. + */ +struct nbcon_state { + union { + unsigned int atom; + struct { + }; + }; +}; + +/* + * The nbcon_state struct is used to easily create and interpret values th= at + * are stored in the @console::nbcon_state variable. Ensure this struct st= ays + * within the size boundaries of the atomic variable's underlying type in + * order to avoid any accidental truncation. + */ +static_assert(sizeof(struct nbcon_state) <=3D sizeof(int)); + /** * struct console - The console descriptor structure * @name: The name of the console driver @@ -187,6 +213,8 @@ enum cons_flags { * @dropped: Number of unreported dropped ringbuffer records * @data: Driver private data * @node: hlist node for the console list + * + * @nbcon_state: State for nbcon consoles */ struct console { char name[16]; @@ -206,6 +234,9 @@ struct console { unsigned long dropped; void *data; struct hlist_node node; + + /* nbcon console specific members */ + atomic_t __private nbcon_state; }; =20 #ifdef CONFIG_LOCKDEP diff --git a/kernel/printk/Makefile b/kernel/printk/Makefile index f5b388e810b9..39a2b61c7232 100644 --- a/kernel/printk/Makefile +++ b/kernel/printk/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only obj-y =3D printk.o -obj-$(CONFIG_PRINTK) +=3D printk_safe.o +obj-$(CONFIG_PRINTK) +=3D printk_safe.o nbcon.o obj-$(CONFIG_A11Y_BRAILLE_CONSOLE) +=3D braille.o obj-$(CONFIG_PRINTK_INDEX) +=3D index.o =20 diff --git a/kernel/printk/internal.h b/kernel/printk/internal.h index 7d4979d5c3ce..2ca0ab78802c 100644 --- a/kernel/printk/internal.h +++ b/kernel/printk/internal.h @@ -3,6 +3,7 @@ * internal.h - printk internal definitions */ #include +#include =20 #if defined(CONFIG_PRINTK) && defined(CONFIG_SYSCTL) void __init printk_sysctl_init(void); @@ -61,6 +62,10 @@ void defer_console_output(void); =20 u16 printk_parse_prefix(const char *text, int *level, enum printk_info_flags *flags); + +void nbcon_init(struct console *con); +void nbcon_cleanup(struct console *con); + #else =20 #define PRINTK_PREFIX_MAX 0 @@ -76,6 +81,9 @@ u16 printk_parse_prefix(const char *text, int *level, #define printk_safe_exit_irqrestore(flags) local_irq_restore(flags) =20 static inline bool printk_percpu_data_ready(void) { return false; } +static inline void nbcon_init(struct console *con) { } +static inline void nbcon_cleanup(struct console *con) { } + #endif /* CONFIG_PRINTK */ =20 /** diff --git a/kernel/printk/nbcon.c b/kernel/printk/nbcon.c new file mode 100644 index 000000000000..10266d3e7883 --- /dev/null +++ b/kernel/printk/nbcon.c @@ -0,0 +1,70 @@ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (C) 2022 Linutronix GmbH, John Ogness +// Copyright (C) 2022 Intel, Thomas Gleixner + +#include +#include +#include "internal.h" +/* + * Printk console printing implementation for consoles that do not depend = on + * the legacy style console_lock mechanism. + */ + +/** + * nbcon_state_set - Helper function to set the console state + * @con: Console to update + * @new: The new state to write + * + * Only to be used when the console is not yet or no longer visible in the + * system. Otherwise use nbcon_state_try_cmpxchg(). + */ +static inline void nbcon_state_set(struct console *con, struct nbcon_state= *new) +{ + atomic_set(&ACCESS_PRIVATE(con, nbcon_state), new->atom); +} + +/** + * nbcon_state_read - Helper function to read the console state + * @con: Console to read + * @state: The state to store the result + */ +static inline void nbcon_state_read(struct console *con, struct nbcon_stat= e *state) +{ + state->atom =3D atomic_read(&ACCESS_PRIVATE(con, nbcon_state)); +} + +/** + * nbcon_state_try_cmpxchg() - Helper function for atomic_try_cmpxchg() on= console state + * @con: Console to update + * @cur: Old/expected state + * @new: New state + * + * Return: True on success. False on fail and @cur is updated. + */ +static inline bool nbcon_state_try_cmpxchg(struct console *con, struct nbc= on_state *cur, + struct nbcon_state *new) +{ + return atomic_try_cmpxchg(&ACCESS_PRIVATE(con, nbcon_state), &cur->atom, = new->atom); +} + +/** + * nbcon_init - Initialize the nbcon console specific data + * @con: Console to initialize + */ +void nbcon_init(struct console *con) +{ + struct nbcon_state state =3D { }; + + nbcon_state_set(con, &state); +} + +/** + * nbcon_cleanup - Cleanup the nbcon console specific data + * @con: Console to cleanup + */ +void nbcon_cleanup(struct console *con) +{ + struct nbcon_state state =3D { }; + + nbcon_state_set(con, &state); +} diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c index 8787d3a72114..c0246093ea41 100644 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -3324,9 +3324,10 @@ static void try_enable_default_console(struct consol= e *newcon) 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" : "", \ +#define con_printk(lvl, con, fmt, ...) \ + printk(lvl pr_fmt("%s%sconsole [%s%d] " fmt), \ + (con->flags & CON_NBCON) ? "" : "legacy ", \ + (con->flags & CON_BOOT) ? "boot" : "", \ con->name, con->index, ##__VA_ARGS__) =20 static void console_init_seq(struct console *newcon, bool bootcon_register= ed) @@ -3486,6 +3487,9 @@ void register_console(struct console *newcon) newcon->dropped =3D 0; console_init_seq(newcon, bootcon_registered); =20 + if (newcon->flags & CON_NBCON) + nbcon_init(newcon); + /* * Put this console in the list - keep the * preferred driver at the head of the list. @@ -3577,6 +3581,9 @@ static int unregister_console_locked(struct console *= console) */ synchronize_srcu(&console_srcu); =20 + if (console->flags & CON_NBCON) + nbcon_cleanup(console); + console_sysfs_notify(); =20 if (console->exit) --=20 2.39.2 From nobody Thu Dec 18 19:05:48 2025 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 63B71EEB560 for ; Fri, 8 Sep 2023 18:52:28 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235099AbjIHSwa (ORCPT ); Fri, 8 Sep 2023 14:52:30 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:51564 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232412AbjIHSw2 (ORCPT ); Fri, 8 Sep 2023 14:52:28 -0400 Received: from galois.linutronix.de (Galois.linutronix.de [193.142.43.55]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id E969A10DF for ; Fri, 8 Sep 2023 11:51:50 -0700 (PDT) From: John Ogness DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020; t=1694199011; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=TdUHXK7rHc3QLzmoCiD54LJLsZOtaL7RAJcGFdO6SFw=; b=Ht5tYfsaRbAhJ7aq1/mymaDWSDXdqnngiA2kmU/h3czwVts+VsCLdE4ryVQuiG7NxqVz0r NzCb1MyEewdTgUNQPtPhN2itgcyQ3qSPiQISctE16daojF+jaRgFa5xhDSp7Wm4cIm8fdx JTchfLw/2qkMn8hWA1O4yLan8E/MXI/R8nwSp4ONwKNOo/qzLLORv13+K8Xbz6ZxAp87Nv BIsimb0bTcsQ4uM7iOQwMgwZxvhpM2MYlkAkABHA9SUfwkDdkkF+RmrILoXQNnOKk7u7OE EYwB51fhH6NbyjisUAd4ck3fuV/RdO3biOcv/SArexECVzun68W5O9rxJkExzw== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020e; t=1694199011; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=TdUHXK7rHc3QLzmoCiD54LJLsZOtaL7RAJcGFdO6SFw=; b=/RzsUK5atHOhSTF/Fvq4J8t92BgGY4HMbDY9RJVj9hFsawJ/KWPZKkUFBJbZ6EJzI4RR4b TWg4gbsUaVRkK3DQ== To: Petr Mladek Cc: Sergey Senozhatsky , Steven Rostedt , Thomas Gleixner , linux-kernel@vger.kernel.org, Greg Kroah-Hartman Subject: [PATCH printk v4 2/8] printk: nbcon: Add acquire/release logic Date: Fri, 8 Sep 2023 20:56:02 +0206 Message-Id: <20230908185008.468566-3-john.ogness@linutronix.de> In-Reply-To: <20230908185008.468566-1-john.ogness@linutronix.de> References: <20230908185008.468566-1-john.ogness@linutronix.de> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" From: Thomas Gleixner Add per console acquire/release functionality. The console 'locked' state is a combination of multiple state fields: - The 'prio' field contains the priority of the context that 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. A value of 0 (NBCON_PRIO_NONE) means the console is not locked. - The 'cpu' field denotes on which CPU the console is locked. The acquire mechanism comes with several flavours: - Direct acquire when the console is not owned or is owned by a lower priority context and the console is in a safe state. - Friendly handover mechanism based on a request/grant handshake. The requesting context must have a higher priority than the current owner. The requesting context: 1) Sets its priority into the 'req_prio' field. 2) Waits (with a timeout) for the owning context to unlock the console. 3) Sets the 'prio' field and clears the 'req_prio' field. The owning context: 1) Observes the 'req_prio' field set. 2) Gives up console ownership by clearing the 'prio' field. - Unsafe hostile takeover The new owner takes the console over without 'req_prio' handshake. The new owner must have a higher priority than the previous owner. 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 that either releases the console directly or yields it gracefully over to a requester. All operations on @console::nbcon_state 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: - What is marked as an unsafe section. - Whether to spin-wait if there is already an owner and the console is in an unsafe state. - Whether to attempt an unsafe hostile takeover. 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 (Intel) --- include/linux/console.h | 59 ++++++ kernel/printk/nbcon.c | 432 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 491 insertions(+) diff --git a/include/linux/console.h b/include/linux/console.h index a2d37a7a98a8..eeebb82d6d07 100644 --- a/include/linux/console.h +++ b/include/linux/console.h @@ -175,13 +175,29 @@ enum cons_flags { * struct nbcon_state - console state for nbcon consoles * @atom: Compound of the state fields for atomic operations * + * @req_prio: The priority of a handover request + * @prio: The priority of the current owner + * @unsafe: Console is busy in a non takeover region + * @unsafe_takeover: A hostile takeover in an unsafe state happened in the + * past. The console cannot be safe until re-initialized. + * @cpu: The CPU on which the owner runs + * * To be used for reading and preparing of the value stored in the nbcon * state variable @console::nbcon_state. + * + * The @prio and @req_prio fields are particularly important to allow + * spin-waiting to timeout and give up without the risk of a waiter being + * assigned the lock after giving up. */ struct nbcon_state { union { unsigned int atom; struct { + unsigned int prio : 2; + unsigned int req_prio : 2; + unsigned int unsafe : 1; + unsigned int unsafe_takeover : 1; + unsigned int cpu : 24; }; }; }; @@ -194,6 +210,49 @@ struct nbcon_state { */ static_assert(sizeof(struct nbcon_state) <=3D sizeof(int)); =20 +/** + * nbcon_prio - console owner priority for nbcon consoles + * @NBCON_PRIO_NONE: Unused + * @NBCON_PRIO_NORMAL: Normal (non-emergency) usage + * @NBCON_PRIO_EMERGENCY: Emergency output (WARN/OOPS...) + * @NBCON_PRIO_PANIC: Panic output + * @NBCON_PRIO_MAX: The number of priority levels + * + * A context wanting to produce emergency output can carefully takeover the + * console, even without consent of the owner. Ideally such a takeover is = only + * when @nbcon_state::unsafe is not set. However, a context wanting to pro= duce + * panic output can ignore the unsafe flag as a last resort. If panic outp= ut + * is active, no takeover is possible until the panic output releases the + * console. + */ +enum nbcon_prio { + NBCON_PRIO_NONE =3D 0, + NBCON_PRIO_NORMAL, + NBCON_PRIO_EMERGENCY, + NBCON_PRIO_PANIC, + NBCON_PRIO_MAX, +}; + +struct console; + +/** + * struct nbcon_context - Context for console acquire/release + * @console: The associated console + * @spinwait_max_us: Limit for spin-wait acquire + * @prio: Priority of the context + * @allow_unsafe_takeover: Allow performing takeover even if unsafe. Can + * be used only with NBCON_PRIO_PANIC @prio. It + * might cause a system freeze when the console + * is used later. + */ +struct nbcon_context { + /* members set by caller */ + struct console *console; + unsigned int spinwait_max_us; + enum nbcon_prio prio; + unsigned int allow_unsafe_takeover : 1; +}; + /** * struct console - The console descriptor structure * @name: The name of the console driver diff --git a/kernel/printk/nbcon.c b/kernel/printk/nbcon.c index 10266d3e7883..57ddfb7f0994 100644 --- a/kernel/printk/nbcon.c +++ b/kernel/printk/nbcon.c @@ -4,10 +4,43 @@ =20 #include #include +#include #include "internal.h" /* * Printk console printing implementation for consoles that do not depend = on * the legacy style console_lock mechanism. + * + * Console is locked on a CPU when @nbcon_state::prio is set and + * @nbcon_state:cpu =3D=3D current CPU. This is valid for the current exec= ution + * context. + * + * Nesting execution contexts on the same CPU can carefully take over if + * the driver allows reentrancy via @nbcon_state::unsafe =3D false. When t= he + * interrupted context resumes it checks the state before entering an unsa= fe + * region and aborts the operation if it detects a takeover. + * + * In case of panic the nesting context can take over the console forceful= ly. + * + * A concurrent writer on a different CPU with a higher priority can direc= tly + * take over if the console is not in an unsafe state by carefully writing + * its priority into @nbcon_state::prio. + * + * If the console is in an unsafe state, the concurrent writer with a high= er + * priority can request to take over the console by: + * + * 1) Carefully writing the desired priority into @nbcon_state::req_prio + * if there is no higher priority request pending. + * + * 2) Carefully spin on @nbcon_state::prio until it is no longer locked. + * + * 3) Attempt to lock the console by carefully writing the desired + * priority to @nbcon_state::prio and carefully removing the desired + * priority from @nbcon_state::req_prio. + * + * In case the owner does not react on the request and does not make + * observable progress, the waiter will timeout and can then decide to do + * an unsafe hostile takeover. Upon unsafe hostile takeover, the console + * is kept permanently in the unsafe state. */ =20 /** @@ -47,6 +80,405 @@ static inline bool nbcon_state_try_cmpxchg(struct conso= le *con, struct nbcon_sta return atomic_try_cmpxchg(&ACCESS_PRIVATE(con, nbcon_state), &cur->atom, = new->atom); } =20 +/** + * nbcon_context_try_acquire_direct - Try to acquire directly + * @ctxt: The context of the caller + * @cur: The current console state + * + * Return: 0 on success and @cur is updated to the new console state. + * Otherwise an error code on failure. + * + * Errors: + * + * -EPERM: A panic is in progress and this is not the panic CPU + * or this context does not have a priority above the + * current owner or waiter. No acquire method can be + * successful for this context. + * + * -EBUSY: The console is in an unsafe state. The caller should + * try using the handover acquire method. + * + * The general procedure is to change @nbcon_state::prio from unowned to + * owned. Or, if the console is not in the unsafe state, to change + * @nbcon_state::prio to a higher priority owner. + */ +static int nbcon_context_try_acquire_direct(struct nbcon_context *ctxt, + struct nbcon_state *cur) +{ + unsigned int cpu =3D smp_processor_id(); + struct console *con =3D ctxt->console; + struct nbcon_state new; + + do { + if (other_cpu_in_panic()) + return -EPERM; + + if (ctxt->prio <=3D cur->prio || ctxt->prio <=3D cur->req_prio) + return -EPERM; + + if (cur->unsafe) + return -EBUSY; + + /* + * The console should never be safe for a direct acquire + * if an unsafe hostile takeover has ever happened. + */ + WARN_ON_ONCE(cur->unsafe_takeover); + + new.atom =3D cur->atom; + new.prio =3D ctxt->prio; + new.req_prio =3D NBCON_PRIO_NONE; + new.unsafe =3D cur->unsafe_takeover; + new.cpu =3D cpu; + + } while (!nbcon_state_try_cmpxchg(con, cur, &new)); + + cur->atom =3D new.atom; + + return 0; +} + +static bool nbcon_waiter_matches(struct nbcon_state *cur, int expected_pri= o) +{ + /* + * The request context is well defined by the @req_prio because: + * + * - Only a context with a higher priority can take over the request. + * - There are only three priorities. + * - Only one CPU is allowed to request PANIC priority. + * - Lower priorities are ignored during panic() until reboot. + * + * As a result, the following scenario is *not* possible: + * + * 1. Another context with a higher priority directly takes ownership. + * 2. The higher priority context releases the ownership. + * 3. A lower priority context takes the ownership. + * 4. Another context with the same priority as this context + * creates a request and starts waiting. + */ + + return (cur->req_prio =3D=3D expected_prio); +} + +/** + * nbcon_context_try_acquire_requested - Try to acquire after having + * requested a handover + * @ctxt: The context of the caller + * @cur: The current console state + * + * Return: 0 on success and @cur is updated to the new console state. + * Otherwise an error code on failure. + * + * Errors: + * + * -EPERM: A panic is in progress and this is not the panic CPU + * or this context is no longer the waiter. For the + * former case, the caller must carefully remove the + * request before aborting the acquire. + * + * -EBUSY: The console is still locked. The caller should + * continue waiting. + * + * This is a helper function for nbcon_context_try_acquire_handover(). + */ +static int nbcon_context_try_acquire_requested(struct nbcon_context *ctxt, + struct nbcon_state *cur) +{ + unsigned int cpu =3D smp_processor_id(); + struct console *con =3D ctxt->console; + struct nbcon_state new; + + do { + /* + * Note: If the acquire is aborted due to a panic CPU, + * the caller must still remove the request! + */ + if (other_cpu_in_panic()) + return -EPERM; + + /* + * If an unsafe hostile takeover has occurred, a handover + * is no longer possible. + */ + if (cur->unsafe_takeover) + return -EPERM; + + /* Is this context still the requester? */ + if (!nbcon_waiter_matches(cur, ctxt->prio)) + return -EPERM; + + /* If still locked, caller should continue waiting. */ + if (cur->prio !=3D NBCON_PRIO_NONE) + return -EBUSY; + + /* + * The previous owner should have never released ownership + * in an unsafe region. + */ + WARN_ON_ONCE(cur->unsafe); + + new.atom =3D cur->atom; + new.prio =3D ctxt->prio; + new.req_prio =3D NBCON_PRIO_NONE; + new.unsafe =3D cur->unsafe_takeover; + new.cpu =3D cpu; + + } while (!nbcon_state_try_cmpxchg(con, cur, &new)); + + /* Handover success. This context now owns the console. */ + + cur->atom =3D new.atom; + + return 0; +} + +/** + * nbcon_context_try_acquire_handover - Try to acquire via handover + * @ctxt: The context of the caller + * @cur: The current console state + * + * Return: 0 on success and @cur is updated to the new console state. + * Otherwise an error code on failure. + * + * Errors: + * + * -EPERM: This context is on the same CPU as the current owner + * or the console is permanently in an unsafe state or + * this context is unwilling to wait or a panic is in + * progress and this is not the panic CPU. This is not + * the panic context, so no acquire method can be + * successful for this context. + * + * -EBUSY: The current owner or waiter is such that this context + * is not able to execute a handover. The caller can use + * an unsafe hostile takeover to acquire. + * + * -EAGAIN: @cur is not the current console state. @cur has been + * updated. The caller should retry with direct acquire. + * + * The general procedure is to set @req_prio and wait until unowned. Then + * set @prio (claiming ownership) and clearing @req_prio. + * + * Note that it is expected that the caller tried + * nbcon_context_try_acquire_direct() with @cur before calling this functi= on. + */ +static int nbcon_context_try_acquire_handover(struct nbcon_context *ctxt, + struct nbcon_state *cur) +{ + unsigned int cpu =3D smp_processor_id(); + struct console *con =3D ctxt->console; + struct nbcon_state new; + int timeout; + int err =3D 0; + + /* + * Handovers are not possible on the same CPU or when the console + * is permanently in an unsafe state or if the caller is unwilling + * to wait. + */ + if (cur->cpu =3D=3D cpu || + cur->unsafe_takeover || + ctxt->spinwait_max_us =3D=3D 0) { + goto fail_handover; + } + + /* Setup a request for handover. */ + new.atom =3D cur->atom; + new.req_prio =3D ctxt->prio; + if (!nbcon_state_try_cmpxchg(con, cur, &new)) + return -EAGAIN; + + cur->atom =3D new.atom; + + /* Wait until there is no owner and then acquire directly. */ + for (timeout =3D ctxt->spinwait_max_us; timeout >=3D 0; timeout--) { + /* On successful acquire, this request is cleared. */ + err =3D nbcon_context_try_acquire_requested(ctxt, cur); + if (!err) + return 0; + + /* + * If the acquire should be aborted, it must be ensured + * that the request is removed before returning to caller. + */ + if (err =3D=3D -EPERM) + break; + + udelay(1); + + /* Re-read the state because some time has passed. */ + nbcon_state_read(con, cur); + } + + /* Timed out or should abort. Carefully remove handover request. */ + do { + /* No need to remove request if there is a new waiter. */ + if (!nbcon_waiter_matches(cur, ctxt->prio)) + goto fail_handover; + + /* Unset request for handover. */ + new.atom =3D cur->atom; + new.req_prio =3D NBCON_PRIO_NONE; + if (nbcon_state_try_cmpxchg(con, cur, &new)) { + /* + * Request successfully unset. Report failure of + * acquiring via handover. + */ + cur->atom =3D new.atom; + goto fail_handover; + } + + /* + * Unable to remove request. Try to acquire in case + * the owner has released the lock. + */ + } while (nbcon_context_try_acquire_requested(ctxt, cur)); + + /* Acquire at timeout succeeded! */ + return 0; + +fail_handover: + /* + * If this is the panic context, the caller can try to acquire using + * the unsafe hostile takeover method. + */ + if (ctxt->prio =3D=3D NBCON_PRIO_PANIC && + ctxt->prio > cur->prio && + ctxt->prio > cur->req_prio && + !other_cpu_in_panic()) { + return -EBUSY; + } + return -EPERM; +} + +/** + * nbcon_context_acquire_hostile - Acquire via unsafe hostile takeover + * @ctxt: The context of the caller + * @cur: The current console state + * + * @cur is updated to the new console state. + * + * The general procedure is to set @prio (forcing ownership). This method + * must only be used as a final attempt during panic. + */ +static void nbcon_context_acquire_hostile(struct nbcon_context *ctxt, + struct nbcon_state *cur) +{ + unsigned int cpu =3D smp_processor_id(); + struct console *con =3D ctxt->console; + struct nbcon_state new; + + do { + new.atom =3D cur->atom; + new.cpu =3D cpu; + new.prio =3D ctxt->prio; + new.unsafe |=3D cur->unsafe_takeover; + new.unsafe_takeover |=3D cur->unsafe; + + } while (!nbcon_state_try_cmpxchg(con, cur, &new)); + + cur->atom =3D new.atom; +} + +/** + * nbcon_context_try_acquire - Try to acquire nbcon console + * @ctxt: The context of the caller + * + * Return: True if the console was acquired. False otherwise. + * + * If the caller allowed an unsafe hostile takeover, on success the + * caller should check the current console state to see if it is + * in an unsafe state. Otherwise, on success the caller may assume + * the console is not in an unsafe state. + */ +__maybe_unused +static bool nbcon_context_try_acquire(struct nbcon_context *ctxt) +{ + __maybe_unused + unsigned int cpu =3D smp_processor_id(); + struct console *con =3D ctxt->console; + struct nbcon_state cur; + int err; + + /* unsafe hostile takeovers are only allowed for panic */ + WARN_ON_ONCE(ctxt->allow_unsafe_takeover && (ctxt->prio !=3D NBCON_PRIO_P= ANIC)); + + nbcon_state_read(con, &cur); + + do { + err =3D nbcon_context_try_acquire_direct(ctxt, &cur); + if (!err) + goto success; + else if (err =3D=3D -EPERM) + return false; + + err =3D nbcon_context_try_acquire_handover(ctxt, &cur); + if (!err) + goto success; + else if (err =3D=3D -EPERM) + return false; + + } while (err =3D=3D -EAGAIN); + + /* Only attempt unsafe hostile takeover if explicitly requested. */ + if (!ctxt->allow_unsafe_takeover) + return false; + + nbcon_context_acquire_hostile(ctxt, &cur); +success: + return true; +} + +static bool nbcon_owner_matches(struct nbcon_state *cur, int expected_cpu, + int expected_prio) +{ + /* + * Since consoles can only be acquired by higher priorities, + * owning contexts are uniquely identified by @prio. However, + * since contexts can unexpectedly lose ownership, it is + * possible that later another owner appears with the same + * priority. For this reason @cpu is also needed. + */ + + if (cur->prio !=3D expected_prio) + return false; + + if (cur->cpu !=3D expected_cpu) + return false; + + return true; +} + +/** + * nbcon_context_release - Release the console + * @ctxt: The nbcon context from nbcon_context_try_acquire() + */ +__maybe_unused +static void nbcon_context_release(struct nbcon_context *ctxt) +{ + unsigned int cpu =3D smp_processor_id(); + struct console *con =3D ctxt->console; + struct nbcon_state cur; + struct nbcon_state new; + + nbcon_state_read(con, &cur); + + do { + if (!nbcon_owner_matches(&cur, cpu, ctxt->prio)) + return; + + new.atom =3D cur.atom; + new.prio =3D NBCON_PRIO_NONE; + + /* + * If @unsafe_takeover is set, it is kept set so that + * the state remains permanently unsafe. + */ + new.unsafe |=3D cur.unsafe_takeover; + + } while (!nbcon_state_try_cmpxchg(con, &cur, &new)); +} + /** * nbcon_init - Initialize the nbcon console specific data * @con: Console to initialize --=20 2.39.2 From nobody Thu Dec 18 19:05:48 2025 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 200D0EEB562 for ; Fri, 8 Sep 2023 18:51:53 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S241385AbjIHSvy (ORCPT ); Fri, 8 Sep 2023 14:51:54 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:57426 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229665AbjIHSvx (ORCPT ); Fri, 8 Sep 2023 14:51:53 -0400 Received: from galois.linutronix.de (Galois.linutronix.de [IPv6:2a0a:51c0:0:12e:550::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 6EB9C19BC for ; Fri, 8 Sep 2023 11:51:18 -0700 (PDT) From: John Ogness DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020; t=1694199012; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=ZN61Yy4XSz9CP6DFAbMX5JI5My6PbyQNjYXE4FEmNGo=; b=YHEupqhklhm8R/QAhZK9ScmnErHg9LEyYAlTnnnN90vZPgN7SpKF3fGxOZbF5trtDarXVZ +1r2oxC4p3ICWejXGwxTwZpktKFhDORm2TVsya4vh8FfSPaRI3BQg2IasV5YmIoe12MrSU NvnoSUtq0wPu0aiXSIs+RfQO92nF6MloFcrgcZKvLPh0Xg7yMx7D/JleiOv93K4iSIoDcA 5kTC3hJ7FZLiS1e4SvIypSBx+7Qt+xDKTFTaZwLb3zl4G/nUbACiy4ozu8j3TVHfMaUVVy eOMj2/hLWFaZEihcVBIdg9kVj9l9/fIs+fx0iNe/ubtz/Akbt5xwJrk2zN3TcA== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020e; t=1694199012; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=ZN61Yy4XSz9CP6DFAbMX5JI5My6PbyQNjYXE4FEmNGo=; b=31OH1/qaNXMWm4TVF2X5SrE+xp20PFUhRf6u6fh4PARwj8J/3eg4/E6ipgCWHgPFIxLdVZ 3gstFOM77rUx0LDw== To: Petr Mladek Cc: Sergey Senozhatsky , Steven Rostedt , Thomas Gleixner , linux-kernel@vger.kernel.org Subject: [PATCH printk v4 3/8] printk: Make static printk buffers available to nbcon Date: Fri, 8 Sep 2023 20:56:03 +0206 Message-Id: <20230908185008.468566-4-john.ogness@linutronix.de> In-Reply-To: <20230908185008.468566-1-john.ogness@linutronix.de> References: <20230908185008.468566-1-john.ogness@linutronix.de> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" The nbcon boot consoles also need printk buffers that are available very early. Since the nbcon boot consoles will also be serialized by the console_lock, they can use the same static printk buffers that the legacy consoles are using. Make the legacy static printk buffers available outside of printk.c so they can be used by nbcon.c. Signed-off-by: John Ogness Reviewed-by: Petr Mladek --- kernel/printk/internal.h | 2 ++ kernel/printk/printk.c | 13 +++++++++---- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/kernel/printk/internal.h b/kernel/printk/internal.h index 2ca0ab78802c..7199d60bfc25 100644 --- a/kernel/printk/internal.h +++ b/kernel/printk/internal.h @@ -86,6 +86,8 @@ static inline void nbcon_cleanup(struct console *con) { } =20 #endif /* CONFIG_PRINTK */ =20 +extern struct printk_buffers printk_shared_pbufs; + /** * struct printk_buffers - Buffers to read/format/output printk messages. * @outbuf: After formatting, contains text to output. diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c index c0246093ea41..9a2ddab16abe 100644 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -2844,6 +2844,13 @@ static bool printk_get_next_message(struct printk_me= ssage *pmsg, u64 seq, return true; } =20 +/* + * Used as the printk buffers for non-panic, serialized console printing. + * This is for legacy (!CON_NBCON) as well as all boot (CON_BOOT) consoles. + * Its usage requires the console_lock held. + */ +struct printk_buffers printk_shared_pbufs; + /* * Print one record for the given console. The record printed is whatever * record is the next available record for the given console. @@ -2861,12 +2868,10 @@ static bool printk_get_next_message(struct printk_m= essage *pmsg, u64 seq, */ static bool console_emit_next_record(struct console *con, bool *handover, = int cookie) { - static struct printk_buffers pbufs; - bool is_extended =3D console_srcu_read_flags(con) & CON_EXTENDED; - char *outbuf =3D &pbufs.outbuf[0]; + char *outbuf =3D &printk_shared_pbufs.outbuf[0]; struct printk_message pmsg =3D { - .pbufs =3D &pbufs, + .pbufs =3D &printk_shared_pbufs, }; unsigned long flags; =20 --=20 2.39.2 From nobody Thu Dec 18 19:05:48 2025 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 66105EEB566 for ; Fri, 8 Sep 2023 18:51:57 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S243160AbjIHSv6 (ORCPT ); Fri, 8 Sep 2023 14:51:58 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:57504 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S242245AbjIHSvz (ORCPT ); Fri, 8 Sep 2023 14:51:55 -0400 Received: from galois.linutronix.de (Galois.linutronix.de [IPv6:2a0a:51c0:0:12e:550::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 71C2A8E for ; Fri, 8 Sep 2023 11:51:19 -0700 (PDT) From: John Ogness DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020; t=1694199012; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=6He536R9YKn+8XFiXel4OVcUGGr/X1V5MuFFOnacgQ4=; b=qnS1CWRfCglNCihDDP3iLgR1hu6R3WjBuyJJjx+j0gtrHQd1w0DWfJqpihUzCwga5f5GFN 5QzodThoNIlEq8/hJ/QmKFqL0fcuSuyLK/bP75e5ejZ3MDFARz8EG+vb/UzIG1Yh7ljiHd CDUGwUZ6xAuSPMSMaStvgq2GW6iUYDZMR9Z+rlw/6v2vyGEi8CVqsIBrJ3DVNRYIxTEN+R THn00okcaDTTPJwu8WujAoAcRfV3sAGh19r3GR7r3ILlnQ6QZP0JKsgdvxvAxd7odadosR m8TUYrPU8rHIFVVvl1vRlFM/9vbbDpW38i/Tft92spMiQmKbG8iKOz/IADf0zg== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020e; t=1694199012; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=6He536R9YKn+8XFiXel4OVcUGGr/X1V5MuFFOnacgQ4=; b=Z6Ysms0Pq8vAPRebFrFJcq1vSfvJUe9EKvcGTDH9XAxKz+eeqkjRh86q+Kl3lvUYhzUtbQ jYkquwZ+gQKUxcCQ== To: Petr Mladek Cc: Sergey Senozhatsky , Steven Rostedt , Thomas Gleixner , linux-kernel@vger.kernel.org, Greg Kroah-Hartman Subject: [PATCH printk v4 4/8] printk: nbcon: Add buffer management Date: Fri, 8 Sep 2023 20:56:04 +0206 Message-Id: <20230908185008.468566-5-john.ogness@linutronix.de> In-Reply-To: <20230908185008.468566-1-john.ogness@linutronix.de> References: <20230908185008.468566-1-john.ogness@linutronix.de> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" From: Thomas Gleixner 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: - Adding a global output buffer instance for the panic context. This is the only situation where hostile takeovers can occur and there is always at most 1 panic context. - Allocating an output buffer per non-boot console upon console registration. This buffer is used by the console owner when not in panic context. (For boot consoles, the existing shared global legacy output buffer is used instead. Boot console printing will be synchronized with legacy console printing.) - Choosing the appropriate buffer is handled in the acquire/release functions. Co-developed-by: John Ogness Signed-off-by: John Ogness Signed-off-by: Thomas Gleixner (Intel) Reviewed-by: Petr Mladek --- include/linux/console.h | 7 +++++ kernel/printk/internal.h | 12 ++++++-- kernel/printk/nbcon.c | 65 ++++++++++++++++++++++++++++++++++++---- kernel/printk/printk.c | 17 ++++++----- 4 files changed, 87 insertions(+), 14 deletions(-) diff --git a/include/linux/console.h b/include/linux/console.h index eeebb82d6d07..b7279ebafe0f 100644 --- a/include/linux/console.h +++ b/include/linux/console.h @@ -234,6 +234,7 @@ enum nbcon_prio { }; =20 struct console; +struct printk_buffers; =20 /** * struct nbcon_context - Context for console acquire/release @@ -244,6 +245,7 @@ struct console; * be used only with NBCON_PRIO_PANIC @prio. It * might cause a system freeze when the console * is used later. + * @pbufs: Pointer to the text buffer for this context */ struct nbcon_context { /* members set by caller */ @@ -251,6 +253,9 @@ struct nbcon_context { unsigned int spinwait_max_us; enum nbcon_prio prio; unsigned int allow_unsafe_takeover : 1; + + /* members set by acquire */ + struct printk_buffers *pbufs; }; =20 /** @@ -274,6 +279,7 @@ struct nbcon_context { * @node: hlist node for the console list * * @nbcon_state: State for nbcon consoles + * @pbufs: Pointer to nbcon private buffer */ struct console { char name[16]; @@ -296,6 +302,7 @@ struct console { =20 /* nbcon console specific members */ atomic_t __private nbcon_state; + struct printk_buffers *pbufs; }; =20 #ifdef CONFIG_LOCKDEP diff --git a/kernel/printk/internal.h b/kernel/printk/internal.h index 7199d60bfc25..f6161cd75d7d 100644 --- a/kernel/printk/internal.h +++ b/kernel/printk/internal.h @@ -13,6 +13,12 @@ int devkmsg_sysctl_set_loglvl(struct ctl_table *table, i= nt write, #define printk_sysctl_init() do { } while (0) #endif =20 +#define con_printk(lvl, con, fmt, ...) \ + printk(lvl pr_fmt("%s%sconsole [%s%d] " fmt), \ + (con->flags & CON_NBCON) ? "" : "legacy ", \ + (con->flags & CON_BOOT) ? "boot" : "", \ + con->name, con->index, ##__VA_ARGS__) + #ifdef CONFIG_PRINTK =20 #ifdef CONFIG_PRINTK_CALLER @@ -63,8 +69,9 @@ void defer_console_output(void); u16 printk_parse_prefix(const char *text, int *level, enum printk_info_flags *flags); =20 +bool nbcon_alloc(struct console *con); void nbcon_init(struct console *con); -void nbcon_cleanup(struct console *con); +void nbcon_free(struct console *con); =20 #else =20 @@ -81,8 +88,9 @@ void nbcon_cleanup(struct console *con); #define printk_safe_exit_irqrestore(flags) local_irq_restore(flags) =20 static inline bool printk_percpu_data_ready(void) { return false; } +static inline bool nbcon_alloc(struct console *con) { return false; } static inline void nbcon_init(struct console *con) { } -static inline void nbcon_cleanup(struct console *con) { } +static inline void nbcon_free(struct console *con) { } =20 #endif /* CONFIG_PRINTK */ =20 diff --git a/kernel/printk/nbcon.c b/kernel/printk/nbcon.c index 57ddfb7f0994..cad1cf663078 100644 --- a/kernel/printk/nbcon.c +++ b/kernel/printk/nbcon.c @@ -5,6 +5,7 @@ #include #include #include +#include #include "internal.h" /* * Printk console printing implementation for consoles that do not depend = on @@ -20,6 +21,9 @@ * region and aborts the operation if it detects a takeover. * * In case of panic the nesting context can take over the console forceful= ly. + * If the interrupted context touches the assigned record buffer after + * takeover, it does not cause harm because the interrupting single panic + * context is assigned its own panic record buffer. * * A concurrent writer on a different CPU with a higher priority can direc= tly * take over if the console is not in an unsafe state by carefully writing @@ -380,6 +384,8 @@ static void nbcon_context_acquire_hostile(struct nbcon_= context *ctxt, cur->atom =3D new.atom; } =20 +static struct printk_buffers panic_nbcon_pbufs; + /** * nbcon_context_try_acquire - Try to acquire nbcon console * @ctxt: The context of the caller @@ -394,7 +400,6 @@ static void nbcon_context_acquire_hostile(struct nbcon_= context *ctxt, __maybe_unused static bool nbcon_context_try_acquire(struct nbcon_context *ctxt) { - __maybe_unused unsigned int cpu =3D smp_processor_id(); struct console *con =3D ctxt->console; struct nbcon_state cur; @@ -426,6 +431,12 @@ static bool nbcon_context_try_acquire(struct nbcon_con= text *ctxt) =20 nbcon_context_acquire_hostile(ctxt, &cur); success: + /* Assign the appropriate buffer for this context. */ + if (atomic_read(&panic_cpu) =3D=3D cpu) + ctxt->pbufs =3D &panic_nbcon_pbufs; + else + ctxt->pbufs =3D con->pbufs; + return true; } =20 @@ -465,7 +476,7 @@ static void nbcon_context_release(struct nbcon_context = *ctxt) =20 do { if (!nbcon_owner_matches(&cur, cpu, ctxt->prio)) - return; + break; =20 new.atom =3D cur.atom; new.prio =3D NBCON_PRIO_NONE; @@ -477,26 +488,70 @@ static void nbcon_context_release(struct nbcon_contex= t *ctxt) new.unsafe |=3D cur.unsafe_takeover; =20 } while (!nbcon_state_try_cmpxchg(con, &cur, &new)); + + ctxt->pbufs =3D NULL; +} + +/** + * nbcon_alloc - Allocate buffers needed by the nbcon console + * @con: Console to allocate buffers for + * + * Return: True on success. False otherwise and the console cannot + * be used. + * + * This is not part of nbcon_init() because buffer allocation must + * be performed earlier in the console registration process. + */ +bool nbcon_alloc(struct console *con) +{ + if (con->flags & CON_BOOT) { + /* + * Boot console printing is synchronized with legacy console + * printing, so boot consoles can share the same global printk + * buffers. + */ + con->pbufs =3D &printk_shared_pbufs; + } else { + con->pbufs =3D kmalloc(sizeof(*con->pbufs), GFP_KERNEL); + if (!con->pbufs) { + con_printk(KERN_ERR, con, "failed to allocate printing buffer\n"); + return false; + } + } + + return true; } =20 /** * nbcon_init - Initialize the nbcon console specific data * @con: Console to initialize + * + * nbcon_alloc() *must* be called and succeed before this function + * is called. */ void nbcon_init(struct console *con) { struct nbcon_state state =3D { }; =20 + /* nbcon_alloc() must have been called and successful! */ + BUG_ON(!con->pbufs); + nbcon_state_set(con, &state); } =20 /** - * nbcon_cleanup - Cleanup the nbcon console specific data - * @con: Console to cleanup + * nbcon_free - Free and cleanup the nbcon console specific data + * @con: Console to free/cleanup nbcon data */ -void nbcon_cleanup(struct console *con) +void nbcon_free(struct console *con) { struct nbcon_state state =3D { }; =20 nbcon_state_set(con, &state); + + /* Boot consoles share global printk buffers. */ + if (!(con->flags & CON_BOOT)) + kfree(con->pbufs); + + con->pbufs =3D NULL; } diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c index 9a2ddab16abe..d1c43fa1ffd3 100644 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -3329,12 +3329,6 @@ static void try_enable_default_console(struct consol= e *newcon) newcon->flags |=3D CON_CONSDEV; } =20 -#define con_printk(lvl, con, fmt, ...) \ - printk(lvl pr_fmt("%s%sconsole [%s%d] " fmt), \ - (con->flags & CON_NBCON) ? "" : "legacy ", \ - (con->flags & CON_BOOT) ? "boot" : "", \ - con->name, con->index, ##__VA_ARGS__) - static void console_init_seq(struct console *newcon, bool bootcon_register= ed) { struct console *con; @@ -3448,6 +3442,15 @@ void register_console(struct console *newcon) goto unlock; } =20 + if (newcon->flags & CON_NBCON) { + /* + * Ensure the nbcon console buffers can be allocated + * before modifying any global data. + */ + if (!nbcon_alloc(newcon)) + goto unlock; + } + /* * See if we want to enable this console driver by default. * @@ -3587,7 +3590,7 @@ static int unregister_console_locked(struct console *= console) synchronize_srcu(&console_srcu); =20 if (console->flags & CON_NBCON) - nbcon_cleanup(console); + nbcon_free(console); =20 console_sysfs_notify(); =20 --=20 2.39.2 From nobody Thu Dec 18 19:05:48 2025 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 2A531EEB562 for ; Fri, 8 Sep 2023 18:53:12 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236169AbjIHSxN (ORCPT ); Fri, 8 Sep 2023 14:53:13 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:34714 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S244081AbjIHSxK (ORCPT ); Fri, 8 Sep 2023 14:53:10 -0400 Received: from galois.linutronix.de (Galois.linutronix.de [IPv6:2a0a:51c0:0:12e:550::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id A00ED19BC for ; Fri, 8 Sep 2023 11:52:33 -0700 (PDT) From: John Ogness DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020; t=1694199013; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=3AhXHgTl54l+2B1p5seos+XuRz43slfuqFnWPDcr6jw=; b=wqeA+DS3j4lZ9CtmYTWGxA7Vwv0ozInzpLy02fDJ59KlRkApaENw6u+iXsZkhUW9BzxzoZ 6CNA6Ewj65Xyrjrr9rF3cDNuop898JA9dB9EKijMWJSj1k6qlpRg1BjVTQmJ/OP+n7dA2p 1NfMC/d8Av6Yw7Rd+S05eJVuP0LqX068x9Ih2wf5U29gdl/A1hQovDz6L1UhjCi4Zr7uin sTE4HLilsqYmvs41zjLgi8Mm5uChtoP+9iE8BJicLP1ZIoFOWzPRaaMiSf+zQPknNYV90F sq0RunpIQGJurPLP0jzeCp0Vu27AuYadsseF4Hz3H/ayvhgYjIZBqdMkkYvlxw== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020e; t=1694199013; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=3AhXHgTl54l+2B1p5seos+XuRz43slfuqFnWPDcr6jw=; b=7L1m2xFCYDXI8ZHN1jJ9/MTYPL7pqILEBKjBdjRjrW1foSnsb/I36X5npEIIftWV8LAF2M dxHM9j3C/StrabAQ== To: Petr Mladek Cc: Sergey Senozhatsky , Steven Rostedt , Thomas Gleixner , linux-kernel@vger.kernel.org Subject: [PATCH printk v4 5/8] printk: nbcon: Add ownership state functions Date: Fri, 8 Sep 2023 20:56:05 +0206 Message-Id: <20230908185008.468566-6-john.ogness@linutronix.de> In-Reply-To: <20230908185008.468566-1-john.ogness@linutronix.de> References: <20230908185008.468566-1-john.ogness@linutronix.de> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" From: Thomas Gleixner Provide functions that are related to the safe handover mechanism and allow console drivers to dynamically specify unsafe regions: - nbcon_context_can_proceed() Invoked by a console owner to check whether a handover request is pending or whether the console has been taken over by another context. If a handover request is pending, this function will also perform the handover, thus cancelling its own ownership. - nbcon_context_enter_unsafe()/nbcon_context_exit_unsafe() Invoked by a console owner to denote that the driver is about to enter or leave a critical region where a take over is unsafe. These functions are also cancellation points where loss of ownership can occur. The unsafe state is stored in the console state and allows a new context to make informed decisions whether to attempt a takeover of such a console. The unsafe state is also available to the driver so that it can make informed decisions about the required actions and possibly take a special emergency path. Co-developed-by: John Ogness Signed-off-by: John Ogness Signed-off-by: Thomas Gleixner (Intel) Reviewed-by: Petr Mladek --- kernel/printk/nbcon.c | 110 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 109 insertions(+), 1 deletion(-) diff --git a/kernel/printk/nbcon.c b/kernel/printk/nbcon.c index cad1cf663078..644c4b9a4540 100644 --- a/kernel/printk/nbcon.c +++ b/kernel/printk/nbcon.c @@ -464,7 +464,6 @@ static bool nbcon_owner_matches(struct nbcon_state *cur= , int expected_cpu, * nbcon_context_release - Release the console * @ctxt: The nbcon context from nbcon_context_try_acquire() */ -__maybe_unused static void nbcon_context_release(struct nbcon_context *ctxt) { unsigned int cpu =3D smp_processor_id(); @@ -492,6 +491,115 @@ static void nbcon_context_release(struct nbcon_contex= t *ctxt) ctxt->pbufs =3D NULL; } =20 +/** + * nbcon_context_can_proceed - Check whether ownership can proceed + * @ctxt: The nbcon context from nbcon_context_try_acquire() + * @cur: The current console state + * + * Return: True if this context still owns the console. False if + * ownership was handed over or taken. + * + * Must be invoked after the record was dumped into the assigned buffer + * and at appropriate safe places in the driver. + * + * When this function returns false then the calling context no longer owns + * the console and is no longer allowed to go forward. In this case it must + * back out immediately and carefully. The buffer content is also no longer + * trusted since it no longer belongs to the calling context. + */ +static bool nbcon_context_can_proceed(struct nbcon_context *ctxt, struct n= bcon_state *cur) +{ + unsigned int cpu =3D smp_processor_id(); + + /* Make sure this context still owns the console. */ + if (!nbcon_owner_matches(cur, cpu, ctxt->prio)) + return false; + + /* The console owner can proceed if there is no waiter. */ + if (cur->req_prio =3D=3D NBCON_PRIO_NONE) + return true; + + /* + * A console owner within an unsafe region is always allowed to + * proceed, even if there are waiters. It can perform a handover + * when exiting the unsafe region. Otherwise the waiter will + * need to perform an unsafe hostile takeover. + */ + if (cur->unsafe) + return true; + + /* Waiters always have higher priorities than owners. */ + WARN_ON_ONCE(cur->req_prio <=3D cur->prio); + + /* + * 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. + * Release and hand over. + */ + nbcon_context_release(ctxt); + + /* + * It is not known whether the handover succeeded. The outermost + * callsite has to make the final decision whether printing + * should proceed or not (via reacquire, possibly hostile). The + * console is now unlocked so go back all the way instead of + * trying to implement heuristics in tons of places. + */ + return false; +} + +#define nbcon_context_enter_unsafe(c) __nbcon_context_update_unsafe(c, tru= e) +#define nbcon_context_exit_unsafe(c) __nbcon_context_update_unsafe(c, fals= e) + +/** + * __nbcon_context_update_unsafe - Update the unsafe bit in @con->nbcon_st= ate + * @ctxt: The nbcon context from nbcon_context_try_acquire() + * @unsafe: The new value for the unsafe bit + * + * Return: True if the unsafe state was updated and this context still + * owns the console. Otherwise false if ownership was handed + * over or taken. + * + * This function allows console owners to modify the unsafe status of the + * console. + * + * When this function returns false then the calling context no longer owns + * the console and is no longer allowed to go forward. In this case it must + * back out immediately and carefully. The buffer content is also no longer + * trusted since it no longer belongs to the calling context. + * + * Internal helper to avoid duplicated code. + */ +__maybe_unused +static bool __nbcon_context_update_unsafe(struct nbcon_context *ctxt, bool= unsafe) +{ + struct console *con =3D ctxt->console; + struct nbcon_state cur; + struct nbcon_state new; + + nbcon_state_read(con, &cur); + + do { + /* + * The unsafe bit must not be cleared if an + * unsafe hostile takeover has occurred. + */ + if (!unsafe && cur.unsafe_takeover) + goto out; + + if (!nbcon_context_can_proceed(ctxt, &cur)) + return false; + + new.atom =3D cur.atom; + new.unsafe =3D unsafe; + } while (!nbcon_state_try_cmpxchg(con, &cur, &new)); + + cur.atom =3D new.atom; +out: + return nbcon_context_can_proceed(ctxt, &cur); +} + /** * nbcon_alloc - Allocate buffers needed by the nbcon console * @con: Console to allocate buffers for --=20 2.39.2 From nobody Thu Dec 18 19:05:48 2025 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 9D682EEB560 for ; Fri, 8 Sep 2023 19:04:48 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S241600AbjIHTEu (ORCPT ); Fri, 8 Sep 2023 15:04:50 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:34040 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234443AbjIHTEt (ORCPT ); Fri, 8 Sep 2023 15:04:49 -0400 Received: from galois.linutronix.de (Galois.linutronix.de [193.142.43.55]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 3F6DAA9 for ; Fri, 8 Sep 2023 12:04:44 -0700 (PDT) From: John Ogness DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020; t=1694199013; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=PRoaVhYaww++NQ1OVEc2Vvw3cxYIxsw8EjfPkNwCRuk=; b=E7DE645kgFHYXahip9NTMTkLFgZfgzyq5o4PxdXwFjHvVSMyCSVACUIlS2WESKE36WIZRN 8N6V6S4y6i4ziV4hoM8dp92c39Of4tDX4V3c/1bMDpRD3sGj29NS3LdvLAchAC1/AyFDcn yZk7qGdW8dfo2Tg40PmutmjvLvNfn3KT/v+4mrKYAEog6tmCeCwHF2YTQa5+IdyMRopyKN LJPkLl1wVn3uflNdCnGkaAGpp1iyIHvuDl8C9+Gz6D/WPjLfD3EiDCfVc3ypnKhRt40wl2 M9isIrsjA4u4KBEWlX/x5TboW7yJKaLUkaerLx5n7hCnfMWZXhZRjEWjs78JJg== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020e; t=1694199013; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=PRoaVhYaww++NQ1OVEc2Vvw3cxYIxsw8EjfPkNwCRuk=; b=tuqTwy6WEaXH2jpJSJYCpnCY8uRyH25be5sWMeEcpHRz0jNdE87GqwN2AeF94TY1NSA7Ok MTN8jdEQgg34WlCQ== To: Petr Mladek Cc: Sergey Senozhatsky , Steven Rostedt , Thomas Gleixner , linux-kernel@vger.kernel.org, Greg Kroah-Hartman Subject: [PATCH printk v4 6/8] printk: nbcon: Add sequence handling Date: Fri, 8 Sep 2023 20:56:06 +0206 Message-Id: <20230908185008.468566-7-john.ogness@linutronix.de> In-Reply-To: <20230908185008.468566-1-john.ogness@linutronix.de> References: <20230908185008.468566-1-john.ogness@linutronix.de> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" From: Thomas Gleixner Add an atomic_long_t field @nbcon_seq to the console struct to store the sequence number for nbcon consoles. For nbcon consoles this will be used instead of the non-atomic @seq field. The new field allows for safe atomic sequence number updates without requiring any locking. On 64bit systems the new field stores the full sequence number. On 32bit systems the new field stores the lower 32 bits of the sequence number, which are expanded to 64bit as needed by folding the values based on the sequence numbers available in the ringbuffer. For 32bit systems, 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. Co-developed-by: John Ogness Signed-off-by: John Ogness Signed-off-by: Thomas Gleixner (Intel) Reviewed-by: Petr Mladek --- include/linux/console.h | 4 ++ kernel/printk/internal.h | 7 +++ kernel/printk/nbcon.c | 125 +++++++++++++++++++++++++++++++++++++-- kernel/printk/printk.c | 31 +++++++--- 4 files changed, 155 insertions(+), 12 deletions(-) diff --git a/include/linux/console.h b/include/linux/console.h index b7279ebafe0f..9d2580a33308 100644 --- a/include/linux/console.h +++ b/include/linux/console.h @@ -246,6 +246,7 @@ struct printk_buffers; * might cause a system freeze when the console * is used later. * @pbufs: Pointer to the text buffer for this context + * @seq: The sequence number to print for this context */ struct nbcon_context { /* members set by caller */ @@ -256,6 +257,7 @@ struct nbcon_context { =20 /* members set by acquire */ struct printk_buffers *pbufs; + u64 seq; }; =20 /** @@ -279,6 +281,7 @@ struct nbcon_context { * @node: hlist node for the console list * * @nbcon_state: State for nbcon consoles + * @nbcon_seq: Sequence number of the next record for nbcon to print * @pbufs: Pointer to nbcon private buffer */ struct console { @@ -302,6 +305,7 @@ struct console { =20 /* nbcon console specific members */ atomic_t __private nbcon_state; + atomic_long_t __private nbcon_seq; struct printk_buffers *pbufs; }; =20 diff --git a/kernel/printk/internal.h b/kernel/printk/internal.h index f6161cd75d7d..6473f5ae4a18 100644 --- a/kernel/printk/internal.h +++ b/kernel/printk/internal.h @@ -4,6 +4,7 @@ */ #include #include +#include "printk_ringbuffer.h" =20 #if defined(CONFIG_PRINTK) && defined(CONFIG_SYSCTL) void __init printk_sysctl_init(void); @@ -42,6 +43,8 @@ enum printk_info_flags { LOG_CONT =3D 8, /* text is a fragment of a continuation line */ }; =20 +extern struct printk_ringbuffer *prb; + __printf(4, 0) int vprintk_store(int facility, int level, const struct dev_printk_info *dev_info, @@ -69,6 +72,8 @@ void defer_console_output(void); u16 printk_parse_prefix(const char *text, int *level, enum printk_info_flags *flags); =20 +u64 nbcon_seq_read(struct console *con); +void nbcon_seq_force(struct console *con, u64 seq); bool nbcon_alloc(struct console *con); void nbcon_init(struct console *con); void nbcon_free(struct console *con); @@ -88,6 +93,8 @@ void nbcon_free(struct console *con); #define printk_safe_exit_irqrestore(flags) local_irq_restore(flags) =20 static inline bool printk_percpu_data_ready(void) { return false; } +static inline u64 nbcon_seq_read(struct console *con) { return 0; } +static inline void nbcon_seq_force(struct console *con, u64 seq) { } static inline bool nbcon_alloc(struct console *con) { return false; } static inline void nbcon_init(struct console *con) { } static inline void nbcon_free(struct console *con) { } diff --git a/kernel/printk/nbcon.c b/kernel/printk/nbcon.c index 644c4b9a4540..d23aa132fdcb 100644 --- a/kernel/printk/nbcon.c +++ b/kernel/printk/nbcon.c @@ -84,6 +84,112 @@ static inline bool nbcon_state_try_cmpxchg(struct conso= le *con, struct nbcon_sta return atomic_try_cmpxchg(&ACCESS_PRIVATE(con, nbcon_state), &cur->atom, = new->atom); } =20 +#ifdef CONFIG_64BIT + +#define __seq_to_nbcon_seq(seq) (seq) +#define __nbcon_seq_to_seq(seq) (seq) + +#else /* CONFIG_64BIT */ + +#define __seq_to_nbcon_seq(seq) ((u32)seq) + +static inline u64 __nbcon_seq_to_seq(u32 nbcon_seq) +{ + u64 seq; + u64 rb_next_seq; + + /* + * The provided sequence is only the lower 32 bits of the ringbuffer + * sequence. It needs to be expanded to 64bit. Get the next sequence + * number from the ringbuffer and fold it. + * + * 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. + * + * Also the access to the ring buffer is always safe. + */ + rb_next_seq =3D prb_next_seq(prb); + seq =3D rb_next_seq - ((u32)rb_next_seq - nbcon_seq); + + return seq; +} + +#endif /* CONFIG_64BIT */ + +/** + * nbcon_seq_init - Helper function to initialize the console sequence + * @con: Console to work on + * + * Set @con->nbcon_seq to the starting record (specified with con->seq). + * If the starting record no longer exists, the oldest available record + * is chosen. This is especially important on 32bit systems because only + * the lower 32 bits of the sequence number are stored. The upper 32 bits + * are derived from the sequence numbers available in the ringbuffer. + * + * For init only. Do not use for runtime updates. + */ +static void nbcon_seq_init(struct console *con) +{ + u64 seq =3D max_t(u64, con->seq, prb_first_valid_seq(prb)); + + atomic_long_set(&ACCESS_PRIVATE(con, nbcon_seq), __seq_to_nbcon_seq(seq)); + + /* Clear con->seq since nbcon consoles use con->nbcon_seq instead. */ + con->seq =3D 0; +} + +/** + * nbcon_seq_read - Read the current console sequence + * @con: Console to read the sequence of + * + * Return: Sequence number of the next record to print on @con. + */ +u64 nbcon_seq_read(struct console *con) +{ + unsigned long nbcon_seq =3D atomic_long_read(&ACCESS_PRIVATE(con, nbcon_s= eq)); + + return __nbcon_seq_to_seq(nbcon_seq); +} + +/** + * nbcon_seq_force - Force console sequence to a specific value + * @con: Console to work on + * @seq: Sequence number value to set + * + * Only to be used in extreme situations (such as panic with + * CONSOLE_REPLAY_ALL). + */ +void nbcon_seq_force(struct console *con, u64 seq) +{ + atomic_long_set(&ACCESS_PRIVATE(con, nbcon_seq), __seq_to_nbcon_seq(seq)); +} + +/** + * nbcon_seq_try_update - Try to update the console sequence number + * @ctxt: Pointer to an acquire context that contains + * all information about the acquire mode + * @new_seq: The new sequence number to set + * + * @ctxt->seq is updated to the new value of @con::nbcon_seq (expanded to + * the 64bit value). This could be a different value than @new_seq if + * nbcon_seq_force() was used or the current context no longer owns the + * console. In the later case, it will stop printing anyway. + */ +__maybe_unused +static void nbcon_seq_try_update(struct nbcon_context *ctxt, u64 new_seq) +{ + unsigned long nbcon_seq =3D __seq_to_nbcon_seq(ctxt->seq); + struct console *con =3D ctxt->console; + + if (atomic_long_try_cmpxchg(&ACCESS_PRIVATE(con, nbcon_seq), &nbcon_seq, + __seq_to_nbcon_seq(new_seq))) { + ctxt->seq =3D new_seq; + } else { + ctxt->seq =3D nbcon_seq_read(con); + } +} + /** * nbcon_context_try_acquire_direct - Try to acquire directly * @ctxt: The context of the caller @@ -437,6 +543,9 @@ static bool nbcon_context_try_acquire(struct nbcon_cont= ext *ctxt) else ctxt->pbufs =3D con->pbufs; =20 + /* Set the record sequence for this context to print. */ + ctxt->seq =3D nbcon_seq_read(ctxt->console); + return true; } =20 @@ -540,11 +649,14 @@ static bool nbcon_context_can_proceed(struct nbcon_co= ntext *ctxt, struct nbcon_s nbcon_context_release(ctxt); =20 /* - * It is not known whether the handover succeeded. The outermost - * callsite has to make the final decision whether printing - * should proceed or not (via reacquire, possibly hostile). The - * console is now unlocked so go back all the way instead of - * trying to implement heuristics in tons of places. + * It is not clear whether the waiter really took over ownership. The + * outermost callsite must make the final decision whether console + * ownership is needed for it to proceed. If yes, it must reacquire + * ownership (possibly hostile) before carefully proceeding. + * + * The calling context no longer owns the console so go back all the + * way instead of trying to implement reacquire heuristics in tons of + * places. */ return false; } @@ -636,6 +748,8 @@ bool nbcon_alloc(struct console *con) * * nbcon_alloc() *must* be called and succeed before this function * is called. + * + * This function expects that the legacy @con->seq has been set. */ void nbcon_init(struct console *con) { @@ -644,6 +758,7 @@ void nbcon_init(struct console *con) /* nbcon_alloc() must have been called and successful! */ BUG_ON(!con->pbufs); =20 + nbcon_seq_init(con); nbcon_state_set(con, &state); } =20 diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c index d1c43fa1ffd3..325ba9a1f6e7 100644 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -492,7 +492,7 @@ _DEFINE_PRINTKRB(printk_rb_static, CONFIG_LOG_BUF_SHIFT= - PRB_AVGBITS, =20 static struct printk_ringbuffer printk_rb_dynamic; =20 -static struct printk_ringbuffer *prb =3D &printk_rb_static; +struct printk_ringbuffer *prb =3D &printk_rb_static; =20 /* * We cannot access per-CPU data (e.g. per-CPU flush irq_work) before @@ -3166,6 +3166,7 @@ void console_flush_on_panic(enum con_flush_mode mode) =20 if (mode =3D=3D CONSOLE_REPLAY_ALL) { struct console *c; + short flags; int cookie; u64 seq; =20 @@ -3173,11 +3174,17 @@ void console_flush_on_panic(enum con_flush_mode mod= e) =20 cookie =3D console_srcu_read_lock(); for_each_console_srcu(c) { - /* - * This is an unsynchronized assignment, but the - * kernel is in "hope and pray" mode anyway. - */ - c->seq =3D seq; + flags =3D console_srcu_read_flags(c); + + if (flags & CON_NBCON) { + nbcon_seq_force(c, seq); + } else { + /* + * This is an unsynchronized assignment. On + * panic legacy consoles are only best effort. + */ + c->seq =3D seq; + } } console_srcu_read_unlock(cookie); } @@ -3745,6 +3752,7 @@ static bool __pr_flush(struct console *con, int timeo= ut_ms, bool reset_on_progre struct console *c; u64 last_diff =3D 0; u64 printk_seq; + short flags; int cookie; u64 diff; u64 seq; @@ -3766,6 +3774,9 @@ static bool __pr_flush(struct console *con, int timeo= ut_ms, bool reset_on_progre for_each_console_srcu(c) { if (con && con !=3D c) continue; + + flags =3D console_srcu_read_flags(c); + /* * If consoles are not usable, it cannot be expected * that they make forward progress, so only increment @@ -3773,7 +3784,13 @@ static bool __pr_flush(struct console *con, int time= out_ms, bool reset_on_progre */ if (!console_is_usable(c)) continue; - printk_seq =3D c->seq; + + if (flags & CON_NBCON) { + printk_seq =3D nbcon_seq_read(c); + } else { + printk_seq =3D c->seq; + } + if (printk_seq < seq) diff +=3D seq - printk_seq; } --=20 2.39.2 From nobody Thu Dec 18 19:05:48 2025 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 E1279EEB566 for ; Fri, 8 Sep 2023 18:53:13 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S238353AbjIHSxP (ORCPT ); Fri, 8 Sep 2023 14:53:15 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:34580 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234792AbjIHSxL (ORCPT ); Fri, 8 Sep 2023 14:53:11 -0400 Received: from galois.linutronix.de (Galois.linutronix.de [IPv6:2a0a:51c0:0:12e:550::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 1D0BACF for ; Fri, 8 Sep 2023 11:52:36 -0700 (PDT) From: John Ogness DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020; t=1694199014; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=poWu/+5PEmVZ0BYlHFpjUmkrZ3iWrQYZGKNz1/QrzkU=; b=IIAMJ3Hi3qj2Irw8aTY7GmwKmLDFRkx0l+6odQfMTRyQ0SLPpK52fhj+9I/+u/471jMdWH +ovHRDfuo7Z1iuBNRM8MT/q6GOx54/4pQapLPz2hk64pNdB0LFBvPCx+olaexb0I6s/MNX 3/xeQqD+QkDZvoTFdltTV9UPzenmBpxML/ZRsjcAz9Jepn8UminZmG5zbqkBLDsXjWm4oG CApu2VwGa7tN1wvTRAi51T5lD2pDkdNfNVj1AS6kgnIuY/mK4ynqt2LIzHFv6ZiEZxUCu6 rOgLAIeEcMnJ2F5D+XeV2Q+MuN5/lFi5Vv6gmVH8w2fwel7n6TOz1Z2WF/PH2g== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020e; t=1694199014; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=poWu/+5PEmVZ0BYlHFpjUmkrZ3iWrQYZGKNz1/QrzkU=; b=N36uPW8EJKQunPFK0jSy/+uCICUsYgN4StEBx5N0WvuGSZGyuFvBk7i9y6Zjh8XVFI74AR pJtmy9nA4QvB1YBQ== To: Petr Mladek Cc: Sergey Senozhatsky , Steven Rostedt , Thomas Gleixner , linux-kernel@vger.kernel.org, Greg Kroah-Hartman Subject: [PATCH printk v4 7/8] printk: nbcon: Add emit function and callback function for atomic printing Date: Fri, 8 Sep 2023 20:56:07 +0206 Message-Id: <20230908185008.468566-8-john.ogness@linutronix.de> In-Reply-To: <20230908185008.468566-1-john.ogness@linutronix.de> References: <20230908185008.468566-1-john.ogness@linutronix.de> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" From: Thomas Gleixner Implement an emit function for nbcon consoles to output printk messages. It utilizes the lockless printk_get_next_message() and console_prepend_dropped() functions to retrieve/build the output message. The emit function includes the required safety points to check for handover/takeover and calls a new write_atomic callback of the console driver to output the message. It also includes proper handling for updating the nbcon console sequence number. A new nbcon_write_context struct is introduced. This is provided to the write_atomic callback and includes only the information necessary for performing atomic writes. Co-developed-by: John Ogness Signed-off-by: John Ogness Signed-off-by: Thomas Gleixner (Intel) Reviewed-by: Petr Mladek --- include/linux/console.h | 21 ++++++++ kernel/printk/internal.h | 6 +++ kernel/printk/nbcon.c | 106 ++++++++++++++++++++++++++++++++++++++- kernel/printk/printk.c | 9 ++-- 4 files changed, 134 insertions(+), 8 deletions(-) diff --git a/include/linux/console.h b/include/linux/console.h index 9d2580a33308..0ce7a2a856ab 100644 --- a/include/linux/console.h +++ b/include/linux/console.h @@ -245,6 +245,7 @@ struct printk_buffers; * be used only with NBCON_PRIO_PANIC @prio. It * might cause a system freeze when the console * is used later. + * @backlog: Ringbuffer has pending records * @pbufs: Pointer to the text buffer for this context * @seq: The sequence number to print for this context */ @@ -255,11 +256,28 @@ struct nbcon_context { enum nbcon_prio prio; unsigned int allow_unsafe_takeover : 1; =20 + /* members set by emit */ + unsigned int backlog : 1; + /* members set by acquire */ struct printk_buffers *pbufs; u64 seq; }; =20 +/** + * struct nbcon_write_context - Context handed to the nbcon write callbacks + * @ctxt: The core console context + * @outbuf: Pointer to the text buffer for output + * @len: Length to write + * @unsafe_takeover: If a hostile takeover in an unsafe state has occurred + */ +struct nbcon_write_context { + struct nbcon_context __private ctxt; + char *outbuf; + unsigned int len; + bool unsafe_takeover; +}; + /** * struct console - The console descriptor structure * @name: The name of the console driver @@ -280,6 +298,7 @@ struct nbcon_context { * @data: Driver private data * @node: hlist node for the console list * + * @write_atomic: Write callback for atomic context * @nbcon_state: State for nbcon consoles * @nbcon_seq: Sequence number of the next record for nbcon to print * @pbufs: Pointer to nbcon private buffer @@ -304,6 +323,8 @@ struct console { struct hlist_node node; =20 /* nbcon console specific members */ + bool (*write_atomic)(struct console *con, + struct nbcon_write_context *wctxt); atomic_t __private nbcon_state; atomic_long_t __private nbcon_seq; struct printk_buffers *pbufs; diff --git a/kernel/printk/internal.h b/kernel/printk/internal.h index 6473f5ae4a18..6c2afee5ef62 100644 --- a/kernel/printk/internal.h +++ b/kernel/printk/internal.h @@ -130,3 +130,9 @@ struct printk_message { }; =20 bool other_cpu_in_panic(void); +bool printk_get_next_message(struct printk_message *pmsg, u64 seq, + bool is_extended, bool may_supress); + +#ifdef CONFIG_PRINTK +void console_prepend_dropped(struct printk_message *pmsg, unsigned long dr= opped); +#endif diff --git a/kernel/printk/nbcon.c b/kernel/printk/nbcon.c index d23aa132fdcb..e2c274f4142e 100644 --- a/kernel/printk/nbcon.c +++ b/kernel/printk/nbcon.c @@ -176,7 +176,6 @@ void nbcon_seq_force(struct console *con, u64 seq) * nbcon_seq_force() was used or the current context no longer owns the * console. In the later case, it will stop printing anyway. */ -__maybe_unused static void nbcon_seq_try_update(struct nbcon_context *ctxt, u64 new_seq) { unsigned long nbcon_seq =3D __seq_to_nbcon_seq(ctxt->seq); @@ -683,7 +682,6 @@ static bool nbcon_context_can_proceed(struct nbcon_cont= ext *ctxt, struct nbcon_s * * Internal helper to avoid duplicated code. */ -__maybe_unused static bool __nbcon_context_update_unsafe(struct nbcon_context *ctxt, bool= unsafe) { struct console *con =3D ctxt->console; @@ -712,6 +710,110 @@ static bool __nbcon_context_update_unsafe(struct nbco= n_context *ctxt, bool unsaf return nbcon_context_can_proceed(ctxt, &cur); } =20 +/** + * nbcon_emit_next_record - Emit a record in the acquired context + * @wctxt: The write context that will be handed to the write function + * + * Return: True if this context still owns the console. False if + * ownership was handed over or taken. + * + * When this function returns false then the calling context no longer owns + * the console and is no longer allowed to go forward. In this case it must + * back out immediately and carefully. The buffer content is also no longer + * trusted since it no longer belongs to the calling context. If the caller + * wants to do more it must reacquire the console first. + * + * When true is returned, @wctxt->ctxt.backlog indicates whether there are + * still records pending in the ringbuffer, + */ +__maybe_unused +static bool nbcon_emit_next_record(struct nbcon_write_context *wctxt) +{ + struct nbcon_context *ctxt =3D &ACCESS_PRIVATE(wctxt, ctxt); + struct console *con =3D ctxt->console; + bool is_extended =3D console_srcu_read_flags(con) & CON_EXTENDED; + struct printk_message pmsg =3D { + .pbufs =3D ctxt->pbufs, + }; + unsigned long con_dropped; + struct nbcon_state cur; + unsigned long dropped; + bool done; + + /* + * The printk buffers are filled within an unsafe section. This + * prevents NBCON_PRIO_NORMAL and NBCON_PRIO_EMERGENCY from + * clobbering each other. + */ + + if (!nbcon_context_enter_unsafe(ctxt)) + return false; + + ctxt->backlog =3D printk_get_next_message(&pmsg, ctxt->seq, is_extended, = true); + if (!ctxt->backlog) + return nbcon_context_exit_unsafe(ctxt); + + /* + * @con->dropped is not protected in case of an unsafe hostile + * takeover. In that situation the update can be racy so + * annotate it accordingly. + */ + con_dropped =3D data_race(READ_ONCE(con->dropped)); + + dropped =3D con_dropped + pmsg.dropped; + if (dropped && !is_extended) + console_prepend_dropped(&pmsg, dropped); + + if (!nbcon_context_exit_unsafe(ctxt)) + return false; + + /* For skipped records just update seq/dropped in @con. */ + if (pmsg.outbuf_len =3D=3D 0) + goto update_con; + + /* Initialize the write context for driver callbacks. */ + wctxt->outbuf =3D &pmsg.pbufs->outbuf[0]; + wctxt->len =3D pmsg.outbuf_len; + nbcon_state_read(con, &cur); + wctxt->unsafe_takeover =3D cur.unsafe_takeover; + + if (con->write_atomic) { + done =3D con->write_atomic(con, wctxt); + } else { + nbcon_context_release(ctxt); + WARN_ON_ONCE(1); + done =3D false; + } + + /* If not done, the emit was aborted. */ + if (!done) + return false; + + /* + * Since any dropped message was successfully output, reset the + * dropped count for the console. + */ + dropped =3D 0; +update_con: + /* + * The dropped count and the sequence number are updated within an + * unsafe section. This limits update races to the panic context and + * allows the panic context to win. + */ + + if (!nbcon_context_enter_unsafe(ctxt)) + return false; + + if (dropped !=3D con_dropped) { + /* Counterpart to the READ_ONCE() above. */ + WRITE_ONCE(con->dropped, dropped); + } + + nbcon_seq_try_update(ctxt, pmsg.seq + 1); + + return nbcon_context_exit_unsafe(ctxt); +} + /** * nbcon_alloc - Allocate buffers needed by the nbcon console * @con: Console to allocate buffers for diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c index 325ba9a1f6e7..683100002de7 100644 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -696,9 +696,6 @@ static ssize_t msg_print_ext_body(char *buf, size_t siz= e, return len; } =20 -static bool printk_get_next_message(struct printk_message *pmsg, u64 seq, - bool is_extended, bool may_supress); - /* /dev/kmsg - userspace message inject/listen interface */ struct devkmsg_user { atomic64_t seq; @@ -2731,7 +2728,7 @@ static void __console_unlock(void) * If @pmsg->pbufs->outbuf is modified, @pmsg->outbuf_len is updated. */ #ifdef CONFIG_PRINTK -static void console_prepend_dropped(struct printk_message *pmsg, unsigned = long dropped) +void console_prepend_dropped(struct printk_message *pmsg, unsigned long dr= opped) { struct printk_buffers *pbufs =3D pmsg->pbufs; const size_t scratchbuf_sz =3D sizeof(pbufs->scratchbuf); @@ -2785,8 +2782,8 @@ static void console_prepend_dropped(struct printk_mes= sage *pmsg, unsigned long d * of @pmsg are valid. (See the documentation of struct printk_message * for information about the @pmsg fields.) */ -static bool printk_get_next_message(struct printk_message *pmsg, u64 seq, - bool is_extended, bool may_suppress) +bool printk_get_next_message(struct printk_message *pmsg, u64 seq, + bool is_extended, bool may_suppress) { static int panic_console_dropped; =20 --=20 2.39.2 From nobody Thu Dec 18 19:05:48 2025 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 B27F6EEB562 for ; Fri, 8 Sep 2023 18:57:47 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S242912AbjIHS5t (ORCPT ); Fri, 8 Sep 2023 14:57:49 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:46464 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234527AbjIHS5s (ORCPT ); Fri, 8 Sep 2023 14:57:48 -0400 Received: from galois.linutronix.de (Galois.linutronix.de [IPv6:2a0a:51c0:0:12e:550::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 5D0351BF for ; Fri, 8 Sep 2023 11:57:13 -0700 (PDT) From: John Ogness DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020; t=1694199014; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=zsoNHH89SNtOZCvpJWTZfwP83WCUYW1q+GgTPpFsUgQ=; b=hIWEQ7KuQv9FBY8NoQ+5XKehruQdzQOY55LvRTXxGX4SGujykUUa1B/ClZ/Mn49g5RXb/9 LWAHpzRxfgkFq1sFL5FppACC23jdXqbjJo+jAaUqkZr/2mL0QW5BHNIBmyT+mBg4ZpGWms 0M9Ywr+5eVkynAG7O6Sq25+nUcpvMAMEzVHnrvdyZ4pJLHGsD2UuCMdyvgxf43cqVieNqH HpsA1FKG/EPbjrIJstDWnX3ETm+pvDoLh2L1qQozW/rweGvfL/5xlaUGgSJg3HMv642sUY fdf6a51GtTkFJlKlat7ZS77vRTAElyHQGQCScCaSnwAVH6BwziThTVA/WIHD1w== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020e; t=1694199014; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=zsoNHH89SNtOZCvpJWTZfwP83WCUYW1q+GgTPpFsUgQ=; b=g1Fp77vT+dxtiKsbcMzs7QqKe5l15ACNRRe27b4h77Hye7mUVYYM2gq7t/4hR0Dq59vzf3 Obbx5joHPKcxFqAA== To: Petr Mladek Cc: Sergey Senozhatsky , Steven Rostedt , Thomas Gleixner , linux-kernel@vger.kernel.org, Greg Kroah-Hartman Subject: [PATCH printk v4 8/8] printk: nbcon: Allow drivers to mark unsafe regions and check state Date: Fri, 8 Sep 2023 20:56:08 +0206 Message-Id: <20230908185008.468566-9-john.ogness@linutronix.de> In-Reply-To: <20230908185008.468566-1-john.ogness@linutronix.de> References: <20230908185008.468566-1-john.ogness@linutronix.de> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" From: Thomas Gleixner For the write_atomic callback, the console driver may have unsafe regions that need to be appropriately marked. Provide functions that accept the nbcon_write_context struct to allow for the driver to enter and exit unsafe regions. Also provide a function for drivers to check if they are still the owner of the console. Co-developed-by: John Ogness Signed-off-by: John Ogness Signed-off-by: Thomas Gleixner (Intel) Reviewed-by: Petr Mladek --- include/linux/console.h | 10 +++++++ kernel/printk/nbcon.c | 66 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+) diff --git a/include/linux/console.h b/include/linux/console.h index 0ce7a2a856ab..de8fd92a960b 100644 --- a/include/linux/console.h +++ b/include/linux/console.h @@ -454,6 +454,16 @@ static inline bool console_is_registered(const struct = console *con) lockdep_assert_console_list_lock_held(); \ hlist_for_each_entry(con, &console_list, node) =20 +#ifdef CONFIG_PRINTK +extern bool nbcon_can_proceed(struct nbcon_write_context *wctxt); +extern bool nbcon_enter_unsafe(struct nbcon_write_context *wctxt); +extern bool nbcon_exit_unsafe(struct nbcon_write_context *wctxt); +#else +static inline bool nbcon_can_proceed(struct nbcon_write_context *wctxt) { = return false; } +static inline bool nbcon_enter_unsafe(struct nbcon_write_context *wctxt) {= return false; } +static inline bool nbcon_exit_unsafe(struct nbcon_write_context *wctxt) { = return false; } +#endif + extern int console_set_on_cmdline; extern struct console *early_console; =20 diff --git a/kernel/printk/nbcon.c b/kernel/printk/nbcon.c index e2c274f4142e..04fac73c6e96 100644 --- a/kernel/printk/nbcon.c +++ b/kernel/printk/nbcon.c @@ -660,6 +660,32 @@ static bool nbcon_context_can_proceed(struct nbcon_con= text *ctxt, struct nbcon_s return false; } =20 +/** + * nbcon_can_proceed - Check whether ownership can proceed + * @wctxt: The write context that was handed to the write function + * + * Return: True if this context still owns the console. False if + * ownership was handed over or taken. + * + * Must be invoked at appropriate safe places in the driver. + * + * When this function returns false then the calling context no longer owns + * the console and is no longer allowed to go forward. In this case it must + * back out immediately and carefully. The buffer content is also no longer + * trusted since it no longer belongs to the calling context. + */ +bool nbcon_can_proceed(struct nbcon_write_context *wctxt) +{ + struct nbcon_context *ctxt =3D &ACCESS_PRIVATE(wctxt, ctxt); + struct console *con =3D ctxt->console; + struct nbcon_state cur; + + nbcon_state_read(con, &cur); + + return nbcon_context_can_proceed(ctxt, &cur); +} +EXPORT_SYMBOL_GPL(nbcon_can_proceed); + #define nbcon_context_enter_unsafe(c) __nbcon_context_update_unsafe(c, tru= e) #define nbcon_context_exit_unsafe(c) __nbcon_context_update_unsafe(c, fals= e) =20 @@ -710,6 +736,46 @@ static bool __nbcon_context_update_unsafe(struct nbcon= _context *ctxt, bool unsaf return nbcon_context_can_proceed(ctxt, &cur); } =20 +/** + * nbcon_enter_unsafe - Enter an unsafe region in the driver + * @wctxt: The write context that was handed to the write function + * + * Return: True if this context still owns the console. False if + * ownership was handed over or taken. + * + * When this function returns false then the calling context no longer owns + * the console and is no longer allowed to go forward. In this case it must + * back out immediately and carefully. The buffer content is also no longer + * trusted since it no longer belongs to the calling context. + */ +bool nbcon_enter_unsafe(struct nbcon_write_context *wctxt) +{ + struct nbcon_context *ctxt =3D &ACCESS_PRIVATE(wctxt, ctxt); + + return nbcon_context_enter_unsafe(ctxt); +} +EXPORT_SYMBOL_GPL(nbcon_enter_unsafe); + +/** + * nbcon_exit_unsafe - Exit an unsafe region in the driver + * @wctxt: The write context that was handed to the write function + * + * Return: True if this context still owns the console. False if + * ownership was handed over or taken. + * + * When this function returns false then the calling context no longer owns + * the console and is no longer allowed to go forward. In this case it must + * back out immediately and carefully. The buffer content is also no longer + * trusted since it no longer belongs to the calling context. + */ +bool nbcon_exit_unsafe(struct nbcon_write_context *wctxt) +{ + struct nbcon_context *ctxt =3D &ACCESS_PRIVATE(wctxt, ctxt); + + return nbcon_context_exit_unsafe(ctxt); +} +EXPORT_SYMBOL_GPL(nbcon_exit_unsafe); + /** * nbcon_emit_next_record - Emit a record in the acquired context * @wctxt: The write context that will be handed to the write function --=20 2.39.2