Merge branch 'irq-threaded-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[pandora-kernel.git] / kernel / lockdep.c
index accb40c..f74d2d7 100644 (file)
 #include <linux/hash.h>
 #include <linux/ftrace.h>
 #include <linux/stringify.h>
-#include <trace/lockdep.h>
+#include <linux/bitops.h>
 
 #include <asm/sections.h>
 
 #include "lockdep_internals.h"
 
+#define CREATE_TRACE_POINTS
+#include <trace/events/lockdep.h>
+
 #ifdef CONFIG_PROVE_LOCKING
 int prove_locking = 1;
 module_param(prove_locking, int, 0644);
@@ -364,11 +367,21 @@ static int save_trace(struct stack_trace *trace)
 
        save_stack_trace(trace);
 
+       /*
+        * Some daft arches put -1 at the end to indicate its a full trace.
+        *
+        * <rant> this is buggy anyway, since it takes a whole extra entry so a
+        * complete trace that maxes out the entries provided will be reported
+        * as incomplete, friggin useless </rant>
+        */
+       if (trace->entries[trace->nr_entries-1] == ULONG_MAX)
+               trace->nr_entries--;
+
        trace->max_entries = trace->nr_entries;
 
        nr_stack_trace_entries += trace->nr_entries;
 
-       if (nr_stack_trace_entries == MAX_STACK_TRACE_ENTRIES) {
+       if (nr_stack_trace_entries >= MAX_STACK_TRACE_ENTRIES-1) {
                if (!debug_locks_off_graph_unlock())
                        return 0;
 
@@ -386,20 +399,6 @@ unsigned int nr_hardirq_chains;
 unsigned int nr_softirq_chains;
 unsigned int nr_process_chains;
 unsigned int max_lockdep_depth;
-unsigned int max_recursion_depth;
-
-static unsigned int lockdep_dependency_gen_id;
-
-static bool lockdep_dependency_visit(struct lock_class *source,
-                                    unsigned int depth)
-{
-       if (!depth)
-               lockdep_dependency_gen_id++;
-       if (source->dep_gen_id == lockdep_dependency_gen_id)
-               return true;
-       source->dep_gen_id = lockdep_dependency_gen_id;
-       return false;
-}
 
 #ifdef CONFIG_DEBUG_LOCKDEP
 /*
@@ -429,11 +428,8 @@ atomic_t redundant_softirqs_on;
 atomic_t redundant_softirqs_off;
 atomic_t nr_unused_locks;
 atomic_t nr_cyclic_checks;
-atomic_t nr_cyclic_check_recursions;
 atomic_t nr_find_usage_forwards_checks;
-atomic_t nr_find_usage_forwards_recursions;
 atomic_t nr_find_usage_backwards_checks;
-atomic_t nr_find_usage_backwards_recursions;
 #endif
 
 /*
@@ -549,58 +545,6 @@ static void lockdep_print_held_locks(struct task_struct *curr)
        }
 }
 
-static void print_lock_class_header(struct lock_class *class, int depth)
-{
-       int bit;
-
-       printk("%*s->", depth, "");
-       print_lock_name(class);
-       printk(" ops: %lu", class->ops);
-       printk(" {\n");
-
-       for (bit = 0; bit < LOCK_USAGE_STATES; bit++) {
-               if (class->usage_mask & (1 << bit)) {
-                       int len = depth;
-
-                       len += printk("%*s   %s", depth, "", usage_str[bit]);
-                       len += printk(" at:\n");
-                       print_stack_trace(class->usage_traces + bit, len);
-               }
-       }
-       printk("%*s }\n", depth, "");
-
-       printk("%*s ... key      at: ",depth,"");
-       print_ip_sym((unsigned long)class->key);
-}
-
-/*
- * printk all lock dependencies starting at <entry>:
- */
-static void __used
-print_lock_dependencies(struct lock_class *class, int depth)
-{
-       struct lock_list *entry;
-
-       if (lockdep_dependency_visit(class, depth))
-               return;
-
-       if (DEBUG_LOCKS_WARN_ON(depth >= 20))
-               return;
-
-       print_lock_class_header(class, depth);
-
-       list_for_each_entry(entry, &class->locks_after, entry) {
-               if (DEBUG_LOCKS_WARN_ON(!entry->class))
-                       return;
-
-               print_lock_dependencies(entry->class, depth + 1);
-
-               printk("%*s ... acquired at:\n",depth,"");
-               print_stack_trace(&entry->trace, 2);
-               printk("\n");
-       }
-}
-
 static void print_kernel_version(void)
 {
        printk("%s %.*s\n", init_utsname()->release,
@@ -895,23 +839,204 @@ static int add_lock_to_list(struct lock_class *class, struct lock_class *this,
        return 1;
 }
 
+/*
+ * For good efficiency of modular, we use power of 2
+ */
+#define MAX_CIRCULAR_QUEUE_SIZE                4096UL
+#define CQ_MASK                                (MAX_CIRCULAR_QUEUE_SIZE-1)
+
+/*
+ * The circular_queue and helpers is used to implement the
+ * breadth-first search(BFS)algorithem, by which we can build
+ * the shortest path from the next lock to be acquired to the
+ * previous held lock if there is a circular between them.
+ */
+struct circular_queue {
+       unsigned long element[MAX_CIRCULAR_QUEUE_SIZE];
+       unsigned int  front, rear;
+};
+
+static struct circular_queue lock_cq;
+
+unsigned int max_bfs_queue_depth;
+
+static unsigned int lockdep_dependency_gen_id;
+
+static inline void __cq_init(struct circular_queue *cq)
+{
+       cq->front = cq->rear = 0;
+       lockdep_dependency_gen_id++;
+}
+
+static inline int __cq_empty(struct circular_queue *cq)
+{
+       return (cq->front == cq->rear);
+}
+
+static inline int __cq_full(struct circular_queue *cq)
+{
+       return ((cq->rear + 1) & CQ_MASK) == cq->front;
+}
+
+static inline int __cq_enqueue(struct circular_queue *cq, unsigned long elem)
+{
+       if (__cq_full(cq))
+               return -1;
+
+       cq->element[cq->rear] = elem;
+       cq->rear = (cq->rear + 1) & CQ_MASK;
+       return 0;
+}
+
+static inline int __cq_dequeue(struct circular_queue *cq, unsigned long *elem)
+{
+       if (__cq_empty(cq))
+               return -1;
+
+       *elem = cq->element[cq->front];
+       cq->front = (cq->front + 1) & CQ_MASK;
+       return 0;
+}
+
+static inline unsigned int  __cq_get_elem_count(struct circular_queue *cq)
+{
+       return (cq->rear - cq->front) & CQ_MASK;
+}
+
+static inline void mark_lock_accessed(struct lock_list *lock,
+                                       struct lock_list *parent)
+{
+       unsigned long nr;
+
+       nr = lock - list_entries;
+       WARN_ON(nr >= nr_list_entries);
+       lock->parent = parent;
+       lock->class->dep_gen_id = lockdep_dependency_gen_id;
+}
+
+static inline unsigned long lock_accessed(struct lock_list *lock)
+{
+       unsigned long nr;
+
+       nr = lock - list_entries;
+       WARN_ON(nr >= nr_list_entries);
+       return lock->class->dep_gen_id == lockdep_dependency_gen_id;
+}
+
+static inline struct lock_list *get_lock_parent(struct lock_list *child)
+{
+       return child->parent;
+}
+
+static inline int get_lock_depth(struct lock_list *child)
+{
+       int depth = 0;
+       struct lock_list *parent;
+
+       while ((parent = get_lock_parent(child))) {
+               child = parent;
+               depth++;
+       }
+       return depth;
+}
+
+static int __bfs(struct lock_list *source_entry,
+                void *data,
+                int (*match)(struct lock_list *entry, void *data),
+                struct lock_list **target_entry,
+                int forward)
+{
+       struct lock_list *entry;
+       struct list_head *head;
+       struct circular_queue *cq = &lock_cq;
+       int ret = 1;
+
+       if (match(source_entry, data)) {
+               *target_entry = source_entry;
+               ret = 0;
+               goto exit;
+       }
+
+       if (forward)
+               head = &source_entry->class->locks_after;
+       else
+               head = &source_entry->class->locks_before;
+
+       if (list_empty(head))
+               goto exit;
+
+       __cq_init(cq);
+       __cq_enqueue(cq, (unsigned long)source_entry);
+
+       while (!__cq_empty(cq)) {
+               struct lock_list *lock;
+
+               __cq_dequeue(cq, (unsigned long *)&lock);
+
+               if (!lock->class) {
+                       ret = -2;
+                       goto exit;
+               }
+
+               if (forward)
+                       head = &lock->class->locks_after;
+               else
+                       head = &lock->class->locks_before;
+
+               list_for_each_entry(entry, head, entry) {
+                       if (!lock_accessed(entry)) {
+                               unsigned int cq_depth;
+                               mark_lock_accessed(entry, lock);
+                               if (match(entry, data)) {
+                                       *target_entry = entry;
+                                       ret = 0;
+                                       goto exit;
+                               }
+
+                               if (__cq_enqueue(cq, (unsigned long)entry)) {
+                                       ret = -1;
+                                       goto exit;
+                               }
+                               cq_depth = __cq_get_elem_count(cq);
+                               if (max_bfs_queue_depth < cq_depth)
+                                       max_bfs_queue_depth = cq_depth;
+                       }
+               }
+       }
+exit:
+       return ret;
+}
+
+static inline int __bfs_forwards(struct lock_list *src_entry,
+                       void *data,
+                       int (*match)(struct lock_list *entry, void *data),
+                       struct lock_list **target_entry)
+{
+       return __bfs(src_entry, data, match, target_entry, 1);
+
+}
+
+static inline int __bfs_backwards(struct lock_list *src_entry,
+                       void *data,
+                       int (*match)(struct lock_list *entry, void *data),
+                       struct lock_list **target_entry)
+{
+       return __bfs(src_entry, data, match, target_entry, 0);
+
+}
+
 /*
  * Recursive, forwards-direction lock-dependency checking, used for
  * both noncyclic checking and for hardirq-unsafe/softirq-unsafe
  * checking.
- *
- * (to keep the stackframe of the recursive functions small we
- *  use these global variables, and we also mark various helper
- *  functions as noinline.)
  */
-static struct held_lock *check_source, *check_target;
 
 /*
  * Print a dependency chain entry (this is only done when a deadlock
  * has been detected):
  */
 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)
                return 0;
@@ -928,11 +1053,13 @@ print_circular_bug_entry(struct lock_list *target, unsigned int depth)
  * header first:
  */
 static noinline int
-print_circular_bug_header(struct lock_list *entry, unsigned int depth)
+print_circular_bug_header(struct lock_list *entry, unsigned int depth,
+                       struct held_lock *check_src,
+                       struct held_lock *check_tgt)
 {
        struct task_struct *curr = current;
 
-       if (!debug_locks_off_graph_unlock() || debug_locks_silent)
+       if (debug_locks_silent)
                return 0;
 
        printk("\n=======================================================\n");
@@ -941,9 +1068,9 @@ print_circular_bug_header(struct lock_list *entry, unsigned int depth)
        printk(  "-------------------------------------------------------\n");
        printk("%s/%d is trying to acquire lock:\n",
                curr->comm, task_pid_nr(curr));
-       print_lock(check_source);
+       print_lock(check_src);
        printk("\nbut task is already holding lock:\n");
-       print_lock(check_target);
+       print_lock(check_tgt);
        printk("\nwhich lock already depends on the new lock.\n\n");
        printk("\nthe existing dependency chain (in reverse order) is:\n");
 
@@ -952,19 +1079,36 @@ print_circular_bug_header(struct lock_list *entry, unsigned int depth)
        return 0;
 }
 
-static noinline int print_circular_bug_tail(void)
+static inline int class_equal(struct lock_list *entry, void *data)
+{
+       return entry->class == data;
+}
+
+static noinline int print_circular_bug(struct lock_list *this,
+                               struct lock_list *target,
+                               struct held_lock *check_src,
+                               struct held_lock *check_tgt)
 {
        struct task_struct *curr = current;
-       struct lock_list this;
+       struct lock_list *parent;
+       int depth;
 
-       if (debug_locks_silent)
+       if (!debug_locks_off_graph_unlock() || debug_locks_silent)
                return 0;
 
-       this.class = hlock_class(check_source);
-       if (!save_trace(&this.trace))
+       if (!save_trace(&this->trace))
                return 0;
 
-       print_circular_bug_entry(&this, 0);
+       depth = get_lock_depth(target);
+
+       print_circular_bug_header(target, depth, check_src, check_tgt);
+
+       parent = get_lock_parent(target);
+
+       while (parent) {
+               print_circular_bug_entry(parent, --depth);
+               parent = get_lock_parent(parent);
+       }
 
        printk("\nother info that might help us debug this:\n\n");
        lockdep_print_held_locks(curr);
@@ -975,73 +1119,69 @@ static noinline int print_circular_bug_tail(void)
        return 0;
 }
 
-#define RECURSION_LIMIT 40
-
-static int noinline print_infinite_recursion_bug(void)
+static noinline int print_bfs_bug(int ret)
 {
        if (!debug_locks_off_graph_unlock())
                return 0;
 
-       WARN_ON(1);
+       WARN(1, "lockdep bfs error:%d\n", ret);
 
        return 0;
 }
 
-unsigned long __lockdep_count_forward_deps(struct lock_class *class,
-                                          unsigned int depth)
+static int noop_count(struct lock_list *entry, void *data)
 {
-       struct lock_list *entry;
-       unsigned long ret = 1;
+       (*(unsigned long *)data)++;
+       return 0;
+}
 
-       if (lockdep_dependency_visit(class, depth))
-               return 0;
+unsigned long __lockdep_count_forward_deps(struct lock_list *this)
+{
+       unsigned long  count = 0;
+       struct lock_list *uninitialized_var(target_entry);
 
-       /*
-        * Recurse this class's dependency list:
-        */
-       list_for_each_entry(entry, &class->locks_after, entry)
-               ret += __lockdep_count_forward_deps(entry->class, depth + 1);
+       __bfs_forwards(this, (void *)&count, noop_count, &target_entry);
 
-       return ret;
+       return count;
 }
-
 unsigned long lockdep_count_forward_deps(struct lock_class *class)
 {
        unsigned long ret, flags;
+       struct lock_list this;
+
+       this.parent = NULL;
+       this.class = class;
 
        local_irq_save(flags);
        __raw_spin_lock(&lockdep_lock);
-       ret = __lockdep_count_forward_deps(class, 0);
+       ret = __lockdep_count_forward_deps(&this);
        __raw_spin_unlock(&lockdep_lock);
        local_irq_restore(flags);
 
        return ret;
 }
 
-unsigned long __lockdep_count_backward_deps(struct lock_class *class,
-                                           unsigned int depth)
+unsigned long __lockdep_count_backward_deps(struct lock_list *this)
 {
-       struct lock_list *entry;
-       unsigned long ret = 1;
+       unsigned long  count = 0;
+       struct lock_list *uninitialized_var(target_entry);
 
-       if (lockdep_dependency_visit(class, depth))
-               return 0;
-       /*
-        * Recurse this class's dependency list:
-        */
-       list_for_each_entry(entry, &class->locks_before, entry)
-               ret += __lockdep_count_backward_deps(entry->class, depth + 1);
+       __bfs_backwards(this, (void *)&count, noop_count, &target_entry);
 
-       return ret;
+       return count;
 }
 
 unsigned long lockdep_count_backward_deps(struct lock_class *class)
 {
        unsigned long ret, flags;
+       struct lock_list this;
+
+       this.parent = NULL;
+       this.class = class;
 
        local_irq_save(flags);
        __raw_spin_lock(&lockdep_lock);
-       ret = __lockdep_count_backward_deps(class, 0);
+       ret = __lockdep_count_backward_deps(&this);
        __raw_spin_unlock(&lockdep_lock);
        local_irq_restore(flags);
 
@@ -1053,29 +1193,16 @@ unsigned long lockdep_count_backward_deps(struct lock_class *class)
  * lead to <target>. Print an error and return 0 if it does.
  */
 static noinline int
-check_noncircular(struct lock_class *source, unsigned int depth)
+check_noncircular(struct lock_list *root, struct lock_class *target,
+               struct lock_list **target_entry)
 {
-       struct lock_list *entry;
+       int result;
 
-       if (lockdep_dependency_visit(source, depth))
-               return 1;
+       debug_atomic_inc(&nr_cyclic_checks);
 
-       debug_atomic_inc(&nr_cyclic_check_recursions);
-       if (depth > max_recursion_depth)
-               max_recursion_depth = depth;
-       if (depth >= RECURSION_LIMIT)
-               return print_infinite_recursion_bug();
-       /*
-        * Check this lock's dependency list:
-        */
-       list_for_each_entry(entry, &source->locks_after, entry) {
-               if (entry->class == hlock_class(check_target))
-                       return print_circular_bug_header(entry, depth+1);
-               debug_atomic_inc(&nr_cyclic_checks);
-               if (!check_noncircular(entry->class, depth+1))
-                       return print_circular_bug_entry(entry, depth+1);
-       }
-       return 1;
+       result = __bfs_forwards(root, target, class_equal, target_entry);
+
+       return result;
 }
 
 #if defined(CONFIG_TRACE_IRQFLAGS) && defined(CONFIG_PROVE_LOCKING)
@@ -1084,103 +1211,121 @@ check_noncircular(struct lock_class *source, unsigned int depth)
  * proving that two subgraphs can be connected by a new dependency
  * without creating any illegal irq-safe -> irq-unsafe lock dependency.
  */
-static enum lock_usage_bit find_usage_bit;
-static struct lock_class *forwards_match, *backwards_match;
+
+static inline int usage_match(struct lock_list *entry, void *bit)
+{
+       return entry->class->usage_mask & (1 << (enum lock_usage_bit)bit);
+}
+
+
 
 /*
  * Find a node in the forwards-direction dependency sub-graph starting
- * at <source> that matches <find_usage_bit>.
+ * at @root->class that matches @bit.
  *
- * Return 2 if such a node exists in the subgraph, and put that node
- * into <forwards_match>.
+ * Return 0 if such a node exists in the subgraph, and put that node
+ * into *@target_entry.
  *
- * Return 1 otherwise and keep <forwards_match> unchanged.
- * Return 0 on error.
+ * Return 1 otherwise and keep *@target_entry unchanged.
+ * Return <0 on error.
  */
-static noinline int
-find_usage_forwards(struct lock_class *source, unsigned int depth)
+static int
+find_usage_forwards(struct lock_list *root, enum lock_usage_bit bit,
+                       struct lock_list **target_entry)
 {
-       struct lock_list *entry;
-       int ret;
-
-       if (lockdep_dependency_visit(source, depth))
-               return 1;
-
-       if (depth > max_recursion_depth)
-               max_recursion_depth = depth;
-       if (depth >= RECURSION_LIMIT)
-               return print_infinite_recursion_bug();
+       int result;
 
        debug_atomic_inc(&nr_find_usage_forwards_checks);
-       if (source->usage_mask & (1 << find_usage_bit)) {
-               forwards_match = source;
-               return 2;
-       }
 
-       /*
-        * Check this lock's dependency list:
-        */
-       list_for_each_entry(entry, &source->locks_after, entry) {
-               debug_atomic_inc(&nr_find_usage_forwards_recursions);
-               ret = find_usage_forwards(entry->class, depth+1);
-               if (ret == 2 || ret == 0)
-                       return ret;
-       }
-       return 1;
+       result = __bfs_forwards(root, (void *)bit, usage_match, target_entry);
+
+       return result;
 }
 
 /*
  * Find a node in the backwards-direction dependency sub-graph starting
- * at <source> that matches <find_usage_bit>.
+ * at @root->class that matches @bit.
  *
- * Return 2 if such a node exists in the subgraph, and put that node
- * into <backwards_match>.
+ * Return 0 if such a node exists in the subgraph, and put that node
+ * into *@target_entry.
  *
- * Return 1 otherwise and keep <backwards_match> unchanged.
- * Return 0 on error.
+ * Return 1 otherwise and keep *@target_entry unchanged.
+ * Return <0 on error.
  */
-static noinline int
-find_usage_backwards(struct lock_class *source, unsigned int depth)
+static int
+find_usage_backwards(struct lock_list *root, enum lock_usage_bit bit,
+                       struct lock_list **target_entry)
 {
-       struct lock_list *entry;
-       int ret;
+       int result;
 
-       if (lockdep_dependency_visit(source, depth))
-               return 1;
+       debug_atomic_inc(&nr_find_usage_backwards_checks);
 
-       if (!__raw_spin_is_locked(&lockdep_lock))
-               return DEBUG_LOCKS_WARN_ON(1);
+       result = __bfs_backwards(root, (void *)bit, usage_match, target_entry);
 
-       if (depth > max_recursion_depth)
-               max_recursion_depth = depth;
-       if (depth >= RECURSION_LIMIT)
-               return print_infinite_recursion_bug();
+       return result;
+}
 
-       debug_atomic_inc(&nr_find_usage_backwards_checks);
-       if (source->usage_mask & (1 << find_usage_bit)) {
-               backwards_match = source;
-               return 2;
-       }
+static void print_lock_class_header(struct lock_class *class, int depth)
+{
+       int bit;
 
-       if (!source && debug_locks_off_graph_unlock()) {
-               WARN_ON(1);
-               return 0;
-       }
+       printk("%*s->", depth, "");
+       print_lock_name(class);
+       printk(" ops: %lu", class->ops);
+       printk(" {\n");
 
-       /*
-        * Check this lock's dependency list:
-        */
-       list_for_each_entry(entry, &source->locks_before, entry) {
-               debug_atomic_inc(&nr_find_usage_backwards_recursions);
-               ret = find_usage_backwards(entry->class, depth+1);
-               if (ret == 2 || ret == 0)
-                       return ret;
+       for (bit = 0; bit < LOCK_USAGE_STATES; bit++) {
+               if (class->usage_mask & (1 << bit)) {
+                       int len = depth;
+
+                       len += printk("%*s   %s", depth, "", usage_str[bit]);
+                       len += printk(" at:\n");
+                       print_stack_trace(class->usage_traces + bit, len);
+               }
        }
-       return 1;
+       printk("%*s }\n", depth, "");
+
+       printk("%*s ... key      at: ",depth,"");
+       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;
 }
 
 static int
 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 *next,
                         enum lock_usage_bit bit1,
@@ -1213,26 +1358,32 @@ print_bad_irq_dependency(struct task_struct *curr,
 
        printk("\nbut this new dependency connects a %s-irq-safe lock:\n",
                irqclass);
-       print_lock_name(backwards_match);
+       print_lock_name(backwards_entry->class);
        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);
-       print_lock_name(forwards_match);
+       print_lock_name(forwards_entry->class);
        printk("\n... which became %s-irq-unsafe at:\n", irqclass);
        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");
        lockdep_print_held_locks(curr);
 
-       printk("\nthe %s-irq-safe lock's dependencies:\n", irqclass);
-       print_lock_dependencies(backwards_match, 0);
+       printk("\nthe dependencies between %s-irq-safe lock", irqclass);
+       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);
-       print_lock_dependencies(forwards_match, 0);
+       printk("\nthe dependencies between the lock to be acquired");
+       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");
        dump_stack();
@@ -1246,19 +1397,30 @@ check_usage(struct task_struct *curr, struct held_lock *prev,
            enum lock_usage_bit bit_forwards, const char *irqclass)
 {
        int ret;
+       struct lock_list this, that;
+       struct lock_list *uninitialized_var(target_entry);
+       struct lock_list *uninitialized_var(target_entry1);
+
+       this.parent = NULL;
 
-       find_usage_bit = bit_backwards;
-       /* fills in <backwards_match> */
-       ret = find_usage_backwards(hlock_class(prev), 0);
-       if (!ret || ret == 1)
+       this.class = hlock_class(prev);
+       ret = find_usage_backwards(&this, bit_backwards, &target_entry);
+       if (ret < 0)
+               return print_bfs_bug(ret);
+       if (ret == 1)
                return ret;
 
-       find_usage_bit = bit_forwards;
-       ret = find_usage_forwards(hlock_class(next), 0);
-       if (!ret || ret == 1)
+       that.parent = NULL;
+       that.class = hlock_class(next);
+       ret = find_usage_forwards(&that, bit_forwards, &target_entry1);
+       if (ret < 0)
+               return print_bfs_bug(ret);
+       if (ret == 1)
                return ret;
-       /* ret == 2 */
-       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);
 }
 
@@ -1470,6 +1632,8 @@ check_prev_add(struct task_struct *curr, struct held_lock *prev,
 {
        struct lock_list *entry;
        int ret;
+       struct lock_list this;
+       struct lock_list *uninitialized_var(target_entry);
 
        /*
         * Prove that the new <prev> -> <next> dependency would not
@@ -1480,10 +1644,13 @@ check_prev_add(struct task_struct *curr, struct held_lock *prev,
         * We are using global variables to control the recursion, to
         * keep the stackframe size of the recursive functions low:
         */
-       check_source = next;
-       check_target = prev;
-       if (!(check_noncircular(hlock_class(next), 0)))
-               return print_circular_bug_tail();
+       this.class = hlock_class(next);
+       this.parent = NULL;
+       ret = check_noncircular(&this, hlock_class(prev), &target_entry);
+       if (unlikely(!ret))
+               return print_circular_bug(&this, target_entry, next, prev);
+       else if (unlikely(ret < 0))
+               return print_bfs_bug(ret);
 
        if (!check_prev_add_irq(curr, prev, next))
                return 0;
@@ -1882,7 +2049,8 @@ static int mark_lock(struct task_struct *curr, struct held_lock *this,
  * print irq inversion bug:
  */
 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,
                        const char *irqclass)
 {
@@ -1900,17 +2068,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);
        else
                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("\nother info that might help us debug this:\n");
        lockdep_print_held_locks(curr);
 
-       printk("\nthe first lock's dependencies:\n");
-       print_lock_dependencies(hlock_class(this), 0);
-
-       printk("\nthe second lock's dependencies:\n");
-       print_lock_dependencies(other, 0);
+       printk("\nthe shortest dependencies between 2nd lock and 1st lock:\n");
+       if (!save_trace(&root->trace))
+               return 0;
+       print_shortest_lock_dependencies(other, root);
 
        printk("\nstack backtrace:\n");
        dump_stack();
@@ -1927,14 +2094,19 @@ check_usage_forwards(struct task_struct *curr, struct held_lock *this,
                     enum lock_usage_bit bit, const char *irqclass)
 {
        int ret;
-
-       find_usage_bit = bit;
-       /* fills in <forwards_match> */
-       ret = find_usage_forwards(hlock_class(this), 0);
-       if (!ret || ret == 1)
+       struct lock_list root;
+       struct lock_list *uninitialized_var(target_entry);
+
+       root.parent = NULL;
+       root.class = hlock_class(this);
+       ret = find_usage_forwards(&root, bit, &target_entry);
+       if (ret < 0)
+               return print_bfs_bug(ret);
+       if (ret == 1)
                return ret;
 
-       return print_irq_inversion_bug(curr, forwards_match, this, 1, irqclass);
+       return print_irq_inversion_bug(curr, &root, target_entry,
+                                       this, 1, irqclass);
 }
 
 /*
@@ -1946,14 +2118,19 @@ check_usage_backwards(struct task_struct *curr, struct held_lock *this,
                      enum lock_usage_bit bit, const char *irqclass)
 {
        int ret;
-
-       find_usage_bit = bit;
-       /* fills in <backwards_match> */
-       ret = find_usage_backwards(hlock_class(this), 0);
-       if (!ret || ret == 1)
+       struct lock_list root;
+       struct lock_list *uninitialized_var(target_entry);
+
+       root.parent = NULL;
+       root.class = hlock_class(this);
+       ret = find_usage_backwards(&root, bit, &target_entry);
+       if (ret < 0)
+               return print_bfs_bug(ret);
+       if (ret == 1)
                return ret;
 
-       return print_irq_inversion_bug(curr, backwards_match, this, 0, irqclass);
+       return print_irq_inversion_bug(curr, &root, target_entry,
+                                       this, 1, irqclass);
 }
 
 void print_irqtrace_events(struct task_struct *curr)
@@ -2528,13 +2705,15 @@ EXPORT_SYMBOL_GPL(lockdep_init_map);
  */
 static int __lock_acquire(struct lockdep_map *lock, unsigned int subclass,
                          int trylock, int read, int check, int hardirqs_off,
-                         struct lockdep_map *nest_lock, unsigned long ip)
+                         struct lockdep_map *nest_lock, unsigned long ip,
+                         int references)
 {
        struct task_struct *curr = current;
        struct lock_class *class = NULL;
        struct held_lock *hlock;
        unsigned int depth, id;
        int chain_head = 0;
+       int class_idx;
        u64 chain_key;
 
        if (!prove_locking)
@@ -2582,10 +2761,24 @@ static int __lock_acquire(struct lockdep_map *lock, unsigned int subclass,
        if (DEBUG_LOCKS_WARN_ON(depth >= MAX_LOCK_DEPTH))
                return 0;
 
+       class_idx = class - lock_classes + 1;
+
+       if (depth) {
+               hlock = curr->held_locks + depth - 1;
+               if (hlock->class_idx == class_idx && nest_lock) {
+                       if (hlock->references)
+                               hlock->references++;
+                       else
+                               hlock->references = 2;
+
+                       return 1;
+               }
+       }
+
        hlock = curr->held_locks + depth;
        if (DEBUG_LOCKS_WARN_ON(!class))
                return 0;
-       hlock->class_idx = class - lock_classes + 1;
+       hlock->class_idx = class_idx;
        hlock->acquire_ip = ip;
        hlock->instance = lock;
        hlock->nest_lock = nest_lock;
@@ -2593,6 +2786,7 @@ static int __lock_acquire(struct lockdep_map *lock, unsigned int subclass,
        hlock->read = read;
        hlock->check = check;
        hlock->hardirqs_off = !!hardirqs_off;
+       hlock->references = references;
 #ifdef CONFIG_LOCK_STAT
        hlock->waittime_stamp = 0;
        hlock->holdtime_stamp = sched_clock();
@@ -2701,6 +2895,30 @@ static int check_unlock(struct task_struct *curr, struct lockdep_map *lock,
        return 1;
 }
 
+static int match_held_lock(struct held_lock *hlock, struct lockdep_map *lock)
+{
+       if (hlock->instance == lock)
+               return 1;
+
+       if (hlock->references) {
+               struct lock_class *class = lock->class_cache;
+
+               if (!class)
+                       class = look_up_lock_class(lock, 0);
+
+               if (DEBUG_LOCKS_WARN_ON(!class))
+                       return 0;
+
+               if (DEBUG_LOCKS_WARN_ON(!hlock->nest_lock))
+                       return 0;
+
+               if (hlock->class_idx == class - lock_classes + 1)
+                       return 1;
+       }
+
+       return 0;
+}
+
 static int
 __lock_set_class(struct lockdep_map *lock, const char *name,
                 struct lock_class_key *key, unsigned int subclass,
@@ -2724,7 +2942,7 @@ __lock_set_class(struct lockdep_map *lock, const char *name,
                 */
                if (prev_hlock && prev_hlock->irq_context != hlock->irq_context)
                        break;
-               if (hlock->instance == lock)
+               if (match_held_lock(hlock, lock))
                        goto found_it;
                prev_hlock = hlock;
        }
@@ -2743,7 +2961,8 @@ found_it:
                if (!__lock_acquire(hlock->instance,
                        hlock_class(hlock)->subclass, hlock->trylock,
                                hlock->read, hlock->check, hlock->hardirqs_off,
-                               hlock->nest_lock, hlock->acquire_ip))
+                               hlock->nest_lock, hlock->acquire_ip,
+                               hlock->references))
                        return 0;
        }
 
@@ -2782,20 +3001,34 @@ lock_release_non_nested(struct task_struct *curr,
                 */
                if (prev_hlock && prev_hlock->irq_context != hlock->irq_context)
                        break;
-               if (hlock->instance == lock)
+               if (match_held_lock(hlock, lock))
                        goto found_it;
                prev_hlock = hlock;
        }
        return print_unlock_inbalance_bug(curr, lock, ip);
 
 found_it:
-       lock_release_holdtime(hlock);
+       if (hlock->instance == lock)
+               lock_release_holdtime(hlock);
+
+       if (hlock->references) {
+               hlock->references--;
+               if (hlock->references) {
+                       /*
+                        * We had, and after removing one, still have
+                        * references, the current lock stack is still
+                        * valid. We're done!
+                        */
+                       return 1;
+               }
+       }
 
        /*
         * We have the right lock to unlock, 'hlock' points to it.
         * Now we remove it from the stack, and add back the other
         * entries (if any), recalculating the hash along the way:
         */
+
        curr->lockdep_depth = i;
        curr->curr_chain_key = hlock->prev_chain_key;
 
@@ -2804,7 +3037,8 @@ found_it:
                if (!__lock_acquire(hlock->instance,
                        hlock_class(hlock)->subclass, hlock->trylock,
                                hlock->read, hlock->check, hlock->hardirqs_off,
-                               hlock->nest_lock, hlock->acquire_ip))
+                               hlock->nest_lock, hlock->acquire_ip,
+                               hlock->references))
                        return 0;
        }
 
@@ -2834,7 +3068,7 @@ static int lock_release_nested(struct task_struct *curr,
        /*
         * Is the unlock non-nested:
         */
-       if (hlock->instance != lock)
+       if (hlock->instance != lock || hlock->references)
                return lock_release_non_nested(curr, lock, ip);
        curr->lockdep_depth--;
 
@@ -2879,6 +3113,21 @@ __lock_release(struct lockdep_map *lock, int nested, unsigned long ip)
        check_chain_key(curr);
 }
 
+static int __lock_is_held(struct lockdep_map *lock)
+{
+       struct task_struct *curr = current;
+       int i;
+
+       for (i = 0; i < curr->lockdep_depth; i++) {
+               struct held_lock *hlock = curr->held_locks + i;
+
+               if (match_held_lock(hlock, lock))
+                       return 1;
+       }
+
+       return 0;
+}
+
 /*
  * Check whether we follow the irq-flags state precisely:
  */
@@ -2935,8 +3184,6 @@ void lock_set_class(struct lockdep_map *lock, const char *name,
 }
 EXPORT_SYMBOL_GPL(lock_set_class);
 
-DEFINE_TRACE(lock_acquire);
-
 /*
  * We are not always called with irqs disabled - do that here,
  * and also avoid lockdep recursion:
@@ -2957,14 +3204,12 @@ void lock_acquire(struct lockdep_map *lock, unsigned int subclass,
 
        current->lockdep_recursion = 1;
        __lock_acquire(lock, subclass, trylock, read, check,
-                      irqs_disabled_flags(flags), nest_lock, ip);
+                      irqs_disabled_flags(flags), nest_lock, ip, 0);
        current->lockdep_recursion = 0;
        raw_local_irq_restore(flags);
 }
 EXPORT_SYMBOL_GPL(lock_acquire);
 
-DEFINE_TRACE(lock_release);
-
 void lock_release(struct lockdep_map *lock, int nested,
                          unsigned long ip)
 {
@@ -2984,6 +3229,26 @@ void lock_release(struct lockdep_map *lock, int nested,
 }
 EXPORT_SYMBOL_GPL(lock_release);
 
+int lock_is_held(struct lockdep_map *lock)
+{
+       unsigned long flags;
+       int ret = 0;
+
+       if (unlikely(current->lockdep_recursion))
+               return ret;
+
+       raw_local_irq_save(flags);
+       check_flags(flags);
+
+       current->lockdep_recursion = 1;
+       ret = __lock_is_held(lock);
+       current->lockdep_recursion = 0;
+       raw_local_irq_restore(flags);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(lock_is_held);
+
 void lockdep_set_current_reclaim_state(gfp_t gfp_mask)
 {
        current->lockdep_reclaim_gfp = gfp_mask;
@@ -3043,7 +3308,7 @@ __lock_contended(struct lockdep_map *lock, unsigned long ip)
                 */
                if (prev_hlock && prev_hlock->irq_context != hlock->irq_context)
                        break;
-               if (hlock->instance == lock)
+               if (match_held_lock(hlock, lock))
                        goto found_it;
                prev_hlock = hlock;
        }
@@ -3051,6 +3316,9 @@ __lock_contended(struct lockdep_map *lock, unsigned long ip)
        return;
 
 found_it:
+       if (hlock->instance != lock)
+               return;
+
        hlock->waittime_stamp = sched_clock();
 
        contention_point = lock_point(hlock_class(hlock)->contention_point, ip);
@@ -3090,7 +3358,7 @@ __lock_acquired(struct lockdep_map *lock, unsigned long ip)
                 */
                if (prev_hlock && prev_hlock->irq_context != hlock->irq_context)
                        break;
-               if (hlock->instance == lock)
+               if (match_held_lock(hlock, lock))
                        goto found_it;
                prev_hlock = hlock;
        }
@@ -3098,6 +3366,9 @@ __lock_acquired(struct lockdep_map *lock, unsigned long ip)
        return;
 
 found_it:
+       if (hlock->instance != lock)
+               return;
+
        cpu = smp_processor_id();
        if (hlock->waittime_stamp) {
                now = sched_clock();
@@ -3105,6 +3376,8 @@ found_it:
                hlock->holdtime_stamp = now;
        }
 
+       trace_lock_acquired(lock, ip, waittime);
+
        stats = get_lock_stats(hlock_class(hlock));
        if (waittime) {
                if (hlock->read)
@@ -3120,8 +3393,6 @@ found_it:
        lock->ip = ip;
 }
 
-DEFINE_TRACE(lock_contended);
-
 void lock_contended(struct lockdep_map *lock, unsigned long ip)
 {
        unsigned long flags;
@@ -3143,14 +3414,10 @@ void lock_contended(struct lockdep_map *lock, unsigned long ip)
 }
 EXPORT_SYMBOL_GPL(lock_contended);
 
-DEFINE_TRACE(lock_acquired);
-
 void lock_acquired(struct lockdep_map *lock, unsigned long ip)
 {
        unsigned long flags;
 
-       trace_lock_acquired(lock, ip);
-
        if (unlikely(!lock_stat))
                return;
 
@@ -3332,7 +3599,12 @@ void __init lockdep_info(void)
                sizeof(struct list_head) * CLASSHASH_SIZE +
                sizeof(struct lock_list) * MAX_LOCKDEP_ENTRIES +
                sizeof(struct lock_chain) * MAX_LOCKDEP_CHAINS +
-               sizeof(struct list_head) * CHAINHASH_SIZE) / 1024);
+               sizeof(struct list_head) * CHAINHASH_SIZE
+#ifdef CONFIG_PROVE_LOCKING
+               + sizeof(struct circular_queue)
+#endif
+               ) / 1024
+               );
 
        printk(" per task-struct memory footprint: %lu bytes\n",
                sizeof(struct held_lock) * MAX_LOCK_DEPTH);