locking/lockdep: Rework lockdep_lock
authorPeter Zijlstra <peterz@infradead.org>
Fri, 13 Mar 2020 10:09:49 +0000 (11:09 +0100)
committerPeter Zijlstra <peterz@infradead.org>
Fri, 20 Mar 2020 12:06:25 +0000 (13:06 +0100)
A few sites want to assert we own the graph_lock/lockdep_lock, provide
a more conventional lock interface for it with a number of trivial
debug checks.

Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Link: https://lkml.kernel.org/r/20200313102107.GX12561@hirez.programming.kicks-ass.net
kernel/locking/lockdep.c

index 64ea69f..47e3acb 100644 (file)
@@ -84,12 +84,39 @@ module_param(lock_stat, int, 0644);
  * to use a raw spinlock - we really dont want the spinlock
  * code to recurse back into the lockdep code...
  */
-static arch_spinlock_t lockdep_lock = (arch_spinlock_t)__ARCH_SPIN_LOCK_UNLOCKED;
+static arch_spinlock_t __lock = (arch_spinlock_t)__ARCH_SPIN_LOCK_UNLOCKED;
+static struct task_struct *__owner;
+
+static inline void lockdep_lock(void)
+{
+       DEBUG_LOCKS_WARN_ON(!irqs_disabled());
+
+       arch_spin_lock(&__lock);
+       __owner = current;
+       current->lockdep_recursion++;
+}
+
+static inline void lockdep_unlock(void)
+{
+       if (debug_locks && DEBUG_LOCKS_WARN_ON(__owner != current))
+               return;
+
+       current->lockdep_recursion--;
+       __owner = NULL;
+       arch_spin_unlock(&__lock);
+}
+
+static inline bool lockdep_assert_locked(void)
+{
+       return DEBUG_LOCKS_WARN_ON(__owner != current);
+}
+
 static struct task_struct *lockdep_selftest_task_struct;
 
+
 static int graph_lock(void)
 {
-       arch_spin_lock(&lockdep_lock);
+       lockdep_lock();
        /*
         * Make sure that if another CPU detected a bug while
         * walking the graph we dont change it (while the other
@@ -97,27 +124,15 @@ static int graph_lock(void)
         * dropped already)
         */
        if (!debug_locks) {
-               arch_spin_unlock(&lockdep_lock);
+               lockdep_unlock();
                return 0;
        }
-       /* prevent any recursions within lockdep from causing deadlocks */
-       current->lockdep_recursion++;
        return 1;
 }
 
-static inline int graph_unlock(void)
+static inline void graph_unlock(void)
 {
-       if (debug_locks && !arch_spin_is_locked(&lockdep_lock)) {
-               /*
-                * The lockdep graph lock isn't locked while we expect it to
-                * be, we're confused now, bye!
-                */
-               return DEBUG_LOCKS_WARN_ON(1);
-       }
-
-       current->lockdep_recursion--;
-       arch_spin_unlock(&lockdep_lock);
-       return 0;
+       lockdep_unlock();
 }
 
 /*
@@ -128,7 +143,7 @@ static inline int debug_locks_off_graph_unlock(void)
 {
        int ret = debug_locks_off();
 
-       arch_spin_unlock(&lockdep_lock);
+       lockdep_unlock();
 
        return ret;
 }
@@ -1479,6 +1494,8 @@ static int __bfs(struct lock_list *source_entry,
        struct circular_queue *cq = &lock_cq;
        int ret = 1;
 
+       lockdep_assert_locked();
+
        if (match(source_entry, data)) {
                *target_entry = source_entry;
                ret = 0;
@@ -1501,8 +1518,6 @@ static int __bfs(struct lock_list *source_entry,
 
                head = get_dep_list(lock, offset);
 
-               DEBUG_LOCKS_WARN_ON(!irqs_disabled());
-
                list_for_each_entry_rcu(entry, head, entry) {
                        if (!lock_accessed(entry)) {
                                unsigned int cq_depth;
@@ -1729,11 +1744,9 @@ unsigned long lockdep_count_forward_deps(struct lock_class *class)
        this.class = class;
 
        raw_local_irq_save(flags);
-       current->lockdep_recursion++;
-       arch_spin_lock(&lockdep_lock);
+       lockdep_lock();
        ret = __lockdep_count_forward_deps(&this);
-       arch_spin_unlock(&lockdep_lock);
-       current->lockdep_recursion--;
+       lockdep_unlock();
        raw_local_irq_restore(flags);
 
        return ret;
@@ -1758,11 +1771,9 @@ unsigned long lockdep_count_backward_deps(struct lock_class *class)
        this.class = class;
 
        raw_local_irq_save(flags);
-       current->lockdep_recursion++;
-       arch_spin_lock(&lockdep_lock);
+       lockdep_lock();
        ret = __lockdep_count_backward_deps(&this);
-       arch_spin_unlock(&lockdep_lock);
-       current->lockdep_recursion--;
+       lockdep_unlock();
        raw_local_irq_restore(flags);
 
        return ret;
@@ -3046,7 +3057,7 @@ static inline int add_chain_cache(struct task_struct *curr,
         * disabled to make this an IRQ-safe lock.. for recursion reasons
         * lockdep won't complain about its own locking errors.
         */
-       if (DEBUG_LOCKS_WARN_ON(!irqs_disabled()))
+       if (lockdep_assert_locked())
                return 0;
 
        chain = alloc_lock_chain();
@@ -5181,8 +5192,7 @@ static void free_zapped_rcu(struct rcu_head *ch)
                return;
 
        raw_local_irq_save(flags);
-       arch_spin_lock(&lockdep_lock);
-       current->lockdep_recursion++;
+       lockdep_lock();
 
        /* closed head */
        pf = delayed_free.pf + (delayed_free.index ^ 1);
@@ -5194,8 +5204,7 @@ static void free_zapped_rcu(struct rcu_head *ch)
         */
        call_rcu_zapped(delayed_free.pf + delayed_free.index);
 
-       current->lockdep_recursion--;
-       arch_spin_unlock(&lockdep_lock);
+       lockdep_unlock();
        raw_local_irq_restore(flags);
 }
 
@@ -5240,13 +5249,11 @@ static void lockdep_free_key_range_reg(void *start, unsigned long size)
        init_data_structures_once();
 
        raw_local_irq_save(flags);
-       arch_spin_lock(&lockdep_lock);
-       current->lockdep_recursion++;
+       lockdep_lock();
        pf = get_pending_free();
        __lockdep_free_key_range(pf, start, size);
        call_rcu_zapped(pf);
-       current->lockdep_recursion--;
-       arch_spin_unlock(&lockdep_lock);
+       lockdep_unlock();
        raw_local_irq_restore(flags);
 
        /*
@@ -5268,10 +5275,10 @@ static void lockdep_free_key_range_imm(void *start, unsigned long size)
        init_data_structures_once();
 
        raw_local_irq_save(flags);
-       arch_spin_lock(&lockdep_lock);
+       lockdep_lock();
        __lockdep_free_key_range(pf, start, size);
        __free_zapped_classes(pf);
-       arch_spin_unlock(&lockdep_lock);
+       lockdep_unlock();
        raw_local_irq_restore(flags);
 }
 
@@ -5367,10 +5374,10 @@ static void lockdep_reset_lock_imm(struct lockdep_map *lock)
        unsigned long flags;
 
        raw_local_irq_save(flags);
-       arch_spin_lock(&lockdep_lock);
+       lockdep_lock();
        __lockdep_reset_lock(pf, lock);
        __free_zapped_classes(pf);
-       arch_spin_unlock(&lockdep_lock);
+       lockdep_unlock();
        raw_local_irq_restore(flags);
 }