Merge branch 'locking-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull locking fixes from Thomas Gleixner:
"Two fixes to address shortcomings of the rwsem/percpu-rwsem lock
debugging code which emits false positive warnings when the rwsem is
anonymously locked and unlocked"

* 'locking-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
locking/percpu-rwsem: Annotate rwsem ownership transfer by setting RWSEM_OWNER_UNKNOWN
locking/rwsem: Add a new RWSEM_ANONYMOUSLY_OWNED flag

+41 -22
+5 -1
include/linux/percpu-rwsem.h
··· 133 133 lock_release(&sem->rw_sem.dep_map, 1, ip); 134 134 #ifdef CONFIG_RWSEM_SPIN_ON_OWNER 135 135 if (!read) 136 - sem->rw_sem.owner = NULL; 136 + sem->rw_sem.owner = RWSEM_OWNER_UNKNOWN; 137 137 #endif 138 138 } 139 139 ··· 141 141 bool read, unsigned long ip) 142 142 { 143 143 lock_acquire(&sem->rw_sem.dep_map, 0, 1, read, 1, NULL, ip); 144 + #ifdef CONFIG_RWSEM_SPIN_ON_OWNER 145 + if (!read) 146 + sem->rw_sem.owner = current; 147 + #endif 144 148 } 145 149 146 150 #endif
+6
include/linux/rwsem.h
··· 44 44 #endif 45 45 }; 46 46 47 + /* 48 + * Setting bit 0 of the owner field with other non-zero bits will indicate 49 + * that the rwsem is writer-owned with an unknown owner. 50 + */ 51 + #define RWSEM_OWNER_UNKNOWN ((struct task_struct *)-1L) 52 + 47 53 extern struct rw_semaphore *rwsem_down_read_failed(struct rw_semaphore *sem); 48 54 extern struct rw_semaphore *rwsem_down_read_failed_killable(struct rw_semaphore *sem); 49 55 extern struct rw_semaphore *rwsem_down_write_failed(struct rw_semaphore *sem);
+9 -10
kernel/locking/rwsem-xadd.c
··· 352 352 struct task_struct *owner; 353 353 bool ret = true; 354 354 355 + BUILD_BUG_ON(!rwsem_has_anonymous_owner(RWSEM_OWNER_UNKNOWN)); 356 + 355 357 if (need_resched()) 356 358 return false; 357 359 358 360 rcu_read_lock(); 359 361 owner = READ_ONCE(sem->owner); 360 - if (!rwsem_owner_is_writer(owner)) { 361 - /* 362 - * Don't spin if the rwsem is readers owned. 363 - */ 364 - ret = !rwsem_owner_is_reader(owner); 362 + if (!owner || !is_rwsem_owner_spinnable(owner)) { 363 + ret = !owner; /* !owner is spinnable */ 365 364 goto done; 366 365 } 367 366 ··· 381 382 { 382 383 struct task_struct *owner = READ_ONCE(sem->owner); 383 384 384 - if (!rwsem_owner_is_writer(owner)) 385 - goto out; 385 + if (!is_rwsem_owner_spinnable(owner)) 386 + return false; 386 387 387 388 rcu_read_lock(); 388 - while (sem->owner == owner) { 389 + while (owner && (READ_ONCE(sem->owner) == owner)) { 389 390 /* 390 391 * Ensure we emit the owner->on_cpu, dereference _after_ 391 392 * checking sem->owner still matches owner, if that fails, ··· 407 408 cpu_relax(); 408 409 } 409 410 rcu_read_unlock(); 410 - out: 411 + 411 412 /* 412 413 * If there is a new owner or the owner is not set, we continue 413 414 * spinning. 414 415 */ 415 - return !rwsem_owner_is_reader(READ_ONCE(sem->owner)); 416 + return is_rwsem_owner_spinnable(READ_ONCE(sem->owner)); 416 417 } 417 418 418 419 static bool rwsem_optimistic_spin(struct rw_semaphore *sem)
-2
kernel/locking/rwsem.c
··· 221 221 EXPORT_SYMBOL(up_read_non_owner); 222 222 223 223 #endif 224 - 225 -
+21 -9
kernel/locking/rwsem.h
··· 1 1 /* SPDX-License-Identifier: GPL-2.0 */ 2 2 /* 3 3 * The owner field of the rw_semaphore structure will be set to 4 - * RWSEM_READ_OWNED when a reader grabs the lock. A writer will clear 4 + * RWSEM_READER_OWNED when a reader grabs the lock. A writer will clear 5 5 * the owner field when it unlocks. A reader, on the other hand, will 6 6 * not touch the owner field when it unlocks. 7 7 * 8 - * In essence, the owner field now has the following 3 states: 8 + * In essence, the owner field now has the following 4 states: 9 9 * 1) 0 10 10 * - lock is free or the owner hasn't set the field yet 11 11 * 2) RWSEM_READER_OWNED 12 12 * - lock is currently or previously owned by readers (lock is free 13 13 * or not set by owner yet) 14 - * 3) Other non-zero value 15 - * - a writer owns the lock 14 + * 3) RWSEM_ANONYMOUSLY_OWNED bit set with some other bits set as well 15 + * - lock is owned by an anonymous writer, so spinning on the lock 16 + * owner should be disabled. 17 + * 4) Other non-zero value 18 + * - a writer owns the lock and other writers can spin on the lock owner. 16 19 */ 17 - #define RWSEM_READER_OWNED ((struct task_struct *)1UL) 20 + #define RWSEM_ANONYMOUSLY_OWNED (1UL << 0) 21 + #define RWSEM_READER_OWNED ((struct task_struct *)RWSEM_ANONYMOUSLY_OWNED) 18 22 19 23 #ifdef CONFIG_DEBUG_RWSEMS 20 24 # define DEBUG_RWSEMS_WARN_ON(c) DEBUG_LOCKS_WARN_ON(c) ··· 55 51 WRITE_ONCE(sem->owner, RWSEM_READER_OWNED); 56 52 } 57 53 58 - static inline bool rwsem_owner_is_writer(struct task_struct *owner) 54 + /* 55 + * Return true if the a rwsem waiter can spin on the rwsem's owner 56 + * and steal the lock, i.e. the lock is not anonymously owned. 57 + * N.B. !owner is considered spinnable. 58 + */ 59 + static inline bool is_rwsem_owner_spinnable(struct task_struct *owner) 59 60 { 60 - return owner && owner != RWSEM_READER_OWNED; 61 + return !((unsigned long)owner & RWSEM_ANONYMOUSLY_OWNED); 61 62 } 62 63 63 - static inline bool rwsem_owner_is_reader(struct task_struct *owner) 64 + /* 65 + * Return true if rwsem is owned by an anonymous writer or readers. 66 + */ 67 + static inline bool rwsem_has_anonymous_owner(struct task_struct *owner) 64 68 { 65 - return owner == RWSEM_READER_OWNED; 69 + return (unsigned long)owner & RWSEM_ANONYMOUSLY_OWNED; 66 70 } 67 71 #else 68 72 static inline void rwsem_set_owner(struct rw_semaphore *sem)