sched: fix nohz load balancer on cpu offline
[safe/jmp/linux-2.6] / kernel / lockdep.c
index d38a643..06b0c35 100644 (file)
@@ -25,6 +25,7 @@
  * Thanks to Arjan van de Ven for coming up with the initial idea of
  * mapping lock dependencies runtime.
  */
+#define DISABLE_BRANCH_PROFILING
 #include <linux/mutex.h>
 #include <linux/sched.h>
 #include <linux/delay.h>
@@ -124,19 +125,28 @@ static struct lock_list list_entries[MAX_LOCKDEP_ENTRIES];
 unsigned long nr_lock_classes;
 static struct lock_class lock_classes[MAX_LOCKDEP_KEYS];
 
+static inline struct lock_class *hlock_class(struct held_lock *hlock)
+{
+       if (!hlock->class_idx) {
+               DEBUG_LOCKS_WARN_ON(1);
+               return NULL;
+       }
+       return lock_classes + hlock->class_idx - 1;
+}
+
 #ifdef CONFIG_LOCK_STAT
 static DEFINE_PER_CPU(struct lock_class_stats[MAX_LOCKDEP_KEYS], lock_stats);
 
-static int lock_contention_point(struct lock_class *class, unsigned long ip)
+static int lock_point(unsigned long points[], unsigned long ip)
 {
        int i;
 
-       for (i = 0; i < ARRAY_SIZE(class->contention_point); i++) {
-               if (class->contention_point[i] == 0) {
-                       class->contention_point[i] = ip;
+       for (i = 0; i < LOCKSTAT_POINTS; i++) {
+               if (points[i] == 0) {
+                       points[i] = ip;
                        break;
                }
-               if (class->contention_point[i] == ip)
+               if (points[i] == ip)
                        break;
        }
 
@@ -176,6 +186,9 @@ struct lock_class_stats lock_stats(struct lock_class *class)
                for (i = 0; i < ARRAY_SIZE(stats.contention_point); i++)
                        stats.contention_point[i] += pcs->contention_point[i];
 
+               for (i = 0; i < ARRAY_SIZE(stats.contending_point); i++)
+                       stats.contending_point[i] += pcs->contending_point[i];
+
                lock_time_add(&pcs->read_waittime, &stats.read_waittime);
                lock_time_add(&pcs->write_waittime, &stats.write_waittime);
 
@@ -200,6 +213,7 @@ void clear_lock_stats(struct lock_class *class)
                memset(cpu_stats, 0, sizeof(struct lock_class_stats));
        }
        memset(class->contention_point, 0, sizeof(class->contention_point));
+       memset(class->contending_point, 0, sizeof(class->contending_point));
 }
 
 static struct lock_class_stats *get_lock_stats(struct lock_class *class)
@@ -222,7 +236,7 @@ static void lock_release_holdtime(struct held_lock *hlock)
 
        holdtime = sched_clock() - hlock->holdtime_stamp;
 
-       stats = get_lock_stats(hlock->class);
+       stats = get_lock_stats(hlock_class(hlock));
        if (hlock->read)
                lock_time_inc(&stats->read_holdtime, holdtime);
        else
@@ -278,14 +292,12 @@ void lockdep_off(void)
 {
        current->lockdep_recursion++;
 }
-
 EXPORT_SYMBOL(lockdep_off);
 
 void lockdep_on(void)
 {
        current->lockdep_recursion--;
 }
-
 EXPORT_SYMBOL(lockdep_on);
 
 /*
@@ -372,6 +384,19 @@ 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
 /*
  * We cannot printk in early bootup code. Not even early_printk()
@@ -505,7 +530,7 @@ static void print_lockdep_cache(struct lockdep_map *lock)
 
 static void print_lock(struct held_lock *hlock)
 {
-       print_lock_name(hlock->class);
+       print_lock_name(hlock_class(hlock));
        printk(", at: ");
        print_ip_sym(hlock->acquire_ip);
 }
@@ -554,10 +579,14 @@ static void print_lock_class_header(struct lock_class *class, int depth)
 /*
  * printk all lock dependencies starting at <entry>:
  */
-static void print_lock_dependencies(struct lock_class *class, int depth)
+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;
 
@@ -850,11 +879,11 @@ static int add_lock_to_list(struct lock_class *class, struct lock_class *this,
        if (!entry)
                return 0;
 
-       entry->class = this;
-       entry->distance = distance;
        if (!save_trace(&entry->trace))
                return 0;
 
+       entry->class = this;
+       entry->distance = distance;
        /*
         * Since we never remove from the dependency list, the list can
         * be walked lockless by other CPUs, it's only allocation
@@ -932,7 +961,7 @@ static noinline int print_circular_bug_tail(void)
        if (debug_locks_silent)
                return 0;
 
-       this.class = check_source->class;
+       this.class = hlock_class(check_source);
        if (!save_trace(&this.trace))
                return 0;
 
@@ -959,6 +988,67 @@ static int noinline print_infinite_recursion_bug(void)
        return 0;
 }
 
+unsigned long __lockdep_count_forward_deps(struct lock_class *class,
+                                          unsigned int depth)
+{
+       struct lock_list *entry;
+       unsigned long ret = 1;
+
+       if (lockdep_dependency_visit(class, depth))
+               return 0;
+
+       /*
+        * Recurse this class's dependency list:
+        */
+       list_for_each_entry(entry, &class->locks_after, entry)
+               ret += __lockdep_count_forward_deps(entry->class, depth + 1);
+
+       return ret;
+}
+
+unsigned long lockdep_count_forward_deps(struct lock_class *class)
+{
+       unsigned long ret, flags;
+
+       local_irq_save(flags);
+       __raw_spin_lock(&lockdep_lock);
+       ret = __lockdep_count_forward_deps(class, 0);
+       __raw_spin_unlock(&lockdep_lock);
+       local_irq_restore(flags);
+
+       return ret;
+}
+
+unsigned long __lockdep_count_backward_deps(struct lock_class *class,
+                                           unsigned int depth)
+{
+       struct lock_list *entry;
+       unsigned long ret = 1;
+
+       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);
+
+       return ret;
+}
+
+unsigned long lockdep_count_backward_deps(struct lock_class *class)
+{
+       unsigned long ret, flags;
+
+       local_irq_save(flags);
+       __raw_spin_lock(&lockdep_lock);
+       ret = __lockdep_count_backward_deps(class, 0);
+       __raw_spin_unlock(&lockdep_lock);
+       local_irq_restore(flags);
+
+       return ret;
+}
+
 /*
  * Prove that the dependency graph starting at <entry> can not
  * lead to <target>. Print an error and return 0 if it does.
@@ -968,6 +1058,9 @@ check_noncircular(struct lock_class *source, unsigned int depth)
 {
        struct lock_list *entry;
 
+       if (lockdep_dependency_visit(source, depth))
+               return 1;
+
        debug_atomic_inc(&nr_cyclic_check_recursions);
        if (depth > max_recursion_depth)
                max_recursion_depth = depth;
@@ -977,7 +1070,7 @@ check_noncircular(struct lock_class *source, unsigned int depth)
         * Check this lock's dependency list:
         */
        list_for_each_entry(entry, &source->locks_after, entry) {
-               if (entry->class == check_target->class)
+               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))
@@ -1011,6 +1104,9 @@ find_usage_forwards(struct lock_class *source, unsigned int depth)
        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)
@@ -1050,6 +1146,9 @@ find_usage_backwards(struct lock_class *source, unsigned int depth)
        struct lock_list *entry;
        int ret;
 
+       if (lockdep_dependency_visit(source, depth))
+               return 1;
+
        if (!__raw_spin_is_locked(&lockdep_lock))
                return DEBUG_LOCKS_WARN_ON(1);
 
@@ -1064,6 +1163,11 @@ find_usage_backwards(struct lock_class *source, unsigned int depth)
                return 2;
        }
 
+       if (!source && debug_locks_off_graph_unlock()) {
+               WARN_ON(1);
+               return 0;
+       }
+
        /*
         * Check this lock's dependency list:
         */
@@ -1103,9 +1207,9 @@ print_bad_irq_dependency(struct task_struct *curr,
        printk("\nand this task is already holding:\n");
        print_lock(prev);
        printk("which would create a new lock dependency:\n");
-       print_lock_name(prev->class);
+       print_lock_name(hlock_class(prev));
        printk(" ->");
-       print_lock_name(next->class);
+       print_lock_name(hlock_class(next));
        printk("\n");
 
        printk("\nbut this new dependency connects a %s-irq-safe lock:\n",
@@ -1146,12 +1250,12 @@ check_usage(struct task_struct *curr, struct held_lock *prev,
 
        find_usage_bit = bit_backwards;
        /* fills in <backwards_match> */
-       ret = find_usage_backwards(prev->class, 0);
+       ret = find_usage_backwards(hlock_class(prev), 0);
        if (!ret || ret == 1)
                return ret;
 
        find_usage_bit = bit_forwards;
-       ret = find_usage_forwards(next->class, 0);
+       ret = find_usage_forwards(hlock_class(next), 0);
        if (!ret || ret == 1)
                return ret;
        /* ret == 2 */
@@ -1272,18 +1376,32 @@ check_deadlock(struct task_struct *curr, struct held_lock *next,
               struct lockdep_map *next_instance, int read)
 {
        struct held_lock *prev;
+       struct held_lock *nest = NULL;
        int i;
 
        for (i = 0; i < curr->lockdep_depth; i++) {
                prev = curr->held_locks + i;
-               if (prev->class != next->class)
+
+               if (prev->instance == next->nest_lock)
+                       nest = prev;
+
+               if (hlock_class(prev) != hlock_class(next))
                        continue;
+
                /*
                 * Allow read-after-read recursion of the same
                 * lock class (i.e. read_lock(lock)+read_lock(lock)):
                 */
                if ((read == 2) && prev->read)
                        return 2;
+
+               /*
+                * We're holding the nest_lock, which serializes this lock's
+                * nesting behaviour.
+                */
+               if (nest)
+                       return 2;
+
                return print_deadlock_bug(curr, prev, next);
        }
        return 1;
@@ -1329,7 +1447,7 @@ check_prev_add(struct task_struct *curr, struct held_lock *prev,
         */
        check_source = next;
        check_target = prev;
-       if (!(check_noncircular(next->class, 0)))
+       if (!(check_noncircular(hlock_class(next), 0)))
                return print_circular_bug_tail();
 
        if (!check_prev_add_irq(curr, prev, next))
@@ -1353,8 +1471,8 @@ check_prev_add(struct task_struct *curr, struct held_lock *prev,
         *  chains - the second one will be new, but L1 already has
         *  L2 added to its dependency list, due to the first chain.)
         */
-       list_for_each_entry(entry, &prev->class->locks_after, entry) {
-               if (entry->class == next->class) {
+       list_for_each_entry(entry, &hlock_class(prev)->locks_after, entry) {
+               if (entry->class == hlock_class(next)) {
                        if (distance == 1)
                                entry->distance = 1;
                        return 2;
@@ -1365,26 +1483,28 @@ check_prev_add(struct task_struct *curr, struct held_lock *prev,
         * Ok, all validations passed, add the new lock
         * to the previous lock's dependency list:
         */
-       ret = add_lock_to_list(prev->class, next->class,
-                              &prev->class->locks_after, next->acquire_ip, distance);
+       ret = add_lock_to_list(hlock_class(prev), hlock_class(next),
+                              &hlock_class(prev)->locks_after,
+                              next->acquire_ip, distance);
 
        if (!ret)
                return 0;
 
-       ret = add_lock_to_list(next->class, prev->class,
-                              &next->class->locks_before, next->acquire_ip, distance);
+       ret = add_lock_to_list(hlock_class(next), hlock_class(prev),
+                              &hlock_class(next)->locks_before,
+                              next->acquire_ip, distance);
        if (!ret)
                return 0;
 
        /*
         * Debugging printouts:
         */
-       if (verbose(prev->class) || verbose(next->class)) {
+       if (verbose(hlock_class(prev)) || verbose(hlock_class(next))) {
                graph_unlock();
                printk("\n new dependency: ");
-               print_lock_name(prev->class);
+               print_lock_name(hlock_class(prev));
                printk(" => ");
-               print_lock_name(next->class);
+               print_lock_name(hlock_class(next));
                printk("\n");
                dump_stack();
                return graph_lock();
@@ -1481,7 +1601,7 @@ static inline int lookup_chain_cache(struct task_struct *curr,
                                     struct held_lock *hlock,
                                     u64 chain_key)
 {
-       struct lock_class *class = hlock->class;
+       struct lock_class *class = hlock_class(hlock);
        struct list_head *hash_head = chainhashentry(chain_key);
        struct lock_chain *chain;
        struct held_lock *hlock_curr, *hlock_next;
@@ -1554,7 +1674,7 @@ cache_hit:
        if (likely(cn + chain->depth <= MAX_LOCKDEP_CHAIN_HLOCKS)) {
                chain->base = cn;
                for (j = 0; j < chain->depth - 1; j++, i++) {
-                       int lock_id = curr->held_locks[i].class - lock_classes;
+                       int lock_id = curr->held_locks[i].class_idx - 1;
                        chain_hlocks[chain->base + j] = lock_id;
                }
                chain_hlocks[chain->base + j] = class - lock_classes;
@@ -1643,14 +1763,13 @@ static void check_chain_key(struct task_struct *curr)
                hlock = curr->held_locks + i;
                if (chain_key != hlock->prev_chain_key) {
                        debug_locks_off();
-                       printk("hm#1, depth: %u [%u], %016Lx != %016Lx\n",
+                       WARN(1, "hm#1, depth: %u [%u], %016Lx != %016Lx\n",
                                curr->lockdep_depth, i,
                                (unsigned long long)chain_key,
                                (unsigned long long)hlock->prev_chain_key);
-                       WARN_ON(1);
                        return;
                }
-               id = hlock->class - lock_classes;
+               id = hlock->class_idx - 1;
                if (DEBUG_LOCKS_WARN_ON(id >= MAX_LOCKDEP_KEYS))
                        return;
 
@@ -1662,11 +1781,10 @@ static void check_chain_key(struct task_struct *curr)
        }
        if (chain_key != curr->curr_chain_key) {
                debug_locks_off();
-               printk("hm#2, depth: %u [%u], %016Lx != %016Lx\n",
+               WARN(1, "hm#2, depth: %u [%u], %016Lx != %016Lx\n",
                        curr->lockdep_depth, i,
                        (unsigned long long)chain_key,
                        (unsigned long long)curr->curr_chain_key);
-               WARN_ON(1);
        }
 #endif
 }
@@ -1695,7 +1813,7 @@ print_usage_bug(struct task_struct *curr, struct held_lock *this,
        print_lock(this);
 
        printk("{%s} state was registered at:\n", usage_str[prev_bit]);
-       print_stack_trace(this->class->usage_traces + prev_bit, 1);
+       print_stack_trace(hlock_class(this)->usage_traces + prev_bit, 1);
 
        print_irqtrace_events(curr);
        printk("\nother info that might help us debug this:\n");
@@ -1714,7 +1832,7 @@ static inline int
 valid_state(struct task_struct *curr, struct held_lock *this,
            enum lock_usage_bit new_bit, enum lock_usage_bit bad_bit)
 {
-       if (unlikely(this->class->usage_mask & (1 << bad_bit)))
+       if (unlikely(hlock_class(this)->usage_mask & (1 << bad_bit)))
                return print_usage_bug(curr, this, bad_bit, new_bit);
        return 1;
 }
@@ -1753,7 +1871,7 @@ print_irq_inversion_bug(struct task_struct *curr, struct lock_class *other,
        lockdep_print_held_locks(curr);
 
        printk("\nthe first lock's dependencies:\n");
-       print_lock_dependencies(this->class, 0);
+       print_lock_dependencies(hlock_class(this), 0);
 
        printk("\nthe second lock's dependencies:\n");
        print_lock_dependencies(other, 0);
@@ -1776,7 +1894,7 @@ check_usage_forwards(struct task_struct *curr, struct held_lock *this,
 
        find_usage_bit = bit;
        /* fills in <forwards_match> */
-       ret = find_usage_forwards(this->class, 0);
+       ret = find_usage_forwards(hlock_class(this), 0);
        if (!ret || ret == 1)
                return ret;
 
@@ -1795,7 +1913,7 @@ check_usage_backwards(struct task_struct *curr, struct held_lock *this,
 
        find_usage_bit = bit;
        /* fills in <backwards_match> */
-       ret = find_usage_backwards(this->class, 0);
+       ret = find_usage_backwards(hlock_class(this), 0);
        if (!ret || ret == 1)
                return ret;
 
@@ -1861,7 +1979,7 @@ static int mark_lock_irq(struct task_struct *curr, struct held_lock *this,
                                LOCK_ENABLED_HARDIRQS_READ, "hard-read"))
                        return 0;
 #endif
-               if (hardirq_verbose(this->class))
+               if (hardirq_verbose(hlock_class(this)))
                        ret = 2;
                break;
        case LOCK_USED_IN_SOFTIRQ:
@@ -1886,7 +2004,7 @@ static int mark_lock_irq(struct task_struct *curr, struct held_lock *this,
                                LOCK_ENABLED_SOFTIRQS_READ, "soft-read"))
                        return 0;
 #endif
-               if (softirq_verbose(this->class))
+               if (softirq_verbose(hlock_class(this)))
                        ret = 2;
                break;
        case LOCK_USED_IN_HARDIRQ_READ:
@@ -1899,7 +2017,7 @@ static int mark_lock_irq(struct task_struct *curr, struct held_lock *this,
                if (!check_usage_forwards(curr, this,
                                          LOCK_ENABLED_HARDIRQS, "hard"))
                        return 0;
-               if (hardirq_verbose(this->class))
+               if (hardirq_verbose(hlock_class(this)))
                        ret = 2;
                break;
        case LOCK_USED_IN_SOFTIRQ_READ:
@@ -1912,7 +2030,7 @@ static int mark_lock_irq(struct task_struct *curr, struct held_lock *this,
                if (!check_usage_forwards(curr, this,
                                          LOCK_ENABLED_SOFTIRQS, "soft"))
                        return 0;
-               if (softirq_verbose(this->class))
+               if (softirq_verbose(hlock_class(this)))
                        ret = 2;
                break;
        case LOCK_ENABLED_HARDIRQS:
@@ -1938,7 +2056,7 @@ static int mark_lock_irq(struct task_struct *curr, struct held_lock *this,
                                   LOCK_USED_IN_HARDIRQ_READ, "hard-read"))
                        return 0;
 #endif
-               if (hardirq_verbose(this->class))
+               if (hardirq_verbose(hlock_class(this)))
                        ret = 2;
                break;
        case LOCK_ENABLED_SOFTIRQS:
@@ -1964,7 +2082,7 @@ static int mark_lock_irq(struct task_struct *curr, struct held_lock *this,
                                   LOCK_USED_IN_SOFTIRQ_READ, "soft-read"))
                        return 0;
 #endif
-               if (softirq_verbose(this->class))
+               if (softirq_verbose(hlock_class(this)))
                        ret = 2;
                break;
        case LOCK_ENABLED_HARDIRQS_READ:
@@ -1979,7 +2097,7 @@ static int mark_lock_irq(struct task_struct *curr, struct held_lock *this,
                                           LOCK_USED_IN_HARDIRQ, "hard"))
                        return 0;
 #endif
-               if (hardirq_verbose(this->class))
+               if (hardirq_verbose(hlock_class(this)))
                        ret = 2;
                break;
        case LOCK_ENABLED_SOFTIRQS_READ:
@@ -1994,7 +2112,7 @@ static int mark_lock_irq(struct task_struct *curr, struct held_lock *this,
                                           LOCK_USED_IN_SOFTIRQ, "soft"))
                        return 0;
 #endif
-               if (softirq_verbose(this->class))
+               if (softirq_verbose(hlock_class(this)))
                        ret = 2;
                break;
        default:
@@ -2055,12 +2173,11 @@ void early_boot_irqs_on(void)
 /*
  * Hardirqs will be enabled:
  */
-void trace_hardirqs_on_caller(unsigned long a0)
+void trace_hardirqs_on_caller(unsigned long ip)
 {
        struct task_struct *curr = current;
-       unsigned long ip;
 
-       time_hardirqs_on(CALLER_ADDR0, a0);
+       time_hardirqs_on(CALLER_ADDR0, ip);
 
        if (unlikely(!debug_locks || current->lockdep_recursion))
                return;
@@ -2074,7 +2191,6 @@ void trace_hardirqs_on_caller(unsigned long a0)
        }
        /* we'll do an OFF -> ON transition: */
        curr->hardirqs_enabled = 1;
-       ip = (unsigned long) __builtin_return_address(0);
 
        if (DEBUG_LOCKS_WARN_ON(!irqs_disabled()))
                return;
@@ -2110,11 +2226,11 @@ EXPORT_SYMBOL(trace_hardirqs_on);
 /*
  * Hardirqs were disabled:
  */
-void trace_hardirqs_off_caller(unsigned long a0)
+void trace_hardirqs_off_caller(unsigned long ip)
 {
        struct task_struct *curr = current;
 
-       time_hardirqs_off(CALLER_ADDR0, a0);
+       time_hardirqs_off(CALLER_ADDR0, ip);
 
        if (unlikely(!debug_locks || current->lockdep_recursion))
                return;
@@ -2127,7 +2243,7 @@ void trace_hardirqs_off_caller(unsigned long a0)
                 * We have done an ON -> OFF transition:
                 */
                curr->hardirqs_enabled = 0;
-               curr->hardirq_disable_ip = _RET_IP_;
+               curr->hardirq_disable_ip = ip;
                curr->hardirq_disable_event = ++curr->irq_events;
                debug_atomic_inc(&hardirqs_off_events);
        } else
@@ -2310,7 +2426,7 @@ static int mark_lock(struct task_struct *curr, struct held_lock *this,
         * If already set then do not dirty the cacheline,
         * nor do any checks:
         */
-       if (likely(this->class->usage_mask & new_mask))
+       if (likely(hlock_class(this)->usage_mask & new_mask))
                return 1;
 
        if (!graph_lock())
@@ -2318,14 +2434,14 @@ static int mark_lock(struct task_struct *curr, struct held_lock *this,
        /*
         * Make sure we didnt race:
         */
-       if (unlikely(this->class->usage_mask & new_mask)) {
+       if (unlikely(hlock_class(this)->usage_mask & new_mask)) {
                graph_unlock();
                return 1;
        }
 
-       this->class->usage_mask |= new_mask;
+       hlock_class(this)->usage_mask |= new_mask;
 
-       if (!save_trace(this->class->usage_traces + new_bit))
+       if (!save_trace(hlock_class(this)->usage_traces + new_bit))
                return 0;
 
        switch (new_bit) {
@@ -2396,7 +2512,6 @@ void lockdep_init_map(struct lockdep_map *lock, const char *name,
        if (subclass)
                register_lock_class(lock, subclass, 1);
 }
-
 EXPORT_SYMBOL_GPL(lockdep_init_map);
 
 /*
@@ -2405,7 +2520,7 @@ 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,
-                         unsigned long ip)
+                         struct lockdep_map *nest_lock, unsigned long ip)
 {
        struct task_struct *curr = current;
        struct lock_class *class = NULL;
@@ -2459,14 +2574,16 @@ static int __lock_acquire(struct lockdep_map *lock, unsigned int subclass,
                return 0;
 
        hlock = curr->held_locks + depth;
-
-       hlock->class = class;
+       if (DEBUG_LOCKS_WARN_ON(!class))
+               return 0;
+       hlock->class_idx = class - lock_classes + 1;
        hlock->acquire_ip = ip;
        hlock->instance = lock;
+       hlock->nest_lock = nest_lock;
        hlock->trylock = trylock;
        hlock->read = read;
        hlock->check = check;
-       hlock->hardirqs_off = hardirqs_off;
+       hlock->hardirqs_off = !!hardirqs_off;
 #ifdef CONFIG_LOCK_STAT
        hlock->waittime_stamp = 0;
        hlock->holdtime_stamp = sched_clock();
@@ -2574,6 +2691,57 @@ static int check_unlock(struct task_struct *curr, struct lockdep_map *lock,
        return 1;
 }
 
+static int
+__lock_set_class(struct lockdep_map *lock, const char *name,
+                struct lock_class_key *key, unsigned int subclass,
+                unsigned long ip)
+{
+       struct task_struct *curr = current;
+       struct held_lock *hlock, *prev_hlock;
+       struct lock_class *class;
+       unsigned int depth;
+       int i;
+
+       depth = curr->lockdep_depth;
+       if (DEBUG_LOCKS_WARN_ON(!depth))
+               return 0;
+
+       prev_hlock = NULL;
+       for (i = depth-1; i >= 0; i--) {
+               hlock = curr->held_locks + i;
+               /*
+                * We must not cross into another context:
+                */
+               if (prev_hlock && prev_hlock->irq_context != hlock->irq_context)
+                       break;
+               if (hlock->instance == lock)
+                       goto found_it;
+               prev_hlock = hlock;
+       }
+       return print_unlock_inbalance_bug(curr, lock, ip);
+
+found_it:
+       lockdep_init_map(lock, name, key, 0);
+       class = register_lock_class(lock, subclass, 0);
+       hlock->class_idx = class - lock_classes + 1;
+
+       curr->lockdep_depth = i;
+       curr->curr_chain_key = hlock->prev_chain_key;
+
+       for (; i < depth; i++) {
+               hlock = curr->held_locks + i;
+               if (!__lock_acquire(hlock->instance,
+                       hlock_class(hlock)->subclass, hlock->trylock,
+                               hlock->read, hlock->check, hlock->hardirqs_off,
+                               hlock->nest_lock, hlock->acquire_ip))
+                       return 0;
+       }
+
+       if (DEBUG_LOCKS_WARN_ON(curr->lockdep_depth != depth))
+               return 0;
+       return 1;
+}
+
 /*
  * Remove the lock to the list of currently held locks in a
  * potentially non-nested (out of order) manner. This is a
@@ -2624,9 +2792,9 @@ found_it:
        for (i++; i < depth; i++) {
                hlock = curr->held_locks + i;
                if (!__lock_acquire(hlock->instance,
-                       hlock->class->subclass, hlock->trylock,
+                       hlock_class(hlock)->subclass, hlock->trylock,
                                hlock->read, hlock->check, hlock->hardirqs_off,
-                               hlock->acquire_ip))
+                               hlock->nest_lock, hlock->acquire_ip))
                        return 0;
        }
 
@@ -2669,7 +2837,7 @@ static int lock_release_nested(struct task_struct *curr,
 
 #ifdef CONFIG_DEBUG_LOCKDEP
        hlock->prev_chain_key = 0;
-       hlock->class = NULL;
+       hlock->class_idx = 0;
        hlock->acquire_ip = 0;
        hlock->irq_context = 0;
 #endif
@@ -2738,18 +2906,35 @@ static void check_flags(unsigned long flags)
 #endif
 }
 
+void lock_set_class(struct lockdep_map *lock, const char *name,
+                   struct lock_class_key *key, unsigned int subclass,
+                   unsigned long ip)
+{
+       unsigned long flags;
+
+       if (unlikely(current->lockdep_recursion))
+               return;
+
+       raw_local_irq_save(flags);
+       current->lockdep_recursion = 1;
+       check_flags(flags);
+       if (__lock_set_class(lock, name, key, subclass, ip))
+               check_chain_key(current);
+       current->lockdep_recursion = 0;
+       raw_local_irq_restore(flags);
+}
+EXPORT_SYMBOL_GPL(lock_set_class);
+
 /*
  * We are not always called with irqs disabled - do that here,
  * and also avoid lockdep recursion:
  */
 void lock_acquire(struct lockdep_map *lock, unsigned int subclass,
-                         int trylock, int read, int check, unsigned long ip)
+                         int trylock, int read, int check,
+                         struct lockdep_map *nest_lock, unsigned long ip)
 {
        unsigned long flags;
 
-       if (unlikely(!lock_stat && !prove_locking))
-               return;
-
        if (unlikely(current->lockdep_recursion))
                return;
 
@@ -2758,11 +2943,10 @@ 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), ip);
+                      irqs_disabled_flags(flags), nest_lock, ip);
        current->lockdep_recursion = 0;
        raw_local_irq_restore(flags);
 }
-
 EXPORT_SYMBOL_GPL(lock_acquire);
 
 void lock_release(struct lockdep_map *lock, int nested,
@@ -2770,9 +2954,6 @@ void lock_release(struct lockdep_map *lock, int nested,
 {
        unsigned long flags;
 
-       if (unlikely(!lock_stat && !prove_locking))
-               return;
-
        if (unlikely(current->lockdep_recursion))
                return;
 
@@ -2783,7 +2964,6 @@ void lock_release(struct lockdep_map *lock, int nested,
        current->lockdep_recursion = 0;
        raw_local_irq_restore(flags);
 }
-
 EXPORT_SYMBOL_GPL(lock_release);
 
 #ifdef CONFIG_LOCK_STAT
@@ -2821,7 +3001,7 @@ __lock_contended(struct lockdep_map *lock, unsigned long ip)
        struct held_lock *hlock, *prev_hlock;
        struct lock_class_stats *stats;
        unsigned int depth;
-       int i, point;
+       int i, contention_point, contending_point;
 
        depth = curr->lockdep_depth;
        if (DEBUG_LOCKS_WARN_ON(!depth))
@@ -2845,18 +3025,22 @@ __lock_contended(struct lockdep_map *lock, unsigned long ip)
 found_it:
        hlock->waittime_stamp = sched_clock();
 
-       point = lock_contention_point(hlock->class, ip);
+       contention_point = lock_point(hlock_class(hlock)->contention_point, ip);
+       contending_point = lock_point(hlock_class(hlock)->contending_point,
+                                     lock->ip);
 
-       stats = get_lock_stats(hlock->class);
-       if (point < ARRAY_SIZE(stats->contention_point))
-               stats->contention_point[i]++;
+       stats = get_lock_stats(hlock_class(hlock));
+       if (contention_point < LOCKSTAT_POINTS)
+               stats->contention_point[contention_point]++;
+       if (contending_point < LOCKSTAT_POINTS)
+               stats->contending_point[contending_point]++;
        if (lock->cpu != smp_processor_id())
                stats->bounces[bounce_contended + !!hlock->read]++;
        put_lock_stats(stats);
 }
 
 static void
-__lock_acquired(struct lockdep_map *lock)
+__lock_acquired(struct lockdep_map *lock, unsigned long ip)
 {
        struct task_struct *curr = current;
        struct held_lock *hlock, *prev_hlock;
@@ -2893,7 +3077,7 @@ found_it:
                hlock->holdtime_stamp = now;
        }
 
-       stats = get_lock_stats(hlock->class);
+       stats = get_lock_stats(hlock_class(hlock));
        if (waittime) {
                if (hlock->read)
                        lock_time_inc(&stats->read_waittime, waittime);
@@ -2905,6 +3089,7 @@ found_it:
        put_lock_stats(stats);
 
        lock->cpu = cpu;
+       lock->ip = ip;
 }
 
 void lock_contended(struct lockdep_map *lock, unsigned long ip)
@@ -2926,7 +3111,7 @@ void lock_contended(struct lockdep_map *lock, unsigned long ip)
 }
 EXPORT_SYMBOL_GPL(lock_contended);
 
-void lock_acquired(struct lockdep_map *lock)
+void lock_acquired(struct lockdep_map *lock, unsigned long ip)
 {
        unsigned long flags;
 
@@ -2939,7 +3124,7 @@ void lock_acquired(struct lockdep_map *lock)
        raw_local_irq_save(flags);
        check_flags(flags);
        current->lockdep_recursion = 1;
-       __lock_acquired(lock);
+       __lock_acquired(lock, ip);
        current->lockdep_recursion = 0;
        raw_local_irq_restore(flags);
 }
@@ -2988,6 +3173,7 @@ static void zap_class(struct lock_class *class)
        list_del_rcu(&class->hash_entry);
        list_del_rcu(&class->lock_entry);
 
+       class->key = NULL;
 }
 
 static inline int within(const void *addr, void *start, unsigned long size)
@@ -3097,10 +3283,10 @@ void __init lockdep_info(void)
 {
        printk("Lock dependency validator: Copyright (c) 2006 Red Hat, Inc., Ingo Molnar\n");
 
-       printk("... MAX_LOCKDEP_SUBCLASSES:    %lu\n", MAX_LOCKDEP_SUBCLASSES);
+       printk("... MAX_LOCKDEP_SUBCLASSES:  %lu\n", MAX_LOCKDEP_SUBCLASSES);
        printk("... MAX_LOCK_DEPTH:          %lu\n", MAX_LOCK_DEPTH);
        printk("... MAX_LOCKDEP_KEYS:        %lu\n", MAX_LOCKDEP_KEYS);
-       printk("... CLASSHASH_SIZE:           %lu\n", CLASSHASH_SIZE);
+       printk("... CLASSHASH_SIZE:          %lu\n", CLASSHASH_SIZE);
        printk("... MAX_LOCKDEP_ENTRIES:     %lu\n", MAX_LOCKDEP_ENTRIES);
        printk("... MAX_LOCKDEP_CHAINS:      %lu\n", MAX_LOCKDEP_CHAINS);
        printk("... CHAINHASH_SIZE:          %lu\n", CHAINHASH_SIZE);
@@ -3236,9 +3422,10 @@ retry:
                }
                printk(" ignoring it.\n");
                unlock = 0;
+       } else {
+               if (count != 10)
+                       printk(KERN_CONT " locked it.\n");
        }
-       if (count != 10)
-               printk(" locked it.\n");
 
        do_each_thread(g, p) {
                /*
@@ -3261,7 +3448,6 @@ retry:
        if (unlock)
                read_unlock(&tasklist_lock);
 }
-
 EXPORT_SYMBOL_GPL(debug_show_all_locks);
 
 /*
@@ -3282,7 +3468,6 @@ void debug_show_held_locks(struct task_struct *task)
 {
                __debug_show_held_locks(task);
 }
-
 EXPORT_SYMBOL_GPL(debug_show_held_locks);
 
 void lockdep_sys_exit(void)