Skip to content

Commit e1b98fa

Browse files
jstancekIngo Molnar
authored andcommitted
locking/rwsem: Add missing ACQUIRE to read_slowpath exit when queue is empty
LTP mtest06 has been observed to occasionally hit "still mapped when deleted" and following BUG_ON on arm64. The extra mapcount originated from pagefault handler, which handled pagefault for vma that has already been detached. vma is detached under mmap_sem write lock by detach_vmas_to_be_unmapped(), which also invalidates vmacache. When the pagefault handler (under mmap_sem read lock) calls find_vma(), vmacache_valid() wrongly reports vmacache as valid. After rwsem down_read() returns via 'queue empty' path (as of v5.2), it does so without an ACQUIRE on sem->count: down_read() __down_read() rwsem_down_read_failed() __rwsem_down_read_failed_common() raw_spin_lock_irq(&sem->wait_lock); if (list_empty(&sem->wait_list)) { if (atomic_long_read(&sem->count) >= 0) { raw_spin_unlock_irq(&sem->wait_lock); return sem; The problem can be reproduced by running LTP mtest06 in a loop and building the kernel (-j $NCPUS) in parallel. It does reproduces since v4.20 on arm64 HPE Apollo 70 (224 CPUs, 256GB RAM, 2 nodes). It triggers reliably in about an hour. The patched kernel ran fine for 10+ hours. Signed-off-by: Jan Stancek <[email protected]> Signed-off-by: Peter Zijlstra (Intel) <[email protected]> Reviewed-by: Will Deacon <[email protected]> Acked-by: Waiman Long <[email protected]> Cc: Linus Torvalds <[email protected]> Cc: Peter Zijlstra <[email protected]> Cc: Thomas Gleixner <[email protected]> Cc: [email protected] Fixes: 4b486b5 ("locking/rwsem: Exit read lock slowpath if queue empty & no writer") Link: https://lkml.kernel.org/r/50b8914e20d1d62bb2dee42d342836c2c16ebee7.1563438048.git.jstancek@redhat.com Signed-off-by: Ingo Molnar <[email protected]>
1 parent 7813430 commit e1b98fa

File tree

1 file changed

+2
-0
lines changed

1 file changed

+2
-0
lines changed

kernel/locking/rwsem.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1036,6 +1036,8 @@ rwsem_down_read_slowpath(struct rw_semaphore *sem, int state)
10361036
*/
10371037
if (adjustment && !(atomic_long_read(&sem->count) &
10381038
(RWSEM_WRITER_MASK | RWSEM_FLAG_HANDOFF))) {
1039+
/* Provide lock ACQUIRE */
1040+
smp_acquire__after_ctrl_dep();
10391041
raw_spin_unlock_irq(&sem->wait_lock);
10401042
rwsem_set_reader_owned(sem);
10411043
lockevent_inc(rwsem_rlock_fast);

0 commit comments

Comments
 (0)