summaryrefslogtreecommitdiffstats
path: root/sys/kern/kern_lock.c
diff options
context:
space:
mode:
authorkib <kib@FreeBSD.org>2014-11-02 13:10:31 +0000
committerkib <kib@FreeBSD.org>2014-11-02 13:10:31 +0000
commitcf11d25e1821ead21e66c6d5ce99d1b3c7c2dedd (patch)
tree771e235c218a61739696264fe066341f046c7f9b /sys/kern/kern_lock.c
parentc53f11d985b382be2a49d0c6b8de39dd30f32a71 (diff)
downloadFreeBSD-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.c13
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;
}
OpenPOWER on IntegriCloud