Merge tag 'core-debugobjects-2023-05-28' of git://git.kernel.org/pub/scm/linux/kernel...
authorLinus Torvalds <torvalds@linux-foundation.org>
Sun, 28 May 2023 11:15:33 +0000 (07:15 -0400)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sun, 28 May 2023 11:15:33 +0000 (07:15 -0400)
Pull debugobjects fixes from Thomas Gleixner:
 "Two fixes for debugobjects:

   - Prevent the allocation path from waking up kswapd.

     That's a long standing issue due to the GFP_ATOMIC allocation flag.
     As debug objects can be invoked from pretty much any context waking
     kswapd can end up in arbitrary lock chains versus the waitqueue
     lock

   - Correct the explicit lockdep wait-type violation in
     debug_object_fill_pool()"

* tag 'core-debugobjects-2023-05-28' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  debugobjects: Don't wake up kswapd from fill_pool()
  debugobjects,locking: Annotate debug_object_fill_pool() wait type violation

1  2 
include/linux/lockdep.h
kernel/locking/lockdep.c

diff --combined include/linux/lockdep.h
@@@ -134,8 -134,7 +134,8 @@@ struct held_lock 
        unsigned int read:2;        /* see lock_acquire() comment */
        unsigned int check:1;       /* see lock_acquire() comment */
        unsigned int hardirqs_off:1;
 -      unsigned int references:12;                                     /* 32 bits */
 +      unsigned int sync:1;
 +      unsigned int references:11;                                     /* 32 bits */
        unsigned int pin_count;
  };
  
@@@ -269,10 -268,6 +269,10 @@@ extern void lock_acquire(struct lockdep
  
  extern void lock_release(struct lockdep_map *lock, unsigned long ip);
  
 +extern void lock_sync(struct lockdep_map *lock, unsigned int subclass,
 +                    int read, int check, struct lockdep_map *nest_lock,
 +                    unsigned long ip);
 +
  /* lock_is_held_type() returns */
  #define LOCK_STATE_UNKNOWN    -1
  #define LOCK_STATE_NOT_HELD   0
@@@ -344,6 -339,16 +344,16 @@@ extern void lock_unpin_lock(struct lock
  #define lockdep_repin_lock(l,c)       lock_repin_lock(&(l)->dep_map, (c))
  #define lockdep_unpin_lock(l,c)       lock_unpin_lock(&(l)->dep_map, (c))
  
+ /*
+  * Must use lock_map_aquire_try() with override maps to avoid
+  * lockdep thinking they participate in the block chain.
+  */
+ #define DEFINE_WAIT_OVERRIDE_MAP(_name, _wait_type)   \
+       struct lockdep_map _name = {                    \
+               .name = #_name "-wait-type-override",   \
+               .wait_type_inner = _wait_type,          \
+               .lock_type = LD_LOCK_WAIT_OVERRIDE, }
  #else /* !CONFIG_LOCKDEP */
  
  static inline void lockdep_init_task(struct task_struct *task)
@@@ -432,6 -437,9 +442,9 @@@ extern int lockdep_is_held(const void *
  #define lockdep_repin_lock(l, c)              do { (void)(l); (void)(c); } while (0)
  #define lockdep_unpin_lock(l, c)              do { (void)(l); (void)(c); } while (0)
  
+ #define DEFINE_WAIT_OVERRIDE_MAP(_name, _wait_type)   \
+       struct lockdep_map __maybe_unused _name = {}
  #endif /* !LOCKDEP */
  
  enum xhlock_context_t {
@@@ -556,10 -564,10 +569,11 @@@ do {                                                                    
  #define rwsem_release(l, i)                   lock_release(l, i)
  
  #define lock_map_acquire(l)                   lock_acquire_exclusive(l, 0, 0, NULL, _THIS_IP_)
+ #define lock_map_acquire_try(l)                       lock_acquire_exclusive(l, 0, 1, NULL, _THIS_IP_)
  #define lock_map_acquire_read(l)              lock_acquire_shared_recursive(l, 0, 0, NULL, _THIS_IP_)
  #define lock_map_acquire_tryread(l)           lock_acquire_shared_recursive(l, 0, 1, NULL, _THIS_IP_)
  #define lock_map_release(l)                   lock_release(l, _THIS_IP_)
 +#define lock_map_sync(l)                      lock_sync(l, 0, 0, 1, NULL, _THIS_IP_)
  
  #ifdef CONFIG_PROVE_LOCKING
  # define might_lock(lock)                                             \
diff --combined kernel/locking/lockdep.c
@@@ -1881,8 -1881,6 +1881,8 @@@ print_circular_lock_scenario(struct hel
        struct lock_class *source = hlock_class(src);
        struct lock_class *target = hlock_class(tgt);
        struct lock_class *parent = prt->class;
 +      int src_read = src->read;
 +      int tgt_read = tgt->read;
  
        /*
         * A direct locking problem where unsafe_class lock is taken
        printk(" Possible unsafe locking scenario:\n\n");
        printk("       CPU0                    CPU1\n");
        printk("       ----                    ----\n");
 -      printk("  lock(");
 +      if (tgt_read != 0)
 +              printk("  rlock(");
 +      else
 +              printk("  lock(");
        __print_lock_name(target);
        printk(KERN_CONT ");\n");
        printk("                               lock(");
        printk("                               lock(");
        __print_lock_name(target);
        printk(KERN_CONT ");\n");
 -      printk("  lock(");
 +      if (src_read != 0)
 +              printk("  rlock(");
 +      else if (src->sync)
 +              printk("  sync(");
 +      else
 +              printk("  lock(");
        __print_lock_name(source);
        printk(KERN_CONT ");\n");
        printk("\n *** DEADLOCK ***\n\n");
@@@ -2263,6 -2253,9 +2263,9 @@@ static inline bool usage_match(struct l
  
  static inline bool usage_skip(struct lock_list *entry, void *mask)
  {
+       if (entry->class->lock_type == LD_LOCK_NORMAL)
+               return false;
        /*
         * Skip local_lock() for irq inversion detection.
         *
         * As a result, we will skip local_lock(), when we search for irq
         * inversion bugs.
         */
-       if (entry->class->lock_type == LD_LOCK_PERCPU) {
-               if (DEBUG_LOCKS_WARN_ON(entry->class->wait_type_inner < LD_WAIT_CONFIG))
-                       return false;
+       if (entry->class->lock_type == LD_LOCK_PERCPU &&
+           DEBUG_LOCKS_WARN_ON(entry->class->wait_type_inner < LD_WAIT_CONFIG))
+               return false;
  
-               return true;
-       }
+       /*
+        * Skip WAIT_OVERRIDE for irq inversion detection -- it's not actually
+        * a lock and only used to override the wait_type.
+        */
  
-       return false;
+       return true;
  }
  
  /*
@@@ -4541,13 -4536,7 +4546,13 @@@ mark_usage(struct task_struct *curr, st
                                        return 0;
                }
        }
 -      if (!hlock->hardirqs_off) {
 +
 +      /*
 +       * For lock_sync(), don't mark the ENABLED usage, since lock_sync()
 +       * creates no critical section and no extra dependency can be introduced
 +       * by interrupts
 +       */
 +      if (!hlock->hardirqs_off && !hlock->sync) {
                if (hlock->read) {
                        if (!mark_lock(curr, hlock,
                                        LOCK_ENABLED_HARDIRQ_READ))
@@@ -4768,7 -4757,8 +4773,8 @@@ static int check_wait_context(struct ta
  
        for (; depth < curr->lockdep_depth; depth++) {
                struct held_lock *prev = curr->held_locks + depth;
-               u8 prev_inner = hlock_class(prev)->wait_type_inner;
+               struct lock_class *class = hlock_class(prev);
+               u8 prev_inner = class->wait_type_inner;
  
                if (prev_inner) {
                        /*
                         * Also due to trylocks.
                         */
                        curr_inner = min(curr_inner, prev_inner);
+                       /*
+                        * Allow override for annotations -- this is typically
+                        * only valid/needed for code that only exists when
+                        * CONFIG_PREEMPT_RT=n.
+                        */
+                       if (unlikely(class->lock_type == LD_LOCK_WAIT_OVERRIDE))
+                               curr_inner = prev_inner;
                }
        }
  
@@@ -4926,7 -4924,7 +4940,7 @@@ static int __lock_is_held(const struct 
  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,
 -                        int references, int pin_count)
 +                        int references, int pin_count, int sync)
  {
        struct task_struct *curr = current;
        struct lock_class *class = NULL;
  
        class_idx = class - lock_classes;
  
 -      if (depth) { /* we're holding locks */
 +      if (depth && !sync) {
 +              /* we're holding locks and the new held lock is not a sync */
                hlock = curr->held_locks + depth - 1;
                if (hlock->class_idx == class_idx && nest_lock) {
                        if (!references)
        hlock->trylock = trylock;
        hlock->read = read;
        hlock->check = check;
 +      hlock->sync = !!sync;
        hlock->hardirqs_off = !!hardirqs_off;
        hlock->references = references;
  #ifdef CONFIG_LOCK_STAT
        if (!validate_chain(curr, hlock, chain_head, chain_key))
                return 0;
  
 +      /* For lock_sync(), we are done here since no actual critical section */
 +      if (hlock->sync)
 +              return 1;
 +
        curr->curr_chain_key = chain_key;
        curr->lockdep_depth++;
        check_chain_key(curr);
@@@ -5219,7 -5211,7 +5233,7 @@@ static int reacquire_held_locks(struct 
                                    hlock->read, hlock->check,
                                    hlock->hardirqs_off,
                                    hlock->nest_lock, hlock->acquire_ip,
 -                                  hlock->references, hlock->pin_count)) {
 +                                  hlock->references, hlock->pin_count, 0)) {
                case 0:
                        return 1;
                case 1:
@@@ -5689,7 -5681,7 +5703,7 @@@ void lock_acquire(struct lockdep_map *l
  
        lockdep_recursion_inc();
        __lock_acquire(lock, subclass, trylock, read, check,
 -                     irqs_disabled_flags(flags), nest_lock, ip, 0, 0);
 +                     irqs_disabled_flags(flags), nest_lock, ip, 0, 0, 0);
        lockdep_recursion_finish();
        raw_local_irq_restore(flags);
  }
@@@ -5715,34 -5707,6 +5729,34 @@@ void lock_release(struct lockdep_map *l
  }
  EXPORT_SYMBOL_GPL(lock_release);
  
 +/*
 + * lock_sync() - A special annotation for synchronize_{s,}rcu()-like API.
 + *
 + * No actual critical section is created by the APIs annotated with this: these
 + * APIs are used to wait for one or multiple critical sections (on other CPUs
 + * or threads), and it means that calling these APIs inside these critical
 + * sections is potential deadlock.
 + */
 +void lock_sync(struct lockdep_map *lock, unsigned subclass, int read,
 +             int check, struct lockdep_map *nest_lock, unsigned long ip)
 +{
 +      unsigned long flags;
 +
 +      if (unlikely(!lockdep_enabled()))
 +              return;
 +
 +      raw_local_irq_save(flags);
 +      check_flags(flags);
 +
 +      lockdep_recursion_inc();
 +      __lock_acquire(lock, subclass, 0, read, check,
 +                     irqs_disabled_flags(flags), nest_lock, ip, 0, 0, 1);
 +      check_chain_key(current);
 +      lockdep_recursion_finish();
 +      raw_local_irq_restore(flags);
 +}
 +EXPORT_SYMBOL_GPL(lock_sync);
 +
  noinstr int lock_is_held_type(const struct lockdep_map *lock, int read)
  {
        unsigned long flags;