Commit 94c61c0aeffe64452e742087cf803d0347ef8418

Authored by Tim Pepper
Committed by Peter Zijlstra
1 parent 512e67f991

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 Inline Diff

kernel/lockdep_proc.c
1 /* 1 /*
2 * kernel/lockdep_proc.c 2 * kernel/lockdep_proc.c
3 * 3 *
4 * Runtime locking correctness validator 4 * Runtime locking correctness validator
5 * 5 *
6 * Started by Ingo Molnar: 6 * Started by Ingo Molnar:
7 * 7 *
8 * Copyright (C) 2006,2007 Red Hat, Inc., Ingo Molnar <mingo@redhat.com> 8 * Copyright (C) 2006,2007 Red Hat, Inc., Ingo Molnar <mingo@redhat.com>
9 * Copyright (C) 2007 Red Hat, Inc., Peter Zijlstra <pzijlstr@redhat.com> 9 * Copyright (C) 2007 Red Hat, Inc., Peter Zijlstra <pzijlstr@redhat.com>
10 * 10 *
11 * Code for /proc/lockdep and /proc/lockdep_stats: 11 * Code for /proc/lockdep and /proc/lockdep_stats:
12 * 12 *
13 */ 13 */
14 #include <linux/module.h> 14 #include <linux/module.h>
15 #include <linux/proc_fs.h> 15 #include <linux/proc_fs.h>
16 #include <linux/seq_file.h> 16 #include <linux/seq_file.h>
17 #include <linux/kallsyms.h> 17 #include <linux/kallsyms.h>
18 #include <linux/debug_locks.h> 18 #include <linux/debug_locks.h>
19 #include <linux/vmalloc.h> 19 #include <linux/vmalloc.h>
20 #include <linux/sort.h> 20 #include <linux/sort.h>
21 #include <asm/uaccess.h> 21 #include <asm/uaccess.h>
22 #include <asm/div64.h> 22 #include <asm/div64.h>
23 23
24 #include "lockdep_internals.h" 24 #include "lockdep_internals.h"
25 25
26 static void *l_next(struct seq_file *m, void *v, loff_t *pos) 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 (*pos)++; 30 (*pos)++;
31 31
32 if (class->lock_entry.next != &all_lock_classes) 32 if (v == SEQ_START_TOKEN)
33 class = list_entry(class->lock_entry.next, struct lock_class, 33 class = m->private;
34 lock_entry); 34 else {
35 else 35 class = v;
36 class = NULL;
37 m->private = class;
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 return class; 44 return class;
40 } 45 }
41 46
42 static void *l_start(struct seq_file *m, loff_t *pos) 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) 52 if (*pos == 0)
47 seq_printf(m, "all lock classes:\n"); 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 static void l_stop(struct seq_file *m, void *v) 62 static void l_stop(struct seq_file *m, void *v)
53 { 63 {
54 } 64 }
55 65
56 static unsigned long count_forward_deps(struct lock_class *class) 66 static unsigned long count_forward_deps(struct lock_class *class)
57 { 67 {
58 struct lock_list *entry; 68 struct lock_list *entry;
59 unsigned long ret = 1; 69 unsigned long ret = 1;
60 70
61 /* 71 /*
62 * Recurse this class's dependency list: 72 * Recurse this class's dependency list:
63 */ 73 */
64 list_for_each_entry(entry, &class->locks_after, entry) 74 list_for_each_entry(entry, &class->locks_after, entry)
65 ret += count_forward_deps(entry->class); 75 ret += count_forward_deps(entry->class);
66 76
67 return ret; 77 return ret;
68 } 78 }
69 79
70 static unsigned long count_backward_deps(struct lock_class *class) 80 static unsigned long count_backward_deps(struct lock_class *class)
71 { 81 {
72 struct lock_list *entry; 82 struct lock_list *entry;
73 unsigned long ret = 1; 83 unsigned long ret = 1;
74 84
75 /* 85 /*
76 * Recurse this class's dependency list: 86 * Recurse this class's dependency list:
77 */ 87 */
78 list_for_each_entry(entry, &class->locks_before, entry) 88 list_for_each_entry(entry, &class->locks_before, entry)
79 ret += count_backward_deps(entry->class); 89 ret += count_backward_deps(entry->class);
80 90
81 return ret; 91 return ret;
82 } 92 }
83 93
84 static void print_name(struct seq_file *m, struct lock_class *class) 94 static void print_name(struct seq_file *m, struct lock_class *class)
85 { 95 {
86 char str[128]; 96 char str[128];
87 const char *name = class->name; 97 const char *name = class->name;
88 98
89 if (!name) { 99 if (!name) {
90 name = __get_key_name(class->key, str); 100 name = __get_key_name(class->key, str);
91 seq_printf(m, "%s", name); 101 seq_printf(m, "%s", name);
92 } else{ 102 } else{
93 seq_printf(m, "%s", name); 103 seq_printf(m, "%s", name);
94 if (class->name_version > 1) 104 if (class->name_version > 1)
95 seq_printf(m, "#%d", class->name_version); 105 seq_printf(m, "#%d", class->name_version);
96 if (class->subclass) 106 if (class->subclass)
97 seq_printf(m, "/%d", class->subclass); 107 seq_printf(m, "/%d", class->subclass);
98 } 108 }
99 } 109 }
100 110
101 static int l_show(struct seq_file *m, void *v) 111 static int l_show(struct seq_file *m, void *v)
102 { 112 {
103 unsigned long nr_forward_deps, nr_backward_deps; 113 unsigned long nr_forward_deps, nr_backward_deps;
104 struct lock_class *class = m->private; 114 struct lock_class *class = v;
105 struct lock_list *entry; 115 struct lock_list *entry;
106 char c1, c2, c3, c4; 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 seq_printf(m, "%p", class->key); 123 seq_printf(m, "%p", class->key);
109 #ifdef CONFIG_DEBUG_LOCKDEP 124 #ifdef CONFIG_DEBUG_LOCKDEP
110 seq_printf(m, " OPS:%8ld", class->ops); 125 seq_printf(m, " OPS:%8ld", class->ops);
111 #endif 126 #endif
112 nr_forward_deps = count_forward_deps(class); 127 nr_forward_deps = count_forward_deps(class);
113 seq_printf(m, " FD:%5ld", nr_forward_deps); 128 seq_printf(m, " FD:%5ld", nr_forward_deps);
114 129
115 nr_backward_deps = count_backward_deps(class); 130 nr_backward_deps = count_backward_deps(class);
116 seq_printf(m, " BD:%5ld", nr_backward_deps); 131 seq_printf(m, " BD:%5ld", nr_backward_deps);
117 132
118 get_usage_chars(class, &c1, &c2, &c3, &c4); 133 get_usage_chars(class, &c1, &c2, &c3, &c4);
119 seq_printf(m, " %c%c%c%c", c1, c2, c3, c4); 134 seq_printf(m, " %c%c%c%c", c1, c2, c3, c4);
120 135
121 seq_printf(m, ": "); 136 seq_printf(m, ": ");
122 print_name(m, class); 137 print_name(m, class);
123 seq_puts(m, "\n"); 138 seq_puts(m, "\n");
124 139
125 list_for_each_entry(entry, &class->locks_after, entry) { 140 list_for_each_entry(entry, &class->locks_after, entry) {
126 if (entry->distance == 1) { 141 if (entry->distance == 1) {
127 seq_printf(m, " -> [%p] ", entry->class); 142 seq_printf(m, " -> [%p] ", entry->class);
128 print_name(m, entry->class); 143 print_name(m, entry->class);
129 seq_puts(m, "\n"); 144 seq_puts(m, "\n");
130 } 145 }
131 } 146 }
132 seq_puts(m, "\n"); 147 seq_puts(m, "\n");
133 148
134 return 0; 149 return 0;
135 } 150 }
136 151
137 static const struct seq_operations lockdep_ops = { 152 static const struct seq_operations lockdep_ops = {
138 .start = l_start, 153 .start = l_start,
139 .next = l_next, 154 .next = l_next,
140 .stop = l_stop, 155 .stop = l_stop,
141 .show = l_show, 156 .show = l_show,
142 }; 157 };
143 158
144 static int lockdep_open(struct inode *inode, struct file *file) 159 static int lockdep_open(struct inode *inode, struct file *file)
145 { 160 {
146 int res = seq_open(file, &lockdep_ops); 161 int res = seq_open(file, &lockdep_ops);
147 if (!res) { 162 if (!res) {
148 struct seq_file *m = file->private_data; 163 struct seq_file *m = file->private_data;
149 164
150 if (!list_empty(&all_lock_classes)) 165 if (!list_empty(&all_lock_classes))
151 m->private = list_entry(all_lock_classes.next, 166 m->private = list_entry(all_lock_classes.next,
152 struct lock_class, lock_entry); 167 struct lock_class, lock_entry);
153 else 168 else
154 m->private = NULL; 169 m->private = NULL;
155 } 170 }
156 return res; 171 return res;
157 } 172 }
158 173
159 static const struct file_operations proc_lockdep_operations = { 174 static const struct file_operations proc_lockdep_operations = {
160 .open = lockdep_open, 175 .open = lockdep_open,
161 .read = seq_read, 176 .read = seq_read,
162 .llseek = seq_lseek, 177 .llseek = seq_lseek,
163 .release = seq_release, 178 .release = seq_release,
164 }; 179 };
165 180
166 static void lockdep_stats_debug_show(struct seq_file *m) 181 static void lockdep_stats_debug_show(struct seq_file *m)
167 { 182 {
168 #ifdef CONFIG_DEBUG_LOCKDEP 183 #ifdef CONFIG_DEBUG_LOCKDEP
169 unsigned int hi1 = debug_atomic_read(&hardirqs_on_events), 184 unsigned int hi1 = debug_atomic_read(&hardirqs_on_events),
170 hi2 = debug_atomic_read(&hardirqs_off_events), 185 hi2 = debug_atomic_read(&hardirqs_off_events),
171 hr1 = debug_atomic_read(&redundant_hardirqs_on), 186 hr1 = debug_atomic_read(&redundant_hardirqs_on),
172 hr2 = debug_atomic_read(&redundant_hardirqs_off), 187 hr2 = debug_atomic_read(&redundant_hardirqs_off),
173 si1 = debug_atomic_read(&softirqs_on_events), 188 si1 = debug_atomic_read(&softirqs_on_events),
174 si2 = debug_atomic_read(&softirqs_off_events), 189 si2 = debug_atomic_read(&softirqs_off_events),
175 sr1 = debug_atomic_read(&redundant_softirqs_on), 190 sr1 = debug_atomic_read(&redundant_softirqs_on),
176 sr2 = debug_atomic_read(&redundant_softirqs_off); 191 sr2 = debug_atomic_read(&redundant_softirqs_off);
177 192
178 seq_printf(m, " chain lookup misses: %11u\n", 193 seq_printf(m, " chain lookup misses: %11u\n",
179 debug_atomic_read(&chain_lookup_misses)); 194 debug_atomic_read(&chain_lookup_misses));
180 seq_printf(m, " chain lookup hits: %11u\n", 195 seq_printf(m, " chain lookup hits: %11u\n",
181 debug_atomic_read(&chain_lookup_hits)); 196 debug_atomic_read(&chain_lookup_hits));
182 seq_printf(m, " cyclic checks: %11u\n", 197 seq_printf(m, " cyclic checks: %11u\n",
183 debug_atomic_read(&nr_cyclic_checks)); 198 debug_atomic_read(&nr_cyclic_checks));
184 seq_printf(m, " cyclic-check recursions: %11u\n", 199 seq_printf(m, " cyclic-check recursions: %11u\n",
185 debug_atomic_read(&nr_cyclic_check_recursions)); 200 debug_atomic_read(&nr_cyclic_check_recursions));
186 seq_printf(m, " find-mask forwards checks: %11u\n", 201 seq_printf(m, " find-mask forwards checks: %11u\n",
187 debug_atomic_read(&nr_find_usage_forwards_checks)); 202 debug_atomic_read(&nr_find_usage_forwards_checks));
188 seq_printf(m, " find-mask forwards recursions: %11u\n", 203 seq_printf(m, " find-mask forwards recursions: %11u\n",
189 debug_atomic_read(&nr_find_usage_forwards_recursions)); 204 debug_atomic_read(&nr_find_usage_forwards_recursions));
190 seq_printf(m, " find-mask backwards checks: %11u\n", 205 seq_printf(m, " find-mask backwards checks: %11u\n",
191 debug_atomic_read(&nr_find_usage_backwards_checks)); 206 debug_atomic_read(&nr_find_usage_backwards_checks));
192 seq_printf(m, " find-mask backwards recursions:%11u\n", 207 seq_printf(m, " find-mask backwards recursions:%11u\n",
193 debug_atomic_read(&nr_find_usage_backwards_recursions)); 208 debug_atomic_read(&nr_find_usage_backwards_recursions));
194 209
195 seq_printf(m, " hardirq on events: %11u\n", hi1); 210 seq_printf(m, " hardirq on events: %11u\n", hi1);
196 seq_printf(m, " hardirq off events: %11u\n", hi2); 211 seq_printf(m, " hardirq off events: %11u\n", hi2);
197 seq_printf(m, " redundant hardirq ons: %11u\n", hr1); 212 seq_printf(m, " redundant hardirq ons: %11u\n", hr1);
198 seq_printf(m, " redundant hardirq offs: %11u\n", hr2); 213 seq_printf(m, " redundant hardirq offs: %11u\n", hr2);
199 seq_printf(m, " softirq on events: %11u\n", si1); 214 seq_printf(m, " softirq on events: %11u\n", si1);
200 seq_printf(m, " softirq off events: %11u\n", si2); 215 seq_printf(m, " softirq off events: %11u\n", si2);
201 seq_printf(m, " redundant softirq ons: %11u\n", sr1); 216 seq_printf(m, " redundant softirq ons: %11u\n", sr1);
202 seq_printf(m, " redundant softirq offs: %11u\n", sr2); 217 seq_printf(m, " redundant softirq offs: %11u\n", sr2);
203 #endif 218 #endif
204 } 219 }
205 220
206 static int lockdep_stats_show(struct seq_file *m, void *v) 221 static int lockdep_stats_show(struct seq_file *m, void *v)
207 { 222 {
208 struct lock_class *class; 223 struct lock_class *class;
209 unsigned long nr_unused = 0, nr_uncategorized = 0, 224 unsigned long nr_unused = 0, nr_uncategorized = 0,
210 nr_irq_safe = 0, nr_irq_unsafe = 0, 225 nr_irq_safe = 0, nr_irq_unsafe = 0,
211 nr_softirq_safe = 0, nr_softirq_unsafe = 0, 226 nr_softirq_safe = 0, nr_softirq_unsafe = 0,
212 nr_hardirq_safe = 0, nr_hardirq_unsafe = 0, 227 nr_hardirq_safe = 0, nr_hardirq_unsafe = 0,
213 nr_irq_read_safe = 0, nr_irq_read_unsafe = 0, 228 nr_irq_read_safe = 0, nr_irq_read_unsafe = 0,
214 nr_softirq_read_safe = 0, nr_softirq_read_unsafe = 0, 229 nr_softirq_read_safe = 0, nr_softirq_read_unsafe = 0,
215 nr_hardirq_read_safe = 0, nr_hardirq_read_unsafe = 0, 230 nr_hardirq_read_safe = 0, nr_hardirq_read_unsafe = 0,
216 sum_forward_deps = 0, factor = 0; 231 sum_forward_deps = 0, factor = 0;
217 232
218 list_for_each_entry(class, &all_lock_classes, lock_entry) { 233 list_for_each_entry(class, &all_lock_classes, lock_entry) {
219 234
220 if (class->usage_mask == 0) 235 if (class->usage_mask == 0)
221 nr_unused++; 236 nr_unused++;
222 if (class->usage_mask == LOCKF_USED) 237 if (class->usage_mask == LOCKF_USED)
223 nr_uncategorized++; 238 nr_uncategorized++;
224 if (class->usage_mask & LOCKF_USED_IN_IRQ) 239 if (class->usage_mask & LOCKF_USED_IN_IRQ)
225 nr_irq_safe++; 240 nr_irq_safe++;
226 if (class->usage_mask & LOCKF_ENABLED_IRQS) 241 if (class->usage_mask & LOCKF_ENABLED_IRQS)
227 nr_irq_unsafe++; 242 nr_irq_unsafe++;
228 if (class->usage_mask & LOCKF_USED_IN_SOFTIRQ) 243 if (class->usage_mask & LOCKF_USED_IN_SOFTIRQ)
229 nr_softirq_safe++; 244 nr_softirq_safe++;
230 if (class->usage_mask & LOCKF_ENABLED_SOFTIRQS) 245 if (class->usage_mask & LOCKF_ENABLED_SOFTIRQS)
231 nr_softirq_unsafe++; 246 nr_softirq_unsafe++;
232 if (class->usage_mask & LOCKF_USED_IN_HARDIRQ) 247 if (class->usage_mask & LOCKF_USED_IN_HARDIRQ)
233 nr_hardirq_safe++; 248 nr_hardirq_safe++;
234 if (class->usage_mask & LOCKF_ENABLED_HARDIRQS) 249 if (class->usage_mask & LOCKF_ENABLED_HARDIRQS)
235 nr_hardirq_unsafe++; 250 nr_hardirq_unsafe++;
236 if (class->usage_mask & LOCKF_USED_IN_IRQ_READ) 251 if (class->usage_mask & LOCKF_USED_IN_IRQ_READ)
237 nr_irq_read_safe++; 252 nr_irq_read_safe++;
238 if (class->usage_mask & LOCKF_ENABLED_IRQS_READ) 253 if (class->usage_mask & LOCKF_ENABLED_IRQS_READ)
239 nr_irq_read_unsafe++; 254 nr_irq_read_unsafe++;
240 if (class->usage_mask & LOCKF_USED_IN_SOFTIRQ_READ) 255 if (class->usage_mask & LOCKF_USED_IN_SOFTIRQ_READ)
241 nr_softirq_read_safe++; 256 nr_softirq_read_safe++;
242 if (class->usage_mask & LOCKF_ENABLED_SOFTIRQS_READ) 257 if (class->usage_mask & LOCKF_ENABLED_SOFTIRQS_READ)
243 nr_softirq_read_unsafe++; 258 nr_softirq_read_unsafe++;
244 if (class->usage_mask & LOCKF_USED_IN_HARDIRQ_READ) 259 if (class->usage_mask & LOCKF_USED_IN_HARDIRQ_READ)
245 nr_hardirq_read_safe++; 260 nr_hardirq_read_safe++;
246 if (class->usage_mask & LOCKF_ENABLED_HARDIRQS_READ) 261 if (class->usage_mask & LOCKF_ENABLED_HARDIRQS_READ)
247 nr_hardirq_read_unsafe++; 262 nr_hardirq_read_unsafe++;
248 263
249 sum_forward_deps += count_forward_deps(class); 264 sum_forward_deps += count_forward_deps(class);
250 } 265 }
251 #ifdef CONFIG_DEBUG_LOCKDEP 266 #ifdef CONFIG_DEBUG_LOCKDEP
252 DEBUG_LOCKS_WARN_ON(debug_atomic_read(&nr_unused_locks) != nr_unused); 267 DEBUG_LOCKS_WARN_ON(debug_atomic_read(&nr_unused_locks) != nr_unused);
253 #endif 268 #endif
254 seq_printf(m, " lock-classes: %11lu [max: %lu]\n", 269 seq_printf(m, " lock-classes: %11lu [max: %lu]\n",
255 nr_lock_classes, MAX_LOCKDEP_KEYS); 270 nr_lock_classes, MAX_LOCKDEP_KEYS);
256 seq_printf(m, " direct dependencies: %11lu [max: %lu]\n", 271 seq_printf(m, " direct dependencies: %11lu [max: %lu]\n",
257 nr_list_entries, MAX_LOCKDEP_ENTRIES); 272 nr_list_entries, MAX_LOCKDEP_ENTRIES);
258 seq_printf(m, " indirect dependencies: %11lu\n", 273 seq_printf(m, " indirect dependencies: %11lu\n",
259 sum_forward_deps); 274 sum_forward_deps);
260 275
261 /* 276 /*
262 * Total number of dependencies: 277 * Total number of dependencies:
263 * 278 *
264 * All irq-safe locks may nest inside irq-unsafe locks, 279 * All irq-safe locks may nest inside irq-unsafe locks,
265 * plus all the other known dependencies: 280 * plus all the other known dependencies:
266 */ 281 */
267 seq_printf(m, " all direct dependencies: %11lu\n", 282 seq_printf(m, " all direct dependencies: %11lu\n",
268 nr_irq_unsafe * nr_irq_safe + 283 nr_irq_unsafe * nr_irq_safe +
269 nr_hardirq_unsafe * nr_hardirq_safe + 284 nr_hardirq_unsafe * nr_hardirq_safe +
270 nr_list_entries); 285 nr_list_entries);
271 286
272 /* 287 /*
273 * Estimated factor between direct and indirect 288 * Estimated factor between direct and indirect
274 * dependencies: 289 * dependencies:
275 */ 290 */
276 if (nr_list_entries) 291 if (nr_list_entries)
277 factor = sum_forward_deps / nr_list_entries; 292 factor = sum_forward_deps / nr_list_entries;
278 293
279 #ifdef CONFIG_PROVE_LOCKING 294 #ifdef CONFIG_PROVE_LOCKING
280 seq_printf(m, " dependency chains: %11lu [max: %lu]\n", 295 seq_printf(m, " dependency chains: %11lu [max: %lu]\n",
281 nr_lock_chains, MAX_LOCKDEP_CHAINS); 296 nr_lock_chains, MAX_LOCKDEP_CHAINS);
282 #endif 297 #endif
283 298
284 #ifdef CONFIG_TRACE_IRQFLAGS 299 #ifdef CONFIG_TRACE_IRQFLAGS
285 seq_printf(m, " in-hardirq chains: %11u\n", 300 seq_printf(m, " in-hardirq chains: %11u\n",
286 nr_hardirq_chains); 301 nr_hardirq_chains);
287 seq_printf(m, " in-softirq chains: %11u\n", 302 seq_printf(m, " in-softirq chains: %11u\n",
288 nr_softirq_chains); 303 nr_softirq_chains);
289 #endif 304 #endif
290 seq_printf(m, " in-process chains: %11u\n", 305 seq_printf(m, " in-process chains: %11u\n",
291 nr_process_chains); 306 nr_process_chains);
292 seq_printf(m, " stack-trace entries: %11lu [max: %lu]\n", 307 seq_printf(m, " stack-trace entries: %11lu [max: %lu]\n",
293 nr_stack_trace_entries, MAX_STACK_TRACE_ENTRIES); 308 nr_stack_trace_entries, MAX_STACK_TRACE_ENTRIES);
294 seq_printf(m, " combined max dependencies: %11u\n", 309 seq_printf(m, " combined max dependencies: %11u\n",
295 (nr_hardirq_chains + 1) * 310 (nr_hardirq_chains + 1) *
296 (nr_softirq_chains + 1) * 311 (nr_softirq_chains + 1) *
297 (nr_process_chains + 1) 312 (nr_process_chains + 1)
298 ); 313 );
299 seq_printf(m, " hardirq-safe locks: %11lu\n", 314 seq_printf(m, " hardirq-safe locks: %11lu\n",
300 nr_hardirq_safe); 315 nr_hardirq_safe);
301 seq_printf(m, " hardirq-unsafe locks: %11lu\n", 316 seq_printf(m, " hardirq-unsafe locks: %11lu\n",
302 nr_hardirq_unsafe); 317 nr_hardirq_unsafe);
303 seq_printf(m, " softirq-safe locks: %11lu\n", 318 seq_printf(m, " softirq-safe locks: %11lu\n",
304 nr_softirq_safe); 319 nr_softirq_safe);
305 seq_printf(m, " softirq-unsafe locks: %11lu\n", 320 seq_printf(m, " softirq-unsafe locks: %11lu\n",
306 nr_softirq_unsafe); 321 nr_softirq_unsafe);
307 seq_printf(m, " irq-safe locks: %11lu\n", 322 seq_printf(m, " irq-safe locks: %11lu\n",
308 nr_irq_safe); 323 nr_irq_safe);
309 seq_printf(m, " irq-unsafe locks: %11lu\n", 324 seq_printf(m, " irq-unsafe locks: %11lu\n",
310 nr_irq_unsafe); 325 nr_irq_unsafe);
311 326
312 seq_printf(m, " hardirq-read-safe locks: %11lu\n", 327 seq_printf(m, " hardirq-read-safe locks: %11lu\n",
313 nr_hardirq_read_safe); 328 nr_hardirq_read_safe);
314 seq_printf(m, " hardirq-read-unsafe locks: %11lu\n", 329 seq_printf(m, " hardirq-read-unsafe locks: %11lu\n",
315 nr_hardirq_read_unsafe); 330 nr_hardirq_read_unsafe);
316 seq_printf(m, " softirq-read-safe locks: %11lu\n", 331 seq_printf(m, " softirq-read-safe locks: %11lu\n",
317 nr_softirq_read_safe); 332 nr_softirq_read_safe);
318 seq_printf(m, " softirq-read-unsafe locks: %11lu\n", 333 seq_printf(m, " softirq-read-unsafe locks: %11lu\n",
319 nr_softirq_read_unsafe); 334 nr_softirq_read_unsafe);
320 seq_printf(m, " irq-read-safe locks: %11lu\n", 335 seq_printf(m, " irq-read-safe locks: %11lu\n",
321 nr_irq_read_safe); 336 nr_irq_read_safe);
322 seq_printf(m, " irq-read-unsafe locks: %11lu\n", 337 seq_printf(m, " irq-read-unsafe locks: %11lu\n",
323 nr_irq_read_unsafe); 338 nr_irq_read_unsafe);
324 339
325 seq_printf(m, " uncategorized locks: %11lu\n", 340 seq_printf(m, " uncategorized locks: %11lu\n",
326 nr_uncategorized); 341 nr_uncategorized);
327 seq_printf(m, " unused locks: %11lu\n", 342 seq_printf(m, " unused locks: %11lu\n",
328 nr_unused); 343 nr_unused);
329 seq_printf(m, " max locking depth: %11u\n", 344 seq_printf(m, " max locking depth: %11u\n",
330 max_lockdep_depth); 345 max_lockdep_depth);
331 seq_printf(m, " max recursion depth: %11u\n", 346 seq_printf(m, " max recursion depth: %11u\n",
332 max_recursion_depth); 347 max_recursion_depth);
333 lockdep_stats_debug_show(m); 348 lockdep_stats_debug_show(m);
334 seq_printf(m, " debug_locks: %11u\n", 349 seq_printf(m, " debug_locks: %11u\n",
335 debug_locks); 350 debug_locks);
336 351
337 return 0; 352 return 0;
338 } 353 }
339 354
340 static int lockdep_stats_open(struct inode *inode, struct file *file) 355 static int lockdep_stats_open(struct inode *inode, struct file *file)
341 { 356 {
342 return single_open(file, lockdep_stats_show, NULL); 357 return single_open(file, lockdep_stats_show, NULL);
343 } 358 }
344 359
345 static const struct file_operations proc_lockdep_stats_operations = { 360 static const struct file_operations proc_lockdep_stats_operations = {
346 .open = lockdep_stats_open, 361 .open = lockdep_stats_open,
347 .read = seq_read, 362 .read = seq_read,
348 .llseek = seq_lseek, 363 .llseek = seq_lseek,
349 .release = single_release, 364 .release = single_release,
350 }; 365 };
351 366
352 #ifdef CONFIG_LOCK_STAT 367 #ifdef CONFIG_LOCK_STAT
353 368
354 struct lock_stat_data { 369 struct lock_stat_data {
355 struct lock_class *class; 370 struct lock_class *class;
356 struct lock_class_stats stats; 371 struct lock_class_stats stats;
357 }; 372 };
358 373
359 struct lock_stat_seq { 374 struct lock_stat_seq {
360 struct lock_stat_data *iter; 375 struct lock_stat_data *iter;
361 struct lock_stat_data *iter_end; 376 struct lock_stat_data *iter_end;
362 struct lock_stat_data stats[MAX_LOCKDEP_KEYS]; 377 struct lock_stat_data stats[MAX_LOCKDEP_KEYS];
363 }; 378 };
364 379
365 /* 380 /*
366 * sort on absolute number of contentions 381 * sort on absolute number of contentions
367 */ 382 */
368 static int lock_stat_cmp(const void *l, const void *r) 383 static int lock_stat_cmp(const void *l, const void *r)
369 { 384 {
370 const struct lock_stat_data *dl = l, *dr = r; 385 const struct lock_stat_data *dl = l, *dr = r;
371 unsigned long nl, nr; 386 unsigned long nl, nr;
372 387
373 nl = dl->stats.read_waittime.nr + dl->stats.write_waittime.nr; 388 nl = dl->stats.read_waittime.nr + dl->stats.write_waittime.nr;
374 nr = dr->stats.read_waittime.nr + dr->stats.write_waittime.nr; 389 nr = dr->stats.read_waittime.nr + dr->stats.write_waittime.nr;
375 390
376 return nr - nl; 391 return nr - nl;
377 } 392 }
378 393
379 static void seq_line(struct seq_file *m, char c, int offset, int length) 394 static void seq_line(struct seq_file *m, char c, int offset, int length)
380 { 395 {
381 int i; 396 int i;
382 397
383 for (i = 0; i < offset; i++) 398 for (i = 0; i < offset; i++)
384 seq_puts(m, " "); 399 seq_puts(m, " ");
385 for (i = 0; i < length; i++) 400 for (i = 0; i < length; i++)
386 seq_printf(m, "%c", c); 401 seq_printf(m, "%c", c);
387 seq_puts(m, "\n"); 402 seq_puts(m, "\n");
388 } 403 }
389 404
390 static void snprint_time(char *buf, size_t bufsiz, s64 nr) 405 static void snprint_time(char *buf, size_t bufsiz, s64 nr)
391 { 406 {
392 unsigned long rem; 407 unsigned long rem;
393 408
394 rem = do_div(nr, 1000); /* XXX: do_div_signed */ 409 rem = do_div(nr, 1000); /* XXX: do_div_signed */
395 snprintf(buf, bufsiz, "%lld.%02d", (long long)nr, ((int)rem+5)/10); 410 snprintf(buf, bufsiz, "%lld.%02d", (long long)nr, ((int)rem+5)/10);
396 } 411 }
397 412
398 static void seq_time(struct seq_file *m, s64 time) 413 static void seq_time(struct seq_file *m, s64 time)
399 { 414 {
400 char num[15]; 415 char num[15];
401 416
402 snprint_time(num, sizeof(num), time); 417 snprint_time(num, sizeof(num), time);
403 seq_printf(m, " %14s", num); 418 seq_printf(m, " %14s", num);
404 } 419 }
405 420
406 static void seq_lock_time(struct seq_file *m, struct lock_time *lt) 421 static void seq_lock_time(struct seq_file *m, struct lock_time *lt)
407 { 422 {
408 seq_printf(m, "%14lu", lt->nr); 423 seq_printf(m, "%14lu", lt->nr);
409 seq_time(m, lt->min); 424 seq_time(m, lt->min);
410 seq_time(m, lt->max); 425 seq_time(m, lt->max);
411 seq_time(m, lt->total); 426 seq_time(m, lt->total);
412 } 427 }
413 428
414 static void seq_stats(struct seq_file *m, struct lock_stat_data *data) 429 static void seq_stats(struct seq_file *m, struct lock_stat_data *data)
415 { 430 {
416 char name[39]; 431 char name[39];
417 struct lock_class *class; 432 struct lock_class *class;
418 struct lock_class_stats *stats; 433 struct lock_class_stats *stats;
419 int i, namelen; 434 int i, namelen;
420 435
421 class = data->class; 436 class = data->class;
422 stats = &data->stats; 437 stats = &data->stats;
423 438
424 namelen = 38; 439 namelen = 38;
425 if (class->name_version > 1) 440 if (class->name_version > 1)
426 namelen -= 2; /* XXX truncates versions > 9 */ 441 namelen -= 2; /* XXX truncates versions > 9 */
427 if (class->subclass) 442 if (class->subclass)
428 namelen -= 2; 443 namelen -= 2;
429 444
430 if (!class->name) { 445 if (!class->name) {
431 char str[KSYM_NAME_LEN]; 446 char str[KSYM_NAME_LEN];
432 const char *key_name; 447 const char *key_name;
433 448
434 key_name = __get_key_name(class->key, str); 449 key_name = __get_key_name(class->key, str);
435 snprintf(name, namelen, "%s", key_name); 450 snprintf(name, namelen, "%s", key_name);
436 } else { 451 } else {
437 snprintf(name, namelen, "%s", class->name); 452 snprintf(name, namelen, "%s", class->name);
438 } 453 }
439 namelen = strlen(name); 454 namelen = strlen(name);
440 if (class->name_version > 1) { 455 if (class->name_version > 1) {
441 snprintf(name+namelen, 3, "#%d", class->name_version); 456 snprintf(name+namelen, 3, "#%d", class->name_version);
442 namelen += 2; 457 namelen += 2;
443 } 458 }
444 if (class->subclass) { 459 if (class->subclass) {
445 snprintf(name+namelen, 3, "/%d", class->subclass); 460 snprintf(name+namelen, 3, "/%d", class->subclass);
446 namelen += 2; 461 namelen += 2;
447 } 462 }
448 463
449 if (stats->write_holdtime.nr) { 464 if (stats->write_holdtime.nr) {
450 if (stats->read_holdtime.nr) 465 if (stats->read_holdtime.nr)
451 seq_printf(m, "%38s-W:", name); 466 seq_printf(m, "%38s-W:", name);
452 else 467 else
453 seq_printf(m, "%40s:", name); 468 seq_printf(m, "%40s:", name);
454 469
455 seq_printf(m, "%14lu ", stats->bounces[bounce_contended_write]); 470 seq_printf(m, "%14lu ", stats->bounces[bounce_contended_write]);
456 seq_lock_time(m, &stats->write_waittime); 471 seq_lock_time(m, &stats->write_waittime);
457 seq_printf(m, " %14lu ", stats->bounces[bounce_acquired_write]); 472 seq_printf(m, " %14lu ", stats->bounces[bounce_acquired_write]);
458 seq_lock_time(m, &stats->write_holdtime); 473 seq_lock_time(m, &stats->write_holdtime);
459 seq_puts(m, "\n"); 474 seq_puts(m, "\n");
460 } 475 }
461 476
462 if (stats->read_holdtime.nr) { 477 if (stats->read_holdtime.nr) {
463 seq_printf(m, "%38s-R:", name); 478 seq_printf(m, "%38s-R:", name);
464 seq_printf(m, "%14lu ", stats->bounces[bounce_contended_read]); 479 seq_printf(m, "%14lu ", stats->bounces[bounce_contended_read]);
465 seq_lock_time(m, &stats->read_waittime); 480 seq_lock_time(m, &stats->read_waittime);
466 seq_printf(m, " %14lu ", stats->bounces[bounce_acquired_read]); 481 seq_printf(m, " %14lu ", stats->bounces[bounce_acquired_read]);
467 seq_lock_time(m, &stats->read_holdtime); 482 seq_lock_time(m, &stats->read_holdtime);
468 seq_puts(m, "\n"); 483 seq_puts(m, "\n");
469 } 484 }
470 485
471 if (stats->read_waittime.nr + stats->write_waittime.nr == 0) 486 if (stats->read_waittime.nr + stats->write_waittime.nr == 0)
472 return; 487 return;
473 488
474 if (stats->read_holdtime.nr) 489 if (stats->read_holdtime.nr)
475 namelen += 2; 490 namelen += 2;
476 491
477 for (i = 0; i < ARRAY_SIZE(class->contention_point); i++) { 492 for (i = 0; i < ARRAY_SIZE(class->contention_point); i++) {
478 char sym[KSYM_SYMBOL_LEN]; 493 char sym[KSYM_SYMBOL_LEN];
479 char ip[32]; 494 char ip[32];
480 495
481 if (class->contention_point[i] == 0) 496 if (class->contention_point[i] == 0)
482 break; 497 break;
483 498
484 if (!i) 499 if (!i)
485 seq_line(m, '-', 40-namelen, namelen); 500 seq_line(m, '-', 40-namelen, namelen);
486 501
487 sprint_symbol(sym, class->contention_point[i]); 502 sprint_symbol(sym, class->contention_point[i]);
488 snprintf(ip, sizeof(ip), "[<%p>]", 503 snprintf(ip, sizeof(ip), "[<%p>]",
489 (void *)class->contention_point[i]); 504 (void *)class->contention_point[i]);
490 seq_printf(m, "%40s %14lu %29s %s\n", name, 505 seq_printf(m, "%40s %14lu %29s %s\n", name,
491 stats->contention_point[i], 506 stats->contention_point[i],
492 ip, sym); 507 ip, sym);
493 } 508 }
494 if (i) { 509 if (i) {
495 seq_puts(m, "\n"); 510 seq_puts(m, "\n");
496 seq_line(m, '.', 0, 40 + 1 + 10 * (14 + 1)); 511 seq_line(m, '.', 0, 40 + 1 + 10 * (14 + 1));
497 seq_puts(m, "\n"); 512 seq_puts(m, "\n");
498 } 513 }
499 } 514 }
500 515
501 static void seq_header(struct seq_file *m) 516 static void seq_header(struct seq_file *m)
502 { 517 {
503 seq_printf(m, "lock_stat version 0.2\n"); 518 seq_printf(m, "lock_stat version 0.2\n");
504 seq_line(m, '-', 0, 40 + 1 + 10 * (14 + 1)); 519 seq_line(m, '-', 0, 40 + 1 + 10 * (14 + 1));
505 seq_printf(m, "%40s %14s %14s %14s %14s %14s %14s %14s %14s " 520 seq_printf(m, "%40s %14s %14s %14s %14s %14s %14s %14s %14s "
506 "%14s %14s\n", 521 "%14s %14s\n",
507 "class name", 522 "class name",
508 "con-bounces", 523 "con-bounces",
509 "contentions", 524 "contentions",
510 "waittime-min", 525 "waittime-min",
511 "waittime-max", 526 "waittime-max",
512 "waittime-total", 527 "waittime-total",
513 "acq-bounces", 528 "acq-bounces",
514 "acquisitions", 529 "acquisitions",
515 "holdtime-min", 530 "holdtime-min",
516 "holdtime-max", 531 "holdtime-max",
517 "holdtime-total"); 532 "holdtime-total");
518 seq_line(m, '-', 0, 40 + 1 + 10 * (14 + 1)); 533 seq_line(m, '-', 0, 40 + 1 + 10 * (14 + 1));
519 seq_printf(m, "\n"); 534 seq_printf(m, "\n");
520 } 535 }
521 536
522 static void *ls_start(struct seq_file *m, loff_t *pos) 537 static void *ls_start(struct seq_file *m, loff_t *pos)
523 { 538 {
524 struct lock_stat_seq *data = m->private; 539 struct lock_stat_seq *data = m->private;
525 540
526 if (data->iter == data->stats) 541 if (*pos == 0)
527 seq_header(m); 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 data->iter = NULL; 546 data->iter = NULL;
531 547
532 return data->iter; 548 return data->iter;
533 } 549 }
534 550
535 static void *ls_next(struct seq_file *m, void *v, loff_t *pos) 551 static void *ls_next(struct seq_file *m, void *v, loff_t *pos)
536 { 552 {
537 struct lock_stat_seq *data = m->private; 553 struct lock_stat_seq *data = m->private;
538 554
539 (*pos)++; 555 (*pos)++;
540 556
541 data->iter = v; 557 if (v == SEQ_START_TOKEN)
542 data->iter++; 558 data->iter = data->stats;
559 else {
560 data->iter = v;
561 data->iter++;
562 }
563
543 if (data->iter == data->iter_end) 564 if (data->iter == data->iter_end)
544 data->iter = NULL; 565 data->iter = NULL;
545 566
546 return data->iter; 567 return data->iter;
547 } 568 }
548 569
549 static void ls_stop(struct seq_file *m, void *v) 570 static void ls_stop(struct seq_file *m, void *v)
550 { 571 {
551 } 572 }
552 573
553 static int ls_show(struct seq_file *m, void *v) 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 return 0; 581 return 0;
559 } 582 }
560 583
561 static struct seq_operations lockstat_ops = { 584 static struct seq_operations lockstat_ops = {
562 .start = ls_start, 585 .start = ls_start,
563 .next = ls_next, 586 .next = ls_next,
564 .stop = ls_stop, 587 .stop = ls_stop,
565 .show = ls_show, 588 .show = ls_show,
566 }; 589 };
567 590
568 static int lock_stat_open(struct inode *inode, struct file *file) 591 static int lock_stat_open(struct inode *inode, struct file *file)
569 { 592 {
570 int res; 593 int res;
571 struct lock_class *class; 594 struct lock_class *class;
572 struct lock_stat_seq *data = vmalloc(sizeof(struct lock_stat_seq)); 595 struct lock_stat_seq *data = vmalloc(sizeof(struct lock_stat_seq));
573 596
574 if (!data) 597 if (!data)
575 return -ENOMEM; 598 return -ENOMEM;
576 599
577 res = seq_open(file, &lockstat_ops); 600 res = seq_open(file, &lockstat_ops);
578 if (!res) { 601 if (!res) {
579 struct lock_stat_data *iter = data->stats; 602 struct lock_stat_data *iter = data->stats;
580 struct seq_file *m = file->private_data; 603 struct seq_file *m = file->private_data;
581 604
582 data->iter = iter; 605 data->iter = iter;
583 list_for_each_entry(class, &all_lock_classes, lock_entry) { 606 list_for_each_entry(class, &all_lock_classes, lock_entry) {
584 iter->class = class; 607 iter->class = class;
585 iter->stats = lock_stats(class); 608 iter->stats = lock_stats(class);
586 iter++; 609 iter++;
587 } 610 }
588 data->iter_end = iter; 611 data->iter_end = iter;
589 612
590 sort(data->stats, data->iter_end - data->iter, 613 sort(data->stats, data->iter_end - data->iter,
591 sizeof(struct lock_stat_data), 614 sizeof(struct lock_stat_data),
592 lock_stat_cmp, NULL); 615 lock_stat_cmp, NULL);
593 616
594 m->private = data; 617 m->private = data;
595 } else 618 } else
596 vfree(data); 619 vfree(data);
597 620
598 return res; 621 return res;
599 } 622 }
600 623
601 static ssize_t lock_stat_write(struct file *file, const char __user *buf, 624 static ssize_t lock_stat_write(struct file *file, const char __user *buf,
602 size_t count, loff_t *ppos) 625 size_t count, loff_t *ppos)
603 { 626 {
604 struct lock_class *class; 627 struct lock_class *class;
605 char c; 628 char c;
606 629
607 if (count) { 630 if (count) {
608 if (get_user(c, buf)) 631 if (get_user(c, buf))
609 return -EFAULT; 632 return -EFAULT;
610 633
611 if (c != '0') 634 if (c != '0')
612 return count; 635 return count;
613 636
614 list_for_each_entry(class, &all_lock_classes, lock_entry) 637 list_for_each_entry(class, &all_lock_classes, lock_entry)
615 clear_lock_stats(class); 638 clear_lock_stats(class);
616 } 639 }
617 return count; 640 return count;
618 } 641 }
619 642
620 static int lock_stat_release(struct inode *inode, struct file *file) 643 static int lock_stat_release(struct inode *inode, struct file *file)
621 { 644 {
622 struct seq_file *seq = file->private_data; 645 struct seq_file *seq = file->private_data;
623 646
624 vfree(seq->private); 647 vfree(seq->private);
625 seq->private = NULL; 648 seq->private = NULL;
626 return seq_release(inode, file); 649 return seq_release(inode, file);
627 } 650 }
628 651
629 static const struct file_operations proc_lock_stat_operations = { 652 static const struct file_operations proc_lock_stat_operations = {
630 .open = lock_stat_open, 653 .open = lock_stat_open,
631 .write = lock_stat_write, 654 .write = lock_stat_write,
632 .read = seq_read, 655 .read = seq_read,
633 .llseek = seq_lseek, 656 .llseek = seq_lseek,
634 .release = lock_stat_release, 657 .release = lock_stat_release,
635 }; 658 };
636 #endif /* CONFIG_LOCK_STAT */ 659 #endif /* CONFIG_LOCK_STAT */
637 660
638 static int __init lockdep_proc_init(void) 661 static int __init lockdep_proc_init(void)
639 { 662 {
640 struct proc_dir_entry *entry; 663 struct proc_dir_entry *entry;
641 664
642 entry = create_proc_entry("lockdep", S_IRUSR, NULL); 665 entry = create_proc_entry("lockdep", S_IRUSR, NULL);
643 if (entry) 666 if (entry)
644 entry->proc_fops = &proc_lockdep_operations; 667 entry->proc_fops = &proc_lockdep_operations;
645 668
646 entry = create_proc_entry("lockdep_stats", S_IRUSR, NULL); 669 entry = create_proc_entry("lockdep_stats", S_IRUSR, NULL);
647 if (entry) 670 if (entry)
648 entry->proc_fops = &proc_lockdep_stats_operations; 671 entry->proc_fops = &proc_lockdep_stats_operations;
649 672
650 #ifdef CONFIG_LOCK_STAT 673 #ifdef CONFIG_LOCK_STAT
651 entry = create_proc_entry("lock_stat", S_IRUSR, NULL); 674 entry = create_proc_entry("lock_stat", S_IRUSR, NULL);
652 if (entry) 675 if (entry)
653 entry->proc_fops = &proc_lock_stat_operations; 676 entry->proc_fops = &proc_lock_stat_operations;
654 #endif 677 #endif
655 678
656 return 0; 679 return 0;
657 } 680 }
658 681