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