| From foo@baz Sun Jun 17 12:07:34 CEST 2018 |
| From: Waiman Long <longman@redhat.com> |
| Date: Tue, 15 May 2018 17:49:51 -0400 |
| Subject: locking/percpu-rwsem: Annotate rwsem ownership transfer by setting RWSEM_OWNER_UNKNOWN |
| |
| From: Waiman Long <longman@redhat.com> |
| |
| [ Upstream commit 5a817641f68a6399a5fac8b7d2da67a73698ffed ] |
| |
| 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> |
| Signed-off-by: Sasha Levin <alexander.levin@microsoft.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| include/linux/percpu-rwsem.h | 6 +++++- |
| include/linux/rwsem.h | 6 ++++++ |
| kernel/locking/rwsem-xadd.c | 2 ++ |
| 3 files changed, 13 insertions(+), 1 deletion(-) |
| |
| --- a/include/linux/percpu-rwsem.h |
| +++ b/include/linux/percpu-rwsem.h |
| @@ -133,7 +133,7 @@ static inline void percpu_rwsem_release( |
| lock_release(&sem->rw_sem.dep_map, 1, ip); |
| #ifdef CONFIG_RWSEM_SPIN_ON_OWNER |
| if (!read) |
| - sem->rw_sem.owner = NULL; |
| + sem->rw_sem.owner = RWSEM_OWNER_UNKNOWN; |
| #endif |
| } |
| |
| @@ -141,6 +141,10 @@ static inline void percpu_rwsem_acquire( |
| bool read, unsigned long ip) |
| { |
| lock_acquire(&sem->rw_sem.dep_map, 0, 1, read, 1, NULL, ip); |
| +#ifdef CONFIG_RWSEM_SPIN_ON_OWNER |
| + if (!read) |
| + sem->rw_sem.owner = current; |
| +#endif |
| } |
| |
| #endif |
| --- a/include/linux/rwsem.h |
| +++ b/include/linux/rwsem.h |
| @@ -44,6 +44,12 @@ struct rw_semaphore { |
| #endif |
| }; |
| |
| +/* |
| + * Setting bit 0 of the owner field with other non-zero bits will indicate |
| + * that the rwsem is writer-owned with an unknown owner. |
| + */ |
| +#define RWSEM_OWNER_UNKNOWN ((struct task_struct *)-1L) |
| + |
| 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); |
| extern struct rw_semaphore *rwsem_down_write_failed(struct rw_semaphore *sem); |
| --- a/kernel/locking/rwsem-xadd.c |
| +++ b/kernel/locking/rwsem-xadd.c |
| @@ -352,6 +352,8 @@ static inline bool rwsem_can_spin_on_own |
| struct task_struct *owner; |
| bool ret = true; |
| |
| + BUILD_BUG_ON(!rwsem_has_anonymous_owner(RWSEM_OWNER_UNKNOWN)); |
| + |
| if (need_resched()) |
| return false; |
| |