diff options
| author | Anton Vorontsov <anton.vorontsov@linaro.org> | 2012-07-20 20:28:07 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-07-21 13:34:00 -0400 |
| commit | 533827c921c34310f63e859e1d6d0feec439657d (patch) | |
| tree | 6aaba38b5604be6ad3e9f7aa40239b5c3f9444e1 | |
| parent | 1b499d05eecbe04969516717a8e15afb6ad80689 (diff) | |
printk: Implement some unlocked kmsg_dump functions
If used from KDB, the locked variants are prone to deadlocks (suppose we
got to the debugger w/ the logbuf lock held).
So, we have to implement a few routines that grab no logbuf lock.
Yet we don't need these functions in modules, so we don't export them.
Signed-off-by: Anton Vorontsov <anton.vorontsov@linaro.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
| -rw-r--r-- | include/linux/kmsg_dump.h | 16 | ||||
| -rw-r--r-- | kernel/printk.c | 68 |
2 files changed, 71 insertions, 13 deletions
diff --git a/include/linux/kmsg_dump.h b/include/linux/kmsg_dump.h index d6bd50110ec2..2e7a1e032c71 100644 --- a/include/linux/kmsg_dump.h +++ b/include/linux/kmsg_dump.h | |||
| @@ -55,12 +55,17 @@ struct kmsg_dumper { | |||
| 55 | #ifdef CONFIG_PRINTK | 55 | #ifdef CONFIG_PRINTK |
| 56 | void kmsg_dump(enum kmsg_dump_reason reason); | 56 | void kmsg_dump(enum kmsg_dump_reason reason); |
| 57 | 57 | ||
| 58 | bool kmsg_dump_get_line_nolock(struct kmsg_dumper *dumper, bool syslog, | ||
| 59 | char *line, size_t size, size_t *len); | ||
| 60 | |||
| 58 | bool kmsg_dump_get_line(struct kmsg_dumper *dumper, bool syslog, | 61 | bool kmsg_dump_get_line(struct kmsg_dumper *dumper, bool syslog, |
| 59 | char *line, size_t size, size_t *len); | 62 | char *line, size_t size, size_t *len); |
| 60 | 63 | ||
| 61 | bool kmsg_dump_get_buffer(struct kmsg_dumper *dumper, bool syslog, | 64 | bool kmsg_dump_get_buffer(struct kmsg_dumper *dumper, bool syslog, |
| 62 | char *buf, size_t size, size_t *len); | 65 | char *buf, size_t size, size_t *len); |
| 63 | 66 | ||
| 67 | void kmsg_dump_rewind_nolock(struct kmsg_dumper *dumper); | ||
| 68 | |||
| 64 | void kmsg_dump_rewind(struct kmsg_dumper *dumper); | 69 | void kmsg_dump_rewind(struct kmsg_dumper *dumper); |
| 65 | 70 | ||
| 66 | int kmsg_dump_register(struct kmsg_dumper *dumper); | 71 | int kmsg_dump_register(struct kmsg_dumper *dumper); |
| @@ -71,6 +76,13 @@ static inline void kmsg_dump(enum kmsg_dump_reason reason) | |||
| 71 | { | 76 | { |
| 72 | } | 77 | } |
| 73 | 78 | ||
| 79 | static inline bool kmsg_dump_get_line_nolock(struct kmsg_dumper *dumper, | ||
| 80 | bool syslog, const char *line, | ||
| 81 | size_t size, size_t *len) | ||
| 82 | { | ||
| 83 | return false; | ||
| 84 | } | ||
| 85 | |||
| 74 | static inline bool kmsg_dump_get_line(struct kmsg_dumper *dumper, bool syslog, | 86 | static inline bool kmsg_dump_get_line(struct kmsg_dumper *dumper, bool syslog, |
| 75 | const char *line, size_t size, size_t *len) | 87 | const char *line, size_t size, size_t *len) |
| 76 | { | 88 | { |
| @@ -83,6 +95,10 @@ static inline bool kmsg_dump_get_buffer(struct kmsg_dumper *dumper, bool syslog, | |||
| 83 | return false; | 95 | return false; |
| 84 | } | 96 | } |
| 85 | 97 | ||
| 98 | static inline void kmsg_dump_rewind_nolock(struct kmsg_dumper *dumper) | ||
| 99 | { | ||
| 100 | } | ||
| 101 | |||
| 86 | static inline void kmsg_dump_rewind(struct kmsg_dumper *dumper) | 102 | static inline void kmsg_dump_rewind(struct kmsg_dumper *dumper) |
| 87 | { | 103 | { |
| 88 | } | 104 | } |
diff --git a/kernel/printk.c b/kernel/printk.c index c8129678dfbf..ac4bc9e79465 100644 --- a/kernel/printk.c +++ b/kernel/printk.c | |||
| @@ -2510,7 +2510,7 @@ void kmsg_dump(enum kmsg_dump_reason reason) | |||
| 2510 | } | 2510 | } |
| 2511 | 2511 | ||
| 2512 | /** | 2512 | /** |
| 2513 | * kmsg_dump_get_line - retrieve one kmsg log line | 2513 | * kmsg_dump_get_line_nolock - retrieve one kmsg log line (unlocked version) |
| 2514 | * @dumper: registered kmsg dumper | 2514 | * @dumper: registered kmsg dumper |
| 2515 | * @syslog: include the "<4>" prefixes | 2515 | * @syslog: include the "<4>" prefixes |
| 2516 | * @line: buffer to copy the line to | 2516 | * @line: buffer to copy the line to |
| @@ -2525,11 +2525,12 @@ void kmsg_dump(enum kmsg_dump_reason reason) | |||
| 2525 | * | 2525 | * |
| 2526 | * 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 |
| 2527 | * read. | 2527 | * read. |
| 2528 | * | ||
| 2529 | * The function is similar to kmsg_dump_get_line(), but grabs no locks. | ||
| 2528 | */ | 2530 | */ |
| 2529 | bool kmsg_dump_get_line(struct kmsg_dumper *dumper, bool syslog, | 2531 | bool kmsg_dump_get_line_nolock(struct kmsg_dumper *dumper, bool syslog, |
| 2530 | char *line, size_t size, size_t *len) | 2532 | char *line, size_t size, size_t *len) |
| 2531 | { | 2533 | { |
| 2532 | unsigned long flags; | ||
| 2533 | struct log *msg; | 2534 | struct log *msg; |
| 2534 | size_t l = 0; | 2535 | size_t l = 0; |
| 2535 | bool ret = false; | 2536 | bool ret = false; |
| @@ -2537,7 +2538,6 @@ bool kmsg_dump_get_line(struct kmsg_dumper *dumper, bool syslog, | |||
| 2537 | if (!dumper->active) | 2538 | if (!dumper->active) |
| 2538 | goto out; | 2539 | goto out; |
| 2539 | 2540 | ||
| 2540 | raw_spin_lock_irqsave(&logbuf_lock, flags); | ||
| 2541 | if (dumper->cur_seq < log_first_seq) { | 2541 | if (dumper->cur_seq < log_first_seq) { |
| 2542 | /* messages are gone, move to first available one */ | 2542 | /* messages are gone, move to first available one */ |
| 2543 | dumper->cur_seq = log_first_seq; | 2543 | dumper->cur_seq = log_first_seq; |
| @@ -2545,10 +2545,8 @@ bool kmsg_dump_get_line(struct kmsg_dumper *dumper, bool syslog, | |||
| 2545 | } | 2545 | } |
| 2546 | 2546 | ||
| 2547 | /* last entry */ | 2547 | /* last entry */ |
| 2548 | if (dumper->cur_seq >= log_next_seq) { | 2548 | if (dumper->cur_seq >= log_next_seq) |
| 2549 | raw_spin_unlock_irqrestore(&logbuf_lock, flags); | ||
| 2550 | goto out; | 2549 | goto out; |
| 2551 | } | ||
| 2552 | 2550 | ||
| 2553 | msg = log_from_idx(dumper->cur_idx); | 2551 | msg = log_from_idx(dumper->cur_idx); |
| 2554 | l = msg_print_text(msg, 0, syslog, line, size); | 2552 | l = msg_print_text(msg, 0, syslog, line, size); |
| @@ -2556,12 +2554,41 @@ bool kmsg_dump_get_line(struct kmsg_dumper *dumper, bool syslog, | |||
| 2556 | dumper->cur_idx = log_next(dumper->cur_idx); | 2554 | dumper->cur_idx = log_next(dumper->cur_idx); |
| 2557 | dumper->cur_seq++; | 2555 | dumper->cur_seq++; |
| 2558 | ret = true; | 2556 | ret = true; |
| 2559 | raw_spin_unlock_irqrestore(&logbuf_lock, flags); | ||
| 2560 | out: | 2557 | out: |
| 2561 | if (len) | 2558 | if (len) |
| 2562 | *len = l; | 2559 | *len = l; |
| 2563 | return ret; | 2560 | return ret; |
| 2564 | } | 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 | } | ||
| 2565 | EXPORT_SYMBOL_GPL(kmsg_dump_get_line); | 2592 | EXPORT_SYMBOL_GPL(kmsg_dump_get_line); |
| 2566 | 2593 | ||
| 2567 | /** | 2594 | /** |
| @@ -2664,6 +2691,24 @@ out: | |||
| 2664 | EXPORT_SYMBOL_GPL(kmsg_dump_get_buffer); | 2691 | EXPORT_SYMBOL_GPL(kmsg_dump_get_buffer); |
| 2665 | 2692 | ||
| 2666 | /** | 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 | /** | ||
| 2667 | * kmsg_dump_rewind - reset the interator | 2712 | * kmsg_dump_rewind - reset the interator |
| 2668 | * @dumper: registered kmsg dumper | 2713 | * @dumper: registered kmsg dumper |
| 2669 | * | 2714 | * |
| @@ -2676,10 +2721,7 @@ void kmsg_dump_rewind(struct kmsg_dumper *dumper) | |||
| 2676 | unsigned long flags; | 2721 | unsigned long flags; |
| 2677 | 2722 | ||
| 2678 | raw_spin_lock_irqsave(&logbuf_lock, flags); | 2723 | raw_spin_lock_irqsave(&logbuf_lock, flags); |
| 2679 | dumper->cur_seq = clear_seq; | 2724 | kmsg_dump_rewind_nolock(dumper); |
| 2680 | dumper->cur_idx = clear_idx; | ||
| 2681 | dumper->next_seq = log_next_seq; | ||
| 2682 | dumper->next_idx = log_next_idx; | ||
| 2683 | raw_spin_unlock_irqrestore(&logbuf_lock, flags); | 2725 | raw_spin_unlock_irqrestore(&logbuf_lock, flags); |
| 2684 | } | 2726 | } |
| 2685 | EXPORT_SYMBOL_GPL(kmsg_dump_rewind); | 2727 | EXPORT_SYMBOL_GPL(kmsg_dump_rewind); |
