Commit 7d91de74 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/pmladek/printk

Pull printk updates from Petr Mladek:

 - Add Petr Mladek, Sergey Senozhatsky as printk maintainers, and Steven
   Rostedt as the printk reviewer. This idea came up after the
   discussion about printk issues at Kernel Summit. It was formulated
   and discussed at lkml[1].

 - Extend a lock-less NMI per-cpu buffers idea to handle recursive
   printk() calls by Sergey Senozhatsky[2]. It is the first step in
   sanitizing printk as discussed at Kernel Summit.

   The change allows to see messages that would normally get ignored or
   would cause a deadlock.

   Also it allows to enable lockdep in printk(). This already paid off.
   The testing in linux-next helped to discover two old problems that
   were hidden before[3][4].

 - Remove unused parameter by Sergey Senozhatsky. Clean up after a past
   change.

[1] http://lkml.kernel.org/r/1481798878-31898-1-git-send-email-pmladek@suse.com
[2] http://lkml.kernel.org/r/20161227141611.940-1-sergey.senozhatsky@gmail.com
[3] http://lkml.kernel.org/r/20170215044332.30449-1-sergey.senozhatsky@gmail.com
[4] http://lkml.kernel.org/r/20170217015932.11898-1-sergey.senozhatsky@gmail.com

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/pmladek/printk:
  printk: drop call_console_drivers() unused param
  printk: convert the rest to printk-safe
  printk: remove zap_locks() function
  printk: use printk_safe buffers in printk
  printk: report lost messages in printk safe/nmi contexts
  printk: always use deferred printk when flush printk_safe lines
  printk: introduce per-cpu safe_print seq buffer
  printk: rename nmi.c and exported api
  printk: use vprintk_func in vprintk()
  MAINTAINERS: Add printk maintainers
parents 6ef192f2 d9c23523
...@@ -9997,6 +9997,14 @@ S: Supported ...@@ -9997,6 +9997,14 @@ S: Supported
F: Documentation/preempt-locking.txt F: Documentation/preempt-locking.txt
F: include/linux/preempt.h F: include/linux/preempt.h
PRINTK
M: Petr Mladek <pmladek@suse.com>
M: Sergey Senozhatsky <sergey.senozhatsky@gmail.com>
R: Steven Rostedt <rostedt@goodmis.org>
S: Maintained
F: kernel/printk/
F: include/linux/printk.h
PRISM54 WIRELESS DRIVER PRISM54 WIRELESS DRIVER
M: "Luis R. Rodriguez" <mcgrof@gmail.com> M: "Luis R. Rodriguez" <mcgrof@gmail.com>
L: linux-wireless@vger.kernel.org L: linux-wireless@vger.kernel.org
......
...@@ -147,17 +147,11 @@ void early_printk(const char *s, ...) { } ...@@ -147,17 +147,11 @@ void early_printk(const char *s, ...) { }
#endif #endif
#ifdef CONFIG_PRINTK_NMI #ifdef CONFIG_PRINTK_NMI
extern void printk_nmi_init(void);
extern void printk_nmi_enter(void); extern void printk_nmi_enter(void);
extern void printk_nmi_exit(void); extern void printk_nmi_exit(void);
extern void printk_nmi_flush(void);
extern void printk_nmi_flush_on_panic(void);
#else #else
static inline void printk_nmi_init(void) { }
static inline void printk_nmi_enter(void) { } static inline void printk_nmi_enter(void) { }
static inline void printk_nmi_exit(void) { } static inline void printk_nmi_exit(void) { }
static inline void printk_nmi_flush(void) { }
static inline void printk_nmi_flush_on_panic(void) { }
#endif /* PRINTK_NMI */ #endif /* PRINTK_NMI */
#ifdef CONFIG_PRINTK #ifdef CONFIG_PRINTK
...@@ -209,6 +203,9 @@ void __init setup_log_buf(int early); ...@@ -209,6 +203,9 @@ void __init setup_log_buf(int early);
__printf(1, 2) void dump_stack_set_arch_desc(const char *fmt, ...); __printf(1, 2) void dump_stack_set_arch_desc(const char *fmt, ...);
void dump_stack_print_info(const char *log_lvl); void dump_stack_print_info(const char *log_lvl);
void show_regs_print_info(const char *log_lvl); void show_regs_print_info(const char *log_lvl);
extern void printk_safe_init(void);
extern void printk_safe_flush(void);
extern void printk_safe_flush_on_panic(void);
#else #else
static inline __printf(1, 0) static inline __printf(1, 0)
int vprintk(const char *s, va_list args) int vprintk(const char *s, va_list args)
...@@ -268,6 +265,18 @@ static inline void dump_stack_print_info(const char *log_lvl) ...@@ -268,6 +265,18 @@ static inline void dump_stack_print_info(const char *log_lvl)
static inline void show_regs_print_info(const char *log_lvl) static inline void show_regs_print_info(const char *log_lvl)
{ {
} }
static inline void printk_safe_init(void)
{
}
static inline void printk_safe_flush(void)
{
}
static inline void printk_safe_flush_on_panic(void)
{
}
#endif #endif
extern asmlinkage void dump_stack(void) __cold; extern asmlinkage void dump_stack(void) __cold;
......
...@@ -861,17 +861,19 @@ config LOG_CPU_MAX_BUF_SHIFT ...@@ -861,17 +861,19 @@ config LOG_CPU_MAX_BUF_SHIFT
13 => 8 KB for each CPU 13 => 8 KB for each CPU
12 => 4 KB for each CPU 12 => 4 KB for each CPU
config NMI_LOG_BUF_SHIFT config PRINTK_SAFE_LOG_BUF_SHIFT
int "Temporary per-CPU NMI log buffer size (12 => 4KB, 13 => 8KB)" int "Temporary per-CPU printk log buffer size (12 => 4KB, 13 => 8KB)"
range 10 21 range 10 21
default 13 default 13
depends on PRINTK_NMI depends on PRINTK
help help
Select the size of a per-CPU buffer where NMI messages are temporary Select the size of an alternate printk per-CPU buffer where messages
stored. They are copied to the main log buffer in a safe context printed from usafe contexts are temporary stored. One example would
to avoid a deadlock. The value defines the size as a power of 2. be NMI messages, another one - printk recursion. The messages are
copied to the main log buffer in a safe context to avoid a deadlock.
The value defines the size as a power of 2.
NMI messages are rare and limited. The largest one is when Those messages are rare and limited. The largest one is when
a backtrace is printed. It usually fits into 4KB. Select a backtrace is printed. It usually fits into 4KB. Select
8KB if you want to be on the safe side. 8KB if you want to be on the safe side.
......
...@@ -581,7 +581,7 @@ asmlinkage __visible void __init start_kernel(void) ...@@ -581,7 +581,7 @@ asmlinkage __visible void __init start_kernel(void)
timekeeping_init(); timekeeping_init();
time_init(); time_init();
sched_clock_postinit(); sched_clock_postinit();
printk_nmi_init(); printk_safe_init();
perf_event_init(); perf_event_init();
profile_init(); profile_init();
call_function_init(); call_function_init();
......
...@@ -916,7 +916,7 @@ void crash_kexec(struct pt_regs *regs) ...@@ -916,7 +916,7 @@ void crash_kexec(struct pt_regs *regs)
old_cpu = atomic_cmpxchg(&panic_cpu, PANIC_CPU_INVALID, this_cpu); old_cpu = atomic_cmpxchg(&panic_cpu, PANIC_CPU_INVALID, this_cpu);
if (old_cpu == PANIC_CPU_INVALID) { if (old_cpu == PANIC_CPU_INVALID) {
/* This is the 1st CPU which comes here, so go ahead. */ /* This is the 1st CPU which comes here, so go ahead. */
printk_nmi_flush_on_panic(); printk_safe_flush_on_panic();
__crash_kexec(regs); __crash_kexec(regs);
/* /*
......
...@@ -188,7 +188,7 @@ void panic(const char *fmt, ...) ...@@ -188,7 +188,7 @@ void panic(const char *fmt, ...)
* Bypass the panic_cpu check and call __crash_kexec directly. * Bypass the panic_cpu check and call __crash_kexec directly.
*/ */
if (!_crash_kexec_post_notifiers) { if (!_crash_kexec_post_notifiers) {
printk_nmi_flush_on_panic(); printk_safe_flush_on_panic();
__crash_kexec(NULL); __crash_kexec(NULL);
/* /*
...@@ -213,7 +213,7 @@ void panic(const char *fmt, ...) ...@@ -213,7 +213,7 @@ void panic(const char *fmt, ...)
atomic_notifier_call_chain(&panic_notifier_list, 0, buf); atomic_notifier_call_chain(&panic_notifier_list, 0, buf);
/* Call flush even twice. It tries harder with a single online CPU */ /* Call flush even twice. It tries harder with a single online CPU */
printk_nmi_flush_on_panic(); printk_safe_flush_on_panic();
kmsg_dump(KMSG_DUMP_PANIC); kmsg_dump(KMSG_DUMP_PANIC);
/* /*
......
obj-y = printk.o obj-y = printk.o
obj-$(CONFIG_PRINTK_NMI) += nmi.o obj-$(CONFIG_PRINTK) += printk_safe.o
obj-$(CONFIG_A11Y_BRAILLE_CONSOLE) += braille.o obj-$(CONFIG_A11Y_BRAILLE_CONSOLE) += braille.o
...@@ -16,42 +16,55 @@ ...@@ -16,42 +16,55 @@
*/ */
#include <linux/percpu.h> #include <linux/percpu.h>
typedef __printf(1, 0) int (*printk_func_t)(const char *fmt, va_list args); #ifdef CONFIG_PRINTK
int __printf(1, 0) vprintk_default(const char *fmt, va_list args); #define PRINTK_SAFE_CONTEXT_MASK 0x7fffffff
#define PRINTK_NMI_CONTEXT_MASK 0x80000000
#ifdef CONFIG_PRINTK_NMI
extern raw_spinlock_t logbuf_lock; extern raw_spinlock_t logbuf_lock;
__printf(1, 0) int vprintk_default(const char *fmt, va_list args);
__printf(1, 0) int vprintk_func(const char *fmt, va_list args);
void __printk_safe_enter(void);
void __printk_safe_exit(void);
#define printk_safe_enter_irqsave(flags) \
do { \
local_irq_save(flags); \
__printk_safe_enter(); \
} while (0)
#define printk_safe_exit_irqrestore(flags) \
do { \
__printk_safe_exit(); \
local_irq_restore(flags); \
} while (0)
#define printk_safe_enter_irq() \
do { \
local_irq_disable(); \
__printk_safe_enter(); \
} while (0)
#define printk_safe_exit_irq() \
do { \
__printk_safe_exit(); \
local_irq_enable(); \
} while (0)
#else
__printf(1, 0) int vprintk_func(const char *fmt, va_list args) { return 0; }
/* /*
* printk() could not take logbuf_lock in NMI context. Instead, * In !PRINTK builds we still export logbuf_lock spin_lock, console_sem
* it temporary stores the strings into a per-CPU buffer. * semaphore and some of console functions (console_unlock()/etc.), so
* The alternative implementation is chosen transparently * printk-safe must preserve the existing local IRQ guarantees.
* via per-CPU variable.
*/ */
DECLARE_PER_CPU(printk_func_t, printk_func); #define printk_safe_enter_irqsave(flags) local_irq_save(flags)
static inline __printf(1, 0) int vprintk_func(const char *fmt, va_list args) #define printk_safe_exit_irqrestore(flags) local_irq_restore(flags)
{
return this_cpu_read(printk_func)(fmt, args); #define printk_safe_enter_irq() local_irq_disable()
} #define printk_safe_exit_irq() local_irq_enable()
extern atomic_t nmi_message_lost; #endif /* CONFIG_PRINTK */
static inline int get_nmi_message_lost(void)
{
return atomic_xchg(&nmi_message_lost, 0);
}
#else /* CONFIG_PRINTK_NMI */
static inline __printf(1, 0) int vprintk_func(const char *fmt, va_list args)
{
return vprintk_default(fmt, args);
}
static inline int get_nmi_message_lost(void)
{
return 0;
}
#endif /* CONFIG_PRINTK_NMI */
This diff is collapsed.
...@@ -77,7 +77,7 @@ void nmi_trigger_cpumask_backtrace(const cpumask_t *mask, ...@@ -77,7 +77,7 @@ void nmi_trigger_cpumask_backtrace(const cpumask_t *mask,
* Force flush any remote buffers that might be stuck in IRQ context * Force flush any remote buffers that might be stuck in IRQ context
* and therefore could not run their irq_work. * and therefore could not run their irq_work.
*/ */
printk_nmi_flush(); printk_safe_flush();
clear_bit_unlock(0, &backtrace_flag); clear_bit_unlock(0, &backtrace_flag);
put_cpu(); put_cpu();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment