diff options
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/debug/kdb/kdb_main.c | 91 | ||||
| -rw-r--r-- | kernel/debug/kdb/kdb_private.h | 1 | ||||
| -rw-r--r-- | kernel/printk.c | 83 |
3 files changed, 88 insertions, 87 deletions
diff --git a/kernel/debug/kdb/kdb_main.c b/kernel/debug/kdb/kdb_main.c index 67b847dfa2bb..1f91413edb87 100644 --- a/kernel/debug/kdb/kdb_main.c +++ b/kernel/debug/kdb/kdb_main.c | |||
| @@ -14,6 +14,7 @@ | |||
| 14 | #include <linux/ctype.h> | 14 | #include <linux/ctype.h> |
| 15 | #include <linux/string.h> | 15 | #include <linux/string.h> |
| 16 | #include <linux/kernel.h> | 16 | #include <linux/kernel.h> |
| 17 | #include <linux/kmsg_dump.h> | ||
| 17 | #include <linux/reboot.h> | 18 | #include <linux/reboot.h> |
| 18 | #include <linux/sched.h> | 19 | #include <linux/sched.h> |
| 19 | #include <linux/sysrq.h> | 20 | #include <linux/sysrq.h> |
| @@ -2040,8 +2041,15 @@ static int kdb_env(int argc, const char **argv) | |||
| 2040 | */ | 2041 | */ |
| 2041 | static int kdb_dmesg(int argc, const char **argv) | 2042 | static int kdb_dmesg(int argc, const char **argv) |
| 2042 | { | 2043 | { |
| 2043 | char *syslog_data[4], *start, *end, c = '\0', *p; | 2044 | int diag; |
| 2044 | int diag, logging, logsize, lines = 0, adjust = 0, n; | 2045 | int logging; |
| 2046 | int lines = 0; | ||
| 2047 | int adjust = 0; | ||
| 2048 | int n = 0; | ||
| 2049 | int skip = 0; | ||
| 2050 | struct kmsg_dumper dumper = { .active = 1 }; | ||
| 2051 | size_t len; | ||
| 2052 | char buf[201]; | ||
| 2045 | 2053 | ||
| 2046 | if (argc > 2) | 2054 | if (argc > 2) |
| 2047 | return KDB_ARGCOUNT; | 2055 | return KDB_ARGCOUNT; |
| @@ -2064,22 +2072,10 @@ static int kdb_dmesg(int argc, const char **argv) | |||
| 2064 | kdb_set(2, setargs); | 2072 | kdb_set(2, setargs); |
| 2065 | } | 2073 | } |
| 2066 | 2074 | ||
| 2067 | /* syslog_data[0,1] physical start, end+1. syslog_data[2,3] | 2075 | kmsg_dump_rewind_nolock(&dumper); |
| 2068 | * logical start, end+1. */ | 2076 | while (kmsg_dump_get_line_nolock(&dumper, 1, NULL, 0, NULL)) |
| 2069 | kdb_syslog_data(syslog_data); | 2077 | n++; |
| 2070 | if (syslog_data[2] == syslog_data[3]) | 2078 | |
| 2071 | return 0; | ||
| 2072 | logsize = syslog_data[1] - syslog_data[0]; | ||
| 2073 | start = syslog_data[2]; | ||
| 2074 | end = syslog_data[3]; | ||
| 2075 | #define KDB_WRAP(p) (((p - syslog_data[0]) % logsize) + syslog_data[0]) | ||
| 2076 | for (n = 0, p = start; p < end; ++p) { | ||
| 2077 | c = *KDB_WRAP(p); | ||
| 2078 | if (c == '\n') | ||
| 2079 | ++n; | ||
| 2080 | } | ||
| 2081 | if (c != '\n') | ||
| 2082 | ++n; | ||
| 2083 | if (lines < 0) { | 2079 | if (lines < 0) { |
| 2084 | if (adjust >= n) | 2080 | if (adjust >= n) |
| 2085 | kdb_printf("buffer only contains %d lines, nothing " | 2081 | kdb_printf("buffer only contains %d lines, nothing " |
| @@ -2087,21 +2083,11 @@ static int kdb_dmesg(int argc, const char **argv) | |||
| 2087 | else if (adjust - lines >= n) | 2083 | else if (adjust - lines >= n) |
| 2088 | kdb_printf("buffer only contains %d lines, last %d " | 2084 | kdb_printf("buffer only contains %d lines, last %d " |
| 2089 | "lines printed\n", n, n - adjust); | 2085 | "lines printed\n", n, n - adjust); |
| 2090 | if (adjust) { | 2086 | skip = adjust; |
| 2091 | for (; start < end && adjust; ++start) { | 2087 | lines = abs(lines); |
| 2092 | if (*KDB_WRAP(start) == '\n') | ||
| 2093 | --adjust; | ||
| 2094 | } | ||
| 2095 | if (start < end) | ||
| 2096 | ++start; | ||
| 2097 | } | ||
| 2098 | for (p = start; p < end && lines; ++p) { | ||
| 2099 | if (*KDB_WRAP(p) == '\n') | ||
| 2100 | ++lines; | ||
| 2101 | } | ||
| 2102 | end = p; | ||
| 2103 | } else if (lines > 0) { | 2088 | } else if (lines > 0) { |
| 2104 | int skip = n - (adjust + lines); | 2089 | skip = n - lines - adjust; |
| 2090 | lines = abs(lines); | ||
| 2105 | if (adjust >= n) { | 2091 | if (adjust >= n) { |
| 2106 | kdb_printf("buffer only contains %d lines, " | 2092 | kdb_printf("buffer only contains %d lines, " |
| 2107 | "nothing printed\n", n); | 2093 | "nothing printed\n", n); |
| @@ -2112,35 +2098,24 @@ static int kdb_dmesg(int argc, const char **argv) | |||
| 2112 | kdb_printf("buffer only contains %d lines, first " | 2098 | kdb_printf("buffer only contains %d lines, first " |
| 2113 | "%d lines printed\n", n, lines); | 2099 | "%d lines printed\n", n, lines); |
| 2114 | } | 2100 | } |
| 2115 | for (; start < end && skip; ++start) { | 2101 | } else { |
| 2116 | if (*KDB_WRAP(start) == '\n') | 2102 | lines = n; |
| 2117 | --skip; | ||
| 2118 | } | ||
| 2119 | for (p = start; p < end && lines; ++p) { | ||
| 2120 | if (*KDB_WRAP(p) == '\n') | ||
| 2121 | --lines; | ||
| 2122 | } | ||
| 2123 | end = p; | ||
| 2124 | } | 2103 | } |
| 2125 | /* Do a line at a time (max 200 chars) to reduce protocol overhead */ | 2104 | |
| 2126 | c = '\n'; | 2105 | if (skip >= n || skip < 0) |
| 2127 | while (start != end) { | 2106 | return 0; |
| 2128 | char buf[201]; | 2107 | |
| 2129 | p = buf; | 2108 | kmsg_dump_rewind_nolock(&dumper); |
| 2130 | if (KDB_FLAG(CMD_INTERRUPT)) | 2109 | while (kmsg_dump_get_line_nolock(&dumper, 1, buf, sizeof(buf), &len)) { |
| 2131 | return 0; | 2110 | if (skip) { |
| 2132 | while (start < end && (c = *KDB_WRAP(start)) && | 2111 | skip--; |
| 2133 | (p - buf) < sizeof(buf)-1) { | 2112 | continue; |
| 2134 | ++start; | ||
| 2135 | *p++ = c; | ||
| 2136 | if (c == '\n') | ||
| 2137 | break; | ||
| 2138 | } | 2113 | } |
| 2139 | *p = '\0'; | 2114 | if (!lines--) |
| 2140 | kdb_printf("%s", buf); | 2115 | break; |
| 2116 | |||
| 2117 | kdb_printf("%.*s\n", (int)len - 1, buf); | ||
| 2141 | } | 2118 | } |
| 2142 | if (c != '\n') | ||
| 2143 | kdb_printf("\n"); | ||
| 2144 | 2119 | ||
| 2145 | return 0; | 2120 | return 0; |
| 2146 | } | 2121 | } |
diff --git a/kernel/debug/kdb/kdb_private.h b/kernel/debug/kdb/kdb_private.h index 47c4e56e513b..392ec6a25844 100644 --- a/kernel/debug/kdb/kdb_private.h +++ b/kernel/debug/kdb/kdb_private.h | |||
| @@ -205,7 +205,6 @@ extern char kdb_grep_string[]; | |||
| 205 | extern int kdb_grep_leading; | 205 | extern int kdb_grep_leading; |
| 206 | extern int kdb_grep_trailing; | 206 | extern int kdb_grep_trailing; |
| 207 | extern char *kdb_cmds[]; | 207 | extern char *kdb_cmds[]; |
| 208 | extern void kdb_syslog_data(char *syslog_data[]); | ||
| 209 | extern unsigned long kdb_task_state_string(const char *); | 208 | extern unsigned long kdb_task_state_string(const char *); |
| 210 | extern char kdb_task_state_char (const struct task_struct *); | 209 | extern char kdb_task_state_char (const struct task_struct *); |
| 211 | extern unsigned long kdb_task_state(const struct task_struct *p, | 210 | extern unsigned long kdb_task_state(const struct task_struct *p, |
diff --git a/kernel/printk.c b/kernel/printk.c index 177fa49357a5..ac4bc9e79465 100644 --- a/kernel/printk.c +++ b/kernel/printk.c | |||
| @@ -1192,21 +1192,6 @@ SYSCALL_DEFINE3(syslog, int, type, char __user *, buf, int, len) | |||
| 1192 | return do_syslog(type, buf, len, SYSLOG_FROM_CALL); | 1192 | return do_syslog(type, buf, len, SYSLOG_FROM_CALL); |
| 1193 | } | 1193 | } |
| 1194 | 1194 | ||
| 1195 | #ifdef CONFIG_KGDB_KDB | ||
| 1196 | /* kdb dmesg command needs access to the syslog buffer. do_syslog() | ||
| 1197 | * uses locks so it cannot be used during debugging. Just tell kdb | ||
| 1198 | * where the start and end of the physical and logical logs are. This | ||
| 1199 | * is equivalent to do_syslog(3). | ||
| 1200 | */ | ||
| 1201 | void kdb_syslog_data(char *syslog_data[4]) | ||
| 1202 | { | ||
| 1203 | syslog_data[0] = log_buf; | ||
| 1204 | syslog_data[1] = log_buf + log_buf_len; | ||
| 1205 | syslog_data[2] = log_buf + log_first_idx; | ||
| 1206 | syslog_data[3] = log_buf + log_next_idx; | ||
| 1207 | } | ||
| 1208 | #endif /* CONFIG_KGDB_KDB */ | ||
| 1209 | |||
| 1210 | static bool __read_mostly ignore_loglevel; | 1195 | static bool __read_mostly ignore_loglevel; |
| 1211 | 1196 | ||
| 1212 | static int __init ignore_loglevel_setup(char *str) | 1197 | static int __init ignore_loglevel_setup(char *str) |
| @@ -2525,7 +2510,7 @@ void kmsg_dump(enum kmsg_dump_reason reason) | |||
| 2525 | } | 2510 | } |
| 2526 | 2511 | ||
| 2527 | /** | 2512 | /** |
| 2528 | * kmsg_dump_get_line - retrieve one kmsg log line | 2513 | * kmsg_dump_get_line_nolock - retrieve one kmsg log line (unlocked version) |
| 2529 | * @dumper: registered kmsg dumper | 2514 | * @dumper: registered kmsg dumper |
| 2530 | * @syslog: include the "<4>" prefixes | 2515 | * @syslog: include the "<4>" prefixes |
| 2531 | * @line: buffer to copy the line to | 2516 | * @line: buffer to copy the line to |
| @@ -2540,11 +2525,12 @@ void kmsg_dump(enum kmsg_dump_reason reason) | |||
| 2540 | * | 2525 | * |
| 2541 | * A return value of FALSE indicates that there are no more records to | 2526 | * A return value of FALSE indicates that there are no more records to |
| 2542 | * read. | 2527 | * read. |
| 2528 | * | ||
| 2529 | * The function is similar to kmsg_dump_get_line(), but grabs no locks. | ||
| 2543 | */ | 2530 | */ |
| 2544 | bool kmsg_dump_get_line(struct kmsg_dumper *dumper, bool syslog, | 2531 | bool kmsg_dump_get_line_nolock(struct kmsg_dumper *dumper, bool syslog, |
| 2545 | char *line, size_t size, size_t *len) | 2532 | char *line, size_t size, size_t *len) |
| 2546 | { | 2533 | { |
| 2547 | unsigned long flags; | ||
| 2548 | struct log *msg; | 2534 | struct log *msg; |
| 2549 | size_t l = 0; | 2535 | size_t l = 0; |
| 2550 | bool ret = false; | 2536 | bool ret = false; |
| @@ -2552,7 +2538,6 @@ bool kmsg_dump_get_line(struct kmsg_dumper *dumper, bool syslog, | |||
| 2552 | if (!dumper->active) | 2538 | if (!dumper->active) |
| 2553 | goto out; | 2539 | goto out; |
| 2554 | 2540 | ||
| 2555 | raw_spin_lock_irqsave(&logbuf_lock, flags); | ||
| 2556 | if (dumper->cur_seq < log_first_seq) { | 2541 | if (dumper->cur_seq < log_first_seq) { |
| 2557 | /* messages are gone, move to first available one */ | 2542 | /* messages are gone, move to first available one */ |
| 2558 | dumper->cur_seq = log_first_seq; | 2543 | dumper->cur_seq = log_first_seq; |
| @@ -2560,10 +2545,8 @@ bool kmsg_dump_get_line(struct kmsg_dumper *dumper, bool syslog, | |||
| 2560 | } | 2545 | } |
| 2561 | 2546 | ||
| 2562 | /* last entry */ | 2547 | /* last entry */ |
| 2563 | if (dumper->cur_seq >= log_next_seq) { | 2548 | if (dumper->cur_seq >= log_next_seq) |
| 2564 | raw_spin_unlock_irqrestore(&logbuf_lock, flags); | ||
| 2565 | goto out; | 2549 | goto out; |
| 2566 | } | ||
| 2567 | 2550 | ||
| 2568 | msg = log_from_idx(dumper->cur_idx); | 2551 | msg = log_from_idx(dumper->cur_idx); |
| 2569 | l = msg_print_text(msg, 0, syslog, line, size); | 2552 | l = msg_print_text(msg, 0, syslog, line, size); |
| @@ -2571,12 +2554,41 @@ bool kmsg_dump_get_line(struct kmsg_dumper *dumper, bool syslog, | |||
| 2571 | dumper->cur_idx = log_next(dumper->cur_idx); | 2554 | dumper->cur_idx = log_next(dumper->cur_idx); |
| 2572 | dumper->cur_seq++; | 2555 | dumper->cur_seq++; |
| 2573 | ret = true; | 2556 | ret = true; |
| 2574 | raw_spin_unlock_irqrestore(&logbuf_lock, flags); | ||
| 2575 | out: | 2557 | out: |
| 2576 | if (len) | 2558 | if (len) |
| 2577 | *len = l; | 2559 | *len = l; |
| 2578 | return ret; | 2560 | return ret; |
| 2579 | } | 2561 | } |
| 2562 | |||
| 2563 | /** | ||
| 2564 | * kmsg_dump_get_line - retrieve one kmsg log line | ||
| 2565 | * @dumper: registered kmsg dumper | ||
| 2566 | * @syslog: include the "<4>" prefixes | ||
| 2567 | * @line: buffer to copy the line to | ||
| 2568 | * @size: maximum size of the buffer | ||
| 2569 | * @len: length of line placed into buffer | ||
| 2570 | * | ||
| 2571 | * Start at the beginning of the kmsg buffer, with the oldest kmsg | ||
| 2572 | * record, and copy one record into the provided buffer. | ||
| 2573 | * | ||
| 2574 | * Consecutive calls will return the next available record moving | ||
| 2575 | * towards the end of the buffer with the youngest messages. | ||
| 2576 | * | ||
| 2577 | * A return value of FALSE indicates that there are no more records to | ||
| 2578 | * read. | ||
| 2579 | */ | ||
| 2580 | bool kmsg_dump_get_line(struct kmsg_dumper *dumper, bool syslog, | ||
| 2581 | char *line, size_t size, size_t *len) | ||
| 2582 | { | ||
| 2583 | unsigned long flags; | ||
| 2584 | bool ret; | ||
| 2585 | |||
| 2586 | raw_spin_lock_irqsave(&logbuf_lock, flags); | ||
| 2587 | ret = kmsg_dump_get_line_nolock(dumper, syslog, line, size, len); | ||
| 2588 | raw_spin_unlock_irqrestore(&logbuf_lock, flags); | ||
| 2589 | |||
| 2590 | return ret; | ||
| 2591 | } | ||
| 2580 | EXPORT_SYMBOL_GPL(kmsg_dump_get_line); | 2592 | EXPORT_SYMBOL_GPL(kmsg_dump_get_line); |
| 2581 | 2593 | ||
| 2582 | /** | 2594 | /** |
| @@ -2679,6 +2691,24 @@ out: | |||
| 2679 | EXPORT_SYMBOL_GPL(kmsg_dump_get_buffer); | 2691 | EXPORT_SYMBOL_GPL(kmsg_dump_get_buffer); |
| 2680 | 2692 | ||
| 2681 | /** | 2693 | /** |
| 2694 | * kmsg_dump_rewind_nolock - reset the interator (unlocked version) | ||
| 2695 | * @dumper: registered kmsg dumper | ||
| 2696 | * | ||
| 2697 | * Reset the dumper's iterator so that kmsg_dump_get_line() and | ||
| 2698 | * kmsg_dump_get_buffer() can be called again and used multiple | ||
| 2699 | * times within the same dumper.dump() callback. | ||
| 2700 | * | ||
| 2701 | * The function is similar to kmsg_dump_rewind(), but grabs no locks. | ||
| 2702 | */ | ||
| 2703 | void kmsg_dump_rewind_nolock(struct kmsg_dumper *dumper) | ||
| 2704 | { | ||
| 2705 | dumper->cur_seq = clear_seq; | ||
| 2706 | dumper->cur_idx = clear_idx; | ||
| 2707 | dumper->next_seq = log_next_seq; | ||
| 2708 | dumper->next_idx = log_next_idx; | ||
| 2709 | } | ||
| 2710 | |||
| 2711 | /** | ||
| 2682 | * kmsg_dump_rewind - reset the interator | 2712 | * kmsg_dump_rewind - reset the interator |
| 2683 | * @dumper: registered kmsg dumper | 2713 | * @dumper: registered kmsg dumper |
| 2684 | * | 2714 | * |
| @@ -2691,10 +2721,7 @@ void kmsg_dump_rewind(struct kmsg_dumper *dumper) | |||
| 2691 | unsigned long flags; | 2721 | unsigned long flags; |
| 2692 | 2722 | ||
| 2693 | raw_spin_lock_irqsave(&logbuf_lock, flags); | 2723 | raw_spin_lock_irqsave(&logbuf_lock, flags); |
| 2694 | dumper->cur_seq = clear_seq; | 2724 | kmsg_dump_rewind_nolock(dumper); |
| 2695 | dumper->cur_idx = clear_idx; | ||
| 2696 | dumper->next_seq = log_next_seq; | ||
| 2697 | dumper->next_idx = log_next_idx; | ||
| 2698 | raw_spin_unlock_irqrestore(&logbuf_lock, flags); | 2725 | raw_spin_unlock_irqrestore(&logbuf_lock, flags); |
| 2699 | } | 2726 | } |
| 2700 | EXPORT_SYMBOL_GPL(kmsg_dump_rewind); | 2727 | EXPORT_SYMBOL_GPL(kmsg_dump_rewind); |
