Skip to content

Commit ecb5e1a

Browse files
KAGA-KOKOpmladek
authored andcommitted
printk: nbcon: Implement emergency sections
In emergency situations (something has gone wrong but the system continues to operate), usually important information (such as a backtrace) is generated via printk(). This information should be pushed out to the consoles ASAP. Add per-CPU emergency nesting tracking because an emergency can arise while in an emergency situation. Add functions to mark the beginning and end of emergency sections where the urgent messages are generated. Perform direct console flushing at the emergency priority if the current CPU is in an emergency state and it is safe to do so. Note that the emergency state is not system-wide. While one CPU is in an emergency state, another CPU may attempt to print console messages at normal priority. Also note that printk() already attempts to flush consoles in the caller context for normal priority. However, follow-up changes will introduce printing kthreads, in which case the normal priority printk() calls will offload to the kthreads. 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]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Petr Mladek <[email protected]>
1 parent 6690d6b commit ecb5e1a

File tree

3 files changed

+79
-1
lines changed

3 files changed

+79
-1
lines changed

include/linux/console.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -553,10 +553,14 @@ static inline bool console_is_registered(const struct console *con)
553553
hlist_for_each_entry(con, &console_list, node)
554554

555555
#ifdef CONFIG_PRINTK
556+
extern void nbcon_cpu_emergency_enter(void);
557+
extern void nbcon_cpu_emergency_exit(void);
556558
extern bool nbcon_can_proceed(struct nbcon_write_context *wctxt);
557559
extern bool nbcon_enter_unsafe(struct nbcon_write_context *wctxt);
558560
extern bool nbcon_exit_unsafe(struct nbcon_write_context *wctxt);
559561
#else
562+
static inline void nbcon_cpu_emergency_enter(void) { }
563+
static inline void nbcon_cpu_emergency_exit(void) { }
560564
static inline bool nbcon_can_proceed(struct nbcon_write_context *wctxt) { return false; }
561565
static inline bool nbcon_enter_unsafe(struct nbcon_write_context *wctxt) { return false; }
562566
static inline bool nbcon_exit_unsafe(struct nbcon_write_context *wctxt) { return false; }

kernel/printk/internal.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,7 @@ static inline void printk_get_console_flush_type(struct console_flush_type *ft)
182182

183183
switch (nbcon_get_default_prio()) {
184184
case NBCON_PRIO_NORMAL:
185+
case NBCON_PRIO_EMERGENCY:
185186
if (have_nbcon_console && !have_boot_console)
186187
ft->nbcon_atomic = true;
187188

kernel/printk/nbcon.c

Lines changed: 74 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -972,6 +972,36 @@ static bool nbcon_emit_next_record(struct nbcon_write_context *wctxt)
972972
return nbcon_context_exit_unsafe(ctxt);
973973
}
974974

975+
/* Track the nbcon emergency nesting per CPU. */
976+
static DEFINE_PER_CPU(unsigned int, nbcon_pcpu_emergency_nesting);
977+
static unsigned int early_nbcon_pcpu_emergency_nesting __initdata;
978+
979+
/**
980+
* nbcon_get_cpu_emergency_nesting - Get the per CPU emergency nesting pointer
981+
*
982+
* Context: For reading, any context. For writing, any context which could
983+
* not be migrated to another CPU.
984+
* Return: Either a pointer to the per CPU emergency nesting counter of
985+
* the current CPU or to the init data during early boot.
986+
*
987+
* The function is safe for reading per-CPU variables in any context because
988+
* preemption is disabled if the current CPU is in the emergency state. See
989+
* also nbcon_cpu_emergency_enter().
990+
*/
991+
static __ref unsigned int *nbcon_get_cpu_emergency_nesting(void)
992+
{
993+
/*
994+
* The value of __printk_percpu_data_ready gets set in normal
995+
* context and before SMP initialization. As a result it could
996+
* never change while inside an nbcon emergency section.
997+
*/
998+
if (!printk_percpu_data_ready())
999+
return &early_nbcon_pcpu_emergency_nesting;
1000+
1001+
/* Open code this_cpu_ptr() without checking migration. */
1002+
return per_cpu_ptr(&nbcon_pcpu_emergency_nesting, raw_smp_processor_id());
1003+
}
1004+
9751005
/**
9761006
* nbcon_get_default_prio - The appropriate nbcon priority to use for nbcon
9771007
* printing on the current CPU
@@ -981,13 +1011,20 @@ static bool nbcon_emit_next_record(struct nbcon_write_context *wctxt)
9811011
* context for printing.
9821012
*
9831013
* The function is safe for reading per-CPU data in any context because
984-
* preemption is disabled if the current CPU is in the panic state.
1014+
* preemption is disabled if the current CPU is in the emergency or panic
1015+
* state.
9851016
*/
9861017
enum nbcon_prio nbcon_get_default_prio(void)
9871018
{
1019+
unsigned int *cpu_emergency_nesting;
1020+
9881021
if (this_cpu_in_panic())
9891022
return NBCON_PRIO_PANIC;
9901023

1024+
cpu_emergency_nesting = nbcon_get_cpu_emergency_nesting();
1025+
if (*cpu_emergency_nesting)
1026+
return NBCON_PRIO_EMERGENCY;
1027+
9911028
return NBCON_PRIO_NORMAL;
9921029
}
9931030

@@ -1246,6 +1283,42 @@ void nbcon_atomic_flush_unsafe(void)
12461283
__nbcon_atomic_flush_pending(prb_next_reserve_seq(prb), true);
12471284
}
12481285

1286+
/**
1287+
* nbcon_cpu_emergency_enter - Enter an emergency section where printk()
1288+
* messages for that CPU are flushed directly
1289+
*
1290+
* Context: Any context. Disables preemption.
1291+
*
1292+
* When within an emergency section, printk() calls will attempt to flush any
1293+
* pending messages in the ringbuffer.
1294+
*/
1295+
void nbcon_cpu_emergency_enter(void)
1296+
{
1297+
unsigned int *cpu_emergency_nesting;
1298+
1299+
preempt_disable();
1300+
1301+
cpu_emergency_nesting = nbcon_get_cpu_emergency_nesting();
1302+
(*cpu_emergency_nesting)++;
1303+
}
1304+
1305+
/**
1306+
* nbcon_cpu_emergency_exit - Exit an emergency section
1307+
*
1308+
* Context: Within an emergency section. Enables preemption.
1309+
*/
1310+
void nbcon_cpu_emergency_exit(void)
1311+
{
1312+
unsigned int *cpu_emergency_nesting;
1313+
1314+
cpu_emergency_nesting = nbcon_get_cpu_emergency_nesting();
1315+
1316+
if (!WARN_ON_ONCE(*cpu_emergency_nesting == 0))
1317+
(*cpu_emergency_nesting)--;
1318+
1319+
preempt_enable();
1320+
}
1321+
12491322
/**
12501323
* nbcon_alloc - Allocate and init the nbcon console specific data
12511324
* @con: Console to initialize

0 commit comments

Comments
 (0)