2 * kernel/lockdep_proc.c
4 * Runtime locking correctness validator
6 * Started by Ingo Molnar:
8 * Copyright (C) 2006 Red Hat, Inc., Ingo Molnar <mingo@redhat.com>
10 * Code for /proc/lockdep and /proc/lockdep_stats:
13 #include <linux/sched.h>
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>
20 #include "lockdep_internals.h"
22 static void *l_next(struct seq_file
*m
, void *v
, loff_t
*pos
)
24 struct lock_class
*class = v
;
28 if (class->lock_entry
.next
!= &all_lock_classes
)
29 class = list_entry(class->lock_entry
.next
, struct lock_class
,
38 static void *l_start(struct seq_file
*m
, loff_t
*pos
)
40 struct lock_class
*class = m
->private;
42 if (&class->lock_entry
== all_lock_classes
.next
)
43 seq_printf(m
, "all lock classes:\n");
48 static void l_stop(struct seq_file
*m
, void *v
)
52 static unsigned long count_forward_deps(struct lock_class
*class)
54 struct lock_list
*entry
;
55 unsigned long ret
= 1;
58 * Recurse this class's dependency list:
60 list_for_each_entry(entry
, &class->locks_after
, entry
)
61 ret
+= count_forward_deps(entry
->class);
66 static unsigned long count_backward_deps(struct lock_class
*class)
68 struct lock_list
*entry
;
69 unsigned long ret
= 1;
72 * Recurse this class's dependency list:
74 list_for_each_entry(entry
, &class->locks_before
, entry
)
75 ret
+= count_backward_deps(entry
->class);
80 static int l_show(struct seq_file
*m
, void *v
)
82 unsigned long nr_forward_deps
, nr_backward_deps
;
83 struct lock_class
*class = m
->private;
84 char str
[128], c1
, c2
, c3
, c4
;
87 seq_printf(m
, "%p", class->key
);
88 #ifdef CONFIG_DEBUG_LOCKDEP
89 seq_printf(m
, " OPS:%8ld", class->ops
);
91 nr_forward_deps
= count_forward_deps(class);
92 seq_printf(m
, " FD:%5ld", nr_forward_deps
);
94 nr_backward_deps
= count_backward_deps(class);
95 seq_printf(m
, " BD:%5ld", nr_backward_deps
);
97 get_usage_chars(class, &c1
, &c2
, &c3
, &c4
);
98 seq_printf(m
, " %c%c%c%c", c1
, c2
, c3
, c4
);
102 name
= __get_key_name(class->key
, str
);
103 seq_printf(m
, ": %s", name
);
105 seq_printf(m
, ": %s", name
);
106 if (class->name_version
> 1)
107 seq_printf(m
, "#%d", class->name_version
);
109 seq_printf(m
, "/%d", class->subclass
);
116 static const struct seq_operations lockdep_ops
= {
123 static int lockdep_open(struct inode
*inode
, struct file
*file
)
125 int res
= seq_open(file
, &lockdep_ops
);
127 struct seq_file
*m
= file
->private_data
;
129 if (!list_empty(&all_lock_classes
))
130 m
->private = list_entry(all_lock_classes
.next
,
131 struct lock_class
, lock_entry
);
138 static const struct file_operations proc_lockdep_operations
= {
139 .open
= lockdep_open
,
142 .release
= seq_release
,
145 static void lockdep_stats_debug_show(struct seq_file
*m
)
147 #ifdef CONFIG_DEBUG_LOCKDEP
148 unsigned int hi1
= debug_atomic_read(&hardirqs_on_events
),
149 hi2
= debug_atomic_read(&hardirqs_off_events
),
150 hr1
= debug_atomic_read(&redundant_hardirqs_on
),
151 hr2
= debug_atomic_read(&redundant_hardirqs_off
),
152 si1
= debug_atomic_read(&softirqs_on_events
),
153 si2
= debug_atomic_read(&softirqs_off_events
),
154 sr1
= debug_atomic_read(&redundant_softirqs_on
),
155 sr2
= debug_atomic_read(&redundant_softirqs_off
);
157 seq_printf(m
, " chain lookup misses: %11u\n",
158 debug_atomic_read(&chain_lookup_misses
));
159 seq_printf(m
, " chain lookup hits: %11u\n",
160 debug_atomic_read(&chain_lookup_hits
));
161 seq_printf(m
, " cyclic checks: %11u\n",
162 debug_atomic_read(&nr_cyclic_checks
));
163 seq_printf(m
, " cyclic-check recursions: %11u\n",
164 debug_atomic_read(&nr_cyclic_check_recursions
));
165 seq_printf(m
, " find-mask forwards checks: %11u\n",
166 debug_atomic_read(&nr_find_usage_forwards_checks
));
167 seq_printf(m
, " find-mask forwards recursions: %11u\n",
168 debug_atomic_read(&nr_find_usage_forwards_recursions
));
169 seq_printf(m
, " find-mask backwards checks: %11u\n",
170 debug_atomic_read(&nr_find_usage_backwards_checks
));
171 seq_printf(m
, " find-mask backwards recursions:%11u\n",
172 debug_atomic_read(&nr_find_usage_backwards_recursions
));
174 seq_printf(m
, " hardirq on events: %11u\n", hi1
);
175 seq_printf(m
, " hardirq off events: %11u\n", hi2
);
176 seq_printf(m
, " redundant hardirq ons: %11u\n", hr1
);
177 seq_printf(m
, " redundant hardirq offs: %11u\n", hr2
);
178 seq_printf(m
, " softirq on events: %11u\n", si1
);
179 seq_printf(m
, " softirq off events: %11u\n", si2
);
180 seq_printf(m
, " redundant softirq ons: %11u\n", sr1
);
181 seq_printf(m
, " redundant softirq offs: %11u\n", sr2
);
185 static int lockdep_stats_show(struct seq_file
*m
, void *v
)
187 struct lock_class
*class;
188 unsigned long nr_unused
= 0, nr_uncategorized
= 0,
189 nr_irq_safe
= 0, nr_irq_unsafe
= 0,
190 nr_softirq_safe
= 0, nr_softirq_unsafe
= 0,
191 nr_hardirq_safe
= 0, nr_hardirq_unsafe
= 0,
192 nr_irq_read_safe
= 0, nr_irq_read_unsafe
= 0,
193 nr_softirq_read_safe
= 0, nr_softirq_read_unsafe
= 0,
194 nr_hardirq_read_safe
= 0, nr_hardirq_read_unsafe
= 0,
195 sum_forward_deps
= 0, factor
= 0;
197 list_for_each_entry(class, &all_lock_classes
, lock_entry
) {
199 if (class->usage_mask
== 0)
201 if (class->usage_mask
== LOCKF_USED
)
203 if (class->usage_mask
& LOCKF_USED_IN_IRQ
)
205 if (class->usage_mask
& LOCKF_ENABLED_IRQS
)
207 if (class->usage_mask
& LOCKF_USED_IN_SOFTIRQ
)
209 if (class->usage_mask
& LOCKF_ENABLED_SOFTIRQS
)
211 if (class->usage_mask
& LOCKF_USED_IN_HARDIRQ
)
213 if (class->usage_mask
& LOCKF_ENABLED_HARDIRQS
)
215 if (class->usage_mask
& LOCKF_USED_IN_IRQ_READ
)
217 if (class->usage_mask
& LOCKF_ENABLED_IRQS_READ
)
218 nr_irq_read_unsafe
++;
219 if (class->usage_mask
& LOCKF_USED_IN_SOFTIRQ_READ
)
220 nr_softirq_read_safe
++;
221 if (class->usage_mask
& LOCKF_ENABLED_SOFTIRQS_READ
)
222 nr_softirq_read_unsafe
++;
223 if (class->usage_mask
& LOCKF_USED_IN_HARDIRQ_READ
)
224 nr_hardirq_read_safe
++;
225 if (class->usage_mask
& LOCKF_ENABLED_HARDIRQS_READ
)
226 nr_hardirq_read_unsafe
++;
228 sum_forward_deps
+= count_forward_deps(class);
230 #ifdef CONFIG_LOCKDEP_DEBUG
231 DEBUG_LOCKS_WARN_ON(debug_atomic_read(&nr_unused_locks
) != nr_unused
);
233 seq_printf(m
, " lock-classes: %11lu [max: %lu]\n",
234 nr_lock_classes
, MAX_LOCKDEP_KEYS
);
235 seq_printf(m
, " direct dependencies: %11lu [max: %lu]\n",
236 nr_list_entries
, MAX_LOCKDEP_ENTRIES
);
237 seq_printf(m
, " indirect dependencies: %11lu\n",
241 * Total number of dependencies:
243 * All irq-safe locks may nest inside irq-unsafe locks,
244 * plus all the other known dependencies:
246 seq_printf(m
, " all direct dependencies: %11lu\n",
247 nr_irq_unsafe
* nr_irq_safe
+
248 nr_hardirq_unsafe
* nr_hardirq_safe
+
252 * Estimated factor between direct and indirect
256 factor
= sum_forward_deps
/ nr_list_entries
;
258 seq_printf(m
, " dependency chains: %11lu [max: %lu]\n",
259 nr_lock_chains
, MAX_LOCKDEP_CHAINS
);
261 #ifdef CONFIG_TRACE_IRQFLAGS
262 seq_printf(m
, " in-hardirq chains: %11u\n",
264 seq_printf(m
, " in-softirq chains: %11u\n",
267 seq_printf(m
, " in-process chains: %11u\n",
269 seq_printf(m
, " stack-trace entries: %11lu [max: %lu]\n",
270 nr_stack_trace_entries
, MAX_STACK_TRACE_ENTRIES
);
271 seq_printf(m
, " combined max dependencies: %11u\n",
272 (nr_hardirq_chains
+ 1) *
273 (nr_softirq_chains
+ 1) *
274 (nr_process_chains
+ 1)
276 seq_printf(m
, " hardirq-safe locks: %11lu\n",
278 seq_printf(m
, " hardirq-unsafe locks: %11lu\n",
280 seq_printf(m
, " softirq-safe locks: %11lu\n",
282 seq_printf(m
, " softirq-unsafe locks: %11lu\n",
284 seq_printf(m
, " irq-safe locks: %11lu\n",
286 seq_printf(m
, " irq-unsafe locks: %11lu\n",
289 seq_printf(m
, " hardirq-read-safe locks: %11lu\n",
290 nr_hardirq_read_safe
);
291 seq_printf(m
, " hardirq-read-unsafe locks: %11lu\n",
292 nr_hardirq_read_unsafe
);
293 seq_printf(m
, " softirq-read-safe locks: %11lu\n",
294 nr_softirq_read_safe
);
295 seq_printf(m
, " softirq-read-unsafe locks: %11lu\n",
296 nr_softirq_read_unsafe
);
297 seq_printf(m
, " irq-read-safe locks: %11lu\n",
299 seq_printf(m
, " irq-read-unsafe locks: %11lu\n",
302 seq_printf(m
, " uncategorized locks: %11lu\n",
304 seq_printf(m
, " unused locks: %11lu\n",
306 seq_printf(m
, " max locking depth: %11u\n",
308 seq_printf(m
, " max recursion depth: %11u\n",
309 max_recursion_depth
);
310 lockdep_stats_debug_show(m
);
311 seq_printf(m
, " debug_locks: %11u\n",
317 static int lockdep_stats_open(struct inode
*inode
, struct file
*file
)
319 return single_open(file
, lockdep_stats_show
, NULL
);
322 static const struct file_operations proc_lockdep_stats_operations
= {
323 .open
= lockdep_stats_open
,
326 .release
= seq_release
,
329 static int __init
lockdep_proc_init(void)
331 struct proc_dir_entry
*entry
;
333 entry
= create_proc_entry("lockdep", S_IRUSR
, NULL
);
335 entry
->proc_fops
= &proc_lockdep_operations
;
337 entry
= create_proc_entry("lockdep_stats", S_IRUSR
, NULL
);
339 entry
->proc_fops
= &proc_lockdep_stats_operations
;
344 __initcall(lockdep_proc_init
);