Skip to content

Commit

Permalink
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel…
Browse files Browse the repository at this point in the history
…/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/[email protected]
[2] http://lkml.kernel.org/r/[email protected]
[3] http://lkml.kernel.org/r/[email protected]
[4] http://lkml.kernel.org/r/[email protected]

* '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
  • Loading branch information
torvalds committed Feb 23, 2017
2 parents 6ef192f + d9c2352 commit 7d91de7
Show file tree
Hide file tree
Showing 11 changed files with 347 additions and 255 deletions.
8 changes: 8 additions & 0 deletions MAINTAINERS
Original file line number Diff line number Diff line change
Expand Up @@ -9997,6 +9997,14 @@ S: Supported
F: Documentation/preempt-locking.txt
F: include/linux/preempt.h

PRINTK
M: Petr Mladek <[email protected]>
M: Sergey Senozhatsky <[email protected]>
R: Steven Rostedt <[email protected]>
S: Maintained
F: kernel/printk/
F: include/linux/printk.h

PRISM54 WIRELESS DRIVER
M: "Luis R. Rodriguez" <[email protected]>
L: [email protected]
Expand Down
21 changes: 15 additions & 6 deletions include/linux/printk.h
Original file line number Diff line number Diff line change
Expand Up @@ -147,17 +147,11 @@ void early_printk(const char *s, ...) { }
#endif

#ifdef CONFIG_PRINTK_NMI
extern void printk_nmi_init(void);
extern void printk_nmi_enter(void);
extern void printk_nmi_exit(void);
extern void printk_nmi_flush(void);
extern void printk_nmi_flush_on_panic(void);
#else
static inline void printk_nmi_init(void) { }
static inline void printk_nmi_enter(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 */

#ifdef CONFIG_PRINTK
Expand Down Expand Up @@ -209,6 +203,9 @@ void __init setup_log_buf(int early);
__printf(1, 2) void dump_stack_set_arch_desc(const char *fmt, ...);
void dump_stack_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
static inline __printf(1, 0)
int vprintk(const char *s, va_list args)
Expand Down Expand Up @@ -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 printk_safe_init(void)
{
}

static inline void printk_safe_flush(void)
{
}

static inline void printk_safe_flush_on_panic(void)
{
}
#endif

extern asmlinkage void dump_stack(void) __cold;
Expand Down
16 changes: 9 additions & 7 deletions init/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -861,17 +861,19 @@ config LOG_CPU_MAX_BUF_SHIFT
13 => 8 KB for each CPU
12 => 4 KB for each CPU

config NMI_LOG_BUF_SHIFT
int "Temporary per-CPU NMI log buffer size (12 => 4KB, 13 => 8KB)"
config PRINTK_SAFE_LOG_BUF_SHIFT
int "Temporary per-CPU printk log buffer size (12 => 4KB, 13 => 8KB)"
range 10 21
default 13
depends on PRINTK_NMI
depends on PRINTK
help
Select the size of a per-CPU buffer where NMI messages are temporary
stored. They 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.
Select the size of an alternate printk per-CPU buffer where messages
printed from usafe contexts are temporary stored. One example would
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
8KB if you want to be on the safe side.

Expand Down
2 changes: 1 addition & 1 deletion init/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -581,7 +581,7 @@ asmlinkage __visible void __init start_kernel(void)
timekeeping_init();
time_init();
sched_clock_postinit();
printk_nmi_init();
printk_safe_init();
perf_event_init();
profile_init();
call_function_init();
Expand Down
2 changes: 1 addition & 1 deletion kernel/kexec_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -916,7 +916,7 @@ void crash_kexec(struct pt_regs *regs)
old_cpu = atomic_cmpxchg(&panic_cpu, PANIC_CPU_INVALID, this_cpu);
if (old_cpu == PANIC_CPU_INVALID) {
/* This is the 1st CPU which comes here, so go ahead. */
printk_nmi_flush_on_panic();
printk_safe_flush_on_panic();
__crash_kexec(regs);

/*
Expand Down
4 changes: 2 additions & 2 deletions kernel/panic.c
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ void panic(const char *fmt, ...)
* Bypass the panic_cpu check and call __crash_kexec directly.
*/
if (!_crash_kexec_post_notifiers) {
printk_nmi_flush_on_panic();
printk_safe_flush_on_panic();
__crash_kexec(NULL);

/*
Expand All @@ -213,7 +213,7 @@ void panic(const char *fmt, ...)
atomic_notifier_call_chain(&panic_notifier_list, 0, buf);

/* 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);

/*
Expand Down
2 changes: 1 addition & 1 deletion kernel/printk/Makefile
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
obj-y = printk.o
obj-$(CONFIG_PRINTK_NMI) += nmi.o
obj-$(CONFIG_PRINTK) += printk_safe.o
obj-$(CONFIG_A11Y_BRAILLE_CONSOLE) += braille.o
79 changes: 46 additions & 33 deletions kernel/printk/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,42 +16,55 @@
*/
#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);

#ifdef CONFIG_PRINTK_NMI
#define PRINTK_SAFE_CONTEXT_MASK 0x7fffffff
#define PRINTK_NMI_CONTEXT_MASK 0x80000000

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,
* it temporary stores the strings into a per-CPU buffer.
* The alternative implementation is chosen transparently
* via per-CPU variable.
* In !PRINTK builds we still export logbuf_lock spin_lock, console_sem
* semaphore and some of console functions (console_unlock()/etc.), so
* printk-safe must preserve the existing local IRQ guarantees.
*/
DECLARE_PER_CPU(printk_func_t, printk_func);
static inline __printf(1, 0) int vprintk_func(const char *fmt, va_list args)
{
return this_cpu_read(printk_func)(fmt, args);
}

extern atomic_t nmi_message_lost;
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 */
#define printk_safe_enter_irqsave(flags) local_irq_save(flags)
#define printk_safe_exit_irqrestore(flags) local_irq_restore(flags)

#define printk_safe_enter_irq() local_irq_disable()
#define printk_safe_exit_irq() local_irq_enable()

#endif /* CONFIG_PRINTK */
Loading

0 comments on commit 7d91de7

Please sign in to comment.