kern/69934: lockmgr can concurrently grant two exclusive locks

Stephan Uphoff ups at tree.com
Mon Aug 2 19:20:24 PDT 2004


>Number:         69934
>Category:       kern
>Synopsis:       lockmgr can concurrently grant two exclusive locks
>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 02:20:23 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:
Upgrading a lock does not play well together with acquiring
an exclusive lock and can lead to two threads being
granted exclusive access.

Problematic sequence:
Thread A acquires a previous unlocked lock in shared mode.
Thread B tries to acquire the same lock in exclusive mode
and blocks.
Thread A upgrades its lock - waking up thread B.
Thread B wakes up and also acquires the same lock as it only checks
if the lock is not shared or if someone wants to upgrade the lock
and not if someone already upgraded the lock to an exclusive lock.


>How-To-Repeat:
	
>Fix:

Minimal patch:
--------------

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 01:38:07 -0000
@@ -389,7 +389,7 @@
 		/*
 		 * 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)
 			break;


Better Patch:
-------------

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 01:51:34 -0000
@@ -382,14 +382,14 @@
 		/*
 		 * 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)
 			break;
>Release-Note:
>Audit-Trail:
>Unformatted:


More information about the freebsd-bugs mailing list