locking/percpu-rwsem: Annotate rwsem ownership transfer by setting RWSEM_OWNER_UNKNOWN

The filesystem freezing code needs to transfer ownership of a rwsem
embedded in a percpu-rwsem from the task that does the freezing to
another one that does the thawing by calling percpu_rwsem_release()
after freezing and percpu_rwsem_acquire() before thawing.

However, the new rwsem debug code runs afoul with this scheme by warning
that the task that releases the rwsem isn't the one that acquires it,
as reported by Amir Goldstein:

DEBUG_LOCKS_WARN_ON(sem->owner != get_current())
WARNING: CPU: 1 PID: 1401 at /home/amir/build/src/linux/kernel/locking/rwsem.c:133 up_write+0x59/0x79

Call Trace:
percpu_up_write+0x1f/0x28
thaw_super_locked+0xdf/0x120
do_vfs_ioctl+0x270/0x5f1
ksys_ioctl+0x52/0x71
__x64_sys_ioctl+0x16/0x19
do_syscall_64+0x5d/0x167
entry_SYSCALL_64_after_hwframe+0x49/0xbe

To work properly with the rwsem debug code, we need to annotate that the
rwsem ownership is unknown during the tranfer period until a brave soul
comes forward to acquire the ownership. During that period, optimistic
spinning will be disabled.

Reported-by: Amir Goldstein <amir73il@gmail.com>
Tested-by: Amir Goldstein <amir73il@gmail.com>
Signed-off-by: Waiman Long <longman@redhat.com>
Acked-by: Peter Zijlstra <peterz@infradead.org>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Davidlohr Bueso <dave@stgolabs.net>
Cc: Jan Kara <jack@suse.cz>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Matthew Wilcox <willy@infradead.org>
Cc: Oleg Nesterov <oleg@redhat.com>
Cc: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Cc: Theodore Y. Ts'o <tytso@mit.edu>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Will Deacon <will.deacon@arm.com>
Cc: linux-fsdevel@vger.kernel.org
Link: http://lkml.kernel.org/r/1526420991-21213-3-git-send-email-longman@redhat.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>

authored by Waiman Long and committed by Ingo Molnar 5a817641 d7d760ef

+13 -1
+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);
+2
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