Commit 94c61c0aeffe64452e742087cf803d0347ef8418
Committed by
Peter Zijlstra
1 parent
512e67f991
Exists in
master
and in
4 other branches
lockdep: Avoid /proc/lockdep & lock_stat infinite output
Both /proc/lockdep and /proc/lock_stat output may loop infinitely. When a read() requests an amount of data smaller than the amount of data that the seq_file's foo_show() outputs, the output starts looping and outputs the "stuck" element's data infinitely. There may be multiple sequential calls to foo_start(), foo_next()/foo_show(), and foo_stop() for a single open with sequential read of the file. The _start() does not have to start with the 0th element and _show() might be called multiple times in a row for the same element for a given open/read of the seq_file. Also header output should not be happening in _start(). All output should be in _show(), which SEQ_START_TOKEN is meant to help. Having output in _start() may also negatively impact seq_file's seq_read() and traverse() accounting. Signed-off-by: Tim Pepper <lnxninja@linux.vnet.ibm.com> Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl> Signed-off-by: Ingo Molnar <mingo@elte.hu> Cc: Ingo Molnar <mingo@elte.hu> Cc: Al Viro <viro@ftp.linux.org.uk>
Showing 1 changed file with 42 additions and 19 deletions Side-by-side Diff
kernel/lockdep_proc.c
... | ... | @@ -25,28 +25,38 @@ |
25 | 25 | |
26 | 26 | static void *l_next(struct seq_file *m, void *v, loff_t *pos) |
27 | 27 | { |
28 | - struct lock_class *class = v; | |
28 | + struct lock_class *class; | |
29 | 29 | |
30 | 30 | (*pos)++; |
31 | 31 | |
32 | - if (class->lock_entry.next != &all_lock_classes) | |
33 | - class = list_entry(class->lock_entry.next, struct lock_class, | |
34 | - lock_entry); | |
35 | - else | |
36 | - class = NULL; | |
37 | - m->private = class; | |
32 | + if (v == SEQ_START_TOKEN) | |
33 | + class = m->private; | |
34 | + else { | |
35 | + class = v; | |
38 | 36 | |
37 | + if (class->lock_entry.next != &all_lock_classes) | |
38 | + class = list_entry(class->lock_entry.next, | |
39 | + struct lock_class, lock_entry); | |
40 | + else | |
41 | + class = NULL; | |
42 | + } | |
43 | + | |
39 | 44 | return class; |
40 | 45 | } |
41 | 46 | |
42 | 47 | static void *l_start(struct seq_file *m, loff_t *pos) |
43 | 48 | { |
44 | - struct lock_class *class = m->private; | |
49 | + struct lock_class *class; | |
50 | + loff_t i = 0; | |
45 | 51 | |
46 | - if (&class->lock_entry == all_lock_classes.next) | |
47 | - seq_printf(m, "all lock classes:\n"); | |
52 | + if (*pos == 0) | |
53 | + return SEQ_START_TOKEN; | |
48 | 54 | |
49 | - return class; | |
55 | + list_for_each_entry(class, &all_lock_classes, lock_entry) { | |
56 | + if (++i == *pos) | |
57 | + return class; | |
58 | + } | |
59 | + return NULL; | |
50 | 60 | } |
51 | 61 | |
52 | 62 | static void l_stop(struct seq_file *m, void *v) |
53 | 63 | |
... | ... | @@ -101,10 +111,15 @@ |
101 | 111 | static int l_show(struct seq_file *m, void *v) |
102 | 112 | { |
103 | 113 | unsigned long nr_forward_deps, nr_backward_deps; |
104 | - struct lock_class *class = m->private; | |
114 | + struct lock_class *class = v; | |
105 | 115 | struct lock_list *entry; |
106 | 116 | char c1, c2, c3, c4; |
107 | 117 | |
118 | + if (v == SEQ_START_TOKEN) { | |
119 | + seq_printf(m, "all lock classes:\n"); | |
120 | + return 0; | |
121 | + } | |
122 | + | |
108 | 123 | seq_printf(m, "%p", class->key); |
109 | 124 | #ifdef CONFIG_DEBUG_LOCKDEP |
110 | 125 | seq_printf(m, " OPS:%8ld", class->ops); |
111 | 126 | |
... | ... | @@ -523,10 +538,11 @@ |
523 | 538 | { |
524 | 539 | struct lock_stat_seq *data = m->private; |
525 | 540 | |
526 | - if (data->iter == data->stats) | |
527 | - seq_header(m); | |
541 | + if (*pos == 0) | |
542 | + return SEQ_START_TOKEN; | |
528 | 543 | |
529 | - if (data->iter == data->iter_end) | |
544 | + data->iter = data->stats + *pos; | |
545 | + if (data->iter >= data->iter_end) | |
530 | 546 | data->iter = NULL; |
531 | 547 | |
532 | 548 | return data->iter; |
... | ... | @@ -538,8 +554,13 @@ |
538 | 554 | |
539 | 555 | (*pos)++; |
540 | 556 | |
541 | - data->iter = v; | |
542 | - data->iter++; | |
557 | + if (v == SEQ_START_TOKEN) | |
558 | + data->iter = data->stats; | |
559 | + else { | |
560 | + data->iter = v; | |
561 | + data->iter++; | |
562 | + } | |
563 | + | |
543 | 564 | if (data->iter == data->iter_end) |
544 | 565 | data->iter = NULL; |
545 | 566 | |
546 | 567 | |
... | ... | @@ -552,9 +573,11 @@ |
552 | 573 | |
553 | 574 | static int ls_show(struct seq_file *m, void *v) |
554 | 575 | { |
555 | - struct lock_stat_seq *data = m->private; | |
576 | + if (v == SEQ_START_TOKEN) | |
577 | + seq_header(m); | |
578 | + else | |
579 | + seq_stats(m, v); | |
556 | 580 | |
557 | - seq_stats(m, data->iter); | |
558 | 581 | return 0; |
559 | 582 | } |
560 | 583 |