diff options
author | Peter Zijlstra <a.p.zijlstra@chello.nl> | 2009-07-16 09:44:29 -0400 |
---|---|---|
committer | Peter Zijlstra <a.p.zijlstra@chello.nl> | 2009-07-24 04:53:29 -0400 |
commit | af012961450949ea297b209e091bd1a3805b8a0a (patch) | |
tree | d092a182ad014b4508079bacf416deb1e0650c01 /kernel/lockdep.c | |
parent | 12f3dfd022d7e616757a94f0538d3d525d806a16 (diff) |
lockdep: BFS cleanup
Some cleanups of the lockdep code after the BFS series:
- Remove the last traces of the generation id
- Fixup comment style
- Move the bfs routines into lockdep.c
- Cleanup the bfs routines
[ tom.leiming@gmail.com: Fix crash ]
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
LKML-Reference: <1246201486-7308-11-git-send-email-tom.leiming@gmail.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'kernel/lockdep.c')
-rw-r--r-- | kernel/lockdep.c | 284 |
1 files changed, 170 insertions, 114 deletions
diff --git a/kernel/lockdep.c b/kernel/lockdep.c index 744da6265d99..1cedb00e3e7a 100644 --- a/kernel/lockdep.c +++ b/kernel/lockdep.c | |||
@@ -43,6 +43,7 @@ | |||
43 | #include <linux/ftrace.h> | 43 | #include <linux/ftrace.h> |
44 | #include <linux/stringify.h> | 44 | #include <linux/stringify.h> |
45 | #include <linux/bitops.h> | 45 | #include <linux/bitops.h> |
46 | |||
46 | #include <asm/sections.h> | 47 | #include <asm/sections.h> |
47 | 48 | ||
48 | #include "lockdep_internals.h" | 49 | #include "lockdep_internals.h" |
@@ -118,7 +119,7 @@ static inline int debug_locks_off_graph_unlock(void) | |||
118 | static int lockdep_initialized; | 119 | static int lockdep_initialized; |
119 | 120 | ||
120 | unsigned long nr_list_entries; | 121 | unsigned long nr_list_entries; |
121 | struct lock_list list_entries[MAX_LOCKDEP_ENTRIES]; | 122 | static struct lock_list list_entries[MAX_LOCKDEP_ENTRIES]; |
122 | 123 | ||
123 | /* | 124 | /* |
124 | * All data structures here are protected by the global debug_lock. | 125 | * All data structures here are protected by the global debug_lock. |
@@ -390,19 +391,6 @@ unsigned int nr_process_chains; | |||
390 | unsigned int max_lockdep_depth; | 391 | unsigned int max_lockdep_depth; |
391 | unsigned int max_recursion_depth; | 392 | unsigned int max_recursion_depth; |
392 | 393 | ||
393 | static unsigned int lockdep_dependency_gen_id; | ||
394 | |||
395 | static bool lockdep_dependency_visit(struct lock_class *source, | ||
396 | unsigned int depth) | ||
397 | { | ||
398 | if (!depth) | ||
399 | lockdep_dependency_gen_id++; | ||
400 | if (source->dep_gen_id == lockdep_dependency_gen_id) | ||
401 | return true; | ||
402 | source->dep_gen_id = lockdep_dependency_gen_id; | ||
403 | return false; | ||
404 | } | ||
405 | |||
406 | #ifdef CONFIG_DEBUG_LOCKDEP | 394 | #ifdef CONFIG_DEBUG_LOCKDEP |
407 | /* | 395 | /* |
408 | * We cannot printk in early bootup code. Not even early_printk() | 396 | * We cannot printk in early bootup code. Not even early_printk() |
@@ -551,88 +539,6 @@ static void lockdep_print_held_locks(struct task_struct *curr) | |||
551 | } | 539 | } |
552 | } | 540 | } |
553 | 541 | ||
554 | static void print_lock_class_header(struct lock_class *class, int depth) | ||
555 | { | ||
556 | int bit; | ||
557 | |||
558 | printk("%*s->", depth, ""); | ||
559 | print_lock_name(class); | ||
560 | printk(" ops: %lu", class->ops); | ||
561 | printk(" {\n"); | ||
562 | |||
563 | for (bit = 0; bit < LOCK_USAGE_STATES; bit++) { | ||
564 | if (class->usage_mask & (1 << bit)) { | ||
565 | int len = depth; | ||
566 | |||
567 | len += printk("%*s %s", depth, "", usage_str[bit]); | ||
568 | len += printk(" at:\n"); | ||
569 | print_stack_trace(class->usage_traces + bit, len); | ||
570 | } | ||
571 | } | ||
572 | printk("%*s }\n", depth, ""); | ||
573 | |||
574 | printk("%*s ... key at: ",depth,""); | ||
575 | print_ip_sym((unsigned long)class->key); | ||
576 | } | ||
577 | |||
578 | /* | ||
579 | * printk the shortest lock dependencies from @start to @end in reverse order: | ||
580 | */ | ||
581 | static void __used | ||
582 | print_shortest_lock_dependencies(struct lock_list *leaf, | ||
583 | struct lock_list *root) | ||
584 | { | ||
585 | struct lock_list *entry = leaf; | ||
586 | int depth; | ||
587 | |||
588 | /*compute depth from generated tree by BFS*/ | ||
589 | depth = get_lock_depth(leaf); | ||
590 | |||
591 | do { | ||
592 | print_lock_class_header(entry->class, depth); | ||
593 | printk("%*s ... acquired at:\n", depth, ""); | ||
594 | print_stack_trace(&entry->trace, 2); | ||
595 | printk("\n"); | ||
596 | |||
597 | if (depth == 0 && (entry != root)) { | ||
598 | printk("lockdep:%s bad BFS generated tree\n", __func__); | ||
599 | break; | ||
600 | } | ||
601 | |||
602 | entry = get_lock_parent(entry); | ||
603 | depth--; | ||
604 | } while (entry && (depth >= 0)); | ||
605 | |||
606 | return; | ||
607 | } | ||
608 | /* | ||
609 | * printk all lock dependencies starting at <entry>: | ||
610 | */ | ||
611 | static void __used | ||
612 | print_lock_dependencies(struct lock_class *class, int depth) | ||
613 | { | ||
614 | struct lock_list *entry; | ||
615 | |||
616 | if (lockdep_dependency_visit(class, depth)) | ||
617 | return; | ||
618 | |||
619 | if (DEBUG_LOCKS_WARN_ON(depth >= 20)) | ||
620 | return; | ||
621 | |||
622 | print_lock_class_header(class, depth); | ||
623 | |||
624 | list_for_each_entry(entry, &class->locks_after, entry) { | ||
625 | if (DEBUG_LOCKS_WARN_ON(!entry->class)) | ||
626 | return; | ||
627 | |||
628 | print_lock_dependencies(entry->class, depth + 1); | ||
629 | |||
630 | printk("%*s ... acquired at:\n",depth,""); | ||
631 | print_stack_trace(&entry->trace, 2); | ||
632 | printk("\n"); | ||
633 | } | ||
634 | } | ||
635 | |||
636 | static void print_kernel_version(void) | 542 | static void print_kernel_version(void) |
637 | { | 543 | { |
638 | printk("%s %.*s\n", init_utsname()->release, | 544 | printk("%s %.*s\n", init_utsname()->release, |
@@ -927,14 +833,106 @@ static int add_lock_to_list(struct lock_class *class, struct lock_class *this, | |||
927 | return 1; | 833 | return 1; |
928 | } | 834 | } |
929 | 835 | ||
930 | unsigned long bfs_accessed[BITS_TO_LONGS(MAX_LOCKDEP_ENTRIES)]; | 836 | /*For good efficiency of modular, we use power of 2*/ |
931 | static struct circular_queue lock_cq; | 837 | #define MAX_CIRCULAR_QUEUE_SIZE 4096UL |
838 | #define CQ_MASK (MAX_CIRCULAR_QUEUE_SIZE-1) | ||
839 | |||
840 | /* The circular_queue and helpers is used to implement the | ||
841 | * breadth-first search(BFS)algorithem, by which we can build | ||
842 | * the shortest path from the next lock to be acquired to the | ||
843 | * previous held lock if there is a circular between them. | ||
844 | * */ | ||
845 | struct circular_queue { | ||
846 | unsigned long element[MAX_CIRCULAR_QUEUE_SIZE]; | ||
847 | unsigned int front, rear; | ||
848 | }; | ||
849 | |||
850 | static struct circular_queue lock_cq; | ||
851 | static unsigned long bfs_accessed[BITS_TO_LONGS(MAX_LOCKDEP_ENTRIES)]; | ||
852 | |||
932 | unsigned int max_bfs_queue_depth; | 853 | unsigned int max_bfs_queue_depth; |
854 | |||
855 | static inline void __cq_init(struct circular_queue *cq) | ||
856 | { | ||
857 | cq->front = cq->rear = 0; | ||
858 | bitmap_zero(bfs_accessed, MAX_LOCKDEP_ENTRIES); | ||
859 | } | ||
860 | |||
861 | static inline int __cq_empty(struct circular_queue *cq) | ||
862 | { | ||
863 | return (cq->front == cq->rear); | ||
864 | } | ||
865 | |||
866 | static inline int __cq_full(struct circular_queue *cq) | ||
867 | { | ||
868 | return ((cq->rear + 1) & CQ_MASK) == cq->front; | ||
869 | } | ||
870 | |||
871 | static inline int __cq_enqueue(struct circular_queue *cq, unsigned long elem) | ||
872 | { | ||
873 | if (__cq_full(cq)) | ||
874 | return -1; | ||
875 | |||
876 | cq->element[cq->rear] = elem; | ||
877 | cq->rear = (cq->rear + 1) & CQ_MASK; | ||
878 | return 0; | ||
879 | } | ||
880 | |||
881 | static inline int __cq_dequeue(struct circular_queue *cq, unsigned long *elem) | ||
882 | { | ||
883 | if (__cq_empty(cq)) | ||
884 | return -1; | ||
885 | |||
886 | *elem = cq->element[cq->front]; | ||
887 | cq->front = (cq->front + 1) & CQ_MASK; | ||
888 | return 0; | ||
889 | } | ||
890 | |||
891 | static inline unsigned int __cq_get_elem_count(struct circular_queue *cq) | ||
892 | { | ||
893 | return (cq->rear - cq->front) & CQ_MASK; | ||
894 | } | ||
895 | |||
896 | static inline void mark_lock_accessed(struct lock_list *lock, | ||
897 | struct lock_list *parent) | ||
898 | { | ||
899 | unsigned long nr; | ||
900 | nr = lock - list_entries; | ||
901 | WARN_ON(nr >= nr_list_entries); | ||
902 | lock->parent = parent; | ||
903 | set_bit(nr, bfs_accessed); | ||
904 | } | ||
905 | |||
906 | static inline unsigned long lock_accessed(struct lock_list *lock) | ||
907 | { | ||
908 | unsigned long nr; | ||
909 | nr = lock - list_entries; | ||
910 | WARN_ON(nr >= nr_list_entries); | ||
911 | return test_bit(nr, bfs_accessed); | ||
912 | } | ||
913 | |||
914 | static inline struct lock_list *get_lock_parent(struct lock_list *child) | ||
915 | { | ||
916 | return child->parent; | ||
917 | } | ||
918 | |||
919 | static inline int get_lock_depth(struct lock_list *child) | ||
920 | { | ||
921 | int depth = 0; | ||
922 | struct lock_list *parent; | ||
923 | |||
924 | while ((parent = get_lock_parent(child))) { | ||
925 | child = parent; | ||
926 | depth++; | ||
927 | } | ||
928 | return depth; | ||
929 | } | ||
930 | |||
933 | static int __bfs(struct lock_list *source_entry, | 931 | static int __bfs(struct lock_list *source_entry, |
934 | void *data, | 932 | void *data, |
935 | int (*match)(struct lock_list *entry, void *data), | 933 | int (*match)(struct lock_list *entry, void *data), |
936 | struct lock_list **target_entry, | 934 | struct lock_list **target_entry, |
937 | int forward) | 935 | int forward) |
938 | { | 936 | { |
939 | struct lock_list *entry; | 937 | struct lock_list *entry; |
940 | struct list_head *head; | 938 | struct list_head *head; |
@@ -1202,14 +1200,6 @@ check_noncircular(struct lock_list *root, struct lock_class *target, | |||
1202 | * without creating any illegal irq-safe -> irq-unsafe lock dependency. | 1200 | * without creating any illegal irq-safe -> irq-unsafe lock dependency. |
1203 | */ | 1201 | */ |
1204 | 1202 | ||
1205 | |||
1206 | #define BFS_PROCESS_RET(ret) do { \ | ||
1207 | if (ret < 0) \ | ||
1208 | return print_bfs_bug(ret); \ | ||
1209 | if (ret == 1) \ | ||
1210 | return 1; \ | ||
1211 | } while (0) | ||
1212 | |||
1213 | static inline int usage_match(struct lock_list *entry, void *bit) | 1203 | static inline int usage_match(struct lock_list *entry, void *bit) |
1214 | { | 1204 | { |
1215 | return entry->class->usage_mask & (1 << (enum lock_usage_bit)bit); | 1205 | return entry->class->usage_mask & (1 << (enum lock_usage_bit)bit); |
@@ -1263,6 +1253,60 @@ find_usage_backwards(struct lock_list *root, enum lock_usage_bit bit, | |||
1263 | return result; | 1253 | return result; |
1264 | } | 1254 | } |
1265 | 1255 | ||
1256 | static void print_lock_class_header(struct lock_class *class, int depth) | ||
1257 | { | ||
1258 | int bit; | ||
1259 | |||
1260 | printk("%*s->", depth, ""); | ||
1261 | print_lock_name(class); | ||
1262 | printk(" ops: %lu", class->ops); | ||
1263 | printk(" {\n"); | ||
1264 | |||
1265 | for (bit = 0; bit < LOCK_USAGE_STATES; bit++) { | ||
1266 | if (class->usage_mask & (1 << bit)) { | ||
1267 | int len = depth; | ||
1268 | |||
1269 | len += printk("%*s %s", depth, "", usage_str[bit]); | ||
1270 | len += printk(" at:\n"); | ||
1271 | print_stack_trace(class->usage_traces + bit, len); | ||
1272 | } | ||
1273 | } | ||
1274 | printk("%*s }\n", depth, ""); | ||
1275 | |||
1276 | printk("%*s ... key at: ",depth,""); | ||
1277 | print_ip_sym((unsigned long)class->key); | ||
1278 | } | ||
1279 | |||
1280 | /* | ||
1281 | * printk the shortest lock dependencies from @start to @end in reverse order: | ||
1282 | */ | ||
1283 | static void __used | ||
1284 | print_shortest_lock_dependencies(struct lock_list *leaf, | ||
1285 | struct lock_list *root) | ||
1286 | { | ||
1287 | struct lock_list *entry = leaf; | ||
1288 | int depth; | ||
1289 | |||
1290 | /*compute depth from generated tree by BFS*/ | ||
1291 | depth = get_lock_depth(leaf); | ||
1292 | |||
1293 | do { | ||
1294 | print_lock_class_header(entry->class, depth); | ||
1295 | printk("%*s ... acquired at:\n", depth, ""); | ||
1296 | print_stack_trace(&entry->trace, 2); | ||
1297 | printk("\n"); | ||
1298 | |||
1299 | if (depth == 0 && (entry != root)) { | ||
1300 | printk("lockdep:%s bad BFS generated tree\n", __func__); | ||
1301 | break; | ||
1302 | } | ||
1303 | |||
1304 | entry = get_lock_parent(entry); | ||
1305 | depth--; | ||
1306 | } while (entry && (depth >= 0)); | ||
1307 | |||
1308 | return; | ||
1309 | } | ||
1266 | 1310 | ||
1267 | static int | 1311 | static int |
1268 | print_bad_irq_dependency(struct task_struct *curr, | 1312 | print_bad_irq_dependency(struct task_struct *curr, |
@@ -1349,12 +1393,18 @@ check_usage(struct task_struct *curr, struct held_lock *prev, | |||
1349 | 1393 | ||
1350 | this.class = hlock_class(prev); | 1394 | this.class = hlock_class(prev); |
1351 | ret = find_usage_backwards(&this, bit_backwards, &target_entry); | 1395 | ret = find_usage_backwards(&this, bit_backwards, &target_entry); |
1352 | BFS_PROCESS_RET(ret); | 1396 | if (ret < 0) |
1397 | return print_bfs_bug(ret); | ||
1398 | if (ret == 1) | ||
1399 | return ret; | ||
1353 | 1400 | ||
1354 | that.parent = NULL; | 1401 | that.parent = NULL; |
1355 | that.class = hlock_class(next); | 1402 | that.class = hlock_class(next); |
1356 | ret = find_usage_forwards(&that, bit_forwards, &target_entry1); | 1403 | ret = find_usage_forwards(&that, bit_forwards, &target_entry1); |
1357 | BFS_PROCESS_RET(ret); | 1404 | if (ret < 0) |
1405 | return print_bfs_bug(ret); | ||
1406 | if (ret == 1) | ||
1407 | return ret; | ||
1358 | 1408 | ||
1359 | return print_bad_irq_dependency(curr, &this, &that, | 1409 | return print_bad_irq_dependency(curr, &this, &that, |
1360 | target_entry, target_entry1, | 1410 | target_entry, target_entry1, |
@@ -2038,7 +2088,10 @@ check_usage_forwards(struct task_struct *curr, struct held_lock *this, | |||
2038 | root.parent = NULL; | 2088 | root.parent = NULL; |
2039 | root.class = hlock_class(this); | 2089 | root.class = hlock_class(this); |
2040 | ret = find_usage_forwards(&root, bit, &target_entry); | 2090 | ret = find_usage_forwards(&root, bit, &target_entry); |
2041 | BFS_PROCESS_RET(ret); | 2091 | if (ret < 0) |
2092 | return print_bfs_bug(ret); | ||
2093 | if (ret == 1) | ||
2094 | return ret; | ||
2042 | 2095 | ||
2043 | return print_irq_inversion_bug(curr, &root, target_entry, | 2096 | return print_irq_inversion_bug(curr, &root, target_entry, |
2044 | this, 1, irqclass); | 2097 | this, 1, irqclass); |
@@ -2059,7 +2112,10 @@ check_usage_backwards(struct task_struct *curr, struct held_lock *this, | |||
2059 | root.parent = NULL; | 2112 | root.parent = NULL; |
2060 | root.class = hlock_class(this); | 2113 | root.class = hlock_class(this); |
2061 | ret = find_usage_backwards(&root, bit, &target_entry); | 2114 | ret = find_usage_backwards(&root, bit, &target_entry); |
2062 | BFS_PROCESS_RET(ret); | 2115 | if (ret < 0) |
2116 | return print_bfs_bug(ret); | ||
2117 | if (ret == 1) | ||
2118 | return ret; | ||
2063 | 2119 | ||
2064 | return print_irq_inversion_bug(curr, &root, target_entry, | 2120 | return print_irq_inversion_bug(curr, &root, target_entry, |
2065 | this, 1, irqclass); | 2121 | this, 1, irqclass); |