.. | .. |
---|
24 | 24 | |
---|
25 | 25 | #include "lockdep_internals.h" |
---|
26 | 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 | + |
---|
27 | 38 | static void *l_next(struct seq_file *m, void *v, loff_t *pos) |
---|
28 | 39 | { |
---|
29 | | - return seq_list_next(v, &all_lock_classes, pos); |
---|
| 40 | + struct lock_class *class = v; |
---|
| 41 | + |
---|
| 42 | + ++class; |
---|
| 43 | + *pos = class - lock_classes; |
---|
| 44 | + return (*pos > max_lock_class_idx) ? NULL : class; |
---|
30 | 45 | } |
---|
31 | 46 | |
---|
32 | 47 | static void *l_start(struct seq_file *m, loff_t *pos) |
---|
33 | 48 | { |
---|
34 | | - return seq_list_start_head(&all_lock_classes, *pos); |
---|
| 49 | + unsigned long idx = *pos; |
---|
| 50 | + |
---|
| 51 | + if (idx > max_lock_class_idx) |
---|
| 52 | + return NULL; |
---|
| 53 | + return lock_classes + idx; |
---|
35 | 54 | } |
---|
36 | 55 | |
---|
37 | 56 | static void l_stop(struct seq_file *m, void *v) |
---|
.. | .. |
---|
57 | 76 | |
---|
58 | 77 | static int l_show(struct seq_file *m, void *v) |
---|
59 | 78 | { |
---|
60 | | - struct lock_class *class = list_entry(v, struct lock_class, lock_entry); |
---|
| 79 | + struct lock_class *class = v; |
---|
61 | 80 | struct lock_list *entry; |
---|
62 | 81 | char usage[LOCK_USAGE_CHARS]; |
---|
| 82 | + int idx = class - lock_classes; |
---|
63 | 83 | |
---|
64 | | - if (v == &all_lock_classes) { |
---|
| 84 | + if (v == lock_classes) |
---|
65 | 85 | seq_printf(m, "all lock classes:\n"); |
---|
| 86 | + |
---|
| 87 | + if (!test_bit(idx, lock_classes_in_use)) |
---|
66 | 88 | return 0; |
---|
67 | | - } |
---|
68 | 89 | |
---|
69 | 90 | seq_printf(m, "%p", class->key); |
---|
70 | 91 | #ifdef CONFIG_DEBUG_LOCKDEP |
---|
71 | | - seq_printf(m, " OPS:%8ld", class->ops); |
---|
| 92 | + seq_printf(m, " OPS:%8ld", debug_class_ops_read(class)); |
---|
72 | 93 | #endif |
---|
73 | 94 | #ifdef CONFIG_PROVE_LOCKING |
---|
74 | 95 | seq_printf(m, " FD:%5ld", lockdep_count_forward_deps(class)); |
---|
.. | .. |
---|
104 | 125 | #ifdef CONFIG_PROVE_LOCKING |
---|
105 | 126 | static void *lc_start(struct seq_file *m, loff_t *pos) |
---|
106 | 127 | { |
---|
| 128 | + if (*pos < 0) |
---|
| 129 | + return NULL; |
---|
| 130 | + |
---|
107 | 131 | if (*pos == 0) |
---|
108 | 132 | return SEQ_START_TOKEN; |
---|
109 | 133 | |
---|
110 | | - if (*pos - 1 < nr_lock_chains) |
---|
111 | | - return lock_chains + (*pos - 1); |
---|
112 | | - |
---|
113 | | - return NULL; |
---|
| 134 | + return lock_chains + (*pos - 1); |
---|
114 | 135 | } |
---|
115 | 136 | |
---|
116 | 137 | static void *lc_next(struct seq_file *m, void *v, loff_t *pos) |
---|
117 | 138 | { |
---|
118 | | - (*pos)++; |
---|
| 139 | + *pos = lockdep_next_lockchain(*pos - 1) + 1; |
---|
119 | 140 | return lc_start(m, pos); |
---|
120 | 141 | } |
---|
121 | 142 | |
---|
.. | .. |
---|
128 | 149 | struct lock_chain *chain = v; |
---|
129 | 150 | struct lock_class *class; |
---|
130 | 151 | int i; |
---|
| 152 | + static const char * const irq_strs[] = { |
---|
| 153 | + [0] = "0", |
---|
| 154 | + [LOCK_CHAIN_HARDIRQ_CONTEXT] = "hardirq", |
---|
| 155 | + [LOCK_CHAIN_SOFTIRQ_CONTEXT] = "softirq", |
---|
| 156 | + [LOCK_CHAIN_SOFTIRQ_CONTEXT| |
---|
| 157 | + LOCK_CHAIN_HARDIRQ_CONTEXT] = "hardirq|softirq", |
---|
| 158 | + }; |
---|
131 | 159 | |
---|
132 | 160 | if (v == SEQ_START_TOKEN) { |
---|
133 | | - if (nr_chain_hlocks > MAX_LOCKDEP_CHAIN_HLOCKS) |
---|
| 161 | + if (!nr_free_chain_hlocks) |
---|
134 | 162 | seq_printf(m, "(buggered) "); |
---|
135 | 163 | seq_printf(m, "all lock chains:\n"); |
---|
136 | 164 | return 0; |
---|
137 | 165 | } |
---|
138 | 166 | |
---|
139 | | - seq_printf(m, "irq_context: %d\n", chain->irq_context); |
---|
| 167 | + seq_printf(m, "irq_context: %s\n", irq_strs[chain->irq_context]); |
---|
140 | 168 | |
---|
141 | 169 | for (i = 0; i < chain->depth; i++) { |
---|
142 | 170 | class = lock_chain_get_class(chain, i); |
---|
.. | .. |
---|
211 | 239 | |
---|
212 | 240 | #ifdef CONFIG_PROVE_LOCKING |
---|
213 | 241 | struct lock_class *class; |
---|
| 242 | + unsigned long idx; |
---|
214 | 243 | |
---|
215 | | - list_for_each_entry(class, &all_lock_classes, lock_entry) { |
---|
| 244 | + iterate_lock_classes(idx, class) { |
---|
| 245 | + if (!test_bit(idx, lock_classes_in_use)) |
---|
| 246 | + continue; |
---|
216 | 247 | |
---|
217 | 248 | if (class->usage_mask == 0) |
---|
218 | 249 | nr_unused++; |
---|
.. | .. |
---|
245 | 276 | |
---|
246 | 277 | sum_forward_deps += lockdep_count_forward_deps(class); |
---|
247 | 278 | } |
---|
| 279 | + |
---|
248 | 280 | #ifdef CONFIG_DEBUG_LOCKDEP |
---|
249 | 281 | DEBUG_LOCKS_WARN_ON(debug_atomic_read(nr_unused_locks) != nr_unused); |
---|
250 | 282 | #endif |
---|
.. | .. |
---|
270 | 302 | |
---|
271 | 303 | #ifdef CONFIG_PROVE_LOCKING |
---|
272 | 304 | seq_printf(m, " dependency chains: %11lu [max: %lu]\n", |
---|
273 | | - nr_lock_chains, MAX_LOCKDEP_CHAINS); |
---|
274 | | - seq_printf(m, " dependency chain hlocks: %11d [max: %lu]\n", |
---|
275 | | - nr_chain_hlocks, MAX_LOCKDEP_CHAIN_HLOCKS); |
---|
| 305 | + lock_chain_count(), MAX_LOCKDEP_CHAINS); |
---|
| 306 | + seq_printf(m, " dependency chain hlocks used: %11lu [max: %lu]\n", |
---|
| 307 | + MAX_LOCKDEP_CHAIN_HLOCKS - |
---|
| 308 | + (nr_free_chain_hlocks + nr_lost_chain_hlocks), |
---|
| 309 | + MAX_LOCKDEP_CHAIN_HLOCKS); |
---|
| 310 | + seq_printf(m, " dependency chain hlocks lost: %11u\n", |
---|
| 311 | + nr_lost_chain_hlocks); |
---|
276 | 312 | #endif |
---|
277 | 313 | |
---|
278 | 314 | #ifdef CONFIG_TRACE_IRQFLAGS |
---|
.. | .. |
---|
285 | 321 | nr_process_chains); |
---|
286 | 322 | seq_printf(m, " stack-trace entries: %11lu [max: %lu]\n", |
---|
287 | 323 | nr_stack_trace_entries, MAX_STACK_TRACE_ENTRIES); |
---|
| 324 | +#if defined(CONFIG_TRACE_IRQFLAGS) && defined(CONFIG_PROVE_LOCKING) |
---|
| 325 | + seq_printf(m, " number of stack traces: %11llu\n", |
---|
| 326 | + lockdep_stack_trace_count()); |
---|
| 327 | + seq_printf(m, " number of stack hash chains: %11llu\n", |
---|
| 328 | + lockdep_stack_hash_count()); |
---|
| 329 | +#endif |
---|
288 | 330 | seq_printf(m, " combined max dependencies: %11u\n", |
---|
289 | 331 | (nr_hardirq_chains + 1) * |
---|
290 | 332 | (nr_softirq_chains + 1) * |
---|
.. | .. |
---|
326 | 368 | seq_printf(m, " max bfs queue depth: %11u\n", |
---|
327 | 369 | max_bfs_queue_depth); |
---|
328 | 370 | #endif |
---|
| 371 | + seq_printf(m, " max lock class index: %11lu\n", |
---|
| 372 | + max_lock_class_idx); |
---|
329 | 373 | lockdep_stats_debug_show(m); |
---|
330 | 374 | seq_printf(m, " debug_locks: %11u\n", |
---|
331 | 375 | debug_locks); |
---|
332 | 376 | |
---|
| 377 | + /* |
---|
| 378 | + * Zappped classes and lockdep data buffers reuse statistics. |
---|
| 379 | + */ |
---|
| 380 | + seq_puts(m, "\n"); |
---|
| 381 | + seq_printf(m, " zapped classes: %11lu\n", |
---|
| 382 | + nr_zapped_classes); |
---|
| 383 | +#ifdef CONFIG_PROVE_LOCKING |
---|
| 384 | + seq_printf(m, " zapped lock chains: %11lu\n", |
---|
| 385 | + nr_zapped_lock_chains); |
---|
| 386 | + seq_printf(m, " large chain blocks: %11u\n", |
---|
| 387 | + nr_large_chain_blocks); |
---|
| 388 | +#endif |
---|
333 | 389 | return 0; |
---|
334 | 390 | } |
---|
335 | 391 | |
---|
.. | .. |
---|
399 | 455 | |
---|
400 | 456 | static void seq_stats(struct seq_file *m, struct lock_stat_data *data) |
---|
401 | 457 | { |
---|
402 | | - struct lockdep_subclass_key *ckey; |
---|
| 458 | + const struct lockdep_subclass_key *ckey; |
---|
403 | 459 | struct lock_class_stats *stats; |
---|
404 | 460 | struct lock_class *class; |
---|
405 | 461 | const char *cname; |
---|
.. | .. |
---|
591 | 647 | if (!res) { |
---|
592 | 648 | struct lock_stat_data *iter = data->stats; |
---|
593 | 649 | struct seq_file *m = file->private_data; |
---|
| 650 | + unsigned long idx; |
---|
594 | 651 | |
---|
595 | | - list_for_each_entry(class, &all_lock_classes, lock_entry) { |
---|
| 652 | + iterate_lock_classes(idx, class) { |
---|
| 653 | + if (!test_bit(idx, lock_classes_in_use)) |
---|
| 654 | + continue; |
---|
596 | 655 | iter->class = class; |
---|
597 | 656 | iter->stats = lock_stats(class); |
---|
598 | 657 | iter++; |
---|
599 | 658 | } |
---|
| 659 | + |
---|
600 | 660 | data->iter_end = iter; |
---|
601 | 661 | |
---|
602 | 662 | sort(data->stats, data->iter_end - data->stats, |
---|
.. | .. |
---|
614 | 674 | size_t count, loff_t *ppos) |
---|
615 | 675 | { |
---|
616 | 676 | struct lock_class *class; |
---|
| 677 | + unsigned long idx; |
---|
617 | 678 | char c; |
---|
618 | 679 | |
---|
619 | 680 | if (count) { |
---|
.. | .. |
---|
623 | 684 | if (c != '0') |
---|
624 | 685 | return count; |
---|
625 | 686 | |
---|
626 | | - list_for_each_entry(class, &all_lock_classes, lock_entry) |
---|
| 687 | + iterate_lock_classes(idx, class) { |
---|
| 688 | + if (!test_bit(idx, lock_classes_in_use)) |
---|
| 689 | + continue; |
---|
627 | 690 | clear_lock_stats(class); |
---|
| 691 | + } |
---|
628 | 692 | } |
---|
629 | 693 | return count; |
---|
630 | 694 | } |
---|
.. | .. |
---|
637 | 701 | return seq_release(inode, file); |
---|
638 | 702 | } |
---|
639 | 703 | |
---|
640 | | -static const struct file_operations proc_lock_stat_operations = { |
---|
641 | | - .open = lock_stat_open, |
---|
642 | | - .write = lock_stat_write, |
---|
643 | | - .read = seq_read, |
---|
644 | | - .llseek = seq_lseek, |
---|
645 | | - .release = lock_stat_release, |
---|
| 704 | +static const struct proc_ops lock_stat_proc_ops = { |
---|
| 705 | + .proc_open = lock_stat_open, |
---|
| 706 | + .proc_write = lock_stat_write, |
---|
| 707 | + .proc_read = seq_read, |
---|
| 708 | + .proc_lseek = seq_lseek, |
---|
| 709 | + .proc_release = lock_stat_release, |
---|
646 | 710 | }; |
---|
647 | 711 | #endif /* CONFIG_LOCK_STAT */ |
---|
648 | 712 | |
---|
.. | .. |
---|
654 | 718 | #endif |
---|
655 | 719 | proc_create_single("lockdep_stats", S_IRUSR, NULL, lockdep_stats_show); |
---|
656 | 720 | #ifdef CONFIG_LOCK_STAT |
---|
657 | | - proc_create("lock_stat", S_IRUSR | S_IWUSR, NULL, |
---|
658 | | - &proc_lock_stat_operations); |
---|
| 721 | + proc_create("lock_stat", S_IRUSR | S_IWUSR, NULL, &lock_stat_proc_ops); |
---|
659 | 722 | #endif |
---|
660 | 723 | |
---|
661 | 724 | return 0; |
---|