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>
This commit is contained in:
Alexander Kabaev 2004-08-16 15:01:22 +00:00
parent f03b27517b
commit c8b876219f

View File

@ -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)