diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2018-08-15 14:18:53 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-08-15 14:18:53 -0400 |
commit | b125d903881901a53117dfe404c789850b4e98ed (patch) | |
tree | 95dd0bd0bf93c68c8b0ac354dda6ee2fa382dd4e | |
parent | 8c326850304d495deee6ff9a609173a340c5245b (diff) | |
parent | 9f68cb579115faa211ae067b4628cf11162783fb (diff) |
Merge tag 'printk-for-4.19' of git://git.kernel.org/pub/scm/linux/kernel/git/pmladek/printk
Pull printk updates from Petr Mladek:
- Different vendors have a different expectation about a console
quietness. Make it configurable to reduce bike-shedding about the
upstream default
- Decide about the message visibility when the message is stored. It
avoids races caused by a delayed console handling
- Always store printk() messages into the per-CPU buffers again in NMI.
The only exception is when flushing trace log in panic(). There the
risk of loosing messages is worth an eventual reordering
- Handle invalid %pO printf modifiers correctly
- Better handle %p printf modifier tests before crng is initialized
- Some clean up
* tag 'printk-for-4.19' of git://git.kernel.org/pub/scm/linux/kernel/git/pmladek/printk:
lib/vsprintf: Do not handle %pO[^F] as %px
printk: Fix warning about unused suppress_message_printing
printk/nmi: Prevent deadlock when accessing the main log buffer in NMI
printk: Create helper function to queue deferred console handling
printk: Split the code for storing a message into the log buffer
printk: Clean up syslog_print_all()
printk: Remove unnecessary kmalloc() from syslog during clear
printk: Make CONSOLE_LOGLEVEL_QUIET configurable
printk: make sure to print log on console.
lib/test_printf.c: accept "ptrval" as valid result for plain 'p' tests
-rw-r--r-- | include/linux/printk.h | 10 | ||||
-rw-r--r-- | kernel/printk/internal.h | 9 | ||||
-rw-r--r-- | kernel/printk/printk.c | 181 | ||||
-rw-r--r-- | kernel/printk/printk_safe.c | 58 | ||||
-rw-r--r-- | kernel/trace/trace.c | 4 | ||||
-rw-r--r-- | lib/Kconfig.debug | 11 | ||||
-rw-r--r-- | lib/nmi_backtrace.c | 3 | ||||
-rw-r--r-- | lib/test_printf.c | 24 | ||||
-rw-r--r-- | lib/vsprintf.c | 1 |
9 files changed, 189 insertions, 112 deletions
diff --git a/include/linux/printk.h b/include/linux/printk.h index 6d7e800affd8..cf3eccfe1543 100644 --- a/include/linux/printk.h +++ b/include/linux/printk.h | |||
@@ -50,15 +50,15 @@ static inline const char *printk_skip_headers(const char *buffer) | |||
50 | /* We show everything that is MORE important than this.. */ | 50 | /* We show everything that is MORE important than this.. */ |
51 | #define CONSOLE_LOGLEVEL_SILENT 0 /* Mum's the word */ | 51 | #define CONSOLE_LOGLEVEL_SILENT 0 /* Mum's the word */ |
52 | #define CONSOLE_LOGLEVEL_MIN 1 /* Minimum loglevel we let people use */ | 52 | #define CONSOLE_LOGLEVEL_MIN 1 /* Minimum loglevel we let people use */ |
53 | #define CONSOLE_LOGLEVEL_QUIET 4 /* Shhh ..., when booted with "quiet" */ | ||
54 | #define CONSOLE_LOGLEVEL_DEBUG 10 /* issue debug messages */ | 53 | #define CONSOLE_LOGLEVEL_DEBUG 10 /* issue debug messages */ |
55 | #define CONSOLE_LOGLEVEL_MOTORMOUTH 15 /* You can't shut this one up */ | 54 | #define CONSOLE_LOGLEVEL_MOTORMOUTH 15 /* You can't shut this one up */ |
56 | 55 | ||
57 | /* | 56 | /* |
58 | * Default used to be hard-coded at 7, we're now allowing it to be set from | 57 | * Default used to be hard-coded at 7, quiet used to be hardcoded at 4, |
59 | * kernel config. | 58 | * we're now allowing both to be set from kernel config. |
60 | */ | 59 | */ |
61 | #define CONSOLE_LOGLEVEL_DEFAULT CONFIG_CONSOLE_LOGLEVEL_DEFAULT | 60 | #define CONSOLE_LOGLEVEL_DEFAULT CONFIG_CONSOLE_LOGLEVEL_DEFAULT |
61 | #define CONSOLE_LOGLEVEL_QUIET CONFIG_CONSOLE_LOGLEVEL_QUIET | ||
62 | 62 | ||
63 | extern int console_printk[]; | 63 | extern int console_printk[]; |
64 | 64 | ||
@@ -148,9 +148,13 @@ void early_printk(const char *s, ...) { } | |||
148 | #ifdef CONFIG_PRINTK_NMI | 148 | #ifdef CONFIG_PRINTK_NMI |
149 | extern void printk_nmi_enter(void); | 149 | extern void printk_nmi_enter(void); |
150 | extern void printk_nmi_exit(void); | 150 | extern void printk_nmi_exit(void); |
151 | extern void printk_nmi_direct_enter(void); | ||
152 | extern void printk_nmi_direct_exit(void); | ||
151 | #else | 153 | #else |
152 | static inline void printk_nmi_enter(void) { } | 154 | static inline void printk_nmi_enter(void) { } |
153 | static inline void printk_nmi_exit(void) { } | 155 | static inline void printk_nmi_exit(void) { } |
156 | static inline void printk_nmi_direct_enter(void) { } | ||
157 | static inline void printk_nmi_direct_exit(void) { } | ||
154 | #endif /* PRINTK_NMI */ | 158 | #endif /* PRINTK_NMI */ |
155 | 159 | ||
156 | #ifdef CONFIG_PRINTK | 160 | #ifdef CONFIG_PRINTK |
diff --git a/kernel/printk/internal.h b/kernel/printk/internal.h index 2a7d04049af4..0f1898820cba 100644 --- a/kernel/printk/internal.h +++ b/kernel/printk/internal.h | |||
@@ -19,11 +19,16 @@ | |||
19 | #ifdef CONFIG_PRINTK | 19 | #ifdef CONFIG_PRINTK |
20 | 20 | ||
21 | #define PRINTK_SAFE_CONTEXT_MASK 0x3fffffff | 21 | #define PRINTK_SAFE_CONTEXT_MASK 0x3fffffff |
22 | #define PRINTK_NMI_DEFERRED_CONTEXT_MASK 0x40000000 | 22 | #define PRINTK_NMI_DIRECT_CONTEXT_MASK 0x40000000 |
23 | #define PRINTK_NMI_CONTEXT_MASK 0x80000000 | 23 | #define PRINTK_NMI_CONTEXT_MASK 0x80000000 |
24 | 24 | ||
25 | extern raw_spinlock_t logbuf_lock; | 25 | extern raw_spinlock_t logbuf_lock; |
26 | 26 | ||
27 | __printf(5, 0) | ||
28 | int vprintk_store(int facility, int level, | ||
29 | const char *dict, size_t dictlen, | ||
30 | const char *fmt, va_list args); | ||
31 | |||
27 | __printf(1, 0) int vprintk_default(const char *fmt, va_list args); | 32 | __printf(1, 0) int vprintk_default(const char *fmt, va_list args); |
28 | __printf(1, 0) int vprintk_deferred(const char *fmt, va_list args); | 33 | __printf(1, 0) int vprintk_deferred(const char *fmt, va_list args); |
29 | __printf(1, 0) int vprintk_func(const char *fmt, va_list args); | 34 | __printf(1, 0) int vprintk_func(const char *fmt, va_list args); |
@@ -54,6 +59,8 @@ void __printk_safe_exit(void); | |||
54 | local_irq_enable(); \ | 59 | local_irq_enable(); \ |
55 | } while (0) | 60 | } while (0) |
56 | 61 | ||
62 | void defer_console_output(void); | ||
63 | |||
57 | #else | 64 | #else |
58 | 65 | ||
59 | __printf(1, 0) int vprintk_func(const char *fmt, va_list args) { return 0; } | 66 | __printf(1, 0) int vprintk_func(const char *fmt, va_list args) { return 0; } |
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c index 247808333ba4..9a63aeeaaf5d 100644 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c | |||
@@ -349,7 +349,7 @@ static int console_msg_format = MSG_FORMAT_DEFAULT; | |||
349 | */ | 349 | */ |
350 | 350 | ||
351 | enum log_flags { | 351 | enum log_flags { |
352 | LOG_NOCONS = 1, /* already flushed, do not print to console */ | 352 | LOG_NOCONS = 1, /* suppress print, do not print to console */ |
353 | LOG_NEWLINE = 2, /* text ended with a newline */ | 353 | LOG_NEWLINE = 2, /* text ended with a newline */ |
354 | LOG_PREFIX = 4, /* text started with a prefix */ | 354 | LOG_PREFIX = 4, /* text started with a prefix */ |
355 | LOG_CONT = 8, /* text is a fragment of a continuation line */ | 355 | LOG_CONT = 8, /* text is a fragment of a continuation line */ |
@@ -1352,71 +1352,68 @@ static int syslog_print_all(char __user *buf, int size, bool clear) | |||
1352 | { | 1352 | { |
1353 | char *text; | 1353 | char *text; |
1354 | int len = 0; | 1354 | int len = 0; |
1355 | u64 next_seq; | ||
1356 | u64 seq; | ||
1357 | u32 idx; | ||
1355 | 1358 | ||
1356 | text = kmalloc(LOG_LINE_MAX + PREFIX_MAX, GFP_KERNEL); | 1359 | text = kmalloc(LOG_LINE_MAX + PREFIX_MAX, GFP_KERNEL); |
1357 | if (!text) | 1360 | if (!text) |
1358 | return -ENOMEM; | 1361 | return -ENOMEM; |
1359 | 1362 | ||
1360 | logbuf_lock_irq(); | 1363 | logbuf_lock_irq(); |
1361 | if (buf) { | 1364 | /* |
1362 | u64 next_seq; | 1365 | * Find first record that fits, including all following records, |
1363 | u64 seq; | 1366 | * into the user-provided buffer for this dump. |
1364 | u32 idx; | 1367 | */ |
1368 | seq = clear_seq; | ||
1369 | idx = clear_idx; | ||
1370 | while (seq < log_next_seq) { | ||
1371 | struct printk_log *msg = log_from_idx(idx); | ||
1365 | 1372 | ||
1366 | /* | 1373 | len += msg_print_text(msg, true, NULL, 0); |
1367 | * Find first record that fits, including all following records, | 1374 | idx = log_next(idx); |
1368 | * into the user-provided buffer for this dump. | 1375 | seq++; |
1369 | */ | 1376 | } |
1370 | seq = clear_seq; | ||
1371 | idx = clear_idx; | ||
1372 | while (seq < log_next_seq) { | ||
1373 | struct printk_log *msg = log_from_idx(idx); | ||
1374 | |||
1375 | len += msg_print_text(msg, true, NULL, 0); | ||
1376 | idx = log_next(idx); | ||
1377 | seq++; | ||
1378 | } | ||
1379 | 1377 | ||
1380 | /* move first record forward until length fits into the buffer */ | 1378 | /* move first record forward until length fits into the buffer */ |
1381 | seq = clear_seq; | 1379 | seq = clear_seq; |
1382 | idx = clear_idx; | 1380 | idx = clear_idx; |
1383 | while (len > size && seq < log_next_seq) { | 1381 | while (len > size && seq < log_next_seq) { |
1384 | struct printk_log *msg = log_from_idx(idx); | 1382 | struct printk_log *msg = log_from_idx(idx); |
1385 | 1383 | ||
1386 | len -= msg_print_text(msg, true, NULL, 0); | 1384 | len -= msg_print_text(msg, true, NULL, 0); |
1387 | idx = log_next(idx); | 1385 | idx = log_next(idx); |
1388 | seq++; | 1386 | seq++; |
1389 | } | 1387 | } |
1390 | 1388 | ||
1391 | /* last message fitting into this dump */ | 1389 | /* last message fitting into this dump */ |
1392 | next_seq = log_next_seq; | 1390 | next_seq = log_next_seq; |
1393 | 1391 | ||
1394 | len = 0; | 1392 | len = 0; |
1395 | while (len >= 0 && seq < next_seq) { | 1393 | while (len >= 0 && seq < next_seq) { |
1396 | struct printk_log *msg = log_from_idx(idx); | 1394 | struct printk_log *msg = log_from_idx(idx); |
1397 | int textlen; | 1395 | int textlen; |
1398 | 1396 | ||
1399 | textlen = msg_print_text(msg, true, text, | 1397 | textlen = msg_print_text(msg, true, text, |
1400 | LOG_LINE_MAX + PREFIX_MAX); | 1398 | LOG_LINE_MAX + PREFIX_MAX); |
1401 | if (textlen < 0) { | 1399 | if (textlen < 0) { |
1402 | len = textlen; | 1400 | len = textlen; |
1403 | break; | 1401 | break; |
1404 | } | 1402 | } |
1405 | idx = log_next(idx); | 1403 | idx = log_next(idx); |
1406 | seq++; | 1404 | seq++; |
1407 | 1405 | ||
1408 | logbuf_unlock_irq(); | 1406 | logbuf_unlock_irq(); |
1409 | if (copy_to_user(buf + len, text, textlen)) | 1407 | if (copy_to_user(buf + len, text, textlen)) |
1410 | len = -EFAULT; | 1408 | len = -EFAULT; |
1411 | else | 1409 | else |
1412 | len += textlen; | 1410 | len += textlen; |
1413 | logbuf_lock_irq(); | 1411 | logbuf_lock_irq(); |
1414 | 1412 | ||
1415 | if (seq < log_first_seq) { | 1413 | if (seq < log_first_seq) { |
1416 | /* messages are gone, move to next one */ | 1414 | /* messages are gone, move to next one */ |
1417 | seq = log_first_seq; | 1415 | seq = log_first_seq; |
1418 | idx = log_first_idx; | 1416 | idx = log_first_idx; |
1419 | } | ||
1420 | } | 1417 | } |
1421 | } | 1418 | } |
1422 | 1419 | ||
@@ -1430,6 +1427,14 @@ static int syslog_print_all(char __user *buf, int size, bool clear) | |||
1430 | return len; | 1427 | return len; |
1431 | } | 1428 | } |
1432 | 1429 | ||
1430 | static void syslog_clear(void) | ||
1431 | { | ||
1432 | logbuf_lock_irq(); | ||
1433 | clear_seq = log_next_seq; | ||
1434 | clear_idx = log_next_idx; | ||
1435 | logbuf_unlock_irq(); | ||
1436 | } | ||
1437 | |||
1433 | int do_syslog(int type, char __user *buf, int len, int source) | 1438 | int do_syslog(int type, char __user *buf, int len, int source) |
1434 | { | 1439 | { |
1435 | bool clear = false; | 1440 | bool clear = false; |
@@ -1474,7 +1479,7 @@ int do_syslog(int type, char __user *buf, int len, int source) | |||
1474 | break; | 1479 | break; |
1475 | /* Clear ring buffer */ | 1480 | /* Clear ring buffer */ |
1476 | case SYSLOG_ACTION_CLEAR: | 1481 | case SYSLOG_ACTION_CLEAR: |
1477 | syslog_print_all(NULL, 0, true); | 1482 | syslog_clear(); |
1478 | break; | 1483 | break; |
1479 | /* Disable logging to console */ | 1484 | /* Disable logging to console */ |
1480 | case SYSLOG_ACTION_CONSOLE_OFF: | 1485 | case SYSLOG_ACTION_CONSOLE_OFF: |
@@ -1824,28 +1829,16 @@ static size_t log_output(int facility, int level, enum log_flags lflags, const c | |||
1824 | return log_store(facility, level, lflags, 0, dict, dictlen, text, text_len); | 1829 | return log_store(facility, level, lflags, 0, dict, dictlen, text, text_len); |
1825 | } | 1830 | } |
1826 | 1831 | ||
1827 | asmlinkage int vprintk_emit(int facility, int level, | 1832 | /* Must be called under logbuf_lock. */ |
1828 | const char *dict, size_t dictlen, | 1833 | int vprintk_store(int facility, int level, |
1829 | const char *fmt, va_list args) | 1834 | const char *dict, size_t dictlen, |
1835 | const char *fmt, va_list args) | ||
1830 | { | 1836 | { |
1831 | static char textbuf[LOG_LINE_MAX]; | 1837 | static char textbuf[LOG_LINE_MAX]; |
1832 | char *text = textbuf; | 1838 | char *text = textbuf; |
1833 | size_t text_len; | 1839 | size_t text_len; |
1834 | enum log_flags lflags = 0; | 1840 | enum log_flags lflags = 0; |
1835 | unsigned long flags; | ||
1836 | int printed_len; | ||
1837 | bool in_sched = false; | ||
1838 | 1841 | ||
1839 | if (level == LOGLEVEL_SCHED) { | ||
1840 | level = LOGLEVEL_DEFAULT; | ||
1841 | in_sched = true; | ||
1842 | } | ||
1843 | |||
1844 | boot_delay_msec(level); | ||
1845 | printk_delay(); | ||
1846 | |||
1847 | /* This stops the holder of console_sem just where we want him */ | ||
1848 | logbuf_lock_irqsave(flags); | ||
1849 | /* | 1842 | /* |
1850 | * The printf needs to come first; we need the syslog | 1843 | * The printf needs to come first; we need the syslog |
1851 | * prefix which might be passed-in as a parameter. | 1844 | * prefix which might be passed-in as a parameter. |
@@ -1886,8 +1879,32 @@ asmlinkage int vprintk_emit(int facility, int level, | |||
1886 | if (dict) | 1879 | if (dict) |
1887 | lflags |= LOG_PREFIX|LOG_NEWLINE; | 1880 | lflags |= LOG_PREFIX|LOG_NEWLINE; |
1888 | 1881 | ||
1889 | printed_len = log_output(facility, level, lflags, dict, dictlen, text, text_len); | 1882 | if (suppress_message_printing(level)) |
1883 | lflags |= LOG_NOCONS; | ||
1884 | |||
1885 | return log_output(facility, level, lflags, | ||
1886 | dict, dictlen, text, text_len); | ||
1887 | } | ||
1888 | |||
1889 | asmlinkage int vprintk_emit(int facility, int level, | ||
1890 | const char *dict, size_t dictlen, | ||
1891 | const char *fmt, va_list args) | ||
1892 | { | ||
1893 | int printed_len; | ||
1894 | bool in_sched = false; | ||
1895 | unsigned long flags; | ||
1896 | |||
1897 | if (level == LOGLEVEL_SCHED) { | ||
1898 | level = LOGLEVEL_DEFAULT; | ||
1899 | in_sched = true; | ||
1900 | } | ||
1890 | 1901 | ||
1902 | boot_delay_msec(level); | ||
1903 | printk_delay(); | ||
1904 | |||
1905 | /* This stops the holder of console_sem just where we want him */ | ||
1906 | logbuf_lock_irqsave(flags); | ||
1907 | printed_len = vprintk_store(facility, level, dict, dictlen, fmt, args); | ||
1891 | logbuf_unlock_irqrestore(flags); | 1908 | logbuf_unlock_irqrestore(flags); |
1892 | 1909 | ||
1893 | /* If called from the scheduler, we can not call up(). */ | 1910 | /* If called from the scheduler, we can not call up(). */ |
@@ -2013,7 +2030,6 @@ static void call_console_drivers(const char *ext_text, size_t ext_len, | |||
2013 | const char *text, size_t len) {} | 2030 | const char *text, size_t len) {} |
2014 | static size_t msg_print_text(const struct printk_log *msg, | 2031 | static size_t msg_print_text(const struct printk_log *msg, |
2015 | bool syslog, char *buf, size_t size) { return 0; } | 2032 | bool syslog, char *buf, size_t size) { return 0; } |
2016 | static bool suppress_message_printing(int level) { return false; } | ||
2017 | 2033 | ||
2018 | #endif /* CONFIG_PRINTK */ | 2034 | #endif /* CONFIG_PRINTK */ |
2019 | 2035 | ||
@@ -2349,11 +2365,10 @@ skip: | |||
2349 | break; | 2365 | break; |
2350 | 2366 | ||
2351 | msg = log_from_idx(console_idx); | 2367 | msg = log_from_idx(console_idx); |
2352 | if (suppress_message_printing(msg->level)) { | 2368 | if (msg->flags & LOG_NOCONS) { |
2353 | /* | 2369 | /* |
2354 | * Skip record we have buffered and already printed | 2370 | * Skip record if !ignore_loglevel, and |
2355 | * directly to the console when we received it, and | 2371 | * record has level above the console loglevel. |
2356 | * record that has level above the console loglevel. | ||
2357 | */ | 2372 | */ |
2358 | console_idx = log_next(console_idx); | 2373 | console_idx = log_next(console_idx); |
2359 | console_seq++; | 2374 | console_seq++; |
@@ -2878,16 +2893,20 @@ void wake_up_klogd(void) | |||
2878 | preempt_enable(); | 2893 | preempt_enable(); |
2879 | } | 2894 | } |
2880 | 2895 | ||
2881 | int vprintk_deferred(const char *fmt, va_list args) | 2896 | void defer_console_output(void) |
2882 | { | 2897 | { |
2883 | int r; | ||
2884 | |||
2885 | r = vprintk_emit(0, LOGLEVEL_SCHED, NULL, 0, fmt, args); | ||
2886 | |||
2887 | preempt_disable(); | 2898 | preempt_disable(); |
2888 | __this_cpu_or(printk_pending, PRINTK_PENDING_OUTPUT); | 2899 | __this_cpu_or(printk_pending, PRINTK_PENDING_OUTPUT); |
2889 | irq_work_queue(this_cpu_ptr(&wake_up_klogd_work)); | 2900 | irq_work_queue(this_cpu_ptr(&wake_up_klogd_work)); |
2890 | preempt_enable(); | 2901 | preempt_enable(); |
2902 | } | ||
2903 | |||
2904 | int vprintk_deferred(const char *fmt, va_list args) | ||
2905 | { | ||
2906 | int r; | ||
2907 | |||
2908 | r = vprintk_emit(0, LOGLEVEL_SCHED, NULL, 0, fmt, args); | ||
2909 | defer_console_output(); | ||
2891 | 2910 | ||
2892 | return r; | 2911 | return r; |
2893 | } | 2912 | } |
diff --git a/kernel/printk/printk_safe.c b/kernel/printk/printk_safe.c index d7d091309054..a0a74c533e4b 100644 --- a/kernel/printk/printk_safe.c +++ b/kernel/printk/printk_safe.c | |||
@@ -308,24 +308,33 @@ static __printf(1, 0) int vprintk_nmi(const char *fmt, va_list args) | |||
308 | 308 | ||
309 | void printk_nmi_enter(void) | 309 | void printk_nmi_enter(void) |
310 | { | 310 | { |
311 | /* | 311 | this_cpu_or(printk_context, PRINTK_NMI_CONTEXT_MASK); |
312 | * The size of the extra per-CPU buffer is limited. Use it only when | ||
313 | * the main one is locked. If this CPU is not in the safe context, | ||
314 | * the lock must be taken on another CPU and we could wait for it. | ||
315 | */ | ||
316 | if ((this_cpu_read(printk_context) & PRINTK_SAFE_CONTEXT_MASK) && | ||
317 | raw_spin_is_locked(&logbuf_lock)) { | ||
318 | this_cpu_or(printk_context, PRINTK_NMI_CONTEXT_MASK); | ||
319 | } else { | ||
320 | this_cpu_or(printk_context, PRINTK_NMI_DEFERRED_CONTEXT_MASK); | ||
321 | } | ||
322 | } | 312 | } |
323 | 313 | ||
324 | void printk_nmi_exit(void) | 314 | void printk_nmi_exit(void) |
325 | { | 315 | { |
326 | this_cpu_and(printk_context, | 316 | this_cpu_and(printk_context, ~PRINTK_NMI_CONTEXT_MASK); |
327 | ~(PRINTK_NMI_CONTEXT_MASK | | 317 | } |
328 | PRINTK_NMI_DEFERRED_CONTEXT_MASK)); | 318 | |
319 | /* | ||
320 | * Marks a code that might produce many messages in NMI context | ||
321 | * and the risk of losing them is more critical than eventual | ||
322 | * reordering. | ||
323 | * | ||
324 | * It has effect only when called in NMI context. Then printk() | ||
325 | * will try to store the messages into the main logbuf directly | ||
326 | * and use the per-CPU buffers only as a fallback when the lock | ||
327 | * is not available. | ||
328 | */ | ||
329 | void printk_nmi_direct_enter(void) | ||
330 | { | ||
331 | if (this_cpu_read(printk_context) & PRINTK_NMI_CONTEXT_MASK) | ||
332 | this_cpu_or(printk_context, PRINTK_NMI_DIRECT_CONTEXT_MASK); | ||
333 | } | ||
334 | |||
335 | void printk_nmi_direct_exit(void) | ||
336 | { | ||
337 | this_cpu_and(printk_context, ~PRINTK_NMI_DIRECT_CONTEXT_MASK); | ||
329 | } | 338 | } |
330 | 339 | ||
331 | #else | 340 | #else |
@@ -363,6 +372,20 @@ void __printk_safe_exit(void) | |||
363 | 372 | ||
364 | __printf(1, 0) int vprintk_func(const char *fmt, va_list args) | 373 | __printf(1, 0) int vprintk_func(const char *fmt, va_list args) |
365 | { | 374 | { |
375 | /* | ||
376 | * Try to use the main logbuf even in NMI. But avoid calling console | ||
377 | * drivers that might have their own locks. | ||
378 | */ | ||
379 | if ((this_cpu_read(printk_context) & PRINTK_NMI_DIRECT_CONTEXT_MASK) && | ||
380 | raw_spin_trylock(&logbuf_lock)) { | ||
381 | int len; | ||
382 | |||
383 | len = vprintk_store(0, LOGLEVEL_DEFAULT, NULL, 0, fmt, args); | ||
384 | raw_spin_unlock(&logbuf_lock); | ||
385 | defer_console_output(); | ||
386 | return len; | ||
387 | } | ||
388 | |||
366 | /* Use extra buffer in NMI when logbuf_lock is taken or in safe mode. */ | 389 | /* Use extra buffer in NMI when logbuf_lock is taken or in safe mode. */ |
367 | if (this_cpu_read(printk_context) & PRINTK_NMI_CONTEXT_MASK) | 390 | if (this_cpu_read(printk_context) & PRINTK_NMI_CONTEXT_MASK) |
368 | return vprintk_nmi(fmt, args); | 391 | return vprintk_nmi(fmt, args); |
@@ -371,13 +394,6 @@ __printf(1, 0) int vprintk_func(const char *fmt, va_list args) | |||
371 | if (this_cpu_read(printk_context) & PRINTK_SAFE_CONTEXT_MASK) | 394 | if (this_cpu_read(printk_context) & PRINTK_SAFE_CONTEXT_MASK) |
372 | return vprintk_safe(fmt, args); | 395 | return vprintk_safe(fmt, args); |
373 | 396 | ||
374 | /* | ||
375 | * Use the main logbuf when logbuf_lock is available in NMI. | ||
376 | * But avoid calling console drivers that might have their own locks. | ||
377 | */ | ||
378 | if (this_cpu_read(printk_context) & PRINTK_NMI_DEFERRED_CONTEXT_MASK) | ||
379 | return vprintk_deferred(fmt, args); | ||
380 | |||
381 | /* No obstacles. */ | 397 | /* No obstacles. */ |
382 | return vprintk_default(fmt, args); | 398 | return vprintk_default(fmt, args); |
383 | } | 399 | } |
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 823687997b01..176debd3481b 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c | |||
@@ -8288,6 +8288,7 @@ void ftrace_dump(enum ftrace_dump_mode oops_dump_mode) | |||
8288 | tracing_off(); | 8288 | tracing_off(); |
8289 | 8289 | ||
8290 | local_irq_save(flags); | 8290 | local_irq_save(flags); |
8291 | printk_nmi_direct_enter(); | ||
8291 | 8292 | ||
8292 | /* Simulate the iterator */ | 8293 | /* Simulate the iterator */ |
8293 | trace_init_global_iter(&iter); | 8294 | trace_init_global_iter(&iter); |
@@ -8367,7 +8368,8 @@ void ftrace_dump(enum ftrace_dump_mode oops_dump_mode) | |||
8367 | for_each_tracing_cpu(cpu) { | 8368 | for_each_tracing_cpu(cpu) { |
8368 | atomic_dec(&per_cpu_ptr(iter.trace_buffer->data, cpu)->disabled); | 8369 | atomic_dec(&per_cpu_ptr(iter.trace_buffer->data, cpu)->disabled); |
8369 | } | 8370 | } |
8370 | atomic_dec(&dump_running); | 8371 | atomic_dec(&dump_running); |
8372 | printk_nmi_direct_exit(); | ||
8371 | local_irq_restore(flags); | 8373 | local_irq_restore(flags); |
8372 | } | 8374 | } |
8373 | EXPORT_SYMBOL_GPL(ftrace_dump); | 8375 | EXPORT_SYMBOL_GPL(ftrace_dump); |
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 0b066b3c9284..ce5a45e46885 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug | |||
@@ -30,6 +30,17 @@ config CONSOLE_LOGLEVEL_DEFAULT | |||
30 | usage in the kernel. That is controlled by the MESSAGE_LOGLEVEL_DEFAULT | 30 | usage in the kernel. That is controlled by the MESSAGE_LOGLEVEL_DEFAULT |
31 | option. | 31 | option. |
32 | 32 | ||
33 | config CONSOLE_LOGLEVEL_QUIET | ||
34 | int "quiet console loglevel (1-15)" | ||
35 | range 1 15 | ||
36 | default "4" | ||
37 | help | ||
38 | loglevel to use when "quiet" is passed on the kernel commandline. | ||
39 | |||
40 | When "quiet" is passed on the kernel commandline this loglevel | ||
41 | will be used as the loglevel. IOW passing "quiet" will be the | ||
42 | equivalent of passing "loglevel=<CONSOLE_LOGLEVEL_QUIET>" | ||
43 | |||
33 | config MESSAGE_LOGLEVEL_DEFAULT | 44 | config MESSAGE_LOGLEVEL_DEFAULT |
34 | int "Default message log level (1-7)" | 45 | int "Default message log level (1-7)" |
35 | range 1 7 | 46 | range 1 7 |
diff --git a/lib/nmi_backtrace.c b/lib/nmi_backtrace.c index 61a6b5aab07e..15ca78e1c7d4 100644 --- a/lib/nmi_backtrace.c +++ b/lib/nmi_backtrace.c | |||
@@ -87,11 +87,9 @@ void nmi_trigger_cpumask_backtrace(const cpumask_t *mask, | |||
87 | 87 | ||
88 | bool nmi_cpu_backtrace(struct pt_regs *regs) | 88 | bool nmi_cpu_backtrace(struct pt_regs *regs) |
89 | { | 89 | { |
90 | static arch_spinlock_t lock = __ARCH_SPIN_LOCK_UNLOCKED; | ||
91 | int cpu = smp_processor_id(); | 90 | int cpu = smp_processor_id(); |
92 | 91 | ||
93 | if (cpumask_test_cpu(cpu, to_cpumask(backtrace_mask))) { | 92 | if (cpumask_test_cpu(cpu, to_cpumask(backtrace_mask))) { |
94 | arch_spin_lock(&lock); | ||
95 | if (regs && cpu_in_idle(instruction_pointer(regs))) { | 93 | if (regs && cpu_in_idle(instruction_pointer(regs))) { |
96 | pr_warn("NMI backtrace for cpu %d skipped: idling at %pS\n", | 94 | pr_warn("NMI backtrace for cpu %d skipped: idling at %pS\n", |
97 | cpu, (void *)instruction_pointer(regs)); | 95 | cpu, (void *)instruction_pointer(regs)); |
@@ -102,7 +100,6 @@ bool nmi_cpu_backtrace(struct pt_regs *regs) | |||
102 | else | 100 | else |
103 | dump_stack(); | 101 | dump_stack(); |
104 | } | 102 | } |
105 | arch_spin_unlock(&lock); | ||
106 | cpumask_clear_cpu(cpu, to_cpumask(backtrace_mask)); | 103 | cpumask_clear_cpu(cpu, to_cpumask(backtrace_mask)); |
107 | return true; | 104 | return true; |
108 | } | 105 | } |
diff --git a/lib/test_printf.c b/lib/test_printf.c index cea592f402ed..53527ea822b5 100644 --- a/lib/test_printf.c +++ b/lib/test_printf.c | |||
@@ -206,6 +206,7 @@ test_string(void) | |||
206 | #define PTR_WIDTH 16 | 206 | #define PTR_WIDTH 16 |
207 | #define PTR ((void *)0xffff0123456789abUL) | 207 | #define PTR ((void *)0xffff0123456789abUL) |
208 | #define PTR_STR "ffff0123456789ab" | 208 | #define PTR_STR "ffff0123456789ab" |
209 | #define PTR_VAL_NO_CRNG "(____ptrval____)" | ||
209 | #define ZEROS "00000000" /* hex 32 zero bits */ | 210 | #define ZEROS "00000000" /* hex 32 zero bits */ |
210 | 211 | ||
211 | static int __init | 212 | static int __init |
@@ -216,7 +217,16 @@ plain_format(void) | |||
216 | 217 | ||
217 | nchars = snprintf(buf, PLAIN_BUF_SIZE, "%p", PTR); | 218 | nchars = snprintf(buf, PLAIN_BUF_SIZE, "%p", PTR); |
218 | 219 | ||
219 | if (nchars != PTR_WIDTH || strncmp(buf, ZEROS, strlen(ZEROS)) != 0) | 220 | if (nchars != PTR_WIDTH) |
221 | return -1; | ||
222 | |||
223 | if (strncmp(buf, PTR_VAL_NO_CRNG, PTR_WIDTH) == 0) { | ||
224 | pr_warn("crng possibly not yet initialized. plain 'p' buffer contains \"%s\"", | ||
225 | PTR_VAL_NO_CRNG); | ||
226 | return 0; | ||
227 | } | ||
228 | |||
229 | if (strncmp(buf, ZEROS, strlen(ZEROS)) != 0) | ||
220 | return -1; | 230 | return -1; |
221 | 231 | ||
222 | return 0; | 232 | return 0; |
@@ -227,6 +237,7 @@ plain_format(void) | |||
227 | #define PTR_WIDTH 8 | 237 | #define PTR_WIDTH 8 |
228 | #define PTR ((void *)0x456789ab) | 238 | #define PTR ((void *)0x456789ab) |
229 | #define PTR_STR "456789ab" | 239 | #define PTR_STR "456789ab" |
240 | #define PTR_VAL_NO_CRNG "(ptrval)" | ||
230 | 241 | ||
231 | static int __init | 242 | static int __init |
232 | plain_format(void) | 243 | plain_format(void) |
@@ -245,7 +256,16 @@ plain_hash(void) | |||
245 | 256 | ||
246 | nchars = snprintf(buf, PLAIN_BUF_SIZE, "%p", PTR); | 257 | nchars = snprintf(buf, PLAIN_BUF_SIZE, "%p", PTR); |
247 | 258 | ||
248 | if (nchars != PTR_WIDTH || strncmp(buf, PTR_STR, PTR_WIDTH) == 0) | 259 | if (nchars != PTR_WIDTH) |
260 | return -1; | ||
261 | |||
262 | if (strncmp(buf, PTR_VAL_NO_CRNG, PTR_WIDTH) == 0) { | ||
263 | pr_warn("crng possibly not yet initialized. plain 'p' buffer contains \"%s\"", | ||
264 | PTR_VAL_NO_CRNG); | ||
265 | return 0; | ||
266 | } | ||
267 | |||
268 | if (strncmp(buf, PTR_STR, PTR_WIDTH) == 0) | ||
249 | return -1; | 269 | return -1; |
250 | 270 | ||
251 | return 0; | 271 | return 0; |
diff --git a/lib/vsprintf.c b/lib/vsprintf.c index a48aaa79d352..cda186230287 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c | |||
@@ -1942,6 +1942,7 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr, | |||
1942 | case 'F': | 1942 | case 'F': |
1943 | return device_node_string(buf, end, ptr, spec, fmt + 1); | 1943 | return device_node_string(buf, end, ptr, spec, fmt + 1); |
1944 | } | 1944 | } |
1945 | break; | ||
1945 | case 'x': | 1946 | case 'x': |
1946 | return pointer_string(buf, end, ptr, spec); | 1947 | return pointer_string(buf, end, ptr, spec); |
1947 | } | 1948 | } |