diff options
author | Petr Mladek <pmladek@suse.com> | 2018-08-14 07:36:15 -0400 |
---|---|---|
committer | Petr Mladek <pmladek@suse.com> | 2018-08-14 07:36:15 -0400 |
commit | 9f68cb579115faa211ae067b4628cf11162783fb (patch) | |
tree | 051146dd180af1b8a368d1a53b78c78920e15f64 | |
parent | 554ec508653688c21d9b8024af73a1ffaa0164b9 (diff) | |
parent | 03fc7f9c99c1e7ae2925d459e8487f1a6f199f79 (diff) |
Merge branch 'for-4.19-nmi' into for-linus
-rw-r--r-- | include/linux/printk.h | 4 | ||||
-rw-r--r-- | kernel/printk/internal.h | 9 | ||||
-rw-r--r-- | kernel/printk/printk.c | 57 | ||||
-rw-r--r-- | kernel/printk/printk_safe.c | 58 | ||||
-rw-r--r-- | kernel/trace/trace.c | 4 | ||||
-rw-r--r-- | lib/nmi_backtrace.c | 3 |
6 files changed, 87 insertions, 48 deletions
diff --git a/include/linux/printk.h b/include/linux/printk.h index 18602bb3eca8..cf3eccfe1543 100644 --- a/include/linux/printk.h +++ b/include/linux/printk.h | |||
@@ -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 e2cb0fc18e2d..9a63aeeaaf5d 100644 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c | |||
@@ -1829,28 +1829,16 @@ static size_t log_output(int facility, int level, enum log_flags lflags, const c | |||
1829 | 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); |
1830 | } | 1830 | } |
1831 | 1831 | ||
1832 | asmlinkage int vprintk_emit(int facility, int level, | 1832 | /* Must be called under logbuf_lock. */ |
1833 | const char *dict, size_t dictlen, | 1833 | int vprintk_store(int facility, int level, |
1834 | const char *fmt, va_list args) | 1834 | const char *dict, size_t dictlen, |
1835 | const char *fmt, va_list args) | ||
1835 | { | 1836 | { |
1836 | static char textbuf[LOG_LINE_MAX]; | 1837 | static char textbuf[LOG_LINE_MAX]; |
1837 | char *text = textbuf; | 1838 | char *text = textbuf; |
1838 | size_t text_len; | 1839 | size_t text_len; |
1839 | enum log_flags lflags = 0; | 1840 | enum log_flags lflags = 0; |
1840 | unsigned long flags; | ||
1841 | int printed_len; | ||
1842 | bool in_sched = false; | ||
1843 | |||
1844 | if (level == LOGLEVEL_SCHED) { | ||
1845 | level = LOGLEVEL_DEFAULT; | ||
1846 | in_sched = true; | ||
1847 | } | ||
1848 | |||
1849 | boot_delay_msec(level); | ||
1850 | printk_delay(); | ||
1851 | 1841 | ||
1852 | /* This stops the holder of console_sem just where we want him */ | ||
1853 | logbuf_lock_irqsave(flags); | ||
1854 | /* | 1842 | /* |
1855 | * The printf needs to come first; we need the syslog | 1843 | * The printf needs to come first; we need the syslog |
1856 | * prefix which might be passed-in as a parameter. | 1844 | * prefix which might be passed-in as a parameter. |
@@ -1894,8 +1882,29 @@ asmlinkage int vprintk_emit(int facility, int level, | |||
1894 | if (suppress_message_printing(level)) | 1882 | if (suppress_message_printing(level)) |
1895 | lflags |= LOG_NOCONS; | 1883 | lflags |= LOG_NOCONS; |
1896 | 1884 | ||
1897 | printed_len = log_output(facility, level, lflags, dict, dictlen, text, text_len); | 1885 | return log_output(facility, level, lflags, |
1886 | dict, dictlen, text, text_len); | ||
1887 | } | ||
1898 | 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 | } | ||
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); | ||
1899 | logbuf_unlock_irqrestore(flags); | 1908 | logbuf_unlock_irqrestore(flags); |
1900 | 1909 | ||
1901 | /* If called from the scheduler, we can not call up(). */ | 1910 | /* If called from the scheduler, we can not call up(). */ |
@@ -2884,16 +2893,20 @@ void wake_up_klogd(void) | |||
2884 | preempt_enable(); | 2893 | preempt_enable(); |
2885 | } | 2894 | } |
2886 | 2895 | ||
2887 | int vprintk_deferred(const char *fmt, va_list args) | 2896 | void defer_console_output(void) |
2888 | { | 2897 | { |
2889 | int r; | ||
2890 | |||
2891 | r = vprintk_emit(0, LOGLEVEL_SCHED, NULL, 0, fmt, args); | ||
2892 | |||
2893 | preempt_disable(); | 2898 | preempt_disable(); |
2894 | __this_cpu_or(printk_pending, PRINTK_PENDING_OUTPUT); | 2899 | __this_cpu_or(printk_pending, PRINTK_PENDING_OUTPUT); |
2895 | irq_work_queue(this_cpu_ptr(&wake_up_klogd_work)); | 2900 | irq_work_queue(this_cpu_ptr(&wake_up_klogd_work)); |
2896 | 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(); | ||
2897 | 2910 | ||
2898 | return r; | 2911 | return r; |
2899 | } | 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 bcd93031d042..f106ad12f72f 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c | |||
@@ -8265,6 +8265,7 @@ void ftrace_dump(enum ftrace_dump_mode oops_dump_mode) | |||
8265 | tracing_off(); | 8265 | tracing_off(); |
8266 | 8266 | ||
8267 | local_irq_save(flags); | 8267 | local_irq_save(flags); |
8268 | printk_nmi_direct_enter(); | ||
8268 | 8269 | ||
8269 | /* Simulate the iterator */ | 8270 | /* Simulate the iterator */ |
8270 | trace_init_global_iter(&iter); | 8271 | trace_init_global_iter(&iter); |
@@ -8344,7 +8345,8 @@ void ftrace_dump(enum ftrace_dump_mode oops_dump_mode) | |||
8344 | for_each_tracing_cpu(cpu) { | 8345 | for_each_tracing_cpu(cpu) { |
8345 | atomic_dec(&per_cpu_ptr(iter.trace_buffer->data, cpu)->disabled); | 8346 | atomic_dec(&per_cpu_ptr(iter.trace_buffer->data, cpu)->disabled); |
8346 | } | 8347 | } |
8347 | atomic_dec(&dump_running); | 8348 | atomic_dec(&dump_running); |
8349 | printk_nmi_direct_exit(); | ||
8348 | local_irq_restore(flags); | 8350 | local_irq_restore(flags); |
8349 | } | 8351 | } |
8350 | EXPORT_SYMBOL_GPL(ftrace_dump); | 8352 | EXPORT_SYMBOL_GPL(ftrace_dump); |
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 | } |