Merge branch 'release' of git://git.kernel.org/pub/scm/linux/kernel/git/aegl/linux-2.6
[linux-2.6] / kernel / lockdep_proc.c
1 /*
2  * kernel/lockdep_proc.c
3  *
4  * Runtime locking correctness validator
5  *
6  * Started by Ingo Molnar:
7  *
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>
10  *
11  * Code for /proc/lockdep and /proc/lockdep_stats:
12  *
13  */
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>
19 #include <linux/vmalloc.h>
20 #include <linux/sort.h>
21 #include <asm/uaccess.h>
22 #include <asm/div64.h>
23
24 #include "lockdep_internals.h"
25
26 static 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
42 static 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
52 static void l_stop(struct seq_file *m, void *v)
53 {
54 }
55
56 static 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
70 static 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
84 static 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
101 static 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;
105         struct lock_list *entry;
106         char c1, c2, c3, c4;
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
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                 }
131         }
132         seq_puts(m, "\n");
133
134         return 0;
135 }
136
137 static const struct seq_operations lockdep_ops = {
138         .start  = l_start,
139         .next   = l_next,
140         .stop   = l_stop,
141         .show   = l_show,
142 };
143
144 static 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
159 static const struct file_operations proc_lockdep_operations = {
160         .open           = lockdep_open,
161         .read           = seq_read,
162         .llseek         = seq_lseek,
163         .release        = seq_release,
164 };
165
166 static 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
206 static 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         }
251 #ifdef CONFIG_DEBUG_LOCKDEP
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
279 #ifdef CONFIG_PROVE_LOCKING
280         seq_printf(m, " dependency chains:             %11lu [max: %lu]\n",
281                         nr_lock_chains, MAX_LOCKDEP_CHAINS);
282 #endif
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
340 static int lockdep_stats_open(struct inode *inode, struct file *file)
341 {
342         return single_open(file, lockdep_stats_show, NULL);
343 }
344
345 static const struct file_operations proc_lockdep_stats_operations = {
346         .open           = lockdep_stats_open,
347         .read           = seq_read,
348         .llseek         = seq_lseek,
349         .release        = single_release,
350 };
351
352 #ifdef CONFIG_LOCK_STAT
353
354 struct lock_stat_data {
355         struct lock_class *class;
356         struct lock_class_stats stats;
357 };
358
359 struct 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  */
368 static 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
379 static 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
390 static 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
398 static 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
406 static 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
414 static 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
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         }
439         namelen = strlen(name);
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         }
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
455                 seq_printf(m, "%14lu ", stats->bounces[bounce_contended_write]);
456                 seq_lock_time(m, &stats->write_waittime);
457                 seq_printf(m, " %14lu ", stats->bounces[bounce_acquired_write]);
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);
464                 seq_printf(m, "%14lu ", stats->bounces[bounce_contended_read]);
465                 seq_lock_time(m, &stats->read_waittime);
466                 seq_printf(m, " %14lu ", stats->bounces[bounce_acquired_read]);
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");
496                 seq_line(m, '.', 0, 40 + 1 + 10 * (14 + 1));
497                 seq_puts(m, "\n");
498         }
499 }
500
501 static void seq_header(struct seq_file *m)
502 {
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",
507                         "class name",
508                         "con-bounces",
509                         "contentions",
510                         "waittime-min",
511                         "waittime-max",
512                         "waittime-total",
513                         "acq-bounces",
514                         "acquisitions",
515                         "holdtime-min",
516                         "holdtime-max",
517                         "holdtime-total");
518         seq_line(m, '-', 0, 40 + 1 + 10 * (14 + 1));
519         seq_printf(m, "\n");
520 }
521
522 static 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
529         if (data->iter == data->iter_end)
530                 data->iter = NULL;
531
532         return data->iter;
533 }
534
535 static 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
549 static void ls_stop(struct seq_file *m, void *v)
550 {
551 }
552
553 static 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
561 static struct seq_operations lockstat_ops = {
562         .start  = ls_start,
563         .next   = ls_next,
564         .stop   = ls_stop,
565         .show   = ls_show,
566 };
567
568 static 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
601 static 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
620 static 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
629 static 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
638 static 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
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
656         return 0;
657 }
658
659 __initcall(lockdep_proc_init);
660