mirror of
https://git.proxmox.com/git/mirror_zfs.git
synced 2026-05-22 02:27:36 +03:00
Implement a proper rw_tryupgrade
Current rw_tryupgrade does rw_exit and then rw_tryenter(RW_RWITER), and then does rw_enter(RW_READER) if it fails. This violate the assumption that rw_tryupgrade should be atomic and could cause extra contention or even lock inversion. This patch we implement a proper rw_tryupgrade. For rwsem-spinlock, we take the spinlock to check rwsem->count and rwsem->wait_list. For normal rwsem, we use cmpxchg on rwsem->count to change the value from single reader to single writer. Signed-off-by: Chunwei Chen <david.chen@osnexus.com> Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov> Signed-off-by: Tim Chase <tim@chase2k.com> Closes zfsonlinux/zfs#4692 Closes #554
This commit is contained in:
committed by
Brian Behlendorf
parent
c60a51b640
commit
f58040c0fc
@@ -27,6 +27,23 @@
|
||||
|
||||
#include <linux/rwsem.h>
|
||||
|
||||
#ifdef CONFIG_RWSEM_GENERIC_SPINLOCK
|
||||
#define SPL_RWSEM_SINGLE_READER_VALUE (1)
|
||||
#define SPL_RWSEM_SINGLE_WRITER_VALUE (-1)
|
||||
#else
|
||||
#define SPL_RWSEM_SINGLE_READER_VALUE (RWSEM_ACTIVE_READ_BIAS)
|
||||
#define SPL_RWSEM_SINGLE_WRITER_VALUE (RWSEM_ACTIVE_WRITE_BIAS)
|
||||
#endif
|
||||
|
||||
/* Linux 3.16 change activity to count for rwsem-spinlock */
|
||||
#ifdef HAVE_RWSEM_ACTIVITY
|
||||
#define RWSEM_COUNT(sem) sem->activity
|
||||
#else
|
||||
#define RWSEM_COUNT(sem) sem->count
|
||||
#endif
|
||||
|
||||
int rwsem_tryupgrade(struct rw_semaphore *rwsem);
|
||||
|
||||
#if defined(RWSEM_SPINLOCK_IS_RAW)
|
||||
#define spl_rwsem_lock_irqsave(lk, fl) raw_spin_lock_irqsave(lk, fl)
|
||||
#define spl_rwsem_unlock_irqrestore(lk, fl) raw_spin_unlock_irqrestore(lk, fl)
|
||||
|
||||
@@ -223,13 +223,10 @@ RW_LOCK_HELD(krwlock_t *rwp)
|
||||
if (RW_WRITE_HELD(rwp)) { \
|
||||
_rc_ = 1; \
|
||||
} else { \
|
||||
rw_exit(rwp); \
|
||||
if (rw_tryenter(rwp, RW_WRITER)) { \
|
||||
_rc_ = 1; \
|
||||
} else { \
|
||||
rw_enter(rwp, RW_READER); \
|
||||
_rc_ = 0; \
|
||||
} \
|
||||
spl_rw_lockdep_off_maybe(rwp); \
|
||||
if ((_rc_ = rwsem_tryupgrade(SEM(rwp)))) \
|
||||
spl_rw_set_owner(rwp); \
|
||||
spl_rw_lockdep_on_maybe(rwp); \
|
||||
} \
|
||||
_rc_; \
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user