OSDN Git Service

Merge branch 'x86/build' into locking/core, to pick up dependent patches and unify...
authorIngo Molnar <mingo@kernel.org>
Tue, 16 Oct 2018 15:30:11 +0000 (17:30 +0200)
committerIngo Molnar <mingo@kernel.org>
Tue, 16 Oct 2018 15:30:11 +0000 (17:30 +0200)
Signed-off-by: Ingo Molnar <mingo@kernel.org>
22 files changed:
Documentation/locking/lockstat.txt
Documentation/memory-barriers.txt
include/asm-generic/qrwlock.h
include/asm-generic/qspinlock.h
include/linux/lockdep.h
include/linux/rwsem.h
kernel/cpu.c
kernel/futex.c
kernel/jump_label.c
kernel/locking/lockdep.c
kernel/locking/lockdep_internals.h
kernel/locking/lockdep_proc.c
kernel/locking/rtmutex.c
kernel/locking/rwsem-xadd.c
kernel/locking/rwsem.c
kernel/locking/rwsem.h
tools/memory-model/Documentation/explanation.txt
tools/memory-model/Documentation/recipes.txt
tools/memory-model/README
tools/memory-model/linux-kernel.cat
tools/memory-model/litmus-tests/ISA2+pooncelock+pooncelock+pombonce.litmus
tools/memory-model/litmus-tests/README

index 5786ad2..fdbeb0c 100644 (file)
@@ -91,7 +91,7 @@ Look at the current lock statistics:
 07                         &mm->mmap_sem-R:            37            100           1.31      299502.61      325629.52        3256.30         212344       34316685           0.10        7744.91    95016910.20           2.77
 08                         ---------------
 09                           &mm->mmap_sem              1          [<ffffffff811502a7>] khugepaged_scan_mm_slot+0x57/0x280
-19                           &mm->mmap_sem             96          [<ffffffff815351c4>] __do_page_fault+0x1d4/0x510
+10                           &mm->mmap_sem             96          [<ffffffff815351c4>] __do_page_fault+0x1d4/0x510
 11                           &mm->mmap_sem             34          [<ffffffff81113d77>] vm_mmap_pgoff+0x87/0xd0
 12                           &mm->mmap_sem             17          [<ffffffff81127e71>] vm_munmap+0x41/0x80
 13                         ---------------
index 0d8d7ef..c1d9139 100644 (file)
@@ -471,8 +471,7 @@ And a couple of implicit varieties:
      operations after the ACQUIRE operation will appear to happen after the
      ACQUIRE operation with respect to the other components of the system.
      ACQUIRE operations include LOCK operations and both smp_load_acquire()
-     and smp_cond_acquire() operations. The later builds the necessary ACQUIRE
-     semantics from relying on a control dependency and smp_rmb().
+     and smp_cond_load_acquire() operations.
 
      Memory operations that occur before an ACQUIRE operation may appear to
      happen after it completes.
index 0f7062b..36254d2 100644 (file)
@@ -71,8 +71,8 @@ static inline int queued_write_trylock(struct qrwlock *lock)
        if (unlikely(cnts))
                return 0;
 
-       return likely(atomic_cmpxchg_acquire(&lock->cnts,
-                                            cnts, cnts | _QW_LOCKED) == cnts);
+       return likely(atomic_try_cmpxchg_acquire(&lock->cnts, &cnts,
+                               _QW_LOCKED));
 }
 /**
  * queued_read_lock - acquire read lock of a queue rwlock
@@ -96,8 +96,9 @@ static inline void queued_read_lock(struct qrwlock *lock)
  */
 static inline void queued_write_lock(struct qrwlock *lock)
 {
+       u32 cnts = 0;
        /* Optimize for the unfair lock case where the fair flag is 0. */
-       if (atomic_cmpxchg_acquire(&lock->cnts, 0, _QW_LOCKED) == 0)
+       if (likely(atomic_try_cmpxchg_acquire(&lock->cnts, &cnts, _QW_LOCKED)))
                return;
 
        queued_write_lock_slowpath(lock);
index 9cc4575..7541fa7 100644 (file)
@@ -66,10 +66,12 @@ static __always_inline int queued_spin_is_contended(struct qspinlock *lock)
  */
 static __always_inline int queued_spin_trylock(struct qspinlock *lock)
 {
-       if (!atomic_read(&lock->val) &&
-          (atomic_cmpxchg_acquire(&lock->val, 0, _Q_LOCKED_VAL) == 0))
-               return 1;
-       return 0;
+       u32 val = atomic_read(&lock->val);
+
+       if (unlikely(val))
+               return 0;
+
+       return likely(atomic_try_cmpxchg_acquire(&lock->val, &val, _Q_LOCKED_VAL));
 }
 
 extern void queued_spin_lock_slowpath(struct qspinlock *lock, u32 val);
@@ -80,11 +82,11 @@ extern void queued_spin_lock_slowpath(struct qspinlock *lock, u32 val);
  */
 static __always_inline void queued_spin_lock(struct qspinlock *lock)
 {
-       u32 val;
+       u32 val = 0;
 
-       val = atomic_cmpxchg_acquire(&lock->val, 0, _Q_LOCKED_VAL);
-       if (likely(val == 0))
+       if (likely(atomic_try_cmpxchg_acquire(&lock->val, &val, _Q_LOCKED_VAL)))
                return;
+
        queued_spin_lock_slowpath(lock, val);
 }
 
index b0d0b51..1fd82ff 100644 (file)
@@ -99,13 +99,8 @@ struct lock_class {
         */
        unsigned int                    version;
 
-       /*
-        * Statistics counter:
-        */
-       unsigned long                   ops;
-
-       const char                      *name;
        int                             name_version;
+       const char                      *name;
 
 #ifdef CONFIG_LOCK_STAT
        unsigned long                   contention_point[LOCKSTAT_POINTS];
index ab93b6e..67dbb57 100644 (file)
@@ -45,10 +45,10 @@ struct rw_semaphore {
 };
 
 /*
- * Setting bit 0 of the owner field with other non-zero bits will indicate
+ * Setting bit 1 of the owner field but not bit 0 will indicate
  * that the rwsem is writer-owned with an unknown owner.
  */
-#define RWSEM_OWNER_UNKNOWN    ((struct task_struct *)-1L)
+#define RWSEM_OWNER_UNKNOWN    ((struct task_struct *)-2L)
 
 extern struct rw_semaphore *rwsem_down_read_failed(struct rw_semaphore *sem);
 extern struct rw_semaphore *rwsem_down_read_failed_killable(struct rw_semaphore *sem);
index 0097ace..be4859f 100644 (file)
@@ -315,6 +315,16 @@ void lockdep_assert_cpus_held(void)
        percpu_rwsem_assert_held(&cpu_hotplug_lock);
 }
 
+static void lockdep_acquire_cpus_lock(void)
+{
+       rwsem_acquire(&cpu_hotplug_lock.rw_sem.dep_map, 0, 0, _THIS_IP_);
+}
+
+static void lockdep_release_cpus_lock(void)
+{
+       rwsem_release(&cpu_hotplug_lock.rw_sem.dep_map, 1, _THIS_IP_);
+}
+
 /*
  * Wait for currently running CPU hotplug operations to complete (if any) and
  * disable future CPU hotplug (from sysfs). The 'cpu_add_remove_lock' protects
@@ -344,6 +354,17 @@ void cpu_hotplug_enable(void)
        cpu_maps_update_done();
 }
 EXPORT_SYMBOL_GPL(cpu_hotplug_enable);
+
+#else
+
+static void lockdep_acquire_cpus_lock(void)
+{
+}
+
+static void lockdep_release_cpus_lock(void)
+{
+}
+
 #endif /* CONFIG_HOTPLUG_CPU */
 
 #ifdef CONFIG_HOTPLUG_SMT
@@ -616,6 +637,12 @@ static void cpuhp_thread_fun(unsigned int cpu)
         */
        smp_mb();
 
+       /*
+        * The BP holds the hotplug lock, but we're now running on the AP,
+        * ensure that anybody asserting the lock is held, will actually find
+        * it so.
+        */
+       lockdep_acquire_cpus_lock();
        cpuhp_lock_acquire(bringup);
 
        if (st->single) {
@@ -661,6 +688,7 @@ static void cpuhp_thread_fun(unsigned int cpu)
        }
 
        cpuhp_lock_release(bringup);
+       lockdep_release_cpus_lock();
 
        if (!st->should_run)
                complete_ap_thread(st, bringup);
index 11fc3bb..3e2de8f 100644 (file)
@@ -1365,9 +1365,9 @@ static void __unqueue_futex(struct futex_q *q)
 {
        struct futex_hash_bucket *hb;
 
-       if (WARN_ON_SMP(!q->lock_ptr || !spin_is_locked(q->lock_ptr))
-           || WARN_ON(plist_node_empty(&q->list)))
+       if (WARN_ON_SMP(!q->lock_ptr) || WARN_ON(plist_node_empty(&q->list)))
                return;
+       lockdep_assert_held(q->lock_ptr);
 
        hb = container_of(q->lock_ptr, struct futex_hash_bucket, lock);
        plist_del(&q->list, &hb->chain);
index 14a7f98..b28028b 100644 (file)
@@ -105,6 +105,7 @@ void static_key_slow_inc_cpuslocked(struct static_key *key)
        int v, v1;
 
        STATIC_KEY_CHECK_USE(key);
+       lockdep_assert_cpus_held();
 
        /*
         * Careful if we get concurrent static_key_slow_inc() calls;
@@ -150,6 +151,7 @@ EXPORT_SYMBOL_GPL(static_key_slow_inc);
 void static_key_enable_cpuslocked(struct static_key *key)
 {
        STATIC_KEY_CHECK_USE(key);
+       lockdep_assert_cpus_held();
 
        if (atomic_read(&key->enabled) > 0) {
                WARN_ON_ONCE(atomic_read(&key->enabled) != 1);
@@ -180,6 +182,7 @@ EXPORT_SYMBOL_GPL(static_key_enable);
 void static_key_disable_cpuslocked(struct static_key *key)
 {
        STATIC_KEY_CHECK_USE(key);
+       lockdep_assert_cpus_held();
 
        if (atomic_read(&key->enabled) != 1) {
                WARN_ON_ONCE(atomic_read(&key->enabled) != 0);
@@ -205,6 +208,8 @@ static void __static_key_slow_dec_cpuslocked(struct static_key *key,
                                           unsigned long rate_limit,
                                           struct delayed_work *work)
 {
+       lockdep_assert_cpus_held();
+
        /*
         * The negative count check is valid even when a negative
         * key->enabled is in use by static_key_slow_inc(); a
@@ -456,7 +461,7 @@ struct static_key_mod {
 
 static inline struct static_key_mod *static_key_mod(struct static_key *key)
 {
-       WARN_ON_ONCE(!(key->type & JUMP_TYPE_LINKED));
+       WARN_ON_ONCE(!static_key_linked(key));
        return (struct static_key_mod *)(key->type & ~JUMP_TYPE_MASK);
 }
 
index dd13f86..be76f47 100644 (file)
@@ -138,7 +138,7 @@ static struct lock_list list_entries[MAX_LOCKDEP_ENTRIES];
  * get freed - this significantly simplifies the debugging code.
  */
 unsigned long nr_lock_classes;
-static struct lock_class lock_classes[MAX_LOCKDEP_KEYS];
+struct lock_class lock_classes[MAX_LOCKDEP_KEYS];
 
 static inline struct lock_class *hlock_class(struct held_lock *hlock)
 {
@@ -1391,7 +1391,9 @@ static void print_lock_class_header(struct lock_class *class, int depth)
 
        printk("%*s->", depth, "");
        print_lock_name(class);
-       printk(KERN_CONT " ops: %lu", class->ops);
+#ifdef CONFIG_DEBUG_LOCKDEP
+       printk(KERN_CONT " ops: %lu", debug_class_ops_read(class));
+#endif
        printk(KERN_CONT " {\n");
 
        for (bit = 0; bit < LOCK_USAGE_STATES; bit++) {
@@ -2148,76 +2150,6 @@ static int check_no_collision(struct task_struct *curr,
 }
 
 /*
- * This is for building a chain between just two different classes,
- * instead of adding a new hlock upon current, which is done by
- * add_chain_cache().
- *
- * This can be called in any context with two classes, while
- * add_chain_cache() must be done within the lock owener's context
- * since it uses hlock which might be racy in another context.
- */
-static inline int add_chain_cache_classes(unsigned int prev,
-                                         unsigned int next,
-                                         unsigned int irq_context,
-                                         u64 chain_key)
-{
-       struct hlist_head *hash_head = chainhashentry(chain_key);
-       struct lock_chain *chain;
-
-       /*
-        * Allocate a new chain entry from the static array, and add
-        * it to the hash:
-        */
-
-       /*
-        * We might need to take the graph lock, ensure we've got IRQs
-        * 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()))
-               return 0;
-
-       if (unlikely(nr_lock_chains >= MAX_LOCKDEP_CHAINS)) {
-               if (!debug_locks_off_graph_unlock())
-                       return 0;
-
-               print_lockdep_off("BUG: MAX_LOCKDEP_CHAINS too low!");
-               dump_stack();
-               return 0;
-       }
-
-       chain = lock_chains + nr_lock_chains++;
-       chain->chain_key = chain_key;
-       chain->irq_context = irq_context;
-       chain->depth = 2;
-       if (likely(nr_chain_hlocks + chain->depth <= MAX_LOCKDEP_CHAIN_HLOCKS)) {
-               chain->base = nr_chain_hlocks;
-               nr_chain_hlocks += chain->depth;
-               chain_hlocks[chain->base] = prev - 1;
-               chain_hlocks[chain->base + 1] = next -1;
-       }
-#ifdef CONFIG_DEBUG_LOCKDEP
-       /*
-        * Important for check_no_collision().
-        */
-       else {
-               if (!debug_locks_off_graph_unlock())
-                       return 0;
-
-               print_lockdep_off("BUG: MAX_LOCKDEP_CHAIN_HLOCKS too low!");
-               dump_stack();
-               return 0;
-       }
-#endif
-
-       hlist_add_head_rcu(&chain->entry, hash_head);
-       debug_atomic_inc(chain_lookup_misses);
-       inc_chains();
-
-       return 1;
-}
-
-/*
  * Adds a dependency chain into chain hashtable. And must be called with
  * graph_lock held.
  *
@@ -3262,6 +3194,10 @@ static int __lock_is_held(const struct lockdep_map *lock, int read);
 /*
  * This gets called for every mutex_lock*()/spin_lock*() operation.
  * We maintain the dependency maps and validate the locking attempt:
+ *
+ * The callers must make sure that IRQs are disabled before calling it,
+ * otherwise we could get an interrupt which would want to take locks,
+ * which would end up in lockdep again.
  */
 static int __lock_acquire(struct lockdep_map *lock, unsigned int subclass,
                          int trylock, int read, int check, int hardirqs_off,
@@ -3279,14 +3215,6 @@ static int __lock_acquire(struct lockdep_map *lock, unsigned int subclass,
        if (unlikely(!debug_locks))
                return 0;
 
-       /*
-        * Lockdep should run with IRQs disabled, otherwise we could
-        * get an interrupt which would want to take locks, which would
-        * end up in lockdep and have you got a head-ache already?
-        */
-       if (DEBUG_LOCKS_WARN_ON(!irqs_disabled()))
-               return 0;
-
        if (!prove_locking || lock->key == &__lockdep_no_validate__)
                check = 0;
 
@@ -3300,7 +3228,9 @@ static int __lock_acquire(struct lockdep_map *lock, unsigned int subclass,
                if (!class)
                        return 0;
        }
-       atomic_inc((atomic_t *)&class->ops);
+
+       debug_class_ops_inc(class);
+
        if (very_verbose(class)) {
                printk("\nacquire class [%px] %s", class->key, class->name);
                if (class->name_version > 1)
@@ -3543,6 +3473,9 @@ static int reacquire_held_locks(struct task_struct *curr, unsigned int depth,
 {
        struct held_lock *hlock;
 
+       if (DEBUG_LOCKS_WARN_ON(!irqs_disabled()))
+               return 0;
+
        for (hlock = curr->held_locks + idx; idx < depth; idx++, hlock++) {
                if (!__lock_acquire(hlock->instance,
                                    hlock_class(hlock)->subclass,
@@ -3696,6 +3629,13 @@ __lock_release(struct lockdep_map *lock, int nested, unsigned long ip)
        curr->lockdep_depth = i;
        curr->curr_chain_key = hlock->prev_chain_key;
 
+       /*
+        * The most likely case is when the unlock is on the innermost
+        * lock. In this case, we are done!
+        */
+       if (i == depth-1)
+               return 1;
+
        if (reacquire_held_locks(curr, depth, i + 1))
                return 0;
 
@@ -3703,10 +3643,14 @@ __lock_release(struct lockdep_map *lock, int nested, unsigned long ip)
         * We had N bottles of beer on the wall, we drank one, but now
         * there's not N-1 bottles of beer left on the wall...
         */
-       if (DEBUG_LOCKS_WARN_ON(curr->lockdep_depth != depth - 1))
-               return 0;
+       DEBUG_LOCKS_WARN_ON(curr->lockdep_depth != depth-1);
 
-       return 1;
+       /*
+        * Since reacquire_held_locks() would have called check_chain_key()
+        * indirectly via __lock_acquire(), we don't need to do it again
+        * on return.
+        */
+       return 0;
 }
 
 static int __lock_is_held(const struct lockdep_map *lock, int read)
index d459d62..88c847a 100644 (file)
@@ -152,9 +152,15 @@ struct lockdep_stats {
        int     nr_find_usage_forwards_recursions;
        int     nr_find_usage_backwards_checks;
        int     nr_find_usage_backwards_recursions;
+
+       /*
+        * Per lock class locking operation stat counts
+        */
+       unsigned long lock_class_ops[MAX_LOCKDEP_KEYS];
 };
 
 DECLARE_PER_CPU(struct lockdep_stats, lockdep_stats);
+extern struct lock_class lock_classes[MAX_LOCKDEP_KEYS];
 
 #define __debug_atomic_inc(ptr)                                        \
        this_cpu_inc(lockdep_stats.ptr);
@@ -179,9 +185,30 @@ DECLARE_PER_CPU(struct lockdep_stats, lockdep_stats);
        }                                                               \
        __total;                                                        \
 })
+
+static inline void debug_class_ops_inc(struct lock_class *class)
+{
+       int idx;
+
+       idx = class - lock_classes;
+       __debug_atomic_inc(lock_class_ops[idx]);
+}
+
+static inline unsigned long debug_class_ops_read(struct lock_class *class)
+{
+       int idx, cpu;
+       unsigned long ops = 0;
+
+       idx = class - lock_classes;
+       for_each_possible_cpu(cpu)
+               ops += per_cpu(lockdep_stats.lock_class_ops[idx], cpu);
+       return ops;
+}
+
 #else
 # define __debug_atomic_inc(ptr)       do { } while (0)
 # define debug_atomic_inc(ptr)         do { } while (0)
 # define debug_atomic_dec(ptr)         do { } while (0)
 # define debug_atomic_read(ptr)                0
+# define debug_class_ops_inc(ptr)      do { } while (0)
 #endif
index 3dd980d..3d31f9b 100644 (file)
@@ -68,7 +68,7 @@ static int l_show(struct seq_file *m, void *v)
 
        seq_printf(m, "%p", class->key);
 #ifdef CONFIG_DEBUG_LOCKDEP
-       seq_printf(m, " OPS:%8ld", class->ops);
+       seq_printf(m, " OPS:%8ld", debug_class_ops_read(class));
 #endif
 #ifdef CONFIG_PROVE_LOCKING
        seq_printf(m, " FD:%5ld", lockdep_count_forward_deps(class));
index 2823d41..581edcc 100644 (file)
@@ -1485,9 +1485,9 @@ void __sched rt_mutex_lock_nested(struct rt_mutex *lock, unsigned int subclass)
        __rt_mutex_lock(lock, subclass);
 }
 EXPORT_SYMBOL_GPL(rt_mutex_lock_nested);
-#endif
 
-#ifndef CONFIG_DEBUG_LOCK_ALLOC
+#else /* !CONFIG_DEBUG_LOCK_ALLOC */
+
 /**
  * rt_mutex_lock - lock a rt_mutex
  *
index 3064c50..09b1800 100644 (file)
@@ -180,7 +180,7 @@ static void __rwsem_mark_wake(struct rw_semaphore *sem,
                 * but it gives the spinners an early indication that the
                 * readers now have the lock.
                 */
-               rwsem_set_reader_owned(sem);
+               __rwsem_set_reader_owned(sem, waiter->task);
        }
 
        /*
@@ -233,8 +233,19 @@ __rwsem_down_read_failed_common(struct rw_semaphore *sem, int state)
        waiter.type = RWSEM_WAITING_FOR_READ;
 
        raw_spin_lock_irq(&sem->wait_lock);
-       if (list_empty(&sem->wait_list))
+       if (list_empty(&sem->wait_list)) {
+               /*
+                * In case the wait queue is empty and the lock isn't owned
+                * by a writer, this reader can exit the slowpath and return
+                * immediately as its RWSEM_ACTIVE_READ_BIAS has already
+                * been set in the count.
+                */
+               if (atomic_long_read(&sem->count) >= 0) {
+                       raw_spin_unlock_irq(&sem->wait_lock);
+                       return sem;
+               }
                adjustment += RWSEM_WAITING_BIAS;
+       }
        list_add_tail(&waiter.list, &sem->wait_list);
 
        /* we're now waiting on the lock, but no longer actively locking */
index 776308d..e586f0d 100644 (file)
@@ -117,8 +117,9 @@ EXPORT_SYMBOL(down_write_trylock);
 void up_read(struct rw_semaphore *sem)
 {
        rwsem_release(&sem->dep_map, 1, _RET_IP_);
-       DEBUG_RWSEMS_WARN_ON(sem->owner != RWSEM_READER_OWNED);
+       DEBUG_RWSEMS_WARN_ON(!((unsigned long)sem->owner & RWSEM_READER_OWNED));
 
+       rwsem_clear_reader_owned(sem);
        __up_read(sem);
 }
 
@@ -181,7 +182,7 @@ void down_read_non_owner(struct rw_semaphore *sem)
        might_sleep();
 
        __down_read(sem);
-       rwsem_set_reader_owned(sem);
+       __rwsem_set_reader_owned(sem, NULL);
 }
 
 EXPORT_SYMBOL(down_read_non_owner);
@@ -215,7 +216,7 @@ EXPORT_SYMBOL(down_write_killable_nested);
 
 void up_read_non_owner(struct rw_semaphore *sem)
 {
-       DEBUG_RWSEMS_WARN_ON(sem->owner != RWSEM_READER_OWNED);
+       DEBUG_RWSEMS_WARN_ON(!((unsigned long)sem->owner & RWSEM_READER_OWNED));
        __up_read(sem);
 }
 
index b9d0e72..bad2bca 100644 (file)
@@ -1,24 +1,30 @@
 /* SPDX-License-Identifier: GPL-2.0 */
 /*
- * The owner field of the rw_semaphore structure will be set to
- * RWSEM_READER_OWNED when a reader grabs the lock. A writer will clear
- * the owner field when it unlocks. A reader, on the other hand, will
- * not touch the owner field when it unlocks.
+ * The least significant 2 bits of the owner value has the following
+ * meanings when set.
+ *  - RWSEM_READER_OWNED (bit 0): The rwsem is owned by readers
+ *  - RWSEM_ANONYMOUSLY_OWNED (bit 1): The rwsem is anonymously owned,
+ *    i.e. the owner(s) cannot be readily determined. It can be reader
+ *    owned or the owning writer is indeterminate.
  *
- * In essence, the owner field now has the following 4 states:
- *  1) 0
- *     - lock is free or the owner hasn't set the field yet
- *  2) RWSEM_READER_OWNED
- *     - lock is currently or previously owned by readers (lock is free
- *       or not set by owner yet)
- *  3) RWSEM_ANONYMOUSLY_OWNED bit set with some other bits set as well
- *     - lock is owned by an anonymous writer, so spinning on the lock
- *       owner should be disabled.
- *  4) Other non-zero value
- *     - a writer owns the lock and other writers can spin on the lock owner.
+ * When a writer acquires a rwsem, it puts its task_struct pointer
+ * into the owner field. It is cleared after an unlock.
+ *
+ * When a reader acquires a rwsem, it will also puts its task_struct
+ * pointer into the owner field with both the RWSEM_READER_OWNED and
+ * RWSEM_ANONYMOUSLY_OWNED bits set. On unlock, the owner field will
+ * largely be left untouched. So for a free or reader-owned rwsem,
+ * the owner value may contain information about the last reader that
+ * acquires the rwsem. The anonymous bit is set because that particular
+ * reader may or may not still own the lock.
+ *
+ * That information may be helpful in debugging cases where the system
+ * seems to hang on a reader owned rwsem especially if only one reader
+ * is involved. Ideally we would like to track all the readers that own
+ * a rwsem, but the overhead is simply too big.
  */
-#define RWSEM_ANONYMOUSLY_OWNED        (1UL << 0)
-#define RWSEM_READER_OWNED     ((struct task_struct *)RWSEM_ANONYMOUSLY_OWNED)
+#define RWSEM_READER_OWNED     (1UL << 0)
+#define RWSEM_ANONYMOUSLY_OWNED        (1UL << 1)
 
 #ifdef CONFIG_DEBUG_RWSEMS
 # define DEBUG_RWSEMS_WARN_ON(c)       DEBUG_LOCKS_WARN_ON(c)
@@ -44,15 +50,26 @@ static inline void rwsem_clear_owner(struct rw_semaphore *sem)
        WRITE_ONCE(sem->owner, NULL);
 }
 
+/*
+ * The task_struct pointer of the last owning reader will be left in
+ * the owner field.
+ *
+ * Note that the owner value just indicates the task has owned the rwsem
+ * previously, it may not be the real owner or one of the real owners
+ * anymore when that field is examined, so take it with a grain of salt.
+ */
+static inline void __rwsem_set_reader_owned(struct rw_semaphore *sem,
+                                           struct task_struct *owner)
+{
+       unsigned long val = (unsigned long)owner | RWSEM_READER_OWNED
+                                                | RWSEM_ANONYMOUSLY_OWNED;
+
+       WRITE_ONCE(sem->owner, (struct task_struct *)val);
+}
+
 static inline void rwsem_set_reader_owned(struct rw_semaphore *sem)
 {
-       /*
-        * We check the owner value first to make sure that we will only
-        * do a write to the rwsem cacheline when it is really necessary
-        * to minimize cacheline contention.
-        */
-       if (READ_ONCE(sem->owner) != RWSEM_READER_OWNED)
-               WRITE_ONCE(sem->owner, RWSEM_READER_OWNED);
+       __rwsem_set_reader_owned(sem, current);
 }
 
 /*
@@ -72,6 +89,25 @@ static inline bool rwsem_has_anonymous_owner(struct task_struct *owner)
 {
        return (unsigned long)owner & RWSEM_ANONYMOUSLY_OWNED;
 }
+
+#ifdef CONFIG_DEBUG_RWSEMS
+/*
+ * With CONFIG_DEBUG_RWSEMS configured, it will make sure that if there
+ * is a task pointer in owner of a reader-owned rwsem, it will be the
+ * real owner or one of the real owners. The only exception is when the
+ * unlock is done by up_read_non_owner().
+ */
+#define rwsem_clear_reader_owned rwsem_clear_reader_owned
+static inline void rwsem_clear_reader_owned(struct rw_semaphore *sem)
+{
+       unsigned long val = (unsigned long)current | RWSEM_READER_OWNED
+                                                  | RWSEM_ANONYMOUSLY_OWNED;
+       if (READ_ONCE(sem->owner) == (struct task_struct *)val)
+               cmpxchg_relaxed((unsigned long *)&sem->owner, val,
+                               RWSEM_READER_OWNED | RWSEM_ANONYMOUSLY_OWNED);
+}
+#endif
+
 #else
 static inline void rwsem_set_owner(struct rw_semaphore *sem)
 {
@@ -81,7 +117,18 @@ static inline void rwsem_clear_owner(struct rw_semaphore *sem)
 {
 }
 
+static inline void __rwsem_set_reader_owned(struct rw_semaphore *sem,
+                                          struct task_struct *owner)
+{
+}
+
 static inline void rwsem_set_reader_owned(struct rw_semaphore *sem)
 {
 }
 #endif
+
+#ifndef rwsem_clear_reader_owned
+static inline void rwsem_clear_reader_owned(struct rw_semaphore *sem)
+{
+}
+#endif
index 0cbd1ef..35bff92 100644 (file)
@@ -28,7 +28,8 @@ Explanation of the Linux-Kernel Memory Consistency Model
   20. THE HAPPENS-BEFORE RELATION: hb
   21. THE PROPAGATES-BEFORE RELATION: pb
   22. RCU RELATIONS: rcu-link, gp, rscs, rcu-fence, and rb
-  23. ODDS AND ENDS
+  23. LOCKING
+  24. ODDS AND ENDS
 
 
 
@@ -1067,28 +1068,6 @@ allowing out-of-order writes like this to occur.  The model avoided
 violating the write-write coherence rule by requiring the CPU not to
 send the W write to the memory subsystem at all!)
 
-There is one last example of preserved program order in the LKMM: when
-a load-acquire reads from an earlier store-release.  For example:
-
-       smp_store_release(&x, 123);
-       r1 = smp_load_acquire(&x);
-
-If the smp_load_acquire() ends up obtaining the 123 value that was
-stored by the smp_store_release(), the LKMM says that the load must be
-executed after the store; the store cannot be forwarded to the load.
-This requirement does not arise from the operational model, but it
-yields correct predictions on all architectures supported by the Linux
-kernel, although for differing reasons.
-
-On some architectures, including x86 and ARMv8, it is true that the
-store cannot be forwarded to the load.  On others, including PowerPC
-and ARMv7, smp_store_release() generates object code that starts with
-a fence and smp_load_acquire() generates object code that ends with a
-fence.  The upshot is that even though the store may be forwarded to
-the load, it is still true that any instruction preceding the store
-will be executed before the load or any following instructions, and
-the store will be executed before any instruction following the load.
-
 
 AND THEN THERE WAS ALPHA
 ------------------------
@@ -1766,6 +1745,147 @@ before it does, and the critical section in P2 both starts after P1's
 grace period does and ends after it does.
 
 
+LOCKING
+-------
+
+The LKMM includes locking.  In fact, there is special code for locking
+in the formal model, added in order to make tools run faster.
+However, this special code is intended to be more or less equivalent
+to concepts we have already covered.  A spinlock_t variable is treated
+the same as an int, and spin_lock(&s) is treated almost the same as:
+
+       while (cmpxchg_acquire(&s, 0, 1) != 0)
+               cpu_relax();
+
+This waits until s is equal to 0 and then atomically sets it to 1,
+and the read part of the cmpxchg operation acts as an acquire fence.
+An alternate way to express the same thing would be:
+
+       r = xchg_acquire(&s, 1);
+
+along with a requirement that at the end, r = 0.  Similarly,
+spin_trylock(&s) is treated almost the same as:
+
+       return !cmpxchg_acquire(&s, 0, 1);
+
+which atomically sets s to 1 if it is currently equal to 0 and returns
+true if it succeeds (the read part of the cmpxchg operation acts as an
+acquire fence only if the operation is successful).  spin_unlock(&s)
+is treated almost the same as:
+
+       smp_store_release(&s, 0);
+
+The "almost" qualifiers above need some explanation.  In the LKMM, the
+store-release in a spin_unlock() and the load-acquire which forms the
+first half of the atomic rmw update in a spin_lock() or a successful
+spin_trylock() -- we can call these things lock-releases and
+lock-acquires -- have two properties beyond those of ordinary releases
+and acquires.
+
+First, when a lock-acquire reads from a lock-release, the LKMM
+requires that every instruction po-before the lock-release must
+execute before any instruction po-after the lock-acquire.  This would
+naturally hold if the release and acquire operations were on different
+CPUs, but the LKMM says it holds even when they are on the same CPU.
+For example:
+
+       int x, y;
+       spinlock_t s;
+
+       P0()
+       {
+               int r1, r2;
+
+               spin_lock(&s);
+               r1 = READ_ONCE(x);
+               spin_unlock(&s);
+               spin_lock(&s);
+               r2 = READ_ONCE(y);
+               spin_unlock(&s);
+       }
+
+       P1()
+       {
+               WRITE_ONCE(y, 1);
+               smp_wmb();
+               WRITE_ONCE(x, 1);
+       }
+
+Here the second spin_lock() reads from the first spin_unlock(), and
+therefore the load of x must execute before the load of y.  Thus we
+cannot have r1 = 1 and r2 = 0 at the end (this is an instance of the
+MP pattern).
+
+This requirement does not apply to ordinary release and acquire
+fences, only to lock-related operations.  For instance, suppose P0()
+in the example had been written as:
+
+       P0()
+       {
+               int r1, r2, r3;
+
+               r1 = READ_ONCE(x);
+               smp_store_release(&s, 1);
+               r3 = smp_load_acquire(&s);
+               r2 = READ_ONCE(y);
+       }
+
+Then the CPU would be allowed to forward the s = 1 value from the
+smp_store_release() to the smp_load_acquire(), executing the
+instructions in the following order:
+
+               r3 = smp_load_acquire(&s);      // Obtains r3 = 1
+               r2 = READ_ONCE(y);
+               r1 = READ_ONCE(x);
+               smp_store_release(&s, 1);       // Value is forwarded
+
+and thus it could load y before x, obtaining r2 = 0 and r1 = 1.
+
+Second, when a lock-acquire reads from a lock-release, and some other
+stores W and W' occur po-before the lock-release and po-after the
+lock-acquire respectively, the LKMM requires that W must propagate to
+each CPU before W' does.  For example, consider:
+
+       int x, y;
+       spinlock_t x;
+
+       P0()
+       {
+               spin_lock(&s);
+               WRITE_ONCE(x, 1);
+               spin_unlock(&s);
+       }
+
+       P1()
+       {
+               int r1;
+
+               spin_lock(&s);
+               r1 = READ_ONCE(x);
+               WRITE_ONCE(y, 1);
+               spin_unlock(&s);
+       }
+
+       P2()
+       {
+               int r2, r3;
+
+               r2 = READ_ONCE(y);
+               smp_rmb();
+               r3 = READ_ONCE(x);
+       }
+
+If r1 = 1 at the end then the spin_lock() in P1 must have read from
+the spin_unlock() in P0.  Hence the store to x must propagate to P2
+before the store to y does, so we cannot have r2 = 1 and r3 = 0.
+
+These two special requirements for lock-release and lock-acquire do
+not arise from the operational model.  Nevertheless, kernel developers
+have come to expect and rely on them because they do hold on all
+architectures supported by the Linux kernel, albeit for various
+differing reasons.
+
+
 ODDS AND ENDS
 -------------
 
@@ -1831,26 +1951,6 @@ they behave as follows:
        events and the events preceding them against all po-later
        events.
 
-The LKMM includes locking.  In fact, there is special code for locking
-in the formal model, added in order to make tools run faster.
-However, this special code is intended to be exactly equivalent to
-concepts we have already covered.  A spinlock_t variable is treated
-the same as an int, and spin_lock(&s) is treated the same as:
-
-       while (cmpxchg_acquire(&s, 0, 1) != 0)
-               cpu_relax();
-
-which waits until s is equal to 0 and then atomically sets it to 1,
-and where the read part of the atomic update is also an acquire fence.
-An alternate way to express the same thing would be:
-
-       r = xchg_acquire(&s, 1);
-
-along with a requirement that at the end, r = 0.  spin_unlock(&s) is
-treated the same as:
-
-       smp_store_release(&s, 0);
-
 Interestingly, RCU and locking each introduce the possibility of
 deadlock.  When faced with code sequences such as:
 
index af72700..7fe8d7a 100644 (file)
@@ -311,7 +311,7 @@ The smp_wmb() macro orders prior stores against later stores, and the
 smp_rmb() macro orders prior loads against later loads.  Therefore, if
 the final value of r0 is 1, the final value of r1 must also be 1.
 
-The the xlog_state_switch_iclogs() function in fs/xfs/xfs_log.c contains
+The xlog_state_switch_iclogs() function in fs/xfs/xfs_log.c contains
 the following write-side code fragment:
 
        log->l_curr_block -= log->l_logBBsize;
index ee987ce..acf9077 100644 (file)
@@ -171,6 +171,12 @@ The Linux-kernel memory model has the following limitations:
        particular, the "THE PROGRAM ORDER RELATION: po AND po-loc"
        and "A WARNING" sections).
 
+       Note that this limitation in turn limits LKMM's ability to
+       accurately model address, control, and data dependencies.
+       For example, if the compiler can deduce the value of some variable
+       carrying a dependency, then the compiler can break that dependency
+       by substituting a constant of that value.
+
 2.     Multiple access sizes for a single variable are not supported,
        and neither are misaligned or partially overlapping accesses.
 
@@ -190,6 +196,36 @@ The Linux-kernel memory model has the following limitations:
        However, a substantial amount of support is provided for these
        operations, as shown in the linux-kernel.def file.
 
+       a.      When rcu_assign_pointer() is passed NULL, the Linux
+               kernel provides no ordering, but LKMM models this
+               case as a store release.
+
+       b.      The "unless" RMW operations are not currently modeled:
+               atomic_long_add_unless(), atomic_add_unless(),
+               atomic_inc_unless_negative(), and
+               atomic_dec_unless_positive().  These can be emulated
+               in litmus tests, for example, by using atomic_cmpxchg().
+
+       c.      The call_rcu() function is not modeled.  It can be
+               emulated in litmus tests by adding another process that
+               invokes synchronize_rcu() and the body of the callback
+               function, with (for example) a release-acquire from
+               the site of the emulated call_rcu() to the beginning
+               of the additional process.
+
+       d.      The rcu_barrier() function is not modeled.  It can be
+               emulated in litmus tests emulating call_rcu() via
+               (for example) a release-acquire from the end of each
+               additional call_rcu() process to the site of the
+               emulated rcu-barrier().
+
+       e.      Sleepable RCU (SRCU) is not modeled.  It can be
+               emulated, but perhaps not simply.
+
+       f.      Reader-writer locking is not modeled.  It can be
+               emulated in litmus tests using atomic read-modify-write
+               operations.
+
 The "herd7" tool has some additional limitations of its own, apart from
 the memory model:
 
@@ -204,3 +240,6 @@ the memory model:
 Some of these limitations may be overcome in the future, but others are
 more likely to be addressed by incorporating the Linux-kernel memory model
 into other tools.
+
+Finally, please note that LKMM is subject to change as hardware, use cases,
+and compilers evolve.
index 59b5cbe..882fc33 100644 (file)
@@ -38,7 +38,7 @@ let strong-fence = mb | gp
 (* Release Acquire *)
 let acq-po = [Acquire] ; po ; [M]
 let po-rel = [M] ; po ; [Release]
-let rfi-rel-acq = [Release] ; rfi ; [Acquire]
+let po-unlock-rf-lock-po = po ; [UL] ; rf ; [LKR] ; po
 
 (**********************************)
 (* Fundamental coherence ordering *)
@@ -60,13 +60,13 @@ let dep = addr | data
 let rwdep = (dep | ctrl) ; [W]
 let overwrite = co | fr
 let to-w = rwdep | (overwrite & int)
-let to-r = addr | (dep ; rfi) | rfi-rel-acq
+let to-r = addr | (dep ; rfi)
 let fence = strong-fence | wmb | po-rel | rmb | acq-po
-let ppo = to-r | to-w | fence
+let ppo = to-r | to-w | fence | (po-unlock-rf-lock-po & int)
 
 (* Propagation: Ordering from release operations and strong fences. *)
 let A-cumul(r) = rfe? ; r
-let cumul-fence = A-cumul(strong-fence | po-rel) | wmb
+let cumul-fence = A-cumul(strong-fence | po-rel) | wmb | po-unlock-rf-lock-po
 let prop = (overwrite & ext)? ; cumul-fence* ; rfe?
 
 (*
index 0f749e4..094d58d 100644 (file)
@@ -1,11 +1,10 @@
 C ISA2+pooncelock+pooncelock+pombonce
 
 (*
- * Result: Sometimes
+ * Result: Never
  *
- * This test shows that the ordering provided by a lock-protected S
- * litmus test (P0() and P1()) are not visible to external process P2().
- * This is likely to change soon.
+ * This test shows that write-write ordering provided by locks
+ * (in P0() and P1()) is visible to external process P2().
  *)
 
 {}
index 4581ec2..5ee08f1 100644 (file)
@@ -1,4 +1,6 @@
-This directory contains the following litmus tests:
+============
+LITMUS TESTS
+============
 
 CoRR+poonceonce+Once.litmus
        Test of read-read coherence, that is, whether or not two
@@ -36,7 +38,7 @@ IRIW+poonceonces+OnceOnce.litmus
 ISA2+pooncelock+pooncelock+pombonce.litmus
        Tests whether the ordering provided by a lock-protected S
        litmus test is visible to an external process whose accesses are
-       separated by smp_mb().  This addition of an external process to
+       separated by smp_mb().  This addition of an external process to
        S is otherwise known as ISA2.
 
 ISA2+poonceonces.litmus
@@ -151,3 +153,101 @@ Z6.0+pooncerelease+poacquirerelease+fencembonceonce.litmus
 A great many more litmus tests are available here:
 
        https://github.com/paulmckrcu/litmus
+
+==================
+LITMUS TEST NAMING
+==================
+
+Litmus tests are usually named based on their contents, which means that
+looking at the name tells you what the litmus test does.  The naming
+scheme covers litmus tests having a single cycle that passes through
+each process exactly once, so litmus tests not fitting this description
+are named on an ad-hoc basis.
+
+The structure of a litmus-test name is the litmus-test class, a plus
+sign ("+"), and one string for each process, separated by plus signs.
+The end of the name is ".litmus".
+
+The litmus-test classes may be found in the infamous test6.pdf:
+https://www.cl.cam.ac.uk/~pes20/ppc-supplemental/test6.pdf
+Each class defines the pattern of accesses and of the variables accessed.
+For example, if the one process writes to a pair of variables, and
+the other process reads from these same variables, the corresponding
+litmus-test class is "MP" (message passing), which may be found on the
+left-hand end of the second row of tests on page one of test6.pdf.
+
+The strings used to identify the actions carried out by each process are
+complex due to a desire to have short(er) names.  Thus, there is a tool to
+generate these strings from a given litmus test's actions.  For example,
+consider the processes from SB+rfionceonce-poonceonces.litmus:
+
+       P0(int *x, int *y)
+       {
+               int r1;
+               int r2;
+
+               WRITE_ONCE(*x, 1);
+               r1 = READ_ONCE(*x);
+               r2 = READ_ONCE(*y);
+       }
+
+       P1(int *x, int *y)
+       {
+               int r3;
+               int r4;
+
+               WRITE_ONCE(*y, 1);
+               r3 = READ_ONCE(*y);
+               r4 = READ_ONCE(*x);
+       }
+
+The next step is to construct a space-separated list of descriptors,
+interleaving descriptions of the relation between a pair of consecutive
+accesses with descriptions of the second access in the pair.
+
+P0()'s WRITE_ONCE() is read by its first READ_ONCE(), which is a
+reads-from link (rf) and internal to the P0() process.  This is
+"rfi", which is an abbreviation for "reads-from internal".  Because
+some of the tools string these abbreviations together with space
+characters separating processes, the first character is capitalized,
+resulting in "Rfi".
+
+P0()'s second access is a READ_ONCE(), as opposed to (for example)
+smp_load_acquire(), so next is "Once".  Thus far, we have "Rfi Once".
+
+P0()'s third access is also a READ_ONCE(), but to y rather than x.
+This is related to P0()'s second access by program order ("po"),
+to a different variable ("d"), and both accesses are reads ("RR").
+The resulting descriptor is "PodRR".  Because P0()'s third access is
+READ_ONCE(), we add another "Once" descriptor.
+
+A from-read ("fre") relation links P0()'s third to P1()'s first
+access, and the resulting descriptor is "Fre".  P1()'s first access is
+WRITE_ONCE(), which as before gives the descriptor "Once".  The string
+thus far is thus "Rfi Once PodRR Once Fre Once".
+
+The remainder of P1() is similar to P0(), which means we add
+"Rfi Once PodRR Once".  Another fre links P1()'s last access to
+P0()'s first access, which is WRITE_ONCE(), so we add "Fre Once".
+The full string is thus:
+
+       Rfi Once PodRR Once Fre Once Rfi Once PodRR Once Fre Once
+
+This string can be given to the "norm7" and "classify7" tools to
+produce the name:
+
+       $ norm7 -bell linux-kernel.bell \
+               Rfi Once PodRR Once Fre Once Rfi Once PodRR Once Fre Once | \
+         sed -e 's/:.*//g'
+       SB+rfionceonce-poonceonces
+
+Adding the ".litmus" suffix: SB+rfionceonce-poonceonces.litmus
+
+The descriptors that describe connections between consecutive accesses
+within the cycle through a given litmus test can be provided by the herd
+tool (Rfi, Po, Fre, and so on) or by the linux-kernel.bell file (Once,
+Release, Acquire, and so on).
+
+To see the full list of descriptors, execute the following command:
+
+       $ diyone7 -bell linux-kernel.bell -show edges