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