|
@@ -1065,6 +1065,56 @@ print_circular_bug_entry(struct lock_list *target, int depth)
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static void
|
|
|
|
+print_circular_lock_scenario(struct held_lock *src,
|
|
|
|
+ struct held_lock *tgt,
|
|
|
|
+ struct lock_list *prt)
|
|
|
|
+{
|
|
|
|
+ struct lock_class *source = hlock_class(src);
|
|
|
|
+ struct lock_class *target = hlock_class(tgt);
|
|
|
|
+ struct lock_class *parent = prt->class;
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * A direct locking problem where unsafe_class lock is taken
|
|
|
|
+ * directly by safe_class lock, then all we need to show
|
|
|
|
+ * is the deadlock scenario, as it is obvious that the
|
|
|
|
+ * unsafe lock is taken under the safe lock.
|
|
|
|
+ *
|
|
|
|
+ * But if there is a chain instead, where the safe lock takes
|
|
|
|
+ * an intermediate lock (middle_class) where this lock is
|
|
|
|
+ * not the same as the safe lock, then the lock chain is
|
|
|
|
+ * used to describe the problem. Otherwise we would need
|
|
|
|
+ * to show a different CPU case for each link in the chain
|
|
|
|
+ * from the safe_class lock to the unsafe_class lock.
|
|
|
|
+ */
|
|
|
|
+ if (parent != source) {
|
|
|
|
+ printk("Chain exists of:\n ");
|
|
|
|
+ __print_lock_name(source);
|
|
|
|
+ printk(" --> ");
|
|
|
|
+ __print_lock_name(parent);
|
|
|
|
+ printk(" --> ");
|
|
|
|
+ __print_lock_name(target);
|
|
|
|
+ printk("\n\n");
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ printk(" Possible unsafe locking scenario:\n\n");
|
|
|
|
+ printk(" CPU0 CPU1\n");
|
|
|
|
+ printk(" ---- ----\n");
|
|
|
|
+ printk(" lock(");
|
|
|
|
+ __print_lock_name(target);
|
|
|
|
+ printk(");\n");
|
|
|
|
+ printk(" lock(");
|
|
|
|
+ __print_lock_name(parent);
|
|
|
|
+ printk(");\n");
|
|
|
|
+ printk(" lock(");
|
|
|
|
+ __print_lock_name(target);
|
|
|
|
+ printk(");\n");
|
|
|
|
+ printk(" lock(");
|
|
|
|
+ __print_lock_name(source);
|
|
|
|
+ printk(");\n");
|
|
|
|
+ printk("\n *** DEADLOCK ***\n\n");
|
|
|
|
+}
|
|
|
|
+
|
|
/*
|
|
/*
|
|
* When a circular dependency is detected, print the
|
|
* When a circular dependency is detected, print the
|
|
* header first:
|
|
* header first:
|
|
@@ -1108,6 +1158,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;
|
|
|
|
+ struct lock_list *first_parent;
|
|
int depth;
|
|
int depth;
|
|
|
|
|
|
if (!debug_locks_off_graph_unlock() || debug_locks_silent)
|
|
if (!debug_locks_off_graph_unlock() || debug_locks_silent)
|
|
@@ -1121,6 +1172,7 @@ static noinline int print_circular_bug(struct lock_list *this,
|
|
print_circular_bug_header(target, depth, check_src, check_tgt);
|
|
print_circular_bug_header(target, depth, check_src, check_tgt);
|
|
|
|
|
|
parent = get_lock_parent(target);
|
|
parent = get_lock_parent(target);
|
|
|
|
+ first_parent = parent;
|
|
|
|
|
|
while (parent) {
|
|
while (parent) {
|
|
print_circular_bug_entry(parent, --depth);
|
|
print_circular_bug_entry(parent, --depth);
|
|
@@ -1128,6 +1180,9 @@ static noinline int print_circular_bug(struct lock_list *this,
|
|
}
|
|
}
|
|
|
|
|
|
printk("\nother info that might help us debug this:\n\n");
|
|
printk("\nother info that might help us debug this:\n\n");
|
|
|
|
+ print_circular_lock_scenario(check_src, check_tgt,
|
|
|
|
+ first_parent);
|
|
|
|
+
|
|
lockdep_print_held_locks(curr);
|
|
lockdep_print_held_locks(curr);
|
|
|
|
|
|
printk("\nstack backtrace:\n");
|
|
printk("\nstack backtrace:\n");
|