summaryrefslogtreecommitdiffstats
path: root/sys/kern
diff options
context:
space:
mode:
authorkan <kan@FreeBSD.org>2004-08-16 15:01:22 +0000
committerkan <kan@FreeBSD.org>2004-08-16 15:01:22 +0000
commit2c6402abdd646a517d0a0e476a432ee35fd8770f (patch)
treeb367fcda56a40b13622f29f1e200012e1753f08a /sys/kern
parent1d5fa9d950aab078562e5ec6ac4999759ae30cc3 (diff)
downloadFreeBSD-src-2c6402abdd646a517d0a0e476a432ee35fd8770f.zip
FreeBSD-src-2c6402abdd646a517d0a0e476a432ee35fd8770f.tar.gz
Upgrading a lock does not play well together with acquiring an exclusive lock
and can lead to two threads being granted exclusive access. Check that no one has the same lock in exclusive mode before proceeding to acquire it. The LK_WANT_EXCL and LK_WANT_UPGRADE bits act as mini-locks and can block other threads. Normally this is not a problem since the mini locks are upgraded to full locks and the release of the locks will unblock the other threads. However if a thread reset the bits without obtaining a full lock other threads are not awoken. Add missing wakeups for these cases. PR: kern/69964 Submitted by: Stephan Uphoff <ups at tree dot com> Very good catch by: Stephan Uphoff <ups at tree dot com>
Diffstat (limited to 'sys/kern')
-rw-r--r--sys/kern/kern_lock.c17
1 files changed, 12 insertions, 5 deletions
diff --git a/sys/kern/kern_lock.c b/sys/kern/kern_lock.c
index c819ba1..f1b6a42 100644
--- a/sys/kern/kern_lock.c
+++ b/sys/kern/kern_lock.c
@@ -335,8 +335,12 @@ debuglockmgr(lkp, flags, interlkp, td, name, file, line)
error = acquire(&lkp, extflags, LK_SHARE_NONZERO);
lkp->lk_flags &= ~LK_WANT_UPGRADE;
- if (error)
- break;
+ if (error) {
+ if ((lkp->lk_flags & ( LK_WANT_EXCL | LK_WAIT_NONZERO)) == (LK_WANT_EXCL | LK_WAIT_NONZERO))
+ wakeup((void *)lkp);
+ break;
+ }
+
lkp->lk_flags |= LK_HAVE_EXCL;
lkp->lk_lockholder = thr;
if (lkp->lk_exclusivecount != 0)
@@ -382,17 +386,20 @@ debuglockmgr(lkp, flags, interlkp, td, name, file, line)
/*
* Try to acquire the want_exclusive flag.
*/
- error = acquire(&lkp, extflags, (LK_HAVE_EXCL | LK_WANT_EXCL));
+ error = acquire(&lkp, extflags, LK_WANT_EXCL);
if (error)
break;
lkp->lk_flags |= LK_WANT_EXCL;
/*
* Wait for shared locks and upgrades to finish.
*/
- error = acquire(&lkp, extflags, LK_WANT_UPGRADE | LK_SHARE_NONZERO);
+ error = acquire(&lkp, extflags, LK_HAVE_EXCL | LK_WANT_UPGRADE | LK_SHARE_NONZERO);
lkp->lk_flags &= ~LK_WANT_EXCL;
- if (error)
+ if (error) {
+ if (lkp->lk_flags & LK_WAIT_NONZERO)
+ wakeup((void *)lkp);
break;
+ }
lkp->lk_flags |= LK_HAVE_EXCL;
lkp->lk_lockholder = thr;
if (lkp->lk_exclusivecount != 0)
OpenPOWER on IntegriCloud