diff options
Diffstat (limited to 'kernel/printk.c')
-rw-r--r-- | kernel/printk.c | 89 |
1 files changed, 50 insertions, 39 deletions
diff --git a/kernel/printk.c b/kernel/printk.c index 267ce780abe8..abbdd9e2ac82 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 | ||
@@ -62,8 +63,6 @@ void asmlinkage __attribute__((weak)) early_printk(const char *fmt, ...) | |||
62 | #define MINIMUM_CONSOLE_LOGLEVEL 1 /* Minimum loglevel we let people use */ | 63 | #define MINIMUM_CONSOLE_LOGLEVEL 1 /* Minimum loglevel we let people use */ |
63 | #define DEFAULT_CONSOLE_LOGLEVEL 7 /* anything MORE serious than KERN_DEBUG */ | 64 | #define DEFAULT_CONSOLE_LOGLEVEL 7 /* anything MORE serious than KERN_DEBUG */ |
64 | 65 | ||
65 | DECLARE_WAIT_QUEUE_HEAD(log_wait); | ||
66 | |||
67 | int console_printk[4] = { | 66 | int console_printk[4] = { |
68 | DEFAULT_CONSOLE_LOGLEVEL, /* console_loglevel */ | 67 | DEFAULT_CONSOLE_LOGLEVEL, /* console_loglevel */ |
69 | DEFAULT_MESSAGE_LOGLEVEL, /* default_message_loglevel */ | 68 | DEFAULT_MESSAGE_LOGLEVEL, /* default_message_loglevel */ |
@@ -87,6 +86,12 @@ static DEFINE_SEMAPHORE(console_sem); | |||
87 | struct console *console_drivers; | 86 | struct console *console_drivers; |
88 | EXPORT_SYMBOL_GPL(console_drivers); | 87 | EXPORT_SYMBOL_GPL(console_drivers); |
89 | 88 | ||
89 | #ifdef CONFIG_LOCKDEP | ||
90 | static struct lockdep_map console_lock_dep_map = { | ||
91 | .name = "console_lock" | ||
92 | }; | ||
93 | #endif | ||
94 | |||
90 | /* | 95 | /* |
91 | * This is used for debugging the mess that is the VT code by | 96 | * This is used for debugging the mess that is the VT code by |
92 | * keeping track if we have the console semaphore held. It's | 97 | * keeping track if we have the console semaphore held. It's |
@@ -217,6 +222,7 @@ struct log { | |||
217 | static DEFINE_RAW_SPINLOCK(logbuf_lock); | 222 | static DEFINE_RAW_SPINLOCK(logbuf_lock); |
218 | 223 | ||
219 | #ifdef CONFIG_PRINTK | 224 | #ifdef CONFIG_PRINTK |
225 | DECLARE_WAIT_QUEUE_HEAD(log_wait); | ||
220 | /* the next printk record to read by syslog(READ) or /proc/kmsg */ | 226 | /* the next printk record to read by syslog(READ) or /proc/kmsg */ |
221 | static u64 syslog_seq; | 227 | static u64 syslog_seq; |
222 | static u32 syslog_idx; | 228 | static u32 syslog_idx; |
@@ -1918,6 +1924,7 @@ void console_lock(void) | |||
1918 | return; | 1924 | return; |
1919 | console_locked = 1; | 1925 | console_locked = 1; |
1920 | console_may_schedule = 1; | 1926 | console_may_schedule = 1; |
1927 | mutex_acquire(&console_lock_dep_map, 0, 0, _RET_IP_); | ||
1921 | } | 1928 | } |
1922 | EXPORT_SYMBOL(console_lock); | 1929 | EXPORT_SYMBOL(console_lock); |
1923 | 1930 | ||
@@ -1939,6 +1946,7 @@ int console_trylock(void) | |||
1939 | } | 1946 | } |
1940 | console_locked = 1; | 1947 | console_locked = 1; |
1941 | console_may_schedule = 0; | 1948 | console_may_schedule = 0; |
1949 | mutex_acquire(&console_lock_dep_map, 0, 1, _RET_IP_); | ||
1942 | return 1; | 1950 | return 1; |
1943 | } | 1951 | } |
1944 | EXPORT_SYMBOL(console_trylock); | 1952 | EXPORT_SYMBOL(console_trylock); |
@@ -1948,43 +1956,6 @@ int is_console_locked(void) | |||
1948 | return console_locked; | 1956 | return console_locked; |
1949 | } | 1957 | } |
1950 | 1958 | ||
1951 | /* | ||
1952 | * Delayed printk version, for scheduler-internal messages: | ||
1953 | */ | ||
1954 | #define PRINTK_BUF_SIZE 512 | ||
1955 | |||
1956 | #define PRINTK_PENDING_WAKEUP 0x01 | ||
1957 | #define PRINTK_PENDING_SCHED 0x02 | ||
1958 | |||
1959 | static DEFINE_PER_CPU(int, printk_pending); | ||
1960 | static DEFINE_PER_CPU(char [PRINTK_BUF_SIZE], printk_sched_buf); | ||
1961 | |||
1962 | void printk_tick(void) | ||
1963 | { | ||
1964 | if (__this_cpu_read(printk_pending)) { | ||
1965 | int pending = __this_cpu_xchg(printk_pending, 0); | ||
1966 | if (pending & PRINTK_PENDING_SCHED) { | ||
1967 | char *buf = __get_cpu_var(printk_sched_buf); | ||
1968 | printk(KERN_WARNING "[sched_delayed] %s", buf); | ||
1969 | } | ||
1970 | if (pending & PRINTK_PENDING_WAKEUP) | ||
1971 | wake_up_interruptible(&log_wait); | ||
1972 | } | ||
1973 | } | ||
1974 | |||
1975 | int printk_needs_cpu(int cpu) | ||
1976 | { | ||
1977 | if (cpu_is_offline(cpu)) | ||
1978 | printk_tick(); | ||
1979 | return __this_cpu_read(printk_pending); | ||
1980 | } | ||
1981 | |||
1982 | void wake_up_klogd(void) | ||
1983 | { | ||
1984 | if (waitqueue_active(&log_wait)) | ||
1985 | this_cpu_or(printk_pending, PRINTK_PENDING_WAKEUP); | ||
1986 | } | ||
1987 | |||
1988 | static void console_cont_flush(char *text, size_t size) | 1959 | static void console_cont_flush(char *text, size_t size) |
1989 | { | 1960 | { |
1990 | unsigned long flags; | 1961 | unsigned long flags; |
@@ -2099,6 +2070,7 @@ skip: | |||
2099 | local_irq_restore(flags); | 2070 | local_irq_restore(flags); |
2100 | } | 2071 | } |
2101 | console_locked = 0; | 2072 | console_locked = 0; |
2073 | mutex_release(&console_lock_dep_map, 1, _RET_IP_); | ||
2102 | 2074 | ||
2103 | /* Release the exclusive_console once it is used */ | 2075 | /* Release the exclusive_console once it is used */ |
2104 | if (unlikely(exclusive_console)) | 2076 | if (unlikely(exclusive_console)) |
@@ -2446,6 +2418,44 @@ static int __init printk_late_init(void) | |||
2446 | late_initcall(printk_late_init); | 2418 | late_initcall(printk_late_init); |
2447 | 2419 | ||
2448 | #if defined CONFIG_PRINTK | 2420 | #if defined CONFIG_PRINTK |
2421 | /* | ||
2422 | * Delayed printk version, for scheduler-internal messages: | ||
2423 | */ | ||
2424 | #define PRINTK_BUF_SIZE 512 | ||
2425 | |||
2426 | #define PRINTK_PENDING_WAKEUP 0x01 | ||
2427 | #define PRINTK_PENDING_SCHED 0x02 | ||
2428 | |||
2429 | static DEFINE_PER_CPU(int, printk_pending); | ||
2430 | static DEFINE_PER_CPU(char [PRINTK_BUF_SIZE], printk_sched_buf); | ||
2431 | |||
2432 | static void wake_up_klogd_work_func(struct irq_work *irq_work) | ||
2433 | { | ||
2434 | int pending = __this_cpu_xchg(printk_pending, 0); | ||
2435 | |||
2436 | if (pending & PRINTK_PENDING_SCHED) { | ||
2437 | char *buf = __get_cpu_var(printk_sched_buf); | ||
2438 | printk(KERN_WARNING "[sched_delayed] %s", buf); | ||
2439 | } | ||
2440 | |||
2441 | if (pending & PRINTK_PENDING_WAKEUP) | ||
2442 | wake_up_interruptible(&log_wait); | ||
2443 | } | ||
2444 | |||
2445 | static DEFINE_PER_CPU(struct irq_work, wake_up_klogd_work) = { | ||
2446 | .func = wake_up_klogd_work_func, | ||
2447 | .flags = IRQ_WORK_LAZY, | ||
2448 | }; | ||
2449 | |||
2450 | void wake_up_klogd(void) | ||
2451 | { | ||
2452 | preempt_disable(); | ||
2453 | if (waitqueue_active(&log_wait)) { | ||
2454 | this_cpu_or(printk_pending, PRINTK_PENDING_WAKEUP); | ||
2455 | irq_work_queue(&__get_cpu_var(wake_up_klogd_work)); | ||
2456 | } | ||
2457 | preempt_enable(); | ||
2458 | } | ||
2449 | 2459 | ||
2450 | int printk_sched(const char *fmt, ...) | 2460 | int printk_sched(const char *fmt, ...) |
2451 | { | 2461 | { |
@@ -2462,6 +2472,7 @@ int printk_sched(const char *fmt, ...) | |||
2462 | va_end(args); | 2472 | va_end(args); |
2463 | 2473 | ||
2464 | __this_cpu_or(printk_pending, PRINTK_PENDING_SCHED); | 2474 | __this_cpu_or(printk_pending, PRINTK_PENDING_SCHED); |
2475 | irq_work_queue(&__get_cpu_var(wake_up_klogd_work)); | ||
2465 | local_irq_restore(flags); | 2476 | local_irq_restore(flags); |
2466 | 2477 | ||
2467 | return r; | 2478 | return r; |