diff options
author | pjd <pjd@FreeBSD.org> | 2007-10-02 14:48:48 +0000 |
---|---|---|
committer | pjd <pjd@FreeBSD.org> | 2007-10-02 14:48:48 +0000 |
commit | 9281633138328ca36863a2979937bba813fd87ee (patch) | |
tree | c83d5bf93e9034addc290aa0150bf83faf3b7bba /sys/kern/kern_sx.c | |
parent | 23d44f1bb57126f02c3ec8aadef205ab08c43b3c (diff) | |
download | FreeBSD-src-9281633138328ca36863a2979937bba813fd87ee.zip FreeBSD-src-9281633138328ca36863a2979937bba813fd87ee.tar.gz |
Fix sx_try_slock(), so it only fails when there is an exclusive owner.
Before that fix, it was possible for the function to fail if number
of sharers changes between 'x = sx->sx_lock' step and atomic_cmpset_acq_ptr()
call.
This fixes ZFS problem when ZFS returns strange EIO errors under load.
In ZFS there is a code that depends on the fact that sx_try_slock() can
only fail if there is an exclusive owner.
Discussed with: attilio
Reviewed by: jhb
Approved by: re (kensmith)
Diffstat (limited to 'sys/kern/kern_sx.c')
-rw-r--r-- | sys/kern/kern_sx.c | 21 |
1 files changed, 12 insertions, 9 deletions
diff --git a/sys/kern/kern_sx.c b/sys/kern/kern_sx.c index 03ffd0e..23dd4b6 100644 --- a/sys/kern/kern_sx.c +++ b/sys/kern/kern_sx.c @@ -217,15 +217,18 @@ _sx_try_slock(struct sx *sx, const char *file, int line) { uintptr_t x; - x = sx->sx_lock; - KASSERT(x != SX_LOCK_DESTROYED, - ("sx_try_slock() of destroyed sx @ %s:%d", file, line)); - if ((x & SX_LOCK_SHARED) && atomic_cmpset_acq_ptr(&sx->sx_lock, x, - x + SX_ONE_SHARER)) { - LOCK_LOG_TRY("SLOCK", &sx->lock_object, 0, 1, file, line); - WITNESS_LOCK(&sx->lock_object, LOP_TRYLOCK, file, line); - curthread->td_locks++; - return (1); + for (;;) { + x = sx->sx_lock; + KASSERT(x != SX_LOCK_DESTROYED, + ("sx_try_slock() of destroyed sx @ %s:%d", file, line)); + if (!(x & SX_LOCK_SHARED)) + break; + if (atomic_cmpset_acq_ptr(&sx->sx_lock, x, x + SX_ONE_SHARER)) { + LOCK_LOG_TRY("SLOCK", &sx->lock_object, 0, 1, file, line); + WITNESS_LOCK(&sx->lock_object, LOP_TRYLOCK, file, line); + curthread->td_locks++; + return (1); + } } LOCK_LOG_TRY("SLOCK", &sx->lock_object, 0, 0, file, line); |