Blame view

kernel/locking/lockdep_proc.c 17 KB
b24413180   Greg Kroah-Hartman   License cleanup: ...
1
  // SPDX-License-Identifier: GPL-2.0
a8f24a397   Ingo Molnar   [PATCH] lockdep: ...
2
3
4
5
6
7
8
  /*
   * kernel/lockdep_proc.c
   *
   * Runtime locking correctness validator
   *
   * Started by Ingo Molnar:
   *
4b32d0a4e   Peter Zijlstra   lockdep: various ...
9
   *  Copyright (C) 2006,2007 Red Hat, Inc., Ingo Molnar <mingo@redhat.com>
90eec103b   Peter Zijlstra   treewide: Remove ...
10
   *  Copyright (C) 2007 Red Hat, Inc., Peter Zijlstra
a8f24a397   Ingo Molnar   [PATCH] lockdep: ...
11
12
13
14
   *
   * Code for /proc/lockdep and /proc/lockdep_stats:
   *
   */
9984de1a5   Paul Gortmaker   kernel: Map most ...
15
  #include <linux/export.h>
a8f24a397   Ingo Molnar   [PATCH] lockdep: ...
16
17
18
19
  #include <linux/proc_fs.h>
  #include <linux/seq_file.h>
  #include <linux/kallsyms.h>
  #include <linux/debug_locks.h>
c46261de0   Peter Zijlstra   lockstat: human r...
20
21
  #include <linux/vmalloc.h>
  #include <linux/sort.h>
7c0f6ba68   Linus Torvalds   Replace <asm/uacc...
22
  #include <linux/uaccess.h>
c46261de0   Peter Zijlstra   lockstat: human r...
23
  #include <asm/div64.h>
a8f24a397   Ingo Molnar   [PATCH] lockdep: ...
24
25
26
27
28
  
  #include "lockdep_internals.h"
  
  static void *l_next(struct seq_file *m, void *v, loff_t *pos)
  {
8109e1de8   Li Zefan   lockdep: Simplify...
29
  	return seq_list_next(v, &all_lock_classes, pos);
a8f24a397   Ingo Molnar   [PATCH] lockdep: ...
30
31
32
33
  }
  
  static void *l_start(struct seq_file *m, loff_t *pos)
  {
8109e1de8   Li Zefan   lockdep: Simplify...
34
  	return seq_list_start_head(&all_lock_classes, *pos);
a8f24a397   Ingo Molnar   [PATCH] lockdep: ...
35
36
37
38
39
  }
  
  static void l_stop(struct seq_file *m, void *v)
  {
  }
068135e63   Jason Baron   [PATCH] lockdep: ...
40
41
  static void print_name(struct seq_file *m, struct lock_class *class)
  {
99fb4a122   Cyrill Gorcunov   lockdep: Use KSYM...
42
  	char str[KSYM_NAME_LEN];
068135e63   Jason Baron   [PATCH] lockdep: ...
43
44
45
46
47
48
49
50
51
52
53
54
55
  	const char *name = class->name;
  
  	if (!name) {
  		name = __get_key_name(class->key, str);
  		seq_printf(m, "%s", name);
  	} else{
  		seq_printf(m, "%s", name);
  		if (class->name_version > 1)
  			seq_printf(m, "#%d", class->name_version);
  		if (class->subclass)
  			seq_printf(m, "/%d", class->subclass);
  	}
  }
a8f24a397   Ingo Molnar   [PATCH] lockdep: ...
56
57
  static int l_show(struct seq_file *m, void *v)
  {
8109e1de8   Li Zefan   lockdep: Simplify...
58
  	struct lock_class *class = list_entry(v, struct lock_class, lock_entry);
068135e63   Jason Baron   [PATCH] lockdep: ...
59
  	struct lock_list *entry;
f510b233c   Peter Zijlstra   lockdep: get_user...
60
  	char usage[LOCK_USAGE_CHARS];
a8f24a397   Ingo Molnar   [PATCH] lockdep: ...
61

8109e1de8   Li Zefan   lockdep: Simplify...
62
  	if (v == &all_lock_classes) {
94c61c0ae   Tim Pepper   lockdep: Avoid /p...
63
64
65
66
  		seq_printf(m, "all lock classes:
  ");
  		return 0;
  	}
a8f24a397   Ingo Molnar   [PATCH] lockdep: ...
67
68
  	seq_printf(m, "%p", class->key);
  #ifdef CONFIG_DEBUG_LOCKDEP
8ca2b56cd   Waiman Long   locking/lockdep: ...
69
  	seq_printf(m, " OPS:%8ld", debug_class_ops_read(class));
a8f24a397   Ingo Molnar   [PATCH] lockdep: ...
70
  #endif
df60a8441   Stephen Hemminger   lockdep: fix buil...
71
72
73
74
  #ifdef CONFIG_PROVE_LOCKING
  	seq_printf(m, " FD:%5ld", lockdep_count_forward_deps(class));
  	seq_printf(m, " BD:%5ld", lockdep_count_backward_deps(class));
  #endif
a8f24a397   Ingo Molnar   [PATCH] lockdep: ...
75

f510b233c   Peter Zijlstra   lockdep: get_user...
76
77
  	get_usage_chars(class, usage);
  	seq_printf(m, " %s", usage);
a8f24a397   Ingo Molnar   [PATCH] lockdep: ...
78

068135e63   Jason Baron   [PATCH] lockdep: ...
79
80
81
82
83
84
85
  	seq_printf(m, ": ");
  	print_name(m, class);
  	seq_puts(m, "
  ");
  
  	list_for_each_entry(entry, &class->locks_after, entry) {
  		if (entry->distance == 1) {
2429e4ee7   Huang, Ying   lockdep: output l...
86
  			seq_printf(m, " -> [%p] ", entry->class->key);
068135e63   Jason Baron   [PATCH] lockdep: ...
87
88
89
90
  			print_name(m, entry->class);
  			seq_puts(m, "
  ");
  		}
a8f24a397   Ingo Molnar   [PATCH] lockdep: ...
91
92
93
94
95
96
  	}
  	seq_puts(m, "
  ");
  
  	return 0;
  }
15ad7cdcf   Helge Deller   [PATCH] struct se...
97
  static const struct seq_operations lockdep_ops = {
a8f24a397   Ingo Molnar   [PATCH] lockdep: ...
98
99
100
101
102
  	.start	= l_start,
  	.next	= l_next,
  	.stop	= l_stop,
  	.show	= l_show,
  };
cd1a28e84   Huang, Ying   lockdep: add lock...
103
  #ifdef CONFIG_PROVE_LOCKING
443cd507c   Huang, Ying   lockdep: add lock...
104
105
  static void *lc_start(struct seq_file *m, loff_t *pos)
  {
2212684ad   Bart Van Assche   locking/lockdep: ...
106
107
  	if (*pos < 0)
  		return NULL;
443cd507c   Huang, Ying   lockdep: add lock...
108
109
  	if (*pos == 0)
  		return SEQ_START_TOKEN;
2212684ad   Bart Van Assche   locking/lockdep: ...
110
  	return lock_chains + (*pos - 1);
443cd507c   Huang, Ying   lockdep: add lock...
111
  }
12aac19d4   Li Zefan   lockdep: Simplify...
112
113
  static void *lc_next(struct seq_file *m, void *v, loff_t *pos)
  {
2212684ad   Bart Van Assche   locking/lockdep: ...
114
  	*pos = lockdep_next_lockchain(*pos - 1) + 1;
12aac19d4   Li Zefan   lockdep: Simplify...
115
116
  	return lc_start(m, pos);
  }
443cd507c   Huang, Ying   lockdep: add lock...
117
118
119
120
121
122
123
124
125
126
127
  static void lc_stop(struct seq_file *m, void *v)
  {
  }
  
  static int lc_show(struct seq_file *m, void *v)
  {
  	struct lock_chain *chain = v;
  	struct lock_class *class;
  	int i;
  
  	if (v == SEQ_START_TOKEN) {
75dd602a5   Peter Zijlstra   lockdep: Fix lock...
128
129
  		if (nr_chain_hlocks > MAX_LOCKDEP_CHAIN_HLOCKS)
  			seq_printf(m, "(buggered) ");
443cd507c   Huang, Ying   lockdep: add lock...
130
131
132
133
134
135
136
137
138
139
  		seq_printf(m, "all lock chains:
  ");
  		return 0;
  	}
  
  	seq_printf(m, "irq_context: %d
  ", chain->irq_context);
  
  	for (i = 0; i < chain->depth; i++) {
  		class = lock_chain_get_class(chain, i);
8bfe0298f   Rabin Vincent   lockdep: handle c...
140
141
  		if (!class->key)
  			continue;
443cd507c   Huang, Ying   lockdep: add lock...
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
  		seq_printf(m, "[%p] ", class->key);
  		print_name(m, class);
  		seq_puts(m, "
  ");
  	}
  	seq_puts(m, "
  ");
  
  	return 0;
  }
  
  static const struct seq_operations lockdep_chains_ops = {
  	.start	= lc_start,
  	.next	= lc_next,
  	.stop	= lc_stop,
  	.show	= lc_show,
  };
cd1a28e84   Huang, Ying   lockdep: add lock...
159
  #endif /* CONFIG_PROVE_LOCKING */
443cd507c   Huang, Ying   lockdep: add lock...
160

a8f24a397   Ingo Molnar   [PATCH] lockdep: ...
161
162
163
  static void lockdep_stats_debug_show(struct seq_file *m)
  {
  #ifdef CONFIG_DEBUG_LOCKDEP
bd6d29c25   Frederic Weisbecker   lockstat: Make lo...
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
  	unsigned long long hi1 = debug_atomic_read(hardirqs_on_events),
  			   hi2 = debug_atomic_read(hardirqs_off_events),
  			   hr1 = debug_atomic_read(redundant_hardirqs_on),
  			   hr2 = debug_atomic_read(redundant_hardirqs_off),
  			   si1 = debug_atomic_read(softirqs_on_events),
  			   si2 = debug_atomic_read(softirqs_off_events),
  			   sr1 = debug_atomic_read(redundant_softirqs_on),
  			   sr2 = debug_atomic_read(redundant_softirqs_off);
  
  	seq_printf(m, " chain lookup misses:           %11llu
  ",
  		debug_atomic_read(chain_lookup_misses));
  	seq_printf(m, " chain lookup hits:             %11llu
  ",
  		debug_atomic_read(chain_lookup_hits));
  	seq_printf(m, " cyclic checks:                 %11llu
  ",
  		debug_atomic_read(nr_cyclic_checks));
ae813308f   Peter Zijlstra   locking/lockdep: ...
182
183
184
185
186
187
  	seq_printf(m, " redundant checks:              %11llu
  ",
  		debug_atomic_read(nr_redundant_checks));
  	seq_printf(m, " redundant links:               %11llu
  ",
  		debug_atomic_read(nr_redundant));
bd6d29c25   Frederic Weisbecker   lockstat: Make lo...
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
  	seq_printf(m, " find-mask forwards checks:     %11llu
  ",
  		debug_atomic_read(nr_find_usage_forwards_checks));
  	seq_printf(m, " find-mask backwards checks:    %11llu
  ",
  		debug_atomic_read(nr_find_usage_backwards_checks));
  
  	seq_printf(m, " hardirq on events:             %11llu
  ", hi1);
  	seq_printf(m, " hardirq off events:            %11llu
  ", hi2);
  	seq_printf(m, " redundant hardirq ons:         %11llu
  ", hr1);
  	seq_printf(m, " redundant hardirq offs:        %11llu
  ", hr2);
  	seq_printf(m, " softirq on events:             %11llu
  ", si1);
  	seq_printf(m, " softirq off events:            %11llu
  ", si2);
  	seq_printf(m, " redundant softirq ons:         %11llu
  ", sr1);
  	seq_printf(m, " redundant softirq offs:        %11llu
  ", sr2);
a8f24a397   Ingo Molnar   [PATCH] lockdep: ...
211
212
213
214
215
  #endif
  }
  
  static int lockdep_stats_show(struct seq_file *m, void *v)
  {
a8f24a397   Ingo Molnar   [PATCH] lockdep: ...
216
217
218
219
220
221
222
  	unsigned long nr_unused = 0, nr_uncategorized = 0,
  		      nr_irq_safe = 0, nr_irq_unsafe = 0,
  		      nr_softirq_safe = 0, nr_softirq_unsafe = 0,
  		      nr_hardirq_safe = 0, nr_hardirq_unsafe = 0,
  		      nr_irq_read_safe = 0, nr_irq_read_unsafe = 0,
  		      nr_softirq_read_safe = 0, nr_softirq_read_unsafe = 0,
  		      nr_hardirq_read_safe = 0, nr_hardirq_read_unsafe = 0,
dec296082   Sergey Senozhatsky   lockdep: Remove u...
223
  		      sum_forward_deps = 0;
a8f24a397   Ingo Molnar   [PATCH] lockdep: ...
224

68d41d8c9   Yuyang Du   locking/lockdep: ...
225
  #ifdef CONFIG_PROVE_LOCKING
68037aa78   Arnd Bergmann   locking/lockdep: ...
226
  	struct lock_class *class;
a8f24a397   Ingo Molnar   [PATCH] lockdep: ...
227
228
229
230
231
232
233
234
  	list_for_each_entry(class, &all_lock_classes, lock_entry) {
  
  		if (class->usage_mask == 0)
  			nr_unused++;
  		if (class->usage_mask == LOCKF_USED)
  			nr_uncategorized++;
  		if (class->usage_mask & LOCKF_USED_IN_IRQ)
  			nr_irq_safe++;
4fc95e867   Peter Zijlstra   lockdep: sanitize...
235
  		if (class->usage_mask & LOCKF_ENABLED_IRQ)
a8f24a397   Ingo Molnar   [PATCH] lockdep: ...
236
237
238
  			nr_irq_unsafe++;
  		if (class->usage_mask & LOCKF_USED_IN_SOFTIRQ)
  			nr_softirq_safe++;
4fc95e867   Peter Zijlstra   lockdep: sanitize...
239
  		if (class->usage_mask & LOCKF_ENABLED_SOFTIRQ)
a8f24a397   Ingo Molnar   [PATCH] lockdep: ...
240
241
242
  			nr_softirq_unsafe++;
  		if (class->usage_mask & LOCKF_USED_IN_HARDIRQ)
  			nr_hardirq_safe++;
4fc95e867   Peter Zijlstra   lockdep: sanitize...
243
  		if (class->usage_mask & LOCKF_ENABLED_HARDIRQ)
a8f24a397   Ingo Molnar   [PATCH] lockdep: ...
244
245
246
  			nr_hardirq_unsafe++;
  		if (class->usage_mask & LOCKF_USED_IN_IRQ_READ)
  			nr_irq_read_safe++;
4fc95e867   Peter Zijlstra   lockdep: sanitize...
247
  		if (class->usage_mask & LOCKF_ENABLED_IRQ_READ)
a8f24a397   Ingo Molnar   [PATCH] lockdep: ...
248
249
250
  			nr_irq_read_unsafe++;
  		if (class->usage_mask & LOCKF_USED_IN_SOFTIRQ_READ)
  			nr_softirq_read_safe++;
4fc95e867   Peter Zijlstra   lockdep: sanitize...
251
  		if (class->usage_mask & LOCKF_ENABLED_SOFTIRQ_READ)
a8f24a397   Ingo Molnar   [PATCH] lockdep: ...
252
253
254
  			nr_softirq_read_unsafe++;
  		if (class->usage_mask & LOCKF_USED_IN_HARDIRQ_READ)
  			nr_hardirq_read_safe++;
4fc95e867   Peter Zijlstra   lockdep: sanitize...
255
  		if (class->usage_mask & LOCKF_ENABLED_HARDIRQ_READ)
a8f24a397   Ingo Molnar   [PATCH] lockdep: ...
256
  			nr_hardirq_read_unsafe++;
419ca3f13   David Miller   lockdep: fix comb...
257
  		sum_forward_deps += lockdep_count_forward_deps(class);
a8f24a397   Ingo Molnar   [PATCH] lockdep: ...
258
  	}
501b9ebf4   Robert P. J. Day   [PATCH] Fix appar...
259
  #ifdef CONFIG_DEBUG_LOCKDEP
bd6d29c25   Frederic Weisbecker   lockstat: Make lo...
260
  	DEBUG_LOCKS_WARN_ON(debug_atomic_read(nr_unused_locks) != nr_unused);
a8f24a397   Ingo Molnar   [PATCH] lockdep: ...
261
  #endif
68d41d8c9   Yuyang Du   locking/lockdep: ...
262
263
  
  #endif
a8f24a397   Ingo Molnar   [PATCH] lockdep: ...
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
  	seq_printf(m, " lock-classes:                  %11lu [max: %lu]
  ",
  			nr_lock_classes, MAX_LOCKDEP_KEYS);
  	seq_printf(m, " direct dependencies:           %11lu [max: %lu]
  ",
  			nr_list_entries, MAX_LOCKDEP_ENTRIES);
  	seq_printf(m, " indirect dependencies:         %11lu
  ",
  			sum_forward_deps);
  
  	/*
  	 * Total number of dependencies:
  	 *
  	 * All irq-safe locks may nest inside irq-unsafe locks,
  	 * plus all the other known dependencies:
  	 */
  	seq_printf(m, " all direct dependencies:       %11lu
  ",
  			nr_irq_unsafe * nr_irq_safe +
  			nr_hardirq_unsafe * nr_hardirq_safe +
  			nr_list_entries);
8e18257d2   Peter Zijlstra   lockdep: reduce t...
285
  #ifdef CONFIG_PROVE_LOCKING
a8f24a397   Ingo Molnar   [PATCH] lockdep: ...
286
287
  	seq_printf(m, " dependency chains:             %11lu [max: %lu]
  ",
2212684ad   Bart Van Assche   locking/lockdep: ...
288
  			lock_chain_count(), MAX_LOCKDEP_CHAINS);
443cd507c   Huang, Ying   lockdep: add lock...
289
290
  	seq_printf(m, " dependency chain hlocks:       %11d [max: %lu]
  ",
cd1a28e84   Huang, Ying   lockdep: add lock...
291
  			nr_chain_hlocks, MAX_LOCKDEP_CHAIN_HLOCKS);
8e18257d2   Peter Zijlstra   lockdep: reduce t...
292
  #endif
a8f24a397   Ingo Molnar   [PATCH] lockdep: ...
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
  
  #ifdef CONFIG_TRACE_IRQFLAGS
  	seq_printf(m, " in-hardirq chains:             %11u
  ",
  			nr_hardirq_chains);
  	seq_printf(m, " in-softirq chains:             %11u
  ",
  			nr_softirq_chains);
  #endif
  	seq_printf(m, " in-process chains:             %11u
  ",
  			nr_process_chains);
  	seq_printf(m, " stack-trace entries:           %11lu [max: %lu]
  ",
  			nr_stack_trace_entries, MAX_STACK_TRACE_ENTRIES);
8c779229d   Bart Van Assche   locking/lockdep: ...
308
  #if defined(CONFIG_TRACE_IRQFLAGS) && defined(CONFIG_PROVE_LOCKING)
2482da809   Waiman Long   locking/lockdep: ...
309
310
  	seq_printf(m, " number of stack traces:        %11llu
  ",
8c779229d   Bart Van Assche   locking/lockdep: ...
311
  		   lockdep_stack_trace_count());
2482da809   Waiman Long   locking/lockdep: ...
312
313
  	seq_printf(m, " number of stack hash chains:   %11llu
  ",
8c779229d   Bart Van Assche   locking/lockdep: ...
314
315
  		   lockdep_stack_hash_count());
  #endif
a8f24a397   Ingo Molnar   [PATCH] lockdep: ...
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
  	seq_printf(m, " combined max dependencies:     %11u
  ",
  			(nr_hardirq_chains + 1) *
  			(nr_softirq_chains + 1) *
  			(nr_process_chains + 1)
  	);
  	seq_printf(m, " hardirq-safe locks:            %11lu
  ",
  			nr_hardirq_safe);
  	seq_printf(m, " hardirq-unsafe locks:          %11lu
  ",
  			nr_hardirq_unsafe);
  	seq_printf(m, " softirq-safe locks:            %11lu
  ",
  			nr_softirq_safe);
  	seq_printf(m, " softirq-unsafe locks:          %11lu
  ",
  			nr_softirq_unsafe);
  	seq_printf(m, " irq-safe locks:                %11lu
  ",
  			nr_irq_safe);
  	seq_printf(m, " irq-unsafe locks:              %11lu
  ",
  			nr_irq_unsafe);
  
  	seq_printf(m, " hardirq-read-safe locks:       %11lu
  ",
  			nr_hardirq_read_safe);
  	seq_printf(m, " hardirq-read-unsafe locks:     %11lu
  ",
  			nr_hardirq_read_unsafe);
  	seq_printf(m, " softirq-read-safe locks:       %11lu
  ",
  			nr_softirq_read_safe);
  	seq_printf(m, " softirq-read-unsafe locks:     %11lu
  ",
  			nr_softirq_read_unsafe);
  	seq_printf(m, " irq-read-safe locks:           %11lu
  ",
  			nr_irq_read_safe);
  	seq_printf(m, " irq-read-unsafe locks:         %11lu
  ",
  			nr_irq_read_unsafe);
  
  	seq_printf(m, " uncategorized locks:           %11lu
  ",
  			nr_uncategorized);
  	seq_printf(m, " unused locks:                  %11lu
  ",
  			nr_unused);
  	seq_printf(m, " max locking depth:             %11u
  ",
  			max_lockdep_depth);
bbfa26229   Ingo Molnar   lockdep: Fix BFS ...
369
  #ifdef CONFIG_PROVE_LOCKING
12f3dfd02   Ming Lei   lockdep: Add stat...
370
371
372
  	seq_printf(m, " max bfs queue depth:           %11u
  ",
  			max_bfs_queue_depth);
bbfa26229   Ingo Molnar   lockdep: Fix BFS ...
373
  #endif
a8f24a397   Ingo Molnar   [PATCH] lockdep: ...
374
375
376
377
378
379
380
  	lockdep_stats_debug_show(m);
  	seq_printf(m, " debug_locks:                   %11u
  ",
  			debug_locks);
  
  	return 0;
  }
c46261de0   Peter Zijlstra   lockstat: human r...
381
382
383
384
385
386
387
388
  #ifdef CONFIG_LOCK_STAT
  
  struct lock_stat_data {
  	struct lock_class *class;
  	struct lock_class_stats stats;
  };
  
  struct lock_stat_seq {
c46261de0   Peter Zijlstra   lockstat: human r...
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
  	struct lock_stat_data *iter_end;
  	struct lock_stat_data stats[MAX_LOCKDEP_KEYS];
  };
  
  /*
   * sort on absolute number of contentions
   */
  static int lock_stat_cmp(const void *l, const void *r)
  {
  	const struct lock_stat_data *dl = l, *dr = r;
  	unsigned long nl, nr;
  
  	nl = dl->stats.read_waittime.nr + dl->stats.write_waittime.nr;
  	nr = dr->stats.read_waittime.nr + dr->stats.write_waittime.nr;
  
  	return nr - nl;
  }
  
  static void seq_line(struct seq_file *m, char c, int offset, int length)
  {
  	int i;
  
  	for (i = 0; i < offset; i++)
  		seq_puts(m, " ");
  	for (i = 0; i < length; i++)
  		seq_printf(m, "%c", c);
  	seq_puts(m, "
  ");
  }
  
  static void snprint_time(char *buf, size_t bufsiz, s64 nr)
  {
6918bc5c8   Peter Zijlstra   lockstat: fixup s...
421
422
  	s64 div;
  	s32 rem;
c46261de0   Peter Zijlstra   lockstat: human r...
423

2189459d2   Joe Korty   lockstat: fix num...
424
  	nr += 5; /* for display rounding */
6918bc5c8   Peter Zijlstra   lockstat: fixup s...
425
426
  	div = div_s64_rem(nr, 1000, &rem);
  	snprintf(buf, bufsiz, "%lld.%02d", (long long)div, (int)rem/10);
c46261de0   Peter Zijlstra   lockstat: human r...
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
  }
  
  static void seq_time(struct seq_file *m, s64 time)
  {
  	char num[15];
  
  	snprint_time(num, sizeof(num), time);
  	seq_printf(m, " %14s", num);
  }
  
  static void seq_lock_time(struct seq_file *m, struct lock_time *lt)
  {
  	seq_printf(m, "%14lu", lt->nr);
  	seq_time(m, lt->min);
  	seq_time(m, lt->max);
  	seq_time(m, lt->total);
838cc7b48   Peter Zijlstra   lockdep/proc: Fix...
443
  	seq_time(m, lt->nr ? div_s64(lt->total, lt->nr) : 0);
c46261de0   Peter Zijlstra   lockstat: human r...
444
445
446
447
  }
  
  static void seq_stats(struct seq_file *m, struct lock_stat_data *data)
  {
364f6afc4   Bart Van Assche   locking/lockdep: ...
448
  	const struct lockdep_subclass_key *ckey;
c46261de0   Peter Zijlstra   lockstat: human r...
449
  	struct lock_class_stats *stats;
cee34d88c   Peter Zijlstra   lockdep: Fix a ra...
450
451
  	struct lock_class *class;
  	const char *cname;
c46261de0   Peter Zijlstra   lockstat: human r...
452
  	int i, namelen;
cee34d88c   Peter Zijlstra   lockdep: Fix a ra...
453
  	char name[39];
c46261de0   Peter Zijlstra   lockstat: human r...
454
455
456
  
  	class = data->class;
  	stats = &data->stats;
d38e1d5aa   Peter Zijlstra   lockstat: better ...
457
458
459
460
461
  	namelen = 38;
  	if (class->name_version > 1)
  		namelen -= 2; /* XXX truncates versions > 9 */
  	if (class->subclass)
  		namelen -= 2;
cee34d88c   Peter Zijlstra   lockdep: Fix a ra...
462
463
464
465
466
467
468
469
470
  	rcu_read_lock_sched();
  	cname = rcu_dereference_sched(class->name);
  	ckey  = rcu_dereference_sched(class->key);
  
  	if (!cname && !ckey) {
  		rcu_read_unlock_sched();
  		return;
  
  	} else if (!cname) {
d38e1d5aa   Peter Zijlstra   lockstat: better ...
471
472
  		char str[KSYM_NAME_LEN];
  		const char *key_name;
cee34d88c   Peter Zijlstra   lockdep: Fix a ra...
473
  		key_name = __get_key_name(ckey, str);
d38e1d5aa   Peter Zijlstra   lockstat: better ...
474
475
  		snprintf(name, namelen, "%s", key_name);
  	} else {
cee34d88c   Peter Zijlstra   lockdep: Fix a ra...
476
  		snprintf(name, namelen, "%s", cname);
d38e1d5aa   Peter Zijlstra   lockstat: better ...
477
  	}
cee34d88c   Peter Zijlstra   lockdep: Fix a ra...
478
  	rcu_read_unlock_sched();
c46261de0   Peter Zijlstra   lockstat: human r...
479
  	namelen = strlen(name);
d38e1d5aa   Peter Zijlstra   lockstat: better ...
480
481
482
483
484
485
486
487
  	if (class->name_version > 1) {
  		snprintf(name+namelen, 3, "#%d", class->name_version);
  		namelen += 2;
  	}
  	if (class->subclass) {
  		snprintf(name+namelen, 3, "/%d", class->subclass);
  		namelen += 2;
  	}
c46261de0   Peter Zijlstra   lockstat: human r...
488
489
490
491
492
493
  
  	if (stats->write_holdtime.nr) {
  		if (stats->read_holdtime.nr)
  			seq_printf(m, "%38s-W:", name);
  		else
  			seq_printf(m, "%40s:", name);
96645678c   Peter Zijlstra   lockstat: measure...
494
  		seq_printf(m, "%14lu ", stats->bounces[bounce_contended_write]);
c46261de0   Peter Zijlstra   lockstat: human r...
495
  		seq_lock_time(m, &stats->write_waittime);
96645678c   Peter Zijlstra   lockstat: measure...
496
  		seq_printf(m, " %14lu ", stats->bounces[bounce_acquired_write]);
c46261de0   Peter Zijlstra   lockstat: human r...
497
498
499
500
501
502
503
  		seq_lock_time(m, &stats->write_holdtime);
  		seq_puts(m, "
  ");
  	}
  
  	if (stats->read_holdtime.nr) {
  		seq_printf(m, "%38s-R:", name);
96645678c   Peter Zijlstra   lockstat: measure...
504
  		seq_printf(m, "%14lu ", stats->bounces[bounce_contended_read]);
c46261de0   Peter Zijlstra   lockstat: human r...
505
  		seq_lock_time(m, &stats->read_waittime);
96645678c   Peter Zijlstra   lockstat: measure...
506
  		seq_printf(m, " %14lu ", stats->bounces[bounce_acquired_read]);
c46261de0   Peter Zijlstra   lockstat: human r...
507
508
509
510
511
512
513
514
515
516
  		seq_lock_time(m, &stats->read_holdtime);
  		seq_puts(m, "
  ");
  	}
  
  	if (stats->read_waittime.nr + stats->write_waittime.nr == 0)
  		return;
  
  	if (stats->read_holdtime.nr)
  		namelen += 2;
c7e78cff6   Peter Zijlstra   lockstat: contend...
517
  	for (i = 0; i < LOCKSTAT_POINTS; i++) {
c46261de0   Peter Zijlstra   lockstat: human r...
518
519
520
521
522
523
524
  		char ip[32];
  
  		if (class->contention_point[i] == 0)
  			break;
  
  		if (!i)
  			seq_line(m, '-', 40-namelen, namelen);
c46261de0   Peter Zijlstra   lockstat: human r...
525
526
  		snprintf(ip, sizeof(ip), "[<%p>]",
  				(void *)class->contention_point[i]);
3cf9b85b4   Joe Perches   locking, lockdep:...
527
528
529
530
  		seq_printf(m, "%40s %14lu %29s %pS
  ",
  			   name, stats->contention_point[i],
  			   ip, (void *)class->contention_point[i]);
c46261de0   Peter Zijlstra   lockstat: human r...
531
  	}
c7e78cff6   Peter Zijlstra   lockstat: contend...
532
  	for (i = 0; i < LOCKSTAT_POINTS; i++) {
c7e78cff6   Peter Zijlstra   lockstat: contend...
533
534
535
536
537
538
539
  		char ip[32];
  
  		if (class->contending_point[i] == 0)
  			break;
  
  		if (!i)
  			seq_line(m, '-', 40-namelen, namelen);
c7e78cff6   Peter Zijlstra   lockstat: contend...
540
541
  		snprintf(ip, sizeof(ip), "[<%p>]",
  				(void *)class->contending_point[i]);
3cf9b85b4   Joe Perches   locking, lockdep:...
542
543
544
545
  		seq_printf(m, "%40s %14lu %29s %pS
  ",
  			   name, stats->contending_point[i],
  			   ip, (void *)class->contending_point[i]);
c7e78cff6   Peter Zijlstra   lockstat: contend...
546
  	}
c46261de0   Peter Zijlstra   lockstat: human r...
547
548
549
  	if (i) {
  		seq_puts(m, "
  ");
1232e3807   Davidlohr Bueso   lockstat: Report ...
550
  		seq_line(m, '.', 0, 40 + 1 + 12 * (14 + 1));
c46261de0   Peter Zijlstra   lockstat: human r...
551
552
553
554
555
556
557
  		seq_puts(m, "
  ");
  	}
  }
  
  static void seq_header(struct seq_file *m)
  {
1232e3807   Davidlohr Bueso   lockstat: Report ...
558
559
  	seq_puts(m, "lock_stat version 0.4
  ");
9833f8cb9   Peter Zijlstra   lockstat: warn ab...
560
561
562
563
  
  	if (unlikely(!debug_locks))
  		seq_printf(m, "*WARNING* lock debugging disabled!! - possibly due to a lockdep warning
  ");
1232e3807   Davidlohr Bueso   lockstat: Report ...
564
565
  	seq_line(m, '-', 0, 40 + 1 + 12 * (14 + 1));
  	seq_printf(m, "%40s %14s %14s %14s %14s %14s %14s %14s %14s %14s %14s "
96645678c   Peter Zijlstra   lockstat: measure...
566
567
  			"%14s %14s
  ",
c46261de0   Peter Zijlstra   lockstat: human r...
568
  			"class name",
96645678c   Peter Zijlstra   lockstat: measure...
569
  			"con-bounces",
c46261de0   Peter Zijlstra   lockstat: human r...
570
571
572
573
  			"contentions",
  			"waittime-min",
  			"waittime-max",
  			"waittime-total",
1232e3807   Davidlohr Bueso   lockstat: Report ...
574
  			"waittime-avg",
96645678c   Peter Zijlstra   lockstat: measure...
575
  			"acq-bounces",
c46261de0   Peter Zijlstra   lockstat: human r...
576
577
578
  			"acquisitions",
  			"holdtime-min",
  			"holdtime-max",
1232e3807   Davidlohr Bueso   lockstat: Report ...
579
580
581
  			"holdtime-total",
  			"holdtime-avg");
  	seq_line(m, '-', 0, 40 + 1 + 12 * (14 + 1));
c46261de0   Peter Zijlstra   lockstat: human r...
582
583
584
585
586
587
588
  	seq_printf(m, "
  ");
  }
  
  static void *ls_start(struct seq_file *m, loff_t *pos)
  {
  	struct lock_stat_seq *data = m->private;
96004bb2a   Li Zefan   lockdep: Simplify...
589
  	struct lock_stat_data *iter;
c46261de0   Peter Zijlstra   lockstat: human r...
590

94c61c0ae   Tim Pepper   lockdep: Avoid /p...
591
592
  	if (*pos == 0)
  		return SEQ_START_TOKEN;
c46261de0   Peter Zijlstra   lockstat: human r...
593

96004bb2a   Li Zefan   lockdep: Simplify...
594
595
596
  	iter = data->stats + (*pos - 1);
  	if (iter >= data->iter_end)
  		iter = NULL;
4b32d0a4e   Peter Zijlstra   lockdep: various ...
597

96004bb2a   Li Zefan   lockdep: Simplify...
598
  	return iter;
c46261de0   Peter Zijlstra   lockstat: human r...
599
600
601
602
  }
  
  static void *ls_next(struct seq_file *m, void *v, loff_t *pos)
  {
c46261de0   Peter Zijlstra   lockstat: human r...
603
  	(*pos)++;
96004bb2a   Li Zefan   lockdep: Simplify...
604
  	return ls_start(m, pos);
c46261de0   Peter Zijlstra   lockstat: human r...
605
606
607
608
609
610
611
612
  }
  
  static void ls_stop(struct seq_file *m, void *v)
  {
  }
  
  static int ls_show(struct seq_file *m, void *v)
  {
94c61c0ae   Tim Pepper   lockdep: Avoid /p...
613
614
615
616
  	if (v == SEQ_START_TOKEN)
  		seq_header(m);
  	else
  		seq_stats(m, v);
c46261de0   Peter Zijlstra   lockstat: human r...
617

c46261de0   Peter Zijlstra   lockstat: human r...
618
619
  	return 0;
  }
88e9d34c7   James Morris   seq_file: constif...
620
  static const struct seq_operations lockstat_ops = {
c46261de0   Peter Zijlstra   lockstat: human r...
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
  	.start	= ls_start,
  	.next	= ls_next,
  	.stop	= ls_stop,
  	.show	= ls_show,
  };
  
  static int lock_stat_open(struct inode *inode, struct file *file)
  {
  	int res;
  	struct lock_class *class;
  	struct lock_stat_seq *data = vmalloc(sizeof(struct lock_stat_seq));
  
  	if (!data)
  		return -ENOMEM;
  
  	res = seq_open(file, &lockstat_ops);
  	if (!res) {
  		struct lock_stat_data *iter = data->stats;
  		struct seq_file *m = file->private_data;
c46261de0   Peter Zijlstra   lockstat: human r...
640
641
642
643
644
645
  		list_for_each_entry(class, &all_lock_classes, lock_entry) {
  			iter->class = class;
  			iter->stats = lock_stats(class);
  			iter++;
  		}
  		data->iter_end = iter;
96004bb2a   Li Zefan   lockdep: Simplify...
646
  		sort(data->stats, data->iter_end - data->stats,
c46261de0   Peter Zijlstra   lockstat: human r...
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
  				sizeof(struct lock_stat_data),
  				lock_stat_cmp, NULL);
  
  		m->private = data;
  	} else
  		vfree(data);
  
  	return res;
  }
  
  static ssize_t lock_stat_write(struct file *file, const char __user *buf,
  			       size_t count, loff_t *ppos)
  {
  	struct lock_class *class;
  	char c;
  
  	if (count) {
  		if (get_user(c, buf))
  			return -EFAULT;
  
  		if (c != '0')
  			return count;
  
  		list_for_each_entry(class, &all_lock_classes, lock_entry)
  			clear_lock_stats(class);
  	}
  	return count;
  }
  
  static int lock_stat_release(struct inode *inode, struct file *file)
  {
  	struct seq_file *seq = file->private_data;
  
  	vfree(seq->private);
c46261de0   Peter Zijlstra   lockstat: human r...
681
682
683
684
685
686
687
688
689
690
691
  	return seq_release(inode, file);
  }
  
  static const struct file_operations proc_lock_stat_operations = {
  	.open		= lock_stat_open,
  	.write		= lock_stat_write,
  	.read		= seq_read,
  	.llseek		= seq_lseek,
  	.release	= lock_stat_release,
  };
  #endif /* CONFIG_LOCK_STAT */
a8f24a397   Ingo Molnar   [PATCH] lockdep: ...
692
693
  static int __init lockdep_proc_init(void)
  {
fddda2b7b   Christoph Hellwig   proc: introduce p...
694
  	proc_create_seq("lockdep", S_IRUSR, NULL, &lockdep_ops);
cd1a28e84   Huang, Ying   lockdep: add lock...
695
  #ifdef CONFIG_PROVE_LOCKING
fddda2b7b   Christoph Hellwig   proc: introduce p...
696
  	proc_create_seq("lockdep_chains", S_IRUSR, NULL, &lockdep_chains_ops);
cd1a28e84   Huang, Ying   lockdep: add lock...
697
  #endif
3f3942aca   Christoph Hellwig   proc: introduce p...
698
  	proc_create_single("lockdep_stats", S_IRUSR, NULL, lockdep_stats_show);
c46261de0   Peter Zijlstra   lockstat: human r...
699
  #ifdef CONFIG_LOCK_STAT
9795447f7   Li Zefan   lockdep: Fix file...
700
701
  	proc_create("lock_stat", S_IRUSR | S_IWUSR, NULL,
  		    &proc_lock_stat_operations);
c46261de0   Peter Zijlstra   lockstat: human r...
702
  #endif
a8f24a397   Ingo Molnar   [PATCH] lockdep: ...
703
704
705
706
  	return 0;
  }
  
  __initcall(lockdep_proc_init);