Skip to content

Commit 2bb2b7b

Browse files
jognesspmladek
authored andcommitted
printk: add functions to prefer direct printing
Once kthread printing is available, console printing will no longer occur in the context of the printk caller. However, there are some special contexts where it is desirable for the printk caller to directly print out kernel messages. Using pr_flush() to wait for threaded printers is only possible if the caller is in a sleepable context and the kthreads are active. That is not always the case. Introduce printk_prefer_direct_enter() and printk_prefer_direct_exit() functions to explicitly (and globally) activate/deactivate preferred direct console printing. The term "direct console printing" refers to printing to all enabled consoles from the context of the printk caller. The term "prefer" is used because this type of printing is only best effort. If the console is currently locked or other printers are already actively printing, the printk caller will need to rely on the other contexts to handle the printing. This preferred direct printing is how all printing has been handled until now (unless it was explicitly deferred). When kthread printing is introduced, there may be some unanticipated problems due to kthreads being unable to flush important messages. In order to minimize such risks, preferred direct printing is activated for the primary important messages when the system experiences general types of major errors. These are: - emergency reboot/shutdown - cpu and rcu stalls - hard and soft lockups - hung tasks - warn - sysrq Note that since kthread printing does not yet exist, no behavior changes result from this commit. This is only implementing the counter and marking the various places where preferred direct printing is active. Signed-off-by: John Ogness <john.ogness@linutronix.de> Reviewed-by: Petr Mladek <pmladek@suse.com> Acked-by: Paul E. McKenney <paulmck@kernel.org> # for RCU Signed-off-by: Petr Mladek <pmladek@suse.com> Link: https://lore.kernel.org/r/20220421212250.565456-13-john.ogness@linutronix.de
1 parent 3b604ca commit 2bb2b7b

File tree

9 files changed

+78
-2
lines changed

9 files changed

+78
-2
lines changed

drivers/tty/sysrq.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -578,6 +578,7 @@ void __handle_sysrq(int key, bool check_mask)
578578

579579
rcu_sysrq_start();
580580
rcu_read_lock();
581+
printk_prefer_direct_enter();
581582
/*
582583
* Raise the apparent loglevel to maximum so that the sysrq header
583584
* is shown to provide the user with positive feedback. We do not
@@ -619,6 +620,7 @@ void __handle_sysrq(int key, bool check_mask)
619620
pr_cont("\n");
620621
console_loglevel = orig_log_level;
621622
}
623+
printk_prefer_direct_exit();
622624
rcu_read_unlock();
623625
rcu_sysrq_end();
624626

include/linux/printk.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,9 @@ extern void __printk_safe_exit(void);
170170
#define printk_deferred_enter __printk_safe_enter
171171
#define printk_deferred_exit __printk_safe_exit
172172

173+
extern void printk_prefer_direct_enter(void);
174+
extern void printk_prefer_direct_exit(void);
175+
173176
extern bool pr_flush(int timeout_ms, bool reset_on_progress);
174177

175178
/*
@@ -222,6 +225,14 @@ static inline void printk_deferred_exit(void)
222225
{
223226
}
224227

228+
static inline void printk_prefer_direct_enter(void)
229+
{
230+
}
231+
232+
static inline void printk_prefer_direct_exit(void)
233+
{
234+
}
235+
225236
static inline bool pr_flush(int timeout_ms, bool reset_on_progress)
226237
{
227238
return true;

kernel/hung_task.c

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,8 @@ static void check_hung_task(struct task_struct *t, unsigned long timeout)
127127
* complain:
128128
*/
129129
if (sysctl_hung_task_warnings) {
130+
printk_prefer_direct_enter();
131+
130132
if (sysctl_hung_task_warnings > 0)
131133
sysctl_hung_task_warnings--;
132134
pr_err("INFO: task %s:%d blocked for more than %ld seconds.\n",
@@ -142,6 +144,8 @@ static void check_hung_task(struct task_struct *t, unsigned long timeout)
142144

143145
if (sysctl_hung_task_all_cpu_backtrace)
144146
hung_task_show_all_bt = true;
147+
148+
printk_prefer_direct_exit();
145149
}
146150

147151
touch_nmi_watchdog();
@@ -204,12 +208,17 @@ static void check_hung_uninterruptible_tasks(unsigned long timeout)
204208
}
205209
unlock:
206210
rcu_read_unlock();
207-
if (hung_task_show_lock)
211+
if (hung_task_show_lock) {
212+
printk_prefer_direct_enter();
208213
debug_show_all_locks();
214+
printk_prefer_direct_exit();
215+
}
209216

210217
if (hung_task_show_all_bt) {
211218
hung_task_show_all_bt = false;
219+
printk_prefer_direct_enter();
212220
trigger_all_cpu_backtrace();
221+
printk_prefer_direct_exit();
213222
}
214223

215224
if (hung_task_call_panic)

kernel/panic.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -560,6 +560,8 @@ void __warn(const char *file, int line, void *caller, unsigned taint,
560560
{
561561
disable_trace_on_warning();
562562

563+
printk_prefer_direct_enter();
564+
563565
if (file)
564566
pr_warn("WARNING: CPU: %d PID: %d at %s:%d %pS\n",
565567
raw_smp_processor_id(), current->pid, file, line,
@@ -597,6 +599,8 @@ void __warn(const char *file, int line, void *caller, unsigned taint,
597599

598600
/* Just a warning, don't kill lockdep. */
599601
add_taint(taint, LOCKDEP_STILL_OK);
602+
603+
printk_prefer_direct_exit();
600604
}
601605

602606
#ifndef __WARN_FLAGS

kernel/printk/printk.c

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,34 @@ static int console_msg_format = MSG_FORMAT_DEFAULT;
362362
static DEFINE_MUTEX(syslog_lock);
363363

364364
#ifdef CONFIG_PRINTK
365+
static atomic_t printk_prefer_direct = ATOMIC_INIT(0);
366+
367+
/**
368+
* printk_prefer_direct_enter - cause printk() calls to attempt direct
369+
* printing to all enabled consoles
370+
*
371+
* Since it is not possible to call into the console printing code from any
372+
* context, there is no guarantee that direct printing will occur.
373+
*
374+
* This globally effects all printk() callers.
375+
*
376+
* Context: Any context.
377+
*/
378+
void printk_prefer_direct_enter(void)
379+
{
380+
atomic_inc(&printk_prefer_direct);
381+
}
382+
383+
/**
384+
* printk_prefer_direct_exit - restore printk() behavior
385+
*
386+
* Context: Any context.
387+
*/
388+
void printk_prefer_direct_exit(void)
389+
{
390+
WARN_ON(atomic_dec_if_positive(&printk_prefer_direct) < 0);
391+
}
392+
365393
DECLARE_WAIT_QUEUE_HEAD(log_wait);
366394
/* All 3 protected by @syslog_lock. */
367395
/* the next printk record to read by syslog(READ) or /proc/kmsg */

kernel/rcu/tree_stall.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -619,6 +619,7 @@ static void print_cpu_stall(unsigned long gps)
619619
* See Documentation/RCU/stallwarn.rst for info on how to debug
620620
* RCU CPU stall warnings.
621621
*/
622+
printk_prefer_direct_enter();
622623
trace_rcu_stall_warning(rcu_state.name, TPS("SelfDetected"));
623624
pr_err("INFO: %s self-detected stall on CPU\n", rcu_state.name);
624625
raw_spin_lock_irqsave_rcu_node(rdp->mynode, flags);
@@ -656,6 +657,7 @@ static void print_cpu_stall(unsigned long gps)
656657
*/
657658
set_tsk_need_resched(current);
658659
set_preempt_need_resched();
660+
printk_prefer_direct_exit();
659661
}
660662

661663
static void check_cpu_stall(struct rcu_data *rdp)

kernel/reboot.c

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -447,9 +447,11 @@ static int __orderly_reboot(void)
447447
ret = run_cmd(reboot_cmd);
448448

449449
if (ret) {
450+
printk_prefer_direct_enter();
450451
pr_warn("Failed to start orderly reboot: forcing the issue\n");
451452
emergency_sync();
452453
kernel_restart(NULL);
454+
printk_prefer_direct_exit();
453455
}
454456

455457
return ret;
@@ -462,6 +464,7 @@ static int __orderly_poweroff(bool force)
462464
ret = run_cmd(poweroff_cmd);
463465

464466
if (ret && force) {
467+
printk_prefer_direct_enter();
465468
pr_warn("Failed to start orderly shutdown: forcing the issue\n");
466469

467470
/*
@@ -471,6 +474,7 @@ static int __orderly_poweroff(bool force)
471474
*/
472475
emergency_sync();
473476
kernel_power_off();
477+
printk_prefer_direct_exit();
474478
}
475479

476480
return ret;
@@ -528,6 +532,8 @@ EXPORT_SYMBOL_GPL(orderly_reboot);
528532
*/
529533
static void hw_failure_emergency_poweroff_func(struct work_struct *work)
530534
{
535+
printk_prefer_direct_enter();
536+
531537
/*
532538
* We have reached here after the emergency shutdown waiting period has
533539
* expired. This means orderly_poweroff has not been able to shut off
@@ -544,6 +550,8 @@ static void hw_failure_emergency_poweroff_func(struct work_struct *work)
544550
*/
545551
pr_emerg("Hardware protection shutdown failed. Trying emergency restart\n");
546552
emergency_restart();
553+
554+
printk_prefer_direct_exit();
547555
}
548556

549557
static DECLARE_DELAYED_WORK(hw_failure_emergency_poweroff_work,
@@ -582,18 +590,22 @@ void hw_protection_shutdown(const char *reason, int ms_until_forced)
582590
{
583591
static atomic_t allow_proceed = ATOMIC_INIT(1);
584592

593+
printk_prefer_direct_enter();
594+
585595
pr_emerg("HARDWARE PROTECTION shutdown (%s)\n", reason);
586596

587597
/* Shutdown should be initiated only once. */
588598
if (!atomic_dec_and_test(&allow_proceed))
589-
return;
599+
goto out;
590600

591601
/*
592602
* Queue a backup emergency shutdown in the event of
593603
* orderly_poweroff failure
594604
*/
595605
hw_failure_emergency_poweroff(ms_until_forced);
596606
orderly_poweroff(true);
607+
out:
608+
printk_prefer_direct_exit();
597609
}
598610
EXPORT_SYMBOL_GPL(hw_protection_shutdown);
599611

kernel/watchdog.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -424,6 +424,8 @@ static enum hrtimer_restart watchdog_timer_fn(struct hrtimer *hrtimer)
424424
/* Start period for the next softlockup warning. */
425425
update_report_ts();
426426

427+
printk_prefer_direct_enter();
428+
427429
pr_emerg("BUG: soft lockup - CPU#%d stuck for %us! [%s:%d]\n",
428430
smp_processor_id(), duration,
429431
current->comm, task_pid_nr(current));
@@ -442,6 +444,8 @@ static enum hrtimer_restart watchdog_timer_fn(struct hrtimer *hrtimer)
442444
add_taint(TAINT_SOFTLOCKUP, LOCKDEP_STILL_OK);
443445
if (softlockup_panic)
444446
panic("softlockup: hung tasks");
447+
448+
printk_prefer_direct_exit();
445449
}
446450

447451
return HRTIMER_RESTART;

kernel/watchdog_hld.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,8 @@ static void watchdog_overflow_callback(struct perf_event *event,
135135
if (__this_cpu_read(hard_watchdog_warn) == true)
136136
return;
137137

138+
printk_prefer_direct_enter();
139+
138140
pr_emerg("Watchdog detected hard LOCKUP on cpu %d\n",
139141
this_cpu);
140142
print_modules();
@@ -155,6 +157,8 @@ static void watchdog_overflow_callback(struct perf_event *event,
155157
if (hardlockup_panic)
156158
nmi_panic(regs, "Hard LOCKUP");
157159

160+
printk_prefer_direct_exit();
161+
158162
__this_cpu_write(hard_watchdog_warn, true);
159163
return;
160164
}

0 commit comments

Comments
 (0)