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