Skip to content

Commit 98d0052

Browse files
committed
Merge tag 'printk-for-6.2' of git://git.kernel.org/pub/scm/linux/kernel/git/printk/linux
Pull printk updates from Petr Mladek: - Add NMI-safe SRCU reader API. It uses atomic_inc() instead of this_cpu_inc() on strong load-store architectures. - Introduce new console_list_lock to synchronize a manipulation of the list of registered consoles and their flags. This is a first step in removing the big-kernel-lock-like behavior of console_lock(). This semaphore still serializes console->write() calbacks against: - each other. It primary prevents potential races between early and proper console drivers using the same device. - suspend()/resume() callbacks and init() operations in some drivers. - various other operations in the tty/vt and framebufer susbsystems. It is likely that console_lock() serializes even operations that are not directly conflicting with the console->write() callbacks here. This is the most complicated big-kernel-lock aspect of the console_lock() that will be hard to untangle. - Introduce new console_srcu lock that is used to safely iterate and access the registered console drivers under SRCU read lock. This is a prerequisite for introducing atomic console drivers and console kthreads. It will reduce the complexity of serialization against normal consoles and console_lock(). Also it should remove the risk of deadlock during critical situations, like Oops or panic, when only atomic consoles are registered. - Check whether the console is registered instead of enabled on many locations. It was a historical leftover. - Cleanly force a preferred console in xenfb code instead of a dirty hack. - A lot of code and comment clean ups and improvements. * tag 'printk-for-6.2' of git://git.kernel.org/pub/scm/linux/kernel/git/printk/linux: (47 commits) printk: htmldocs: add missing description tty: serial: sh-sci: use setup() callback for early console printk: relieve console_lock of list synchronization duties tty: serial: kgdboc: use console_list_lock to trap exit tty: serial: kgdboc: synchronize tty_find_polling_driver() and register_console() tty: serial: kgdboc: use console_list_lock for list traversal tty: serial: kgdboc: use srcu console list iterator proc: consoles: use console_list_lock for list iteration tty: tty_io: use console_list_lock for list synchronization printk, xen: fbfront: create/use safe function for forcing preferred netconsole: avoid CON_ENABLED misuse to track registration usb: early: xhci-dbc: use console_is_registered() tty: serial: xilinx_uartps: use console_is_registered() tty: serial: samsung_tty: use console_is_registered() tty: serial: pic32_uart: use console_is_registered() tty: serial: earlycon: use console_is_registered() tty: hvc: use console_is_registered() efi: earlycon: use console_is_registered() tty: nfcon: use console_is_registered() serial_core: replace uart_console_enabled() with uart_console_registered() ...
2 parents 73fa58d + 6b2b0d8 commit 98d0052

32 files changed

+725
-237
lines changed

.clang-format

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,7 @@ ForEachMacros:
222222
- 'for_each_component_dais'
223223
- 'for_each_component_dais_safe'
224224
- 'for_each_console'
225+
- 'for_each_console_srcu'
225226
- 'for_each_cpu'
226227
- 'for_each_cpu_and'
227228
- 'for_each_cpu_not'

arch/m68k/emu/nfcon.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ static void nfcon_write(struct console *con, const char *str,
4949
static struct tty_driver *nfcon_device(struct console *con, int *index)
5050
{
5151
*index = 0;
52-
return (con->flags & CON_ENABLED) ? nfcon_tty_driver : NULL;
52+
return console_is_registered(con) ? nfcon_tty_driver : NULL;
5353
}
5454

5555
static struct console nf_console = {
@@ -107,6 +107,11 @@ static int __init nf_debug_setup(char *arg)
107107

108108
stderr_id = nf_get_id("NF_STDERR");
109109
if (stderr_id) {
110+
/*
111+
* The console will be enabled when debug=nfcon is specified
112+
* as a kernel parameter. Since this is a non-standard way
113+
* of enabling consoles, it must be explicitly enabled.
114+
*/
110115
nf_console.flags |= CON_ENABLED;
111116
register_console(&nf_console);
112117
}
@@ -151,7 +156,7 @@ static int __init nfcon_init(void)
151156

152157
nfcon_tty_driver = driver;
153158

154-
if (!(nf_console.flags & CON_ENABLED))
159+
if (!console_is_registered(&nf_console))
155160
register_console(&nf_console);
156161

157162
return 0;

arch/um/kernel/kmsg_dump.c

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,20 +16,26 @@ static void kmsg_dumper_stdout(struct kmsg_dumper *dumper,
1616
struct console *con;
1717
unsigned long flags;
1818
size_t len = 0;
19+
int cookie;
1920

20-
/* only dump kmsg when no console is available */
21-
if (!console_trylock())
22-
return;
21+
/*
22+
* If no consoles are available to output crash information, dump
23+
* the kmsg buffer to stdout.
24+
*/
2325

24-
for_each_console(con) {
25-
if(strcmp(con->name, "tty") == 0 &&
26-
(con->flags & (CON_ENABLED | CON_CONSDEV)) != 0) {
26+
cookie = console_srcu_read_lock();
27+
for_each_console_srcu(con) {
28+
/*
29+
* The ttynull console and disabled consoles are ignored
30+
* since they cannot output. All other consoles are
31+
* expected to output the crash information.
32+
*/
33+
if (strcmp(con->name, "ttynull") != 0 &&
34+
(console_srcu_read_flags(con) & CON_ENABLED)) {
2735
break;
2836
}
2937
}
30-
31-
console_unlock();
32-
38+
console_srcu_read_unlock(cookie);
3339
if (con)
3440
return;
3541

drivers/firmware/efi/earlycon.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@ static void *efi_fb;
2929
*/
3030
static int __init efi_earlycon_remap_fb(void)
3131
{
32-
/* bail if there is no bootconsole or it has been disabled already */
33-
if (!earlycon_console || !(earlycon_console->flags & CON_ENABLED))
32+
/* bail if there is no bootconsole or it was unregistered already */
33+
if (!earlycon_console || !console_is_registered(earlycon_console))
3434
return 0;
3535

3636
efi_fb = memremap(fb_base, screen_info.lfb_size,
@@ -42,8 +42,8 @@ early_initcall(efi_earlycon_remap_fb);
4242

4343
static int __init efi_earlycon_unmap_fb(void)
4444
{
45-
/* unmap the bootconsole fb unless keep_bootcon has left it enabled */
46-
if (efi_fb && !(earlycon_console->flags & CON_ENABLED))
45+
/* unmap the bootconsole fb unless keep_bootcon left it registered */
46+
if (efi_fb && !console_is_registered(earlycon_console))
4747
memunmap(efi_fb);
4848
return 0;
4949
}

drivers/net/netconsole.c

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -332,10 +332,8 @@ static ssize_t enabled_store(struct config_item *item,
332332
}
333333

334334
if (enabled) { /* true */
335-
if (nt->extended && !(netconsole_ext.flags & CON_ENABLED)) {
336-
netconsole_ext.flags |= CON_ENABLED;
335+
if (nt->extended && !console_is_registered(&netconsole_ext))
337336
register_console(&netconsole_ext);
338-
}
339337

340338
/*
341339
* Skip netpoll_parse_options() -- all the attributes are
@@ -869,7 +867,7 @@ static void write_msg(struct console *con, const char *msg, unsigned int len)
869867

870868
static struct console netconsole_ext = {
871869
.name = "netcon_ext",
872-
.flags = CON_EXTENDED, /* starts disabled, registered on first use */
870+
.flags = CON_ENABLED | CON_EXTENDED,
873871
.write = write_ext_msg,
874872
};
875873

@@ -883,6 +881,7 @@ static int __init init_netconsole(void)
883881
{
884882
int err;
885883
struct netconsole_target *nt, *tmp;
884+
bool extended = false;
886885
unsigned long flags;
887886
char *target_config;
888887
char *input = config;
@@ -895,11 +894,12 @@ static int __init init_netconsole(void)
895894
goto fail;
896895
}
897896
/* Dump existing printks when we register */
898-
if (nt->extended)
899-
netconsole_ext.flags |= CON_PRINTBUFFER |
900-
CON_ENABLED;
901-
else
897+
if (nt->extended) {
898+
extended = true;
899+
netconsole_ext.flags |= CON_PRINTBUFFER;
900+
} else {
902901
netconsole.flags |= CON_PRINTBUFFER;
902+
}
903903

904904
spin_lock_irqsave(&target_list_lock, flags);
905905
list_add(&nt->list, &target_list);
@@ -915,7 +915,7 @@ static int __init init_netconsole(void)
915915
if (err)
916916
goto undonotifier;
917917

918-
if (netconsole_ext.flags & CON_ENABLED)
918+
if (extended)
919919
register_console(&netconsole_ext);
920920
register_console(&netconsole);
921921
pr_info("network logging started\n");
@@ -945,7 +945,8 @@ static void __exit cleanup_netconsole(void)
945945
{
946946
struct netconsole_target *nt, *tmp;
947947

948-
unregister_console(&netconsole_ext);
948+
if (console_is_registered(&netconsole_ext))
949+
unregister_console(&netconsole_ext);
949950
unregister_console(&netconsole);
950951
dynamic_netconsole_exit();
951952
unregister_netdevice_notifier(&netconsole_netdev_notifier);

drivers/tty/hvc/hvc_console.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -264,8 +264,8 @@ static void hvc_port_destruct(struct tty_port *port)
264264

265265
static void hvc_check_console(int index)
266266
{
267-
/* Already enabled, bail out */
268-
if (hvc_console.flags & CON_ENABLED)
267+
/* Already registered, bail out */
268+
if (console_is_registered(&hvc_console))
269269
return;
270270

271271
/* If this index is what the user requested, then register

drivers/tty/serial/8250/8250_core.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -565,7 +565,7 @@ serial8250_register_ports(struct uart_driver *drv, struct device *dev)
565565

566566
up->port.dev = dev;
567567

568-
if (uart_console_enabled(&up->port))
568+
if (uart_console_registered(&up->port))
569569
pm_runtime_get_sync(up->port.dev);
570570

571571
serial8250_apply_quirks(up);

drivers/tty/serial/earlycon.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ int __init setup_earlycon(char *buf)
181181
if (!buf || !buf[0])
182182
return -EINVAL;
183183

184-
if (early_con.flags & CON_ENABLED)
184+
if (console_is_registered(&early_con))
185185
return -EALREADY;
186186

187187
again:
@@ -253,7 +253,7 @@ int __init of_setup_earlycon(const struct earlycon_id *match,
253253
bool big_endian;
254254
u64 addr;
255255

256-
if (early_con.flags & CON_ENABLED)
256+
if (console_is_registered(&early_con))
257257
return -EALREADY;
258258

259259
spin_lock_init(&port->lock);

drivers/tty/serial/kgdboc.c

Lines changed: 41 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -189,9 +189,27 @@ static int configure_kgdboc(void)
189189
if (kgdboc_register_kbd(&cptr))
190190
goto do_register;
191191

192+
/*
193+
* tty_find_polling_driver() can call uart_set_options()
194+
* (via poll_init) to configure the uart. Take the console_list_lock
195+
* in order to synchronize against register_console(), which can also
196+
* configure the uart via uart_set_options(). This also allows safe
197+
* traversal of the console list.
198+
*/
199+
console_list_lock();
200+
192201
p = tty_find_polling_driver(cptr, &tty_line);
193-
if (!p)
202+
if (!p) {
203+
console_list_unlock();
194204
goto noconfig;
205+
}
206+
207+
/*
208+
* Take console_lock to serialize device() callback with
209+
* other console operations. For example, fg_console is
210+
* modified under console_lock when switching vt.
211+
*/
212+
console_lock();
195213

196214
for_each_console(cons) {
197215
int idx;
@@ -202,6 +220,10 @@ static int configure_kgdboc(void)
202220
}
203221
}
204222

223+
console_unlock();
224+
225+
console_list_unlock();
226+
205227
kgdb_tty_driver = p;
206228
kgdb_tty_line = tty_line;
207229

@@ -449,6 +471,7 @@ static void kgdboc_earlycon_pre_exp_handler(void)
449471
{
450472
struct console *con;
451473
static bool already_warned;
474+
int cookie;
452475

453476
if (already_warned)
454477
return;
@@ -461,9 +484,14 @@ static void kgdboc_earlycon_pre_exp_handler(void)
461484
* serial drivers might be OK with this, print a warning once per
462485
* boot if we detect this case.
463486
*/
464-
for_each_console(con)
487+
cookie = console_srcu_read_lock();
488+
for_each_console_srcu(con) {
465489
if (con == kgdboc_earlycon_io_ops.cons)
466-
return;
490+
break;
491+
}
492+
console_srcu_read_unlock(cookie);
493+
if (con)
494+
return;
467495

468496
already_warned = true;
469497
pr_warn("kgdboc_earlycon is still using bootconsole\n");
@@ -528,7 +556,15 @@ static int __init kgdboc_earlycon_init(char *opt)
528556
* Look for a matching console, or if the name was left blank just
529557
* pick the first one we find.
530558
*/
531-
console_lock();
559+
560+
/*
561+
* Hold the console_list_lock to guarantee that no consoles are
562+
* unregistered until the kgdboc_earlycon setup is complete.
563+
* Trapping the exit() callback relies on exit() not being
564+
* called until the trap is setup. This also allows safe
565+
* traversal of the console list and race-free reading of @flags.
566+
*/
567+
console_list_lock();
532568
for_each_console(con) {
533569
if (con->write && con->read &&
534570
(con->flags & (CON_BOOT | CON_ENABLED)) &&
@@ -570,7 +606,7 @@ static int __init kgdboc_earlycon_init(char *opt)
570606
}
571607

572608
unlock:
573-
console_unlock();
609+
console_list_unlock();
574610

575611
/* Non-zero means malformed option so we always return zero */
576612
return 0;

drivers/tty/serial/pic32_uart.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -843,7 +843,7 @@ console_initcall(pic32_console_init);
843843
*/
844844
static int __init pic32_late_console_init(void)
845845
{
846-
if (!(pic32_console.flags & CON_ENABLED))
846+
if (!console_is_registered(&pic32_console))
847847
register_console(&pic32_console);
848848

849849
return 0;
@@ -919,7 +919,7 @@ static int pic32_uart_probe(struct platform_device *pdev)
919919
}
920920

921921
#ifdef CONFIG_SERIAL_PIC32_CONSOLE
922-
if (uart_console_enabled(port)) {
922+
if (uart_console_registered(port)) {
923923
/* The peripheral clock has been enabled by console_setup,
924924
* so disable it till the port is used.
925925
*/

0 commit comments

Comments
 (0)