diff options
author | Chunwei Chen <[email protected]> | 2016-05-25 16:35:42 -0700 |
---|---|---|
committer | Brian Behlendorf <[email protected]> | 2016-05-31 11:44:15 -0700 |
commit | f58040c0fc8bc6490fcc75db7fc3e709dfc3c656 (patch) | |
tree | 03aaebb8e0e152ade6edb7a9ae14f4b430314797 /include/sys/rwlock.h | |
parent | c60a51b640bab61c54f370752750841675730899 (diff) |
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 <[email protected]>
Signed-off-by: Brian Behlendorf <[email protected]>
Signed-off-by: Tim Chase <[email protected]>
Closes zfsonlinux/zfs#4692
Closes #554
Diffstat (limited to 'include/sys/rwlock.h')
-rw-r--r-- | include/sys/rwlock.h | 11 |
1 files changed, 4 insertions, 7 deletions
diff --git a/include/sys/rwlock.h b/include/sys/rwlock.h index 14d097b01..facebe3ba 100644 --- a/include/sys/rwlock.h +++ b/include/sys/rwlock.h @@ -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_; \ }) |