diff options
author | Jason Wessel <jason.wessel@windriver.com> | 2010-05-20 22:04:27 -0400 |
---|---|---|
committer | Jason Wessel <jason.wessel@windriver.com> | 2010-05-20 22:04:27 -0400 |
commit | d37d39ae3b4a8f9a21114921fb344fe7cadb1abd (patch) | |
tree | 2c20219725a12c343429758ec378b5c9d08b04bd /kernel | |
parent | efe2f29e324fd20e0449bcd6dc6dbe4734c2ba94 (diff) |
printk,kdb: capture printk() when in kdb shell
Certain calls from the kdb shell will call out to printk(), and any of
these calls should get vectored back to the kdb_printf() so that the
kdb pager and processing can be used, as well as to properly channel
I/O to the polled I/O devices.
CC: Randy Dunlap <rdunlap@xenotime.net>
Signed-off-by: Jason Wessel <jason.wessel@windriver.com>
Acked-by: Andrew Morton <akpm@linux-foundation.org>
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/debug/kdb/kdb_bt.c | 2 | ||||
-rw-r--r-- | kernel/debug/kdb/kdb_io.c | 24 | ||||
-rw-r--r-- | kernel/debug/kdb/kdb_main.c | 4 | ||||
-rw-r--r-- | kernel/printk.c | 9 |
4 files changed, 35 insertions, 4 deletions
diff --git a/kernel/debug/kdb/kdb_bt.c b/kernel/debug/kdb/kdb_bt.c index 483fa4e7aaac..2f62fe85f16a 100644 --- a/kernel/debug/kdb/kdb_bt.c +++ b/kernel/debug/kdb/kdb_bt.c | |||
@@ -23,6 +23,7 @@ static void kdb_show_stack(struct task_struct *p, void *addr) | |||
23 | { | 23 | { |
24 | int old_lvl = console_loglevel; | 24 | int old_lvl = console_loglevel; |
25 | console_loglevel = 15; | 25 | console_loglevel = 15; |
26 | kdb_trap_printk++; | ||
26 | kdb_set_current_task(p); | 27 | kdb_set_current_task(p); |
27 | if (addr) { | 28 | if (addr) { |
28 | show_stack((struct task_struct *)p, addr); | 29 | show_stack((struct task_struct *)p, addr); |
@@ -36,6 +37,7 @@ static void kdb_show_stack(struct task_struct *p, void *addr) | |||
36 | show_stack(p, NULL); | 37 | show_stack(p, NULL); |
37 | } | 38 | } |
38 | console_loglevel = old_lvl; | 39 | console_loglevel = old_lvl; |
40 | kdb_trap_printk--; | ||
39 | } | 41 | } |
40 | 42 | ||
41 | /* | 43 | /* |
diff --git a/kernel/debug/kdb/kdb_io.c b/kernel/debug/kdb/kdb_io.c index 58be7e9c9e95..c9b7f4f90bba 100644 --- a/kernel/debug/kdb/kdb_io.c +++ b/kernel/debug/kdb/kdb_io.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #define CMD_BUFLEN 256 | 29 | #define CMD_BUFLEN 256 |
30 | char kdb_prompt_str[CMD_BUFLEN]; | 30 | char kdb_prompt_str[CMD_BUFLEN]; |
31 | 31 | ||
32 | int kdb_trap_printk; | ||
32 | 33 | ||
33 | static void kgdb_transition_check(char *buffer) | 34 | static void kgdb_transition_check(char *buffer) |
34 | { | 35 | { |
@@ -533,12 +534,12 @@ static int kdb_search_string(char *searched, char *searchfor) | |||
533 | return 0; | 534 | return 0; |
534 | } | 535 | } |
535 | 536 | ||
536 | int kdb_printf(const char *fmt, ...) | 537 | int vkdb_printf(const char *fmt, va_list ap) |
537 | { | 538 | { |
538 | va_list ap; | ||
539 | int diag; | 539 | int diag; |
540 | int linecount; | 540 | int linecount; |
541 | int logging, saved_loglevel = 0; | 541 | int logging, saved_loglevel = 0; |
542 | int saved_trap_printk; | ||
542 | int got_printf_lock = 0; | 543 | int got_printf_lock = 0; |
543 | int retlen = 0; | 544 | int retlen = 0; |
544 | int fnd, len; | 545 | int fnd, len; |
@@ -549,6 +550,9 @@ int kdb_printf(const char *fmt, ...) | |||
549 | unsigned long uninitialized_var(flags); | 550 | unsigned long uninitialized_var(flags); |
550 | 551 | ||
551 | preempt_disable(); | 552 | preempt_disable(); |
553 | saved_trap_printk = kdb_trap_printk; | ||
554 | kdb_trap_printk = 0; | ||
555 | |||
552 | /* Serialize kdb_printf if multiple cpus try to write at once. | 556 | /* Serialize kdb_printf if multiple cpus try to write at once. |
553 | * But if any cpu goes recursive in kdb, just print the output, | 557 | * But if any cpu goes recursive in kdb, just print the output, |
554 | * even if it is interleaved with any other text. | 558 | * even if it is interleaved with any other text. |
@@ -575,9 +579,7 @@ int kdb_printf(const char *fmt, ...) | |||
575 | next_avail = kdb_buffer; | 579 | next_avail = kdb_buffer; |
576 | size_avail = sizeof(kdb_buffer); | 580 | size_avail = sizeof(kdb_buffer); |
577 | } | 581 | } |
578 | va_start(ap, fmt); | ||
579 | vsnprintf(next_avail, size_avail, fmt, ap); | 582 | vsnprintf(next_avail, size_avail, fmt, ap); |
580 | va_end(ap); | ||
581 | 583 | ||
582 | /* | 584 | /* |
583 | * If kdb_parse() found that the command was cmd xxx | grep yyy | 585 | * If kdb_parse() found that the command was cmd xxx | grep yyy |
@@ -805,6 +807,20 @@ kdb_print_out: | |||
805 | } else { | 807 | } else { |
806 | __release(kdb_printf_lock); | 808 | __release(kdb_printf_lock); |
807 | } | 809 | } |
810 | kdb_trap_printk = saved_trap_printk; | ||
808 | preempt_enable(); | 811 | preempt_enable(); |
809 | return retlen; | 812 | return retlen; |
810 | } | 813 | } |
814 | |||
815 | int kdb_printf(const char *fmt, ...) | ||
816 | { | ||
817 | va_list ap; | ||
818 | int r; | ||
819 | |||
820 | va_start(ap, fmt); | ||
821 | r = vkdb_printf(fmt, ap); | ||
822 | va_end(ap); | ||
823 | |||
824 | return r; | ||
825 | } | ||
826 | |||
diff --git a/kernel/debug/kdb/kdb_main.c b/kernel/debug/kdb/kdb_main.c index 64ef9ac14ba9..b724c791b6d4 100644 --- a/kernel/debug/kdb/kdb_main.c +++ b/kernel/debug/kdb/kdb_main.c | |||
@@ -1056,7 +1056,9 @@ static void kdb_dumpregs(struct pt_regs *regs) | |||
1056 | { | 1056 | { |
1057 | int old_lvl = console_loglevel; | 1057 | int old_lvl = console_loglevel; |
1058 | console_loglevel = 15; | 1058 | console_loglevel = 15; |
1059 | kdb_trap_printk++; | ||
1059 | show_regs(regs); | 1060 | show_regs(regs); |
1061 | kdb_trap_printk--; | ||
1060 | kdb_printf("\n"); | 1062 | kdb_printf("\n"); |
1061 | console_loglevel = old_lvl; | 1063 | console_loglevel = old_lvl; |
1062 | } | 1064 | } |
@@ -1819,7 +1821,9 @@ static int kdb_sr(int argc, const char **argv) | |||
1819 | if (argc != 1) | 1821 | if (argc != 1) |
1820 | return KDB_ARGCOUNT; | 1822 | return KDB_ARGCOUNT; |
1821 | sysrq_toggle_support(1); | 1823 | sysrq_toggle_support(1); |
1824 | kdb_trap_printk++; | ||
1822 | handle_sysrq(*argv[1], NULL); | 1825 | handle_sysrq(*argv[1], NULL); |
1826 | kdb_trap_printk--; | ||
1823 | 1827 | ||
1824 | return 0; | 1828 | return 0; |
1825 | } | 1829 | } |
diff --git a/kernel/printk.c b/kernel/printk.c index 9213b8b5bb4f..444b770c9595 100644 --- a/kernel/printk.c +++ b/kernel/printk.c | |||
@@ -33,6 +33,7 @@ | |||
33 | #include <linux/bootmem.h> | 33 | #include <linux/bootmem.h> |
34 | #include <linux/syscalls.h> | 34 | #include <linux/syscalls.h> |
35 | #include <linux/kexec.h> | 35 | #include <linux/kexec.h> |
36 | #include <linux/kdb.h> | ||
36 | #include <linux/ratelimit.h> | 37 | #include <linux/ratelimit.h> |
37 | #include <linux/kmsg_dump.h> | 38 | #include <linux/kmsg_dump.h> |
38 | #include <linux/syslog.h> | 39 | #include <linux/syslog.h> |
@@ -602,6 +603,14 @@ asmlinkage int printk(const char *fmt, ...) | |||
602 | va_list args; | 603 | va_list args; |
603 | int r; | 604 | int r; |
604 | 605 | ||
606 | #ifdef CONFIG_KGDB_KDB | ||
607 | if (unlikely(kdb_trap_printk)) { | ||
608 | va_start(args, fmt); | ||
609 | r = vkdb_printf(fmt, args); | ||
610 | va_end(args); | ||
611 | return r; | ||
612 | } | ||
613 | #endif | ||
605 | va_start(args, fmt); | 614 | va_start(args, fmt); |
606 | r = vprintk(fmt, args); | 615 | r = vprintk(fmt, args); |
607 | va_end(args); | 616 | va_end(args); |