Commit 24208ca7 authored by Ming Lei's avatar Ming Lei Committed by Peter Zijlstra

lockdep: Introduce print_shortest_lock_dependencies

Since the shortest lock dependencies' path may be obtained by BFS,
we print the shortest one by print_shortest_lock_dependencies().
Signed-off-by: default avatarMing Lei <tom.leiming@gmail.com>
Signed-off-by: default avatarPeter Zijlstra <a.p.zijlstra@chello.nl>
LKML-Reference: <1246201486-7308-7-git-send-email-tom.leiming@gmail.com>
Signed-off-by: default avatarIngo Molnar <mingo@elte.hu>
parent d7aaba14
...@@ -575,6 +575,36 @@ static void print_lock_class_header(struct lock_class *class, int depth) ...@@ -575,6 +575,36 @@ static void print_lock_class_header(struct lock_class *class, int depth)
print_ip_sym((unsigned long)class->key); print_ip_sym((unsigned long)class->key);
} }
/*
* printk the shortest lock dependencies from @start to @end in reverse order:
*/
static void __used
print_shortest_lock_dependencies(struct lock_list *leaf,
struct lock_list *root)
{
struct lock_list *entry = leaf;
int depth;
/*compute depth from generated tree by BFS*/
depth = get_lock_depth(leaf);
do {
print_lock_class_header(entry->class, depth);
printk("%*s ... acquired at:\n", depth, "");
print_stack_trace(&entry->trace, 2);
printk("\n");
if (depth == 0 && (entry != root)) {
printk("lockdep:%s bad BFS generated tree\n", __func__);
break;
}
entry = get_lock_parent(entry);
depth--;
} while (entry && (depth >= 0));
return;
}
/* /*
* printk all lock dependencies starting at <entry>: * printk all lock dependencies starting at <entry>:
*/ */
...@@ -992,7 +1022,7 @@ static inline int __bfs_backwards(struct lock_list *src_entry, ...@@ -992,7 +1022,7 @@ static inline int __bfs_backwards(struct lock_list *src_entry,
* has been detected): * has been detected):
*/ */
static noinline int static noinline int
print_circular_bug_entry(struct lock_list *target, unsigned int depth) print_circular_bug_entry(struct lock_list *target, int depth)
{ {
if (debug_locks_silent) if (debug_locks_silent)
return 0; return 0;
...@@ -1047,7 +1077,7 @@ static noinline int print_circular_bug(struct lock_list *this, ...@@ -1047,7 +1077,7 @@ static noinline int print_circular_bug(struct lock_list *this,
{ {
struct task_struct *curr = current; struct task_struct *curr = current;
struct lock_list *parent; struct lock_list *parent;
unsigned long depth; int depth;
if (!debug_locks_off_graph_unlock() || debug_locks_silent) if (!debug_locks_off_graph_unlock() || debug_locks_silent)
return 0; return 0;
...@@ -1169,7 +1199,6 @@ check_noncircular(struct lock_list *root, struct lock_class *target, ...@@ -1169,7 +1199,6 @@ check_noncircular(struct lock_list *root, struct lock_class *target,
* proving that two subgraphs can be connected by a new dependency * proving that two subgraphs can be connected by a new dependency
* without creating any illegal irq-safe -> irq-unsafe lock dependency. * without creating any illegal irq-safe -> irq-unsafe lock dependency.
*/ */
static struct lock_class *forwards_match, *backwards_match;
#define BFS_PROCESS_RET(ret) do { \ #define BFS_PROCESS_RET(ret) do { \
...@@ -1235,6 +1264,10 @@ find_usage_backwards(struct lock_list *root, enum lock_usage_bit bit, ...@@ -1235,6 +1264,10 @@ find_usage_backwards(struct lock_list *root, enum lock_usage_bit bit,
static int static int
print_bad_irq_dependency(struct task_struct *curr, print_bad_irq_dependency(struct task_struct *curr,
struct lock_list *prev_root,
struct lock_list *next_root,
struct lock_list *backwards_entry,
struct lock_list *forwards_entry,
struct held_lock *prev, struct held_lock *prev,
struct held_lock *next, struct held_lock *next,
enum lock_usage_bit bit1, enum lock_usage_bit bit1,
...@@ -1267,26 +1300,32 @@ print_bad_irq_dependency(struct task_struct *curr, ...@@ -1267,26 +1300,32 @@ print_bad_irq_dependency(struct task_struct *curr,
printk("\nbut this new dependency connects a %s-irq-safe lock:\n", printk("\nbut this new dependency connects a %s-irq-safe lock:\n",
irqclass); irqclass);
print_lock_name(backwards_match); print_lock_name(backwards_entry->class);
printk("\n... which became %s-irq-safe at:\n", irqclass); printk("\n... which became %s-irq-safe at:\n", irqclass);
print_stack_trace(backwards_match->usage_traces + bit1, 1); print_stack_trace(backwards_entry->class->usage_traces + bit1, 1);
printk("\nto a %s-irq-unsafe lock:\n", irqclass); printk("\nto a %s-irq-unsafe lock:\n", irqclass);
print_lock_name(forwards_match); print_lock_name(forwards_entry->class);
printk("\n... which became %s-irq-unsafe at:\n", irqclass); printk("\n... which became %s-irq-unsafe at:\n", irqclass);
printk("..."); printk("...");
print_stack_trace(forwards_match->usage_traces + bit2, 1); print_stack_trace(forwards_entry->class->usage_traces + bit2, 1);
printk("\nother info that might help us debug this:\n\n"); printk("\nother info that might help us debug this:\n\n");
lockdep_print_held_locks(curr); lockdep_print_held_locks(curr);
printk("\nthe %s-irq-safe lock's dependencies:\n", irqclass); printk("\nthe dependencies between %s-irq-safe lock", irqclass);
print_lock_dependencies(backwards_match, 0); printk(" and the holding lock:\n");
if (!save_trace(&prev_root->trace))
return 0;
print_shortest_lock_dependencies(backwards_entry, prev_root);
printk("\nthe %s-irq-unsafe lock's dependencies:\n", irqclass); printk("\nthe dependencies between the lock to be acquired");
print_lock_dependencies(forwards_match, 0); printk(" and %s-irq-unsafe lock:\n", irqclass);
if (!save_trace(&next_root->trace))
return 0;
print_shortest_lock_dependencies(forwards_entry, next_root);
printk("\nstack backtrace:\n"); printk("\nstack backtrace:\n");
dump_stack(); dump_stack();
...@@ -1300,22 +1339,24 @@ check_usage(struct task_struct *curr, struct held_lock *prev, ...@@ -1300,22 +1339,24 @@ check_usage(struct task_struct *curr, struct held_lock *prev,
enum lock_usage_bit bit_forwards, const char *irqclass) enum lock_usage_bit bit_forwards, const char *irqclass)
{ {
int ret; int ret;
struct lock_list this; struct lock_list this, that;
struct lock_list *uninitialized_var(target_entry); struct lock_list *uninitialized_var(target_entry);
struct lock_list *uninitialized_var(target_entry1);
this.parent = NULL; this.parent = NULL;
this.class = hlock_class(prev); this.class = hlock_class(prev);
ret = find_usage_backwards(&this, bit_backwards, &target_entry); ret = find_usage_backwards(&this, bit_backwards, &target_entry);
BFS_PROCESS_RET(ret); BFS_PROCESS_RET(ret);
backwards_match = target_entry->class;
this.class = hlock_class(next); that.parent = NULL;
ret = find_usage_forwards(&this, bit_forwards, &target_entry); that.class = hlock_class(next);
ret = find_usage_forwards(&that, bit_forwards, &target_entry1);
BFS_PROCESS_RET(ret); BFS_PROCESS_RET(ret);
forwards_match = target_entry->class;
return print_bad_irq_dependency(curr, prev, next, return print_bad_irq_dependency(curr, &this, &that,
target_entry, target_entry1,
prev, next,
bit_backwards, bit_forwards, irqclass); bit_backwards, bit_forwards, irqclass);
} }
...@@ -1944,7 +1985,8 @@ static int mark_lock(struct task_struct *curr, struct held_lock *this, ...@@ -1944,7 +1985,8 @@ static int mark_lock(struct task_struct *curr, struct held_lock *this,
* print irq inversion bug: * print irq inversion bug:
*/ */
static int static int
print_irq_inversion_bug(struct task_struct *curr, struct lock_class *other, print_irq_inversion_bug(struct task_struct *curr,
struct lock_list *root, struct lock_list *other,
struct held_lock *this, int forwards, struct held_lock *this, int forwards,
const char *irqclass) const char *irqclass)
{ {
...@@ -1962,17 +2004,16 @@ print_irq_inversion_bug(struct task_struct *curr, struct lock_class *other, ...@@ -1962,17 +2004,16 @@ print_irq_inversion_bug(struct task_struct *curr, struct lock_class *other,
printk("but this lock took another, %s-unsafe lock in the past:\n", irqclass); printk("but this lock took another, %s-unsafe lock in the past:\n", irqclass);
else else
printk("but this lock was taken by another, %s-safe lock in the past:\n", irqclass); printk("but this lock was taken by another, %s-safe lock in the past:\n", irqclass);
print_lock_name(other); print_lock_name(other->class);
printk("\n\nand interrupts could create inverse lock ordering between them.\n\n"); printk("\n\nand interrupts could create inverse lock ordering between them.\n\n");
printk("\nother info that might help us debug this:\n"); printk("\nother info that might help us debug this:\n");
lockdep_print_held_locks(curr); lockdep_print_held_locks(curr);
printk("\nthe first lock's dependencies:\n"); printk("\nthe shortest dependencies between 2nd lock and 1st lock:\n");
print_lock_dependencies(hlock_class(this), 0); if (!save_trace(&root->trace))
return 0;
printk("\nthe second lock's dependencies:\n"); print_shortest_lock_dependencies(other, root);
print_lock_dependencies(other, 0);
printk("\nstack backtrace:\n"); printk("\nstack backtrace:\n");
dump_stack(); dump_stack();
...@@ -1997,7 +2038,7 @@ check_usage_forwards(struct task_struct *curr, struct held_lock *this, ...@@ -1997,7 +2038,7 @@ check_usage_forwards(struct task_struct *curr, struct held_lock *this,
ret = find_usage_forwards(&root, bit, &target_entry); ret = find_usage_forwards(&root, bit, &target_entry);
BFS_PROCESS_RET(ret); BFS_PROCESS_RET(ret);
return print_irq_inversion_bug(curr, target_entry->class, return print_irq_inversion_bug(curr, &root, target_entry,
this, 1, irqclass); this, 1, irqclass);
} }
...@@ -2018,7 +2059,7 @@ check_usage_backwards(struct task_struct *curr, struct held_lock *this, ...@@ -2018,7 +2059,7 @@ check_usage_backwards(struct task_struct *curr, struct held_lock *this,
ret = find_usage_backwards(&root, bit, &target_entry); ret = find_usage_backwards(&root, bit, &target_entry);
BFS_PROCESS_RET(ret); BFS_PROCESS_RET(ret);
return print_irq_inversion_bug(curr, target_entry->class, return print_irq_inversion_bug(curr, &root, target_entry,
this, 1, irqclass); this, 1, irqclass);
} }
......
...@@ -219,9 +219,9 @@ static inline struct lock_list *get_lock_parent(struct lock_list *child) ...@@ -219,9 +219,9 @@ static inline struct lock_list *get_lock_parent(struct lock_list *child)
return child->parent; return child->parent;
} }
static inline unsigned long get_lock_depth(struct lock_list *child) static inline int get_lock_depth(struct lock_list *child)
{ {
unsigned long depth = 0; int depth = 0;
struct lock_list *parent; struct lock_list *parent;
while ((parent = get_lock_parent(child))) { while ((parent = get_lock_parent(child))) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment