From: Amerigo Wang <amwang@redhat.com> Date: Thu, 17 Dec 2009 03:38:38 -0500 Subject: [misc] rwsem: fix a bug in rwsem_is_locked() Message-id: <20091217034143.3790.83624.sendpatchset@localhost.localdomain> Patchwork-id: 22016 O-Subject: [PATCH RHEL5] rwsem: fix a bug in rwsem_is_locked() Bugzilla: 526092 RH-Acked-by: Avi Kivity <avi@redhat.com> RH-Acked-by: Don Zickus <dzickus@redhat.com> BZ: https://bugzilla.redhat.com/show_bug.cgi?id=526092 Description: rwsem_is_locked() tests ->activity without locks, so we should always keep ->activity consistent. However, the code in __rwsem_do_wake() breaks this rule, it updates ->activity after _all_ readers waken up, this may give some reader a wrong ->activity value, thus cause rwsem_is_locked() behaves wrong. Brew: https://brewweb.devel.redhat.com/taskinfo?taskID=2154491 Upstream status: Commit 29671f22a. Test status: With the testcase from the customer, I can confirm there is no problem after the patch applied. Signed-off-by: WANG Cong <amwang@redhat.com> diff --git a/include/linux/rwsem-spinlock.h b/include/linux/rwsem-spinlock.h index ae1fcad..557bfae 100644 --- a/include/linux/rwsem-spinlock.h +++ b/include/linux/rwsem-spinlock.h @@ -67,11 +67,7 @@ extern int FASTCALL(__down_write_trylock(struct rw_semaphore *sem)); extern void FASTCALL(__up_read(struct rw_semaphore *sem)); extern void FASTCALL(__up_write(struct rw_semaphore *sem)); extern void FASTCALL(__downgrade_write(struct rw_semaphore *sem)); - -static inline int rwsem_is_locked(struct rw_semaphore *sem) -{ - return (sem->activity != 0); -} +extern int FASTCALL(rwsem_is_locked(struct rw_semaphore *sem)); #endif /* __KERNEL__ */ #endif /* _LINUX_RWSEM_SPINLOCK_H */ diff --git a/lib/rwsem-spinlock.c b/lib/rwsem-spinlock.c index c4cfd6c..37c161b 100644 --- a/lib/rwsem-spinlock.c +++ b/lib/rwsem-spinlock.c @@ -17,6 +17,19 @@ struct rwsem_waiter { #define RWSEM_WAITING_FOR_WRITE 0x00000002 }; +int fastcall rwsem_is_locked(struct rw_semaphore *sem) +{ + int ret = 1; + unsigned long flags; + + if (spin_trylock_irqsave(&sem->wait_lock, flags)) { + ret = (sem->activity != 0); + spin_unlock_irqrestore(&sem->wait_lock, flags); + } + return ret; +} +EXPORT_SYMBOL(rwsem_is_locked); + /* * initialise the semaphore */