Skip to content

Commit 537e62c

Browse files
committed
Merge tag 'printk-for-5.19' of git://git.kernel.org/pub/scm/linux/kernel/git/printk/linux
Pull printk updates from Petr Mladek: - Offload writing printk() messages on consoles to per-console kthreads. It prevents soft-lockups when an extensive amount of messages is printed. It was observed, for example, during boot of large systems with a lot of peripherals like disks or network interfaces. It prevents live-lockups that were observed, for example, when messages about allocation failures were reported and a CPU handled consoles instead of reclaiming the memory. It was hard to solve even with rate limiting because it would need to take into account the amount of messages and the speed of all consoles. It is a must to have for real time. Otherwise, any printk() might break latency guarantees. The per-console kthreads allow to handle each console on its own speed. Slow consoles do not longer slow down faster ones. And printk() does not longer unpredictably slows down various code paths. There are situations when the kthreads are either not available or not reliable, for example, early boot, suspend, or panic. In these situations, printk() uses the legacy mode and tries to handle consoles immediately. - Add documentation for the printk index. * tag 'printk-for-5.19' of git://git.kernel.org/pub/scm/linux/kernel/git/printk/linux: printk, tracing: fix console tracepoint printk: remove @console_locked printk: extend console_lock for per-console locking printk: add kthread console printers printk: add functions to prefer direct printing printk: add pr_flush() printk: move buffer definitions into console_emit_next_record() caller printk: refactor and rework printing logic printk: add con_printk() macro for console details printk: call boot_delay_msec() in printk_delay() printk: get caller_id/timestamp after migration disable printk: wake waiters for safe and NMI contexts printk: wake up all waiters printk: add missing memory barrier to wake_up_klogd() printk: cpu sync always disable interrupts printk: rename cpulock functions printk/index: Printk index feature documentation MAINTAINERS: Add printk indexing maintainers on mention of printk_index
2 parents 2e17ce1 + 1c6fd59 commit 537e62c

File tree

15 files changed

+1174
-321
lines changed

15 files changed

+1174
-321
lines changed

Documentation/core-api/index.rst

+1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ it.
2020
workqueue
2121
printk-basics
2222
printk-formats
23+
printk-index
2324
symbol-namespaces
2425

2526
Data structures and low-level utilities
+137
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
.. SPDX-License-Identifier: GPL-2.0
2+
3+
============
4+
Printk Index
5+
============
6+
7+
There are many ways how to monitor the state of the system. One important
8+
source of information is the system log. It provides a lot of information,
9+
including more or less important warnings and error messages.
10+
11+
There are monitoring tools that filter and take action based on messages
12+
logged.
13+
14+
The kernel messages are evolving together with the code. As a result,
15+
particular kernel messages are not KABI and never will be!
16+
17+
It is a huge challenge for maintaining the system log monitors. It requires
18+
knowing what messages were updated in a particular kernel version and why.
19+
Finding these changes in the sources would require non-trivial parsers.
20+
Also it would require matching the sources with the binary kernel which
21+
is not always trivial. Various changes might be backported. Various kernel
22+
versions might be used on different monitored systems.
23+
24+
This is where the printk index feature might become useful. It provides
25+
a dump of printk formats used all over the source code used for the kernel
26+
and modules on the running system. It is accessible at runtime via debugfs.
27+
28+
The printk index helps to find changes in the message formats. Also it helps
29+
to track the strings back to the kernel sources and the related commit.
30+
31+
32+
User Interface
33+
==============
34+
35+
The index of printk formats are split in into separate files. The files are
36+
named according to the binaries where the printk formats are built-in. There
37+
is always "vmlinux" and optionally also modules, for example::
38+
39+
/sys/kernel/debug/printk/index/vmlinux
40+
/sys/kernel/debug/printk/index/ext4
41+
/sys/kernel/debug/printk/index/scsi_mod
42+
43+
Note that only loaded modules are shown. Also printk formats from a module
44+
might appear in "vmlinux" when the module is built-in.
45+
46+
The content is inspired by the dynamic debug interface and looks like::
47+
48+
$> head -1 /sys/kernel/debug/printk/index/vmlinux; shuf -n 5 vmlinux
49+
# <level[,flags]> filename:line function "format"
50+
<5> block/blk-settings.c:661 disk_stack_limits "%s: Warning: Device %s is misaligned\n"
51+
<4> kernel/trace/trace.c:8296 trace_create_file "Could not create tracefs '%s' entry\n"
52+
<6> arch/x86/kernel/hpet.c:144 _hpet_print_config "hpet: %s(%d):\n"
53+
<6> init/do_mounts.c:605 prepare_namespace "Waiting for root device %s...\n"
54+
<6> drivers/acpi/osl.c:1410 acpi_no_auto_serialize_setup "ACPI: auto-serialization disabled\n"
55+
56+
, where the meaning is:
57+
58+
- :level: log level value: 0-7 for particular severity, -1 as default,
59+
'c' as continuous line without an explicit log level
60+
- :flags: optional flags: currently only 'c' for KERN_CONT
61+
- :filename\:line: source filename and line number of the related
62+
printk() call. Note that there are many wrappers, for example,
63+
pr_warn(), pr_warn_once(), dev_warn().
64+
- :function: function name where the printk() call is used.
65+
- :format: format string
66+
67+
The extra information makes it a bit harder to find differences
68+
between various kernels. Especially the line number might change
69+
very often. On the other hand, it helps a lot to confirm that
70+
it is the same string or find the commit that is responsible
71+
for eventual changes.
72+
73+
74+
printk() Is Not a Stable KABI
75+
=============================
76+
77+
Several developers are afraid that exporting all these implementation
78+
details into the user space will transform particular printk() calls
79+
into KABI.
80+
81+
But it is exactly the opposite. printk() calls must _not_ be KABI.
82+
And the printk index helps user space tools to deal with this.
83+
84+
85+
Subsystem specific printk wrappers
86+
==================================
87+
88+
The printk index is generated using extra metadata that are stored in
89+
a dedicated .elf section ".printk_index". It is achieved using macro
90+
wrappers doing __printk_index_emit() together with the real printk()
91+
call. The same technique is used also for the metadata used by
92+
the dynamic debug feature.
93+
94+
The metadata are stored for a particular message only when it is printed
95+
using these special wrappers. It is implemented for the commonly
96+
used printk() calls, including, for example, pr_warn(), or pr_once().
97+
98+
Additional changes are necessary for various subsystem specific wrappers
99+
that call the original printk() via a common helper function. These needs
100+
their own wrappers adding __printk_index_emit().
101+
102+
Only few subsystem specific wrappers have been updated so far,
103+
for example, dev_printk(). As a result, the printk formats from
104+
some subsystes can be missing in the printk index.
105+
106+
107+
Subsystem specific prefix
108+
=========================
109+
110+
The macro pr_fmt() macro allows to define a prefix that is printed
111+
before the string generated by the related printk() calls.
112+
113+
Subsystem specific wrappers usually add even more complicated
114+
prefixes.
115+
116+
These prefixes can be stored into the printk index metadata
117+
by an optional parameter of __printk_index_emit(). The debugfs
118+
interface might then show the printk formats including these prefixes.
119+
For example, drivers/acpi/osl.c contains::
120+
121+
#define pr_fmt(fmt) "ACPI: OSL: " fmt
122+
123+
static int __init acpi_no_auto_serialize_setup(char *str)
124+
{
125+
acpi_gbl_auto_serialize_methods = FALSE;
126+
pr_info("Auto-serialization disabled\n");
127+
128+
return 1;
129+
}
130+
131+
This results in the following printk index entry::
132+
133+
<6> drivers/acpi/osl.c:1410 acpi_no_auto_serialize_setup "ACPI: auto-serialization disabled\n"
134+
135+
It helps matching messages from the real log with printk index.
136+
Then the source file name, line number, and function name can
137+
be used to match the string with the source code.

MAINTAINERS

+2
Original file line numberDiff line numberDiff line change
@@ -15923,7 +15923,9 @@ F: kernel/printk/
1592315923
PRINTK INDEXING
1592415924
R: Chris Down <[email protected]>
1592515925
S: Maintained
15926+
F: Documentation/core-api/printk-index.rst
1592615927
F: kernel/printk/index.c
15928+
K: printk_index
1592715929

1592815930
PROC FILESYSTEM
1592915931

drivers/tty/sysrq.c

+2
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/console.h

+19
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
#include <linux/atomic.h>
1818
#include <linux/types.h>
19+
#include <linux/mutex.h>
1920

2021
struct vc_data;
2122
struct console_font_op;
@@ -151,6 +152,24 @@ struct console {
151152
int cflag;
152153
uint ispeed;
153154
uint ospeed;
155+
u64 seq;
156+
unsigned long dropped;
157+
struct task_struct *thread;
158+
bool blocked;
159+
160+
/*
161+
* The per-console lock is used by printing kthreads to synchronize
162+
* this console with callers of console_lock(). This is necessary in
163+
* order to allow printing kthreads to run in parallel to each other,
164+
* while each safely accessing the @blocked field and synchronizing
165+
* against direct printing via console_lock/console_unlock.
166+
*
167+
* Note: For synchronizing against direct printing via
168+
* console_trylock/console_unlock, see the static global
169+
* variable @console_kthreads_active.
170+
*/
171+
struct mutex lock;
172+
154173
void *data;
155174
struct console *next;
156175
};

include/linux/printk.h

+56-26
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,11 @@ 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+
176+
extern bool pr_flush(int timeout_ms, bool reset_on_progress);
177+
173178
/*
174179
* Please don't use printk_ratelimit(), because it shares ratelimiting state
175180
* with all other unrelated printk_ratelimit() callsites. Instead use
@@ -220,6 +225,19 @@ static inline void printk_deferred_exit(void)
220225
{
221226
}
222227

228+
static inline void printk_prefer_direct_enter(void)
229+
{
230+
}
231+
232+
static inline void printk_prefer_direct_exit(void)
233+
{
234+
}
235+
236+
static inline bool pr_flush(int timeout_ms, bool reset_on_progress)
237+
{
238+
return true;
239+
}
240+
223241
static inline int printk_ratelimit(void)
224242
{
225243
return 0;
@@ -277,45 +295,57 @@ static inline void printk_trigger_flush(void)
277295
#endif
278296

279297
#ifdef CONFIG_SMP
280-
extern int __printk_cpu_trylock(void);
281-
extern void __printk_wait_on_cpu_lock(void);
282-
extern void __printk_cpu_unlock(void);
298+
extern int __printk_cpu_sync_try_get(void);
299+
extern void __printk_cpu_sync_wait(void);
300+
extern void __printk_cpu_sync_put(void);
301+
302+
#else
303+
304+
#define __printk_cpu_sync_try_get() true
305+
#define __printk_cpu_sync_wait()
306+
#define __printk_cpu_sync_put()
307+
#endif /* CONFIG_SMP */
283308

284309
/**
285-
* printk_cpu_lock_irqsave() - Acquire the printk cpu-reentrant spinning
286-
* lock and disable interrupts.
310+
* printk_cpu_sync_get_irqsave() - Disable interrupts and acquire the printk
311+
* cpu-reentrant spinning lock.
287312
* @flags: Stack-allocated storage for saving local interrupt state,
288-
* to be passed to printk_cpu_unlock_irqrestore().
313+
* to be passed to printk_cpu_sync_put_irqrestore().
289314
*
290315
* If the lock is owned by another CPU, spin until it becomes available.
291316
* Interrupts are restored while spinning.
317+
*
318+
* CAUTION: This function must be used carefully. It does not behave like a
319+
* typical lock. Here are important things to watch out for...
320+
*
321+
* * This function is reentrant on the same CPU. Therefore the calling
322+
* code must not assume exclusive access to data if code accessing the
323+
* data can run reentrant or within NMI context on the same CPU.
324+
*
325+
* * If there exists usage of this function from NMI context, it becomes
326+
* unsafe to perform any type of locking or spinning to wait for other
327+
* CPUs after calling this function from any context. This includes
328+
* using spinlocks or any other busy-waiting synchronization methods.
292329
*/
293-
#define printk_cpu_lock_irqsave(flags) \
294-
for (;;) { \
295-
local_irq_save(flags); \
296-
if (__printk_cpu_trylock()) \
297-
break; \
298-
local_irq_restore(flags); \
299-
__printk_wait_on_cpu_lock(); \
330+
#define printk_cpu_sync_get_irqsave(flags) \
331+
for (;;) { \
332+
local_irq_save(flags); \
333+
if (__printk_cpu_sync_try_get()) \
334+
break; \
335+
local_irq_restore(flags); \
336+
__printk_cpu_sync_wait(); \
300337
}
301338

302339
/**
303-
* printk_cpu_unlock_irqrestore() - Release the printk cpu-reentrant spinning
304-
* lock and restore interrupts.
305-
* @flags: Caller's saved interrupt state, from printk_cpu_lock_irqsave().
340+
* printk_cpu_sync_put_irqrestore() - Release the printk cpu-reentrant spinning
341+
* lock and restore interrupts.
342+
* @flags: Caller's saved interrupt state, from printk_cpu_sync_get_irqsave().
306343
*/
307-
#define printk_cpu_unlock_irqrestore(flags) \
344+
#define printk_cpu_sync_put_irqrestore(flags) \
308345
do { \
309-
__printk_cpu_unlock(); \
346+
__printk_cpu_sync_put(); \
310347
local_irq_restore(flags); \
311-
} while (0) \
312-
313-
#else
314-
315-
#define printk_cpu_lock_irqsave(flags) ((void)flags)
316-
#define printk_cpu_unlock_irqrestore(flags) ((void)flags)
317-
318-
#endif /* CONFIG_SMP */
348+
} while (0)
319349

320350
extern int kptr_restrict;
321351

kernel/hung_task.c

+10-1
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

+4
Original file line numberDiff line numberDiff line change
@@ -579,6 +579,8 @@ void __warn(const char *file, int line, void *caller, unsigned taint,
579579
{
580580
disable_trace_on_warning();
581581

582+
printk_prefer_direct_enter();
583+
582584
if (file)
583585
pr_warn("WARNING: CPU: %d PID: %d at %s:%d %pS\n",
584586
raw_smp_processor_id(), current->pid, file, line,
@@ -608,6 +610,8 @@ void __warn(const char *file, int line, void *caller, unsigned taint,
608610

609611
/* Just a warning, don't kill lockdep. */
610612
add_taint(taint, LOCKDEP_STILL_OK);
613+
614+
printk_prefer_direct_exit();
611615
}
612616

613617
#ifndef __WARN_FLAGS

0 commit comments

Comments
 (0)