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 /kernel/printk.c | |
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>
Diffstat (limited to 'kernel/printk.c')
-rw-r--r-- | kernel/printk.c | 68 |
1 files changed, 55 insertions, 13 deletions
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); |