diff options
Diffstat (limited to 'kernel/printk.c')
-rw-r--r-- | kernel/printk.c | 41 |
1 files changed, 23 insertions, 18 deletions
diff --git a/kernel/printk.c b/kernel/printk.c index 19c0d7bcf24a..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 | ||
@@ -870,10 +871,11 @@ static size_t print_time(u64 ts, char *buf) | |||
870 | if (!printk_time) | 871 | if (!printk_time) |
871 | return 0; | 872 | return 0; |
872 | 873 | ||
874 | rem_nsec = do_div(ts, 1000000000); | ||
875 | |||
873 | if (!buf) | 876 | if (!buf) |
874 | return 15; | 877 | return snprintf(NULL, 0, "[%5lu.000000] ", (unsigned long)ts); |
875 | 878 | ||
876 | rem_nsec = do_div(ts, 1000000000); | ||
877 | return sprintf(buf, "[%5lu.%06lu] ", | 879 | return sprintf(buf, "[%5lu.%06lu] ", |
878 | (unsigned long)ts, rem_nsec / 1000); | 880 | (unsigned long)ts, rem_nsec / 1000); |
879 | } | 881 | } |
@@ -1966,30 +1968,32 @@ int is_console_locked(void) | |||
1966 | static DEFINE_PER_CPU(int, printk_pending); | 1968 | static DEFINE_PER_CPU(int, printk_pending); |
1967 | static DEFINE_PER_CPU(char [PRINTK_BUF_SIZE], printk_sched_buf); | 1969 | static DEFINE_PER_CPU(char [PRINTK_BUF_SIZE], printk_sched_buf); |
1968 | 1970 | ||
1969 | void printk_tick(void) | 1971 | static void wake_up_klogd_work_func(struct irq_work *irq_work) |
1970 | { | 1972 | { |
1971 | if (__this_cpu_read(printk_pending)) { | 1973 | int pending = __this_cpu_xchg(printk_pending, 0); |
1972 | int pending = __this_cpu_xchg(printk_pending, 0); | 1974 | |
1973 | if (pending & PRINTK_PENDING_SCHED) { | 1975 | if (pending & PRINTK_PENDING_SCHED) { |
1974 | char *buf = __get_cpu_var(printk_sched_buf); | 1976 | char *buf = __get_cpu_var(printk_sched_buf); |
1975 | printk(KERN_WARNING "[sched_delayed] %s", buf); | 1977 | printk(KERN_WARNING "[sched_delayed] %s", buf); |
1976 | } | ||
1977 | if (pending & PRINTK_PENDING_WAKEUP) | ||
1978 | wake_up_interruptible(&log_wait); | ||
1979 | } | 1978 | } |
1980 | } | ||
1981 | 1979 | ||
1982 | int printk_needs_cpu(int cpu) | 1980 | if (pending & PRINTK_PENDING_WAKEUP) |
1983 | { | 1981 | wake_up_interruptible(&log_wait); |
1984 | if (cpu_is_offline(cpu)) | ||
1985 | printk_tick(); | ||
1986 | return __this_cpu_read(printk_pending); | ||
1987 | } | 1982 | } |
1988 | 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 | |||
1989 | void wake_up_klogd(void) | 1989 | void wake_up_klogd(void) |
1990 | { | 1990 | { |
1991 | if (waitqueue_active(&log_wait)) | 1991 | preempt_disable(); |
1992 | if (waitqueue_active(&log_wait)) { | ||
1992 | 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(); | ||
1993 | } | 1997 | } |
1994 | 1998 | ||
1995 | static void console_cont_flush(char *text, size_t size) | 1999 | static void console_cont_flush(char *text, size_t size) |
@@ -2470,6 +2474,7 @@ int printk_sched(const char *fmt, ...) | |||
2470 | va_end(args); | 2474 | va_end(args); |
2471 | 2475 | ||
2472 | __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)); | ||
2473 | local_irq_restore(flags); | 2478 | local_irq_restore(flags); |
2474 | 2479 | ||
2475 | return r; | 2480 | return r; |