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