diff options
Diffstat (limited to 'kernel/printk.c')
-rw-r--r-- | kernel/printk.c | 36 |
1 files changed, 20 insertions, 16 deletions
diff --git a/kernel/printk.c b/kernel/printk.c index 357f714ddd49..0b31715f335a 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 | ||
@@ -1967,30 +1968,32 @@ int is_console_locked(void) | |||
1967 | static DEFINE_PER_CPU(int, printk_pending); | 1968 | static DEFINE_PER_CPU(int, printk_pending); |
1968 | static DEFINE_PER_CPU(char [PRINTK_BUF_SIZE], printk_sched_buf); | 1969 | static DEFINE_PER_CPU(char [PRINTK_BUF_SIZE], printk_sched_buf); |
1969 | 1970 | ||
1970 | void printk_tick(void) | 1971 | static void wake_up_klogd_work_func(struct irq_work *irq_work) |
1971 | { | 1972 | { |
1972 | if (__this_cpu_read(printk_pending)) { | 1973 | int pending = __this_cpu_xchg(printk_pending, 0); |
1973 | int pending = __this_cpu_xchg(printk_pending, 0); | 1974 | |
1974 | if (pending & PRINTK_PENDING_SCHED) { | 1975 | if (pending & PRINTK_PENDING_SCHED) { |
1975 | char *buf = __get_cpu_var(printk_sched_buf); | 1976 | char *buf = __get_cpu_var(printk_sched_buf); |
1976 | printk(KERN_WARNING "[sched_delayed] %s", buf); | 1977 | printk(KERN_WARNING "[sched_delayed] %s", buf); |
1977 | } | ||
1978 | if (pending & PRINTK_PENDING_WAKEUP) | ||
1979 | wake_up_interruptible(&log_wait); | ||
1980 | } | 1978 | } |
1981 | } | ||
1982 | 1979 | ||
1983 | int printk_needs_cpu(int cpu) | 1980 | if (pending & PRINTK_PENDING_WAKEUP) |
1984 | { | 1981 | wake_up_interruptible(&log_wait); |
1985 | if (cpu_is_offline(cpu)) | ||
1986 | printk_tick(); | ||
1987 | return __this_cpu_read(printk_pending); | ||
1988 | } | 1982 | } |
1989 | 1983 | ||
1984 | static DEFINE_PER_CPU(struct irq_work, wake_up_klogd_work) = { | ||
1985 | .func = wake_up_klogd_work_func, | ||
1986 | .flags = IRQ_WORK_LAZY, | ||
1987 | }; | ||
1988 | |||
1990 | void wake_up_klogd(void) | 1989 | void wake_up_klogd(void) |
1991 | { | 1990 | { |
1992 | if (waitqueue_active(&log_wait)) | 1991 | preempt_disable(); |
1992 | if (waitqueue_active(&log_wait)) { | ||
1993 | this_cpu_or(printk_pending, PRINTK_PENDING_WAKEUP); | 1993 | this_cpu_or(printk_pending, PRINTK_PENDING_WAKEUP); |
1994 | irq_work_queue(&__get_cpu_var(wake_up_klogd_work)); | ||
1995 | } | ||
1996 | preempt_enable(); | ||
1994 | } | 1997 | } |
1995 | 1998 | ||
1996 | static void console_cont_flush(char *text, size_t size) | 1999 | static void console_cont_flush(char *text, size_t size) |
@@ -2471,6 +2474,7 @@ int printk_sched(const char *fmt, ...) | |||
2471 | va_end(args); | 2474 | va_end(args); |
2472 | 2475 | ||
2473 | __this_cpu_or(printk_pending, PRINTK_PENDING_SCHED); | 2476 | __this_cpu_or(printk_pending, PRINTK_PENDING_SCHED); |
2477 | irq_work_queue(&__get_cpu_var(wake_up_klogd_work)); | ||
2474 | local_irq_restore(flags); | 2478 | local_irq_restore(flags); |
2475 | 2479 | ||
2476 | return r; | 2480 | return r; |