aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/printk.c
diff options
context:
space:
mode:
authorFrederic Weisbecker <fweisbec@gmail.com>2012-10-12 12:00:23 -0400
committerFrederic Weisbecker <fweisbec@gmail.com>2012-11-17 19:01:49 -0500
commit74876a98a87a115254b3a66a14b27320b7f0acaa (patch)
tree06ed1cff8a92b0c687a7ff2fe31c19e8249bbe3c /kernel/printk.c
parentbc6679aef673f9dcb8f718528fc3df49ff661af9 (diff)
printk: Wake up klogd using irq_work
klogd is woken up asynchronously from the tick in order to do it safely. However if printk is called when the tick is stopped, the reader won't be woken up until the next interrupt, which might not fire for a while. As a result, the user may miss some message. To fix this, lets implement the printk tick using a lazy irq work. This subsystem takes care of the timer tick state and can fix up accordingly. Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com> Acked-by: Steven Rostedt <rostedt@goodmis.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: Ingo Molnar <mingo@kernel.org> Cc: Andrew Morton <akpm@linux-foundation.org> Cc: Paul Gortmaker <paul.gortmaker@windriver.com>
Diffstat (limited to 'kernel/printk.c')
-rw-r--r--kernel/printk.c36
1 files changed, 20 insertions, 16 deletions
diff --git a/kernel/printk.c b/kernel/printk.c
index 2d607f4d1797..c9104feba5ec 100644
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -42,6 +42,7 @@
42#include <linux/notifier.h> 42#include <linux/notifier.h>
43#include <linux/rculist.h> 43#include <linux/rculist.h>
44#include <linux/poll.h> 44#include <linux/poll.h>
45#include <linux/irq_work.h>
45 46
46#include <asm/uaccess.h> 47#include <asm/uaccess.h>
47 48
@@ -1955,30 +1956,32 @@ int is_console_locked(void)
1955static DEFINE_PER_CPU(int, printk_pending); 1956static DEFINE_PER_CPU(int, printk_pending);
1956static DEFINE_PER_CPU(char [PRINTK_BUF_SIZE], printk_sched_buf); 1957static DEFINE_PER_CPU(char [PRINTK_BUF_SIZE], printk_sched_buf);
1957 1958
1958void printk_tick(void) 1959static void wake_up_klogd_work_func(struct irq_work *irq_work)
1959{ 1960{
1960 if (__this_cpu_read(printk_pending)) { 1961 int pending = __this_cpu_xchg(printk_pending, 0);
1961 int pending = __this_cpu_xchg(printk_pending, 0); 1962
1962 if (pending & PRINTK_PENDING_SCHED) { 1963 if (pending & PRINTK_PENDING_SCHED) {
1963 char *buf = __get_cpu_var(printk_sched_buf); 1964 char *buf = __get_cpu_var(printk_sched_buf);
1964 printk(KERN_WARNING "[sched_delayed] %s", buf); 1965 printk(KERN_WARNING "[sched_delayed] %s", buf);
1965 }
1966 if (pending & PRINTK_PENDING_WAKEUP)
1967 wake_up_interruptible(&log_wait);
1968 } 1966 }
1969}
1970 1967
1971int printk_needs_cpu(int cpu) 1968 if (pending & PRINTK_PENDING_WAKEUP)
1972{ 1969 wake_up_interruptible(&log_wait);
1973 if (cpu_is_offline(cpu))
1974 printk_tick();
1975 return __this_cpu_read(printk_pending);
1976} 1970}
1977 1971
1972static DEFINE_PER_CPU(struct irq_work, wake_up_klogd_work) = {
1973 .func = wake_up_klogd_work_func,
1974 .flags = IRQ_WORK_LAZY,
1975};
1976
1978void wake_up_klogd(void) 1977void wake_up_klogd(void)
1979{ 1978{
1980 if (waitqueue_active(&log_wait)) 1979 preempt_disable();
1980 if (waitqueue_active(&log_wait)) {
1981 this_cpu_or(printk_pending, PRINTK_PENDING_WAKEUP); 1981 this_cpu_or(printk_pending, PRINTK_PENDING_WAKEUP);
1982 irq_work_queue(&__get_cpu_var(wake_up_klogd_work));
1983 }
1984 preempt_enable();
1982} 1985}
1983 1986
1984static void console_cont_flush(char *text, size_t size) 1987static void console_cont_flush(char *text, size_t size)
@@ -2458,6 +2461,7 @@ int printk_sched(const char *fmt, ...)
2458 va_end(args); 2461 va_end(args);
2459 2462
2460 __this_cpu_or(printk_pending, PRINTK_PENDING_SCHED); 2463 __this_cpu_or(printk_pending, PRINTK_PENDING_SCHED);
2464 irq_work_queue(&__get_cpu_var(wake_up_klogd_work));
2461 local_irq_restore(flags); 2465 local_irq_restore(flags);
2462 2466
2463 return r; 2467 return r;