diff options
author | kib <kib@FreeBSD.org> | 2014-11-02 13:10:31 +0000 |
---|---|---|
committer | kib <kib@FreeBSD.org> | 2014-11-02 13:10:31 +0000 |
commit | cf11d25e1821ead21e66c6d5ce99d1b3c7c2dedd (patch) | |
tree | 771e235c218a61739696264fe066341f046c7f9b /sys/kern/kern_lock.c | |
parent | c53f11d985b382be2a49d0c6b8de39dd30f32a71 (diff) | |
download | FreeBSD-src-cf11d25e1821ead21e66c6d5ce99d1b3c7c2dedd.zip FreeBSD-src-cf11d25e1821ead21e66c6d5ce99d1b3c7c2dedd.tar.gz |
Fix two issues with lockmgr(9) LK_CAN_SHARE() test, which determines
whether the shared request for already shared-locked lock could be
granted. Both problems result in the exclusive locker starvation.
The concurrent exclusive request is indicated by either
LK_EXCLUSIVE_WAITERS or LK_EXCLUSIVE_SPINNERS flags. The reverse
condition, i.e. no exclusive waiters, must check that both flags are
cleared.
Add a flag LK_NODDLKTREAT for shared lock request to indicate that
current thread guarantees that it does not own the lock in shared
mode. This turns back the exclusive lock starvation avoidance code;
see man page update for detailed description.
Use LK_NODDLKTREAT when doing lookup(9).
Reported and tested by: pho
No objections from: attilio
Sponsored by: The FreeBSD Foundation
MFC after: 2 weeks
Diffstat (limited to 'sys/kern/kern_lock.c')
-rw-r--r-- | sys/kern/kern_lock.c | 13 |
1 files changed, 7 insertions, 6 deletions
diff --git a/sys/kern/kern_lock.c b/sys/kern/kern_lock.c index 965033a..24d94cc 100644 --- a/sys/kern/kern_lock.c +++ b/sys/kern/kern_lock.c @@ -115,10 +115,11 @@ CTASSERT(LK_UNLOCKED == (LK_UNLOCKED & } \ } while (0) -#define LK_CAN_SHARE(x) \ - (((x) & LK_SHARE) && (((x) & LK_EXCLUSIVE_WAITERS) == 0 || \ - ((x) & LK_EXCLUSIVE_SPINNERS) == 0 || \ - curthread->td_lk_slocks || (curthread->td_pflags & TDP_DEADLKTREAT))) +#define LK_CAN_SHARE(x, flags) \ + (((x) & LK_SHARE) && \ + (((x) & (LK_EXCLUSIVE_WAITERS | LK_EXCLUSIVE_SPINNERS)) == 0 || \ + (curthread->td_lk_slocks != 0 && !(flags & LK_NODDLKTREAT)) || \ + (curthread->td_pflags & TDP_DEADLKTREAT))) #define LK_TRYOP(x) \ ((x) & LK_NOWAIT) @@ -530,7 +531,7 @@ __lockmgr_args(struct lock *lk, u_int flags, struct lock_object *ilk, * waiters, if we fail to acquire the shared lock * loop back and retry. */ - if (LK_CAN_SHARE(x)) { + if (LK_CAN_SHARE(x, flags)) { if (atomic_cmpset_acq_ptr(&lk->lk_lock, x, x + LK_ONE_SHARER)) break; @@ -635,7 +636,7 @@ __lockmgr_args(struct lock *lk, u_int flags, struct lock_object *ilk, * if the lock can be acquired in shared mode, try * again. */ - if (LK_CAN_SHARE(x)) { + if (LK_CAN_SHARE(x, flags)) { sleepq_release(&lk->lock_object); continue; } |