Skip to content

Commit 6b93bb4

Browse files
KAGA-KOKOpmladek
authored andcommitted
printk: Add non-BKL (nbcon) console basic infrastructure
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 <[email protected]> Signed-off-by: John Ogness <[email protected]> Signed-off-by: Thomas Gleixner (Intel) <[email protected]> Reviewed-by: Petr Mladek <[email protected]> Signed-off-by: Petr Mladek <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 01a46ef commit 6b93bb4

File tree

5 files changed

+120
-4
lines changed

5 files changed

+120
-4
lines changed

include/linux/console.h

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,8 @@ static inline int con_debug_leave(void)
156156
* /dev/kmesg which requires a larger output buffer.
157157
* @CON_SUSPENDED: Indicates if a console is suspended. If true, the
158158
* printing callbacks must not be called.
159+
* @CON_NBCON: Console can operate outside of the legacy style console_lock
160+
* constraints.
159161
*/
160162
enum cons_flags {
161163
CON_PRINTBUFFER = BIT(0),
@@ -166,8 +168,32 @@ enum cons_flags {
166168
CON_BRL = BIT(5),
167169
CON_EXTENDED = BIT(6),
168170
CON_SUSPENDED = BIT(7),
171+
CON_NBCON = BIT(8),
169172
};
170173

174+
/**
175+
* struct nbcon_state - console state for nbcon consoles
176+
* @atom: Compound of the state fields for atomic operations
177+
*
178+
* To be used for reading and preparing of the value stored in the nbcon
179+
* state variable @console::nbcon_state.
180+
*/
181+
struct nbcon_state {
182+
union {
183+
unsigned int atom;
184+
struct {
185+
};
186+
};
187+
};
188+
189+
/*
190+
* The nbcon_state struct is used to easily create and interpret values that
191+
* are stored in the @console::nbcon_state variable. Ensure this struct stays
192+
* within the size boundaries of the atomic variable's underlying type in
193+
* order to avoid any accidental truncation.
194+
*/
195+
static_assert(sizeof(struct nbcon_state) <= sizeof(int));
196+
171197
/**
172198
* struct console - The console descriptor structure
173199
* @name: The name of the console driver
@@ -187,6 +213,8 @@ enum cons_flags {
187213
* @dropped: Number of unreported dropped ringbuffer records
188214
* @data: Driver private data
189215
* @node: hlist node for the console list
216+
*
217+
* @nbcon_state: State for nbcon consoles
190218
*/
191219
struct console {
192220
char name[16];
@@ -206,6 +234,9 @@ struct console {
206234
unsigned long dropped;
207235
void *data;
208236
struct hlist_node node;
237+
238+
/* nbcon console specific members */
239+
atomic_t __private nbcon_state;
209240
};
210241

211242
#ifdef CONFIG_LOCKDEP

kernel/printk/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# SPDX-License-Identifier: GPL-2.0-only
22
obj-y = printk.o
3-
obj-$(CONFIG_PRINTK) += printk_safe.o
3+
obj-$(CONFIG_PRINTK) += printk_safe.o nbcon.o
44
obj-$(CONFIG_A11Y_BRAILLE_CONSOLE) += braille.o
55
obj-$(CONFIG_PRINTK_INDEX) += index.o
66

kernel/printk/internal.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
* internal.h - printk internal definitions
44
*/
55
#include <linux/percpu.h>
6+
#include <linux/console.h>
67

78
#if defined(CONFIG_PRINTK) && defined(CONFIG_SYSCTL)
89
void __init printk_sysctl_init(void);
@@ -61,6 +62,10 @@ void defer_console_output(void);
6162

6263
u16 printk_parse_prefix(const char *text, int *level,
6364
enum printk_info_flags *flags);
65+
66+
void nbcon_init(struct console *con);
67+
void nbcon_cleanup(struct console *con);
68+
6469
#else
6570

6671
#define PRINTK_PREFIX_MAX 0
@@ -76,6 +81,9 @@ u16 printk_parse_prefix(const char *text, int *level,
7681
#define printk_safe_exit_irqrestore(flags) local_irq_restore(flags)
7782

7883
static inline bool printk_percpu_data_ready(void) { return false; }
84+
static inline void nbcon_init(struct console *con) { }
85+
static inline void nbcon_cleanup(struct console *con) { }
86+
7987
#endif /* CONFIG_PRINTK */
8088

8189
/**

kernel/printk/nbcon.c

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
// SPDX-License-Identifier: GPL-2.0-only
2+
// Copyright (C) 2022 Linutronix GmbH, John Ogness
3+
// Copyright (C) 2022 Intel, Thomas Gleixner
4+
5+
#include <linux/kernel.h>
6+
#include <linux/console.h>
7+
#include "internal.h"
8+
/*
9+
* Printk console printing implementation for consoles which does not depend
10+
* on the legacy style console_lock mechanism.
11+
*/
12+
13+
/**
14+
* nbcon_state_set - Helper function to set the console state
15+
* @con: Console to update
16+
* @new: The new state to write
17+
*
18+
* Only to be used when the console is not yet or no longer visible in the
19+
* system. Otherwise use nbcon_state_try_cmpxchg().
20+
*/
21+
static inline void nbcon_state_set(struct console *con, struct nbcon_state *new)
22+
{
23+
atomic_set(&ACCESS_PRIVATE(con, nbcon_state), new->atom);
24+
}
25+
26+
/**
27+
* nbcon_state_read - Helper function to read the console state
28+
* @con: Console to read
29+
* @state: The state to store the result
30+
*/
31+
static inline void nbcon_state_read(struct console *con, struct nbcon_state *state)
32+
{
33+
state->atom = atomic_read(&ACCESS_PRIVATE(con, nbcon_state));
34+
}
35+
36+
/**
37+
* nbcon_state_try_cmpxchg() - Helper function for atomic_try_cmpxchg() on console state
38+
* @con: Console to update
39+
* @cur: Old/expected state
40+
* @new: New state
41+
*
42+
* Return: True on success. False on fail and @cur is updated.
43+
*/
44+
static inline bool nbcon_state_try_cmpxchg(struct console *con, struct nbcon_state *cur,
45+
struct nbcon_state *new)
46+
{
47+
return atomic_try_cmpxchg(&ACCESS_PRIVATE(con, nbcon_state), &cur->atom, new->atom);
48+
}
49+
50+
/**
51+
* nbcon_init - Initialize the nbcon console specific data
52+
* @con: Console to initialize
53+
*/
54+
void nbcon_init(struct console *con)
55+
{
56+
struct nbcon_state state = { };
57+
58+
nbcon_state_set(con, &state);
59+
}
60+
61+
/**
62+
* nbcon_cleanup - Cleanup the nbcon console specific data
63+
* @con: Console to cleanup
64+
*/
65+
void nbcon_cleanup(struct console *con)
66+
{
67+
struct nbcon_state state = { };
68+
69+
nbcon_state_set(con, &state);
70+
}

kernel/printk/printk.c

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3326,9 +3326,10 @@ static void try_enable_default_console(struct console *newcon)
33263326
newcon->flags |= CON_CONSDEV;
33273327
}
33283328

3329-
#define con_printk(lvl, con, fmt, ...) \
3330-
printk(lvl pr_fmt("%sconsole [%s%d] " fmt), \
3331-
(con->flags & CON_BOOT) ? "boot" : "", \
3329+
#define con_printk(lvl, con, fmt, ...) \
3330+
printk(lvl pr_fmt("%s%sconsole [%s%d] " fmt), \
3331+
(con->flags & CON_NBCON) ? "" : "legacy ", \
3332+
(con->flags & CON_BOOT) ? "boot" : "", \
33323333
con->name, con->index, ##__VA_ARGS__)
33333334

33343335
static void console_init_seq(struct console *newcon, bool bootcon_registered)
@@ -3488,6 +3489,9 @@ void register_console(struct console *newcon)
34883489
newcon->dropped = 0;
34893490
console_init_seq(newcon, bootcon_registered);
34903491

3492+
if (newcon->flags & CON_NBCON)
3493+
nbcon_init(newcon);
3494+
34913495
/*
34923496
* Put this console in the list - keep the
34933497
* preferred driver at the head of the list.
@@ -3579,6 +3583,9 @@ static int unregister_console_locked(struct console *console)
35793583
*/
35803584
synchronize_srcu(&console_srcu);
35813585

3586+
if (console->flags & CON_NBCON)
3587+
nbcon_cleanup(console);
3588+
35823589
console_sysfs_notify();
35833590

35843591
if (console->exit)

0 commit comments

Comments
 (0)