kern/69964: [patch] lockmgr can forget to unblock clients
Stephan Uphoff
ups at tree.com
Tue Aug 3 14:30:20 PDT 2004
>Number: 69964
>Category: kern
>Synopsis: [patch] lockmgr can forget to unblock clients
>Confidential: no
>Severity: serious
>Priority: medium
>Responsible: freebsd-bugs
>State: open
>Quarter:
>Keywords:
>Date-Required:
>Class: sw-bug
>Submitter-Id: current-users
>Arrival-Date: Tue Aug 03 21:30:19 GMT 2004
>Closed-Date:
>Last-Modified:
>Originator: Stephan Uphoff
>Release: FreeBSD 5.2.1-RELEASE-p5 i386
>Organization:
>Environment:
System: FreeBSD palm.tree.com 5.2.1-RELEASE-p5 FreeBSD 5.2.1-RELEASE-p5 #2: Fri May 7 20:06:27 EDT 2004 ups at palm.tree.com:/usr/obj/usr/src/sys/PALM i386
>Description:
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 optaining a full lock
other threads are not awoken.
This can happens if obtaining the full lock fails because of a LK_SLEEPFAIL, LK_TIMELOCK
or a signal (if lock priority includes PCATCH .. don't think this is used).
>How-To-Repeat:
>Fix:
The following patch also includes the fix for kern/69934
diff -u -r1.73 kern_lock.c
--- kern_lock.c 23 Jul 2004 20:12:56 -0000 1.73
+++ kern_lock.c 3 Aug 2004 20:15:22 -0000
@@ -335,8 +335,12 @@
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 @@
/*
* 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)
>Release-Note:
>Audit-Trail:
>Unformatted:
More information about the freebsd-bugs
mailing list