summaryrefslogtreecommitdiffstats
path: root/kernel/printk
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 /kernel/printk
parent554ec508653688c21d9b8024af73a1ffaa0164b9 (diff)
parent03fc7f9c99c1e7ae2925d459e8487f1a6f199f79 (diff)
Merge branch 'for-4.19-nmi' into for-linus
Diffstat (limited to 'kernel/printk')
-rw-r--r--kernel/printk/internal.h9
-rw-r--r--kernel/printk/printk.c57
-rw-r--r--kernel/printk/printk_safe.c58
3 files changed, 80 insertions, 44 deletions
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}