Skip to content

Commit c903327

Browse files
committed
Merge tag 'printk-for-6.12' of git://git.kernel.org/pub/scm/linux/kernel/git/printk/linux
Pull printk updates from Petr Mladek: "This is the "last" part of the support for the new nbcon consoles. Where "nbcon" stays for "No Big console lock CONsoles" aka not under the console_lock. New callbacks are added to struct console: - write_thread() for flushing nbcon consoles in task context. - write_atomic() for flushing nbcon consoles in atomic context, including NMI. - con->device_lock() and device_unlock() for taking the driver specific lock, for example, port->lock. New printk-specific kthreads are created: - per-console kthreads which get responsible for flushing normal priority messages on nbcon consoles. - thread which gets responsible for flushing normal priority messages on all consoles when CONFIG_RT enabled. The new callbacks are called under a special per-console lock which has already been added back in v6.7. It allows to distinguish three severities: normal, emergency, and panic. A context with a higher priority could take over the ownership when it is safe even in the middle of handling a record. The panic context could do it even when it is not safe. But it is allowed only for the final desperate flush before entering the infinite loop. The new lock helps to flush the messages directly in emergency and panic contexts. But it is not enough in all situations: - console_lock() is still need for synchronization against boot consoles. - con->device_lock() is need for synchronization against other operations on the same HW, e.g. serial port speed setting, non-printk related read/write. The dependency on con->device_lock() is mutual. Any code taking the driver specific lock has to acquire the related nbcon console context as well. For example, see the new uart_port_lock() API. It provides the necessary synchronization against emergency and panic contexts where the messages are flushed only under the new per-console lock. Maybe surprisingly, a quite tricky part is the decision how to flush the consoles in various situations. It has to take into account: - message priority: normal, emergency, panic - scheduling context: task, atomic, deferred_legacy - registered consoles: boot, legacy, nbcon - threads are running: early boot, suspend, shutdown, panic - caller: printk(), pr_flush(), printk_flush_in_panic(), console_unlock(), console_start(), ... The primary decision is made in printk_get_console_flush_type(). It creates a hint what the caller should do: - flush nbcon consoles directly or via the kthread - call the legacy loop (console_unlock()) directly or via irq_work The existing behavior is preserved for the legacy consoles. The only exception is that they are not longer flushed directly from printk() in panic() before CPUs are stopped. But this blocking happens only when at least one nbcon console is registered. The motivation is to increase a chance to produce the crash dump. They legacy consoles might create a deadlock in compare with nbcon consoles. The nbcon console should allow to see the messages even when the crash dump fails. There are three possible ways how nbcon consoles are flushed: - The per-nbcon-console kthread is responsible for flushing messages added with the normal priority. This is the default mode. - The legacy loop, aka console_unlock(), is used when there is still a boot console registered. There is no easy way how to match an early console driver with a nbcon console driver. And the console_lock() provides the only reliable serialization at the moment. The legacy loop uses either con->write_atomic() or con->write_thread() callbacks depending on whether it is allowed to schedule. The atomic variant has to be used from printk(). - In other situations, the messages are flushed directly using write_atomic() which can be called in any context, including NMI. It is primary needed during early boot or shutdown, in emergency situations, and panic. The emergency priority is used by a code called within nbcon_cpu_emergency_enter()/exit(). At the moment, it is used in four situations: WARN(), Oops, lockdep, and RCU stall reports. Finally, there is no nbcon console at the moment. It means that the changes should _not_ modify the existing behavior. The only exception is CONFIG_RT which would force offloading the legacy loop, for normal priority context, into the dedicated kthread" * tag 'printk-for-6.12' of git://git.kernel.org/pub/scm/linux/kernel/git/printk/linux: (54 commits) printk: Avoid false positive lockdep report for legacy printing printk: nbcon: Assign nice -20 for printing threads printk: Implement legacy printer kthread for PREEMPT_RT tty: sysfs: Add nbcon support for 'active' proc: Add nbcon support for /proc/consoles proc: consoles: Add notation to c_start/c_stop printk: nbcon: Show replay message on takeover printk: Provide helper for message prepending printk: nbcon: Rely on kthreads for normal operation printk: nbcon: Use thread callback if in task context for legacy printk: nbcon: Relocate nbcon_atomic_emit_one() printk: nbcon: Introduce printer kthreads printk: nbcon: Init @nbcon_seq to highest possible printk: nbcon: Add context to usable() and emit() printk: Flush console on unregister_console() printk: Fail pr_flush() if before SYSTEM_SCHEDULING printk: nbcon: Add function for printers to reacquire ownership printk: nbcon: Use raw_cpu_ptr() instead of open coding printk: Use the BITS_PER_LONG macro lockdep: Mark emergency sections in lockdep splats ...
2 parents daa394f + daeed15 commit c903327

File tree

17 files changed

+2123
-211
lines changed

17 files changed

+2123
-211
lines changed

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -423,11 +423,11 @@ static int univ8250_console_setup(struct console *co, char *options)
423423

424424
port = &serial8250_ports[co->index].port;
425425
/* link port to console */
426-
port->cons = co;
426+
uart_port_set_cons(port, co);
427427

428428
retval = serial8250_console_setup(port, options, false);
429429
if (retval != 0)
430-
port->cons = NULL;
430+
uart_port_set_cons(port, NULL);
431431
return retval;
432432
}
433433

@@ -485,7 +485,7 @@ static int univ8250_console_match(struct console *co, char *name, int idx,
485485
continue;
486486

487487
co->index = i;
488-
port->cons = co;
488+
uart_port_set_cons(port, co);
489489
return serial8250_console_setup(port, options, true);
490490
}
491491

drivers/tty/serial/amba-pl011.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2480,7 +2480,7 @@ static int pl011_console_match(struct console *co, char *name, int idx,
24802480
continue;
24812481

24822482
co->index = i;
2483-
port->cons = co;
2483+
uart_port_set_cons(port, co);
24842484
return pl011_console_setup(co, options);
24852485
}
24862486

drivers/tty/serial/serial_core.c

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3176,8 +3176,15 @@ static int serial_core_add_one_port(struct uart_driver *drv, struct uart_port *u
31763176
state->uart_port = uport;
31773177
uport->state = state;
31783178

3179+
/*
3180+
* If this port is in use as a console then the spinlock is already
3181+
* initialised.
3182+
*/
3183+
if (!uart_console_registered(uport))
3184+
uart_port_spin_lock_init(uport);
3185+
31793186
state->pm_state = UART_PM_STATE_UNDEFINED;
3180-
uport->cons = drv->cons;
3187+
uart_port_set_cons(uport, drv->cons);
31813188
uport->minor = drv->tty_driver->minor_start + uport->line;
31823189
uport->name = kasprintf(GFP_KERNEL, "%s%d", drv->dev_name,
31833190
drv->tty_driver->name_base + uport->line);
@@ -3186,13 +3193,6 @@ static int serial_core_add_one_port(struct uart_driver *drv, struct uart_port *u
31863193
goto out;
31873194
}
31883195

3189-
/*
3190-
* If this port is in use as a console then the spinlock is already
3191-
* initialised.
3192-
*/
3193-
if (!uart_console_registered(uport))
3194-
uart_port_spin_lock_init(uport);
3195-
31963196
if (uport->cons && uport->dev)
31973197
of_console_check(uport->dev->of_node, uport->cons->name, uport->line);
31983198

drivers/tty/tty_io.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3573,7 +3573,7 @@ static ssize_t show_cons_active(struct device *dev,
35733573
for_each_console(c) {
35743574
if (!c->device)
35753575
continue;
3576-
if (!c->write)
3576+
if (!(c->flags & CON_NBCON) && !c->write)
35773577
continue;
35783578
if ((c->flags & CON_ENABLED) == 0)
35793579
continue;

fs/proc/consoles.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ static int show_console_dev(struct seq_file *m, void *v)
2121
{ CON_ENABLED, 'E' },
2222
{ CON_CONSDEV, 'C' },
2323
{ CON_BOOT, 'B' },
24+
{ CON_NBCON, 'N' },
2425
{ CON_PRINTBUFFER, 'p' },
2526
{ CON_BRL, 'b' },
2627
{ CON_ANYTIME, 'a' },
@@ -58,8 +59,8 @@ static int show_console_dev(struct seq_file *m, void *v)
5859
seq_printf(m, "%s%d", con->name, con->index);
5960
seq_pad(m, ' ');
6061
seq_printf(m, "%c%c%c (%s)", con->read ? 'R' : '-',
61-
con->write ? 'W' : '-', con->unblank ? 'U' : '-',
62-
flags);
62+
((con->flags & CON_NBCON) || con->write) ? 'W' : '-',
63+
con->unblank ? 'U' : '-', flags);
6364
if (dev)
6465
seq_printf(m, " %4d:%d", MAJOR(dev), MINOR(dev));
6566

@@ -68,6 +69,7 @@ static int show_console_dev(struct seq_file *m, void *v)
6869
}
6970

7071
static void *c_start(struct seq_file *m, loff_t *pos)
72+
__acquires(&console_mutex)
7173
{
7274
struct console *con;
7375
loff_t off = 0;
@@ -94,6 +96,7 @@ static void *c_next(struct seq_file *m, void *v, loff_t *pos)
9496
}
9597

9698
static void c_stop(struct seq_file *m, void *v)
99+
__releases(&console_mutex)
97100
{
98101
console_list_unlock();
99102
}

include/linux/console.h

Lines changed: 143 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@
1616

1717
#include <linux/atomic.h>
1818
#include <linux/bits.h>
19+
#include <linux/irq_work.h>
1920
#include <linux/rculist.h>
21+
#include <linux/rcuwait.h>
2022
#include <linux/types.h>
2123
#include <linux/vesa.h>
2224

@@ -303,7 +305,7 @@ struct nbcon_write_context {
303305
/**
304306
* struct console - The console descriptor structure
305307
* @name: The name of the console driver
306-
* @write: Write callback to output messages (Optional)
308+
* @write: Legacy write callback to output messages (Optional)
307309
* @read: Read callback for console input (Optional)
308310
* @device: The underlying TTY device driver (Optional)
309311
* @unblank: Callback to unblank the console (Optional)
@@ -320,10 +322,14 @@ struct nbcon_write_context {
320322
* @data: Driver private data
321323
* @node: hlist node for the console list
322324
*
323-
* @write_atomic: Write callback for atomic context
324325
* @nbcon_state: State for nbcon consoles
325326
* @nbcon_seq: Sequence number of the next record for nbcon to print
327+
* @nbcon_device_ctxt: Context available for non-printing operations
328+
* @nbcon_prev_seq: Seq num the previous nbcon owner was assigned to print
326329
* @pbufs: Pointer to nbcon private buffer
330+
* @kthread: Printer kthread for this console
331+
* @rcuwait: RCU-safe wait object for @kthread waking
332+
* @irq_work: Defer @kthread waking to IRQ work context
327333
*/
328334
struct console {
329335
char name[16];
@@ -345,11 +351,121 @@ struct console {
345351
struct hlist_node node;
346352

347353
/* nbcon console specific members */
348-
bool (*write_atomic)(struct console *con,
349-
struct nbcon_write_context *wctxt);
354+
355+
/**
356+
* @write_atomic:
357+
*
358+
* NBCON callback to write out text in any context. (Optional)
359+
*
360+
* This callback is called with the console already acquired. However,
361+
* a higher priority context is allowed to take it over by default.
362+
*
363+
* The callback must call nbcon_enter_unsafe() and nbcon_exit_unsafe()
364+
* around any code where the takeover is not safe, for example, when
365+
* manipulating the serial port registers.
366+
*
367+
* nbcon_enter_unsafe() will fail if the context has lost the console
368+
* ownership in the meantime. In this case, the callback is no longer
369+
* allowed to go forward. It must back out immediately and carefully.
370+
* The buffer content is also no longer trusted since it no longer
371+
* belongs to the context.
372+
*
373+
* The callback should allow the takeover whenever it is safe. It
374+
* increases the chance to see messages when the system is in trouble.
375+
* If the driver must reacquire ownership in order to finalize or
376+
* revert hardware changes, nbcon_reacquire_nobuf() can be used.
377+
* However, on reacquire the buffer content is no longer available. A
378+
* reacquire cannot be used to resume printing.
379+
*
380+
* The callback can be called from any context (including NMI).
381+
* Therefore it must avoid usage of any locking and instead rely
382+
* on the console ownership for synchronization.
383+
*/
384+
void (*write_atomic)(struct console *con, struct nbcon_write_context *wctxt);
385+
386+
/**
387+
* @write_thread:
388+
*
389+
* NBCON callback to write out text in task context.
390+
*
391+
* This callback must be called only in task context with both
392+
* device_lock() and the nbcon console acquired with
393+
* NBCON_PRIO_NORMAL.
394+
*
395+
* The same rules for console ownership verification and unsafe
396+
* sections handling applies as with write_atomic().
397+
*
398+
* The console ownership handling is necessary for synchronization
399+
* against write_atomic() which is synchronized only via the context.
400+
*
401+
* The device_lock() provides the primary serialization for operations
402+
* on the device. It might be as relaxed (mutex)[*] or as tight
403+
* (disabled preemption and interrupts) as needed. It allows
404+
* the kthread to operate in the least restrictive mode[**].
405+
*
406+
* [*] Standalone nbcon_context_try_acquire() is not safe with
407+
* the preemption enabled, see nbcon_owner_matches(). But it
408+
* can be safe when always called in the preemptive context
409+
* under the device_lock().
410+
*
411+
* [**] The device_lock() makes sure that nbcon_context_try_acquire()
412+
* would never need to spin which is important especially with
413+
* PREEMPT_RT.
414+
*/
415+
void (*write_thread)(struct console *con, struct nbcon_write_context *wctxt);
416+
417+
/**
418+
* @device_lock:
419+
*
420+
* NBCON callback to begin synchronization with driver code.
421+
*
422+
* Console drivers typically must deal with access to the hardware
423+
* via user input/output (such as an interactive login shell) and
424+
* output of kernel messages via printk() calls. This callback is
425+
* called by the printk-subsystem whenever it needs to synchronize
426+
* with hardware access by the driver. It should be implemented to
427+
* use whatever synchronization mechanism the driver is using for
428+
* itself (for example, the port lock for uart serial consoles).
429+
*
430+
* The callback is always called from task context. It may use any
431+
* synchronization method required by the driver.
432+
*
433+
* IMPORTANT: The callback MUST disable migration. The console driver
434+
* may be using a synchronization mechanism that already takes
435+
* care of this (such as spinlocks). Otherwise this function must
436+
* explicitly call migrate_disable().
437+
*
438+
* The flags argument is provided as a convenience to the driver. It
439+
* will be passed again to device_unlock(). It can be ignored if the
440+
* driver does not need it.
441+
*/
442+
void (*device_lock)(struct console *con, unsigned long *flags);
443+
444+
/**
445+
* @device_unlock:
446+
*
447+
* NBCON callback to finish synchronization with driver code.
448+
*
449+
* It is the counterpart to device_lock().
450+
*
451+
* This callback is always called from task context. It must
452+
* appropriately re-enable migration (depending on how device_lock()
453+
* disabled migration).
454+
*
455+
* The flags argument is the value of the same variable that was
456+
* passed to device_lock().
457+
*/
458+
void (*device_unlock)(struct console *con, unsigned long flags);
459+
350460
atomic_t __private nbcon_state;
351461
atomic_long_t __private nbcon_seq;
462+
struct nbcon_context __private nbcon_device_ctxt;
463+
atomic_long_t __private nbcon_prev_seq;
464+
352465
struct printk_buffers *pbufs;
466+
struct task_struct *kthread;
467+
struct rcuwait rcuwait;
468+
struct irq_work irq_work;
353469
};
354470

355471
#ifdef CONFIG_LOCKDEP
@@ -378,28 +494,34 @@ extern void console_list_unlock(void) __releases(console_mutex);
378494
extern struct hlist_head console_list;
379495

380496
/**
381-
* console_srcu_read_flags - Locklessly read the console flags
497+
* console_srcu_read_flags - Locklessly read flags of a possibly registered
498+
* console
382499
* @con: struct console pointer of console to read flags from
383500
*
384-
* This function provides the necessary READ_ONCE() and data_race()
385-
* notation for locklessly reading the console flags. The READ_ONCE()
386-
* in this function matches the WRITE_ONCE() when @flags are modified
387-
* for registered consoles with console_srcu_write_flags().
501+
* Locklessly reading @con->flags provides a consistent read value because
502+
* there is at most one CPU modifying @con->flags and that CPU is using only
503+
* read-modify-write operations to do so.
504+
*
505+
* Requires console_srcu_read_lock to be held, which implies that @con might
506+
* be a registered console. The purpose of holding console_srcu_read_lock is
507+
* to guarantee that the console state is valid (CON_SUSPENDED/CON_ENABLED)
508+
* and that no exit/cleanup routines will run if the console is currently
509+
* undergoing unregistration.
388510
*
389-
* Only use this function to read console flags when locklessly
390-
* iterating the console list via srcu.
511+
* If the caller is holding the console_list_lock or it is _certain_ that
512+
* @con is not and will not become registered, the caller may read
513+
* @con->flags directly instead.
391514
*
392515
* Context: Any context.
516+
* Return: The current value of the @con->flags field.
393517
*/
394518
static inline short console_srcu_read_flags(const struct console *con)
395519
{
396520
WARN_ON_ONCE(!console_srcu_read_lock_is_held());
397521

398522
/*
399-
* Locklessly reading console->flags provides a consistent
400-
* read value because there is at most one CPU modifying
401-
* console->flags and that CPU is using only read-modify-write
402-
* operations to do so.
523+
* The READ_ONCE() matches the WRITE_ONCE() when @flags are modified
524+
* for registered consoles with console_srcu_write_flags().
403525
*/
404526
return data_race(READ_ONCE(con->flags));
405527
}
@@ -477,13 +599,19 @@ static inline bool console_is_registered(const struct console *con)
477599
hlist_for_each_entry(con, &console_list, node)
478600

479601
#ifdef CONFIG_PRINTK
602+
extern void nbcon_cpu_emergency_enter(void);
603+
extern void nbcon_cpu_emergency_exit(void);
480604
extern bool nbcon_can_proceed(struct nbcon_write_context *wctxt);
481605
extern bool nbcon_enter_unsafe(struct nbcon_write_context *wctxt);
482606
extern bool nbcon_exit_unsafe(struct nbcon_write_context *wctxt);
607+
extern void nbcon_reacquire_nobuf(struct nbcon_write_context *wctxt);
483608
#else
609+
static inline void nbcon_cpu_emergency_enter(void) { }
610+
static inline void nbcon_cpu_emergency_exit(void) { }
484611
static inline bool nbcon_can_proceed(struct nbcon_write_context *wctxt) { return false; }
485612
static inline bool nbcon_enter_unsafe(struct nbcon_write_context *wctxt) { return false; }
486613
static inline bool nbcon_exit_unsafe(struct nbcon_write_context *wctxt) { return false; }
614+
static inline void nbcon_reacquire_nobuf(struct nbcon_write_context *wctxt) { }
487615
#endif
488616

489617
extern int console_set_on_cmdline;

include/linux/printk.h

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
#include <linux/ratelimit_types.h>
1010
#include <linux/once_lite.h>
1111

12+
struct console;
13+
1214
extern const char linux_banner[];
1315
extern const char linux_proc_banner[];
1416

@@ -161,15 +163,16 @@ int _printk(const char *fmt, ...);
161163
*/
162164
__printf(1, 2) __cold int _printk_deferred(const char *fmt, ...);
163165

164-
extern void __printk_safe_enter(void);
165-
extern void __printk_safe_exit(void);
166+
extern void __printk_deferred_enter(void);
167+
extern void __printk_deferred_exit(void);
168+
166169
/*
167170
* The printk_deferred_enter/exit macros are available only as a hack for
168171
* some code paths that need to defer all printk console printing. Interrupts
169172
* must be disabled for the deferred duration.
170173
*/
171-
#define printk_deferred_enter __printk_safe_enter
172-
#define printk_deferred_exit __printk_safe_exit
174+
#define printk_deferred_enter() __printk_deferred_enter()
175+
#define printk_deferred_exit() __printk_deferred_exit()
173176

174177
/*
175178
* Please don't use printk_ratelimit(), because it shares ratelimiting state
@@ -197,6 +200,10 @@ extern asmlinkage void dump_stack_lvl(const char *log_lvl) __cold;
197200
extern asmlinkage void dump_stack(void) __cold;
198201
void printk_trigger_flush(void);
199202
void console_try_replay_all(void);
203+
void printk_legacy_allow_panic_sync(void);
204+
extern bool nbcon_device_try_acquire(struct console *con);
205+
extern void nbcon_device_release(struct console *con);
206+
void nbcon_atomic_flush_unsafe(void);
200207
#else
201208
static inline __printf(1, 0)
202209
int vprintk(const char *s, va_list args)
@@ -279,6 +286,24 @@ static inline void printk_trigger_flush(void)
279286
static inline void console_try_replay_all(void)
280287
{
281288
}
289+
290+
static inline void printk_legacy_allow_panic_sync(void)
291+
{
292+
}
293+
294+
static inline bool nbcon_device_try_acquire(struct console *con)
295+
{
296+
return false;
297+
}
298+
299+
static inline void nbcon_device_release(struct console *con)
300+
{
301+
}
302+
303+
static inline void nbcon_atomic_flush_unsafe(void)
304+
{
305+
}
306+
282307
#endif
283308

284309
bool this_cpu_in_panic(void);

0 commit comments

Comments
 (0)