aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPetr Mladek <pmladek@suse.com>2018-08-14 07:36:15 -0400
committerPetr Mladek <pmladek@suse.com>2018-08-14 07:36:15 -0400
commit9f68cb579115faa211ae067b4628cf11162783fb (patch)
tree051146dd180af1b8a368d1a53b78c78920e15f64
parent554ec508653688c21d9b8024af73a1ffaa0164b9 (diff)
parent03fc7f9c99c1e7ae2925d459e8487f1a6f199f79 (diff)
Merge branch 'for-4.19-nmi' into for-linus
-rw-r--r--include/linux/printk.h4
-rw-r--r--kernel/printk/internal.h9
-rw-r--r--kernel/printk/printk.c57
-rw-r--r--kernel/printk/printk_safe.c58
-rw-r--r--kernel/trace/trace.c4
-rw-r--r--lib/nmi_backtrace.c3
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
149extern void printk_nmi_enter(void); 149extern void printk_nmi_enter(void);
150extern void printk_nmi_exit(void); 150extern void printk_nmi_exit(void);
151extern void printk_nmi_direct_enter(void);
152extern void printk_nmi_direct_exit(void);
151#else 153#else
152static inline void printk_nmi_enter(void) { } 154static inline void printk_nmi_enter(void) { }
153static inline void printk_nmi_exit(void) { } 155static inline void printk_nmi_exit(void) { }
156static inline void printk_nmi_direct_enter(void) { }
157static 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
25extern raw_spinlock_t logbuf_lock; 25extern raw_spinlock_t logbuf_lock;
26 26
27__printf(5, 0)
28int 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
62void 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
1832asmlinkage int vprintk_emit(int facility, int level, 1832/* Must be called under logbuf_lock. */
1833 const char *dict, size_t dictlen, 1833int 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
1889asmlinkage 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
2887int vprintk_deferred(const char *fmt, va_list args) 2896void 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
2904int 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
309void printk_nmi_enter(void) 309void 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
324void printk_nmi_exit(void) 314void 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 */
329void 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
335void 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}
8350EXPORT_SYMBOL_GPL(ftrace_dump); 8352EXPORT_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
88bool nmi_cpu_backtrace(struct pt_regs *regs) 88bool 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 }