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 /kernel/printk | |
parent | 554ec508653688c21d9b8024af73a1ffaa0164b9 (diff) | |
parent | 03fc7f9c99c1e7ae2925d459e8487f1a6f199f79 (diff) |
Merge branch 'for-4.19-nmi' into for-linus
Diffstat (limited to 'kernel/printk')
-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 |
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 | ||
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 | } |