summaryrefslogtreecommitdiffstats
path: root/sys/kern/kern_sx.c
diff options
context:
space:
mode:
authorpjd <pjd@FreeBSD.org>2007-10-02 14:48:48 +0000
committerpjd <pjd@FreeBSD.org>2007-10-02 14:48:48 +0000
commit9281633138328ca36863a2979937bba813fd87ee (patch)
treec83d5bf93e9034addc290aa0150bf83faf3b7bba /sys/kern/kern_sx.c
parent23d44f1bb57126f02c3ec8aadef205ab08c43b3c (diff)
downloadFreeBSD-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.c21
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);
OpenPOWER on IntegriCloud