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 267ce780abe8..f24633afa46a 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 | ||
@@ -1959,30 +1960,32 @@ int is_console_locked(void) | |||
1959 | static DEFINE_PER_CPU(int, printk_pending); | 1960 | static DEFINE_PER_CPU(int, printk_pending); |
1960 | static DEFINE_PER_CPU(char [PRINTK_BUF_SIZE], printk_sched_buf); | 1961 | static DEFINE_PER_CPU(char [PRINTK_BUF_SIZE], printk_sched_buf); |
1961 | 1962 | ||
1962 | void printk_tick(void) | 1963 | static void wake_up_klogd_work_func(struct irq_work *irq_work) |
1963 | { | 1964 | { |
1964 | if (__this_cpu_read(printk_pending)) { | 1965 | int pending = __this_cpu_xchg(printk_pending, 0); |
1965 | int pending = __this_cpu_xchg(printk_pending, 0); | 1966 | |
1966 | if (pending & PRINTK_PENDING_SCHED) { | 1967 | if (pending & PRINTK_PENDING_SCHED) { |
1967 | char *buf = __get_cpu_var(printk_sched_buf); | 1968 | char *buf = __get_cpu_var(printk_sched_buf); |
1968 | printk(KERN_WARNING "[sched_delayed] %s", buf); | 1969 | printk(KERN_WARNING "[sched_delayed] %s", buf); |
1969 | } | ||
1970 | if (pending & PRINTK_PENDING_WAKEUP) | ||
1971 | wake_up_interruptible(&log_wait); | ||
1972 | } | 1970 | } |
1973 | } | ||
1974 | 1971 | ||
1975 | int printk_needs_cpu(int cpu) | 1972 | if (pending & PRINTK_PENDING_WAKEUP) |
1976 | { | 1973 | wake_up_interruptible(&log_wait); |
1977 | if (cpu_is_offline(cpu)) | ||
1978 | printk_tick(); | ||
1979 | return __this_cpu_read(printk_pending); | ||
1980 | } | 1974 | } |
1981 | 1975 | ||
1976 | static DEFINE_PER_CPU(struct irq_work, wake_up_klogd_work) = { | ||
1977 | .func = wake_up_klogd_work_func, | ||
1978 | .flags = IRQ_WORK_LAZY, | ||
1979 | }; | ||
1980 | |||
1982 | void wake_up_klogd(void) | 1981 | void wake_up_klogd(void) |
1983 | { | 1982 | { |
1984 | if (waitqueue_active(&log_wait)) | 1983 | preempt_disable(); |
1984 | if (waitqueue_active(&log_wait)) { | ||
1985 | this_cpu_or(printk_pending, PRINTK_PENDING_WAKEUP); | 1985 | this_cpu_or(printk_pending, PRINTK_PENDING_WAKEUP); |
1986 | irq_work_queue(&__get_cpu_var(wake_up_klogd_work)); | ||
1987 | } | ||
1988 | preempt_enable(); | ||
1986 | } | 1989 | } |
1987 | 1990 | ||
1988 | static void console_cont_flush(char *text, size_t size) | 1991 | static void console_cont_flush(char *text, size_t size) |
@@ -2462,6 +2465,7 @@ int printk_sched(const char *fmt, ...) | |||
2462 | va_end(args); | 2465 | va_end(args); |
2463 | 2466 | ||
2464 | __this_cpu_or(printk_pending, PRINTK_PENDING_SCHED); | 2467 | __this_cpu_or(printk_pending, PRINTK_PENDING_SCHED); |
2468 | irq_work_queue(&__get_cpu_var(wake_up_klogd_work)); | ||
2465 | local_irq_restore(flags); | 2469 | local_irq_restore(flags); |
2466 | 2470 | ||
2467 | return r; | 2471 | return r; |