diff options
Diffstat (limited to 'kernel/lockdep.c')
-rw-r--r-- | kernel/lockdep.c | 115 |
1 files changed, 106 insertions, 9 deletions
diff --git a/kernel/lockdep.c b/kernel/lockdep.c index 8bbeef996c76..93dc70d18cdf 100644 --- a/kernel/lockdep.c +++ b/kernel/lockdep.c | |||
@@ -897,6 +897,79 @@ static int add_lock_to_list(struct lock_class *class, struct lock_class *this, | |||
897 | return 1; | 897 | return 1; |
898 | } | 898 | } |
899 | 899 | ||
900 | static struct circular_queue lock_cq; | ||
901 | static int __search_shortest_path(struct lock_list *source_entry, | ||
902 | struct lock_class *target, | ||
903 | struct lock_list **target_entry, | ||
904 | int forward) | ||
905 | { | ||
906 | struct lock_list *entry; | ||
907 | struct circular_queue *cq = &lock_cq; | ||
908 | int ret = 1; | ||
909 | |||
910 | __cq_init(cq); | ||
911 | |||
912 | mark_lock_accessed(source_entry, NULL); | ||
913 | if (source_entry->class == target) { | ||
914 | *target_entry = source_entry; | ||
915 | ret = 0; | ||
916 | goto exit; | ||
917 | } | ||
918 | |||
919 | __cq_enqueue(cq, (unsigned long)source_entry); | ||
920 | |||
921 | while (!__cq_empty(cq)) { | ||
922 | struct lock_list *lock; | ||
923 | struct list_head *head; | ||
924 | |||
925 | __cq_dequeue(cq, (unsigned long *)&lock); | ||
926 | |||
927 | if (!lock->class) { | ||
928 | ret = -2; | ||
929 | goto exit; | ||
930 | } | ||
931 | |||
932 | if (forward) | ||
933 | head = &lock->class->locks_after; | ||
934 | else | ||
935 | head = &lock->class->locks_before; | ||
936 | |||
937 | list_for_each_entry(entry, head, entry) { | ||
938 | if (!lock_accessed(entry)) { | ||
939 | mark_lock_accessed(entry, lock); | ||
940 | if (entry->class == target) { | ||
941 | *target_entry = entry; | ||
942 | ret = 0; | ||
943 | goto exit; | ||
944 | } | ||
945 | |||
946 | if (__cq_enqueue(cq, (unsigned long)entry)) { | ||
947 | ret = -1; | ||
948 | goto exit; | ||
949 | } | ||
950 | } | ||
951 | } | ||
952 | } | ||
953 | exit: | ||
954 | return ret; | ||
955 | } | ||
956 | |||
957 | static inline int __search_forward_shortest_path(struct lock_list *src_entry, | ||
958 | struct lock_class *target, | ||
959 | struct lock_list **target_entry) | ||
960 | { | ||
961 | return __search_shortest_path(src_entry, target, target_entry, 1); | ||
962 | |||
963 | } | ||
964 | |||
965 | static inline int __search_backward_shortest_path(struct lock_list *src_entry, | ||
966 | struct lock_class *target, | ||
967 | struct lock_list **target_entry) | ||
968 | { | ||
969 | return __search_shortest_path(src_entry, target, target_entry, 0); | ||
970 | |||
971 | } | ||
972 | |||
900 | /* | 973 | /* |
901 | * Recursive, forwards-direction lock-dependency checking, used for | 974 | * Recursive, forwards-direction lock-dependency checking, used for |
902 | * both noncyclic checking and for hardirq-unsafe/softirq-unsafe | 975 | * both noncyclic checking and for hardirq-unsafe/softirq-unsafe |
@@ -934,7 +1007,7 @@ print_circular_bug_header(struct lock_list *entry, unsigned int depth) | |||
934 | { | 1007 | { |
935 | struct task_struct *curr = current; | 1008 | struct task_struct *curr = current; |
936 | 1009 | ||
937 | if (!debug_locks_off_graph_unlock() || debug_locks_silent) | 1010 | if (debug_locks_silent) |
938 | return 0; | 1011 | return 0; |
939 | 1012 | ||
940 | printk("\n=======================================================\n"); | 1013 | printk("\n=======================================================\n"); |
@@ -954,19 +1027,41 @@ print_circular_bug_header(struct lock_list *entry, unsigned int depth) | |||
954 | return 0; | 1027 | return 0; |
955 | } | 1028 | } |
956 | 1029 | ||
957 | static noinline int print_circular_bug_tail(void) | 1030 | static noinline int print_circular_bug(void) |
958 | { | 1031 | { |
959 | struct task_struct *curr = current; | 1032 | struct task_struct *curr = current; |
960 | struct lock_list this; | 1033 | struct lock_list this; |
1034 | struct lock_list *target; | ||
1035 | struct lock_list *parent; | ||
1036 | int result; | ||
1037 | unsigned long depth; | ||
961 | 1038 | ||
962 | if (debug_locks_silent) | 1039 | if (!debug_locks_off_graph_unlock() || debug_locks_silent) |
963 | return 0; | 1040 | return 0; |
964 | 1041 | ||
965 | this.class = hlock_class(check_source); | 1042 | this.class = hlock_class(check_source); |
966 | if (!save_trace(&this.trace)) | 1043 | if (!save_trace(&this.trace)) |
967 | return 0; | 1044 | return 0; |
968 | 1045 | ||
969 | print_circular_bug_entry(&this, 0); | 1046 | result = __search_forward_shortest_path(&this, |
1047 | hlock_class(check_target), | ||
1048 | &target); | ||
1049 | if (result) { | ||
1050 | printk("\n%s:search shortest path failed:%d\n", __func__, | ||
1051 | result); | ||
1052 | return 0; | ||
1053 | } | ||
1054 | |||
1055 | depth = get_lock_depth(target); | ||
1056 | |||
1057 | print_circular_bug_header(target, depth); | ||
1058 | |||
1059 | parent = get_lock_parent(target); | ||
1060 | |||
1061 | while (parent) { | ||
1062 | print_circular_bug_entry(parent, --depth); | ||
1063 | parent = get_lock_parent(parent); | ||
1064 | } | ||
970 | 1065 | ||
971 | printk("\nother info that might help us debug this:\n\n"); | 1066 | printk("\nother info that might help us debug this:\n\n"); |
972 | lockdep_print_held_locks(curr); | 1067 | lockdep_print_held_locks(curr); |
@@ -1072,14 +1167,15 @@ check_noncircular(struct lock_class *source, unsigned int depth) | |||
1072 | */ | 1167 | */ |
1073 | list_for_each_entry(entry, &source->locks_after, entry) { | 1168 | list_for_each_entry(entry, &source->locks_after, entry) { |
1074 | if (entry->class == hlock_class(check_target)) | 1169 | if (entry->class == hlock_class(check_target)) |
1075 | return print_circular_bug_header(entry, depth+1); | 1170 | return 2; |
1076 | debug_atomic_inc(&nr_cyclic_checks); | 1171 | debug_atomic_inc(&nr_cyclic_checks); |
1077 | if (!check_noncircular(entry->class, depth+1)) | 1172 | if (check_noncircular(entry->class, depth+1) == 2) |
1078 | return print_circular_bug_entry(entry, depth+1); | 1173 | return 2; |
1079 | } | 1174 | } |
1080 | return 1; | 1175 | return 1; |
1081 | } | 1176 | } |
1082 | 1177 | ||
1178 | |||
1083 | #if defined(CONFIG_TRACE_IRQFLAGS) && defined(CONFIG_PROVE_LOCKING) | 1179 | #if defined(CONFIG_TRACE_IRQFLAGS) && defined(CONFIG_PROVE_LOCKING) |
1084 | /* | 1180 | /* |
1085 | * Forwards and backwards subgraph searching, for the purposes of | 1181 | * Forwards and backwards subgraph searching, for the purposes of |
@@ -1484,8 +1580,9 @@ check_prev_add(struct task_struct *curr, struct held_lock *prev, | |||
1484 | */ | 1580 | */ |
1485 | check_source = next; | 1581 | check_source = next; |
1486 | check_target = prev; | 1582 | check_target = prev; |
1487 | if (!(check_noncircular(hlock_class(next), 0))) | 1583 | if (check_noncircular(hlock_class(next), 0) == 2) |
1488 | return print_circular_bug_tail(); | 1584 | return print_circular_bug(); |
1585 | |||
1489 | 1586 | ||
1490 | if (!check_prev_add_irq(curr, prev, next)) | 1587 | if (!check_prev_add_irq(curr, prev, next)) |
1491 | return 0; | 1588 | return 0; |