--- /usr/src/sys/kern/kern_sx.c	Thu Apr 12 05:27:25 2007
+++ kern_sx.c	Mon May  7 06:13:08 2007
@@ -170,7 +170,10 @@
 {
 	int flags;
 
-	flags = LO_SLEEPABLE | LO_UPGRADABLE | LO_RECURSABLE;
+	MPASS(!(opts & ~(SX_DUPOK | SX_NOPROFILE | SX_NOWITNESS | SX_QUIET |
+	    SX_ADAPTIVESPIN)));
+
+	flags = LO_RECURSABLE | LO_SLEEPABLE | LO_UPGRADABLE;
 	if (opts & SX_DUPOK)
 		flags |= LO_DUPOK;
 	if (opts & SX_NOPROFILE)
@@ -273,7 +276,12 @@
 	curthread->td_locks--;
 	WITNESS_UNLOCK(&sx->lock_object, 0, file, line);
 	LOCK_LOG_LOCK("SUNLOCK", &sx->lock_object, 0, 0, file, line);
-	if (SX_SHARERS(sx->sx_lock) == 0)
+	/*
+	 * This stub here is bogus since a new shared owner can arrive and
+	 * let the loop restart.  However, there is not an easy way to fix
+	 * it, so it does the less hurting thing.
+	 */
+	if (SX_SHARERS(sx->sx_lock) == 1)
 		lock_profile_release_lock(&sx->lock_object);
 	__sx_sunlock(sx, file, line);
 }
@@ -391,9 +399,9 @@
 #ifdef ADAPTIVE_SX
 	volatile struct thread *owner;
 #endif
+	uint64_t waittime = 0;
 	uintptr_t x;
 	int contested = 0;
-	uint64_t waitstart = 0;
 
 	/* If we already hold an exclusive lock, then recurse. */
 	if (sx_xlocked(sx)) {
@@ -403,8 +411,6 @@
 			CTR2(KTR_LOCK, "%s: %p recursing", __func__, sx);
 		return;
 	}
-	lock_profile_obtain_lock_failed(&(sx)->lock_object,
-	    &contested, &waitstart);
 
 	if (LOCK_LOG_TEST(&sx->lock_object, 0))
 		CTR5(KTR_LOCK, "%s: %s contested (lock=%p) at %s:%d", __func__,
@@ -427,6 +433,8 @@
 					CTR3(KTR_LOCK,
 					    "%s: spinning on %p held by %p",
 					    __func__, sx, owner);
+				lock_profile_obtain_lock_failed(
+				    &sx->lock_object, &contested, &waittime);
 				GIANT_SAVE();
 				while (SX_OWNER(sx->sx_lock) == x &&
 				    TD_IS_RUNNING(owner))
@@ -513,6 +521,8 @@
 			CTR2(KTR_LOCK, "%s: %p blocking on sleep queue",
 			    __func__, sx);
 
+		lock_profile_obtain_lock_failed(&sx->lock_object, &contested,
+		    &waittime);
 		GIANT_SAVE();
 		sleepq_add(&sx->lock_object, NULL, sx->lock_object.lo_name,
 		    SLEEPQ_SX, SQ_EXCLUSIVE_QUEUE);
@@ -522,10 +532,10 @@
 			CTR2(KTR_LOCK, "%s: %p resuming from sleep queue",
 			    __func__, sx);
 	}
-	
+
 	GIANT_RESTORE();
-	lock_profile_obtain_lock_success(&(sx)->lock_object, contested,
-	    waitstart, file, line);
+	lock_profile_obtain_lock_success(&sx->lock_object, contested, waittime,
+	    file, line);
 }
 
 /*
@@ -592,14 +602,14 @@
 #ifdef ADAPTIVE_SX
 	volatile struct thread *owner;
 #endif
+	uint64_t waittime = 0;
 	uintptr_t x;
-	uint64_t waitstart = 0;
 	int contested = 0;
+
 	/*
 	 * As with rwlocks, we don't make any attempt to try to block
 	 * shared locks once there is an exclusive waiter.
 	 */
-	
 	for (;;) {
 		x = sx->sx_lock;
 
@@ -613,20 +623,16 @@
 			MPASS(!(x & SX_LOCK_SHARED_WAITERS));
 			if (atomic_cmpset_acq_ptr(&sx->sx_lock, x,
 			    x + SX_ONE_SHARER)) {
-				if (SX_SHARERS(x) == 0)
-					lock_profile_obtain_lock_success(
-					    &sx->lock_object, contested,
-					    waitstart, file, line);
 				if (LOCK_LOG_TEST(&sx->lock_object, 0))
 					CTR4(KTR_LOCK,
 					    "%s: %p succeed %p -> %p", __func__,
 					    sx, (void *)x,
 					    (void *)(x + SX_ONE_SHARER));
+				lock_profile_obtain_lock_success(
+				    &sx->lock_object, contested, waittime,
+				    file, line);
 				break;
 			}
-			lock_profile_obtain_lock_failed(&sx->lock_object, &contested,
-			    &waitstart);
-
 			continue;
 		}
 
@@ -640,23 +646,20 @@
 			x = SX_OWNER(x);
 			owner = (struct thread *)x;
 			if (TD_IS_RUNNING(owner)) {
-				lock_profile_obtain_lock_failed(&sx->lock_object, &contested,
-				    &waitstart);
 				if (LOCK_LOG_TEST(&sx->lock_object, 0))
 					CTR3(KTR_LOCK,
 					    "%s: spinning on %p held by %p",
 					    __func__, sx, owner);
+				lock_profile_obtain_lock_failed(
+				    &sx->lock_object, &contested, &waittime);
 				GIANT_SAVE();
 				while (SX_OWNER(sx->sx_lock) == x &&
 				    TD_IS_RUNNING(owner))
 					cpu_spinwait();
 				continue;
 			}
-		} 
+		}
 #endif
-		else
-			lock_profile_obtain_lock_failed(&sx->lock_object, &contested,
-			    &waitstart);
 
 		/*
 		 * Some other thread already has an exclusive lock, so
@@ -713,7 +716,9 @@
 		if (LOCK_LOG_TEST(&sx->lock_object, 0))
 			CTR2(KTR_LOCK, "%s: %p blocking on sleep queue",
 			    __func__, sx);
-		
+
+		lock_profile_obtain_lock_failed(&sx->lock_object, &contested,
+		    &waittime);
 		GIANT_SAVE();
 		sleepq_add(&sx->lock_object, NULL, sx->lock_object.lo_name,
 		    SLEEPQ_SX, SQ_SHARED_QUEUE);
@@ -773,7 +778,6 @@
 			MPASS(x == SX_SHARERS_LOCK(1));
 			if (atomic_cmpset_ptr(&sx->sx_lock, SX_SHARERS_LOCK(1),
 			    SX_LOCK_UNLOCKED)) {
-				lock_profile_release_lock(&sx->lock_object);
 				if (LOCK_LOG_TEST(&sx->lock_object, 0))
 					CTR2(KTR_LOCK, "%s: %p last succeeded",
 					    __func__, sx);
@@ -788,7 +792,6 @@
 		 */
 		MPASS(x == (SX_SHARERS_LOCK(1) | SX_LOCK_EXCLUSIVE_WAITERS));
 
-		lock_profile_release_lock(&sx->lock_object);
 		sleepq_lock(&sx->lock_object);
 
 		/*
--- /usr/src/sys/sys/sx.h	2007/04/03 23:02:12
+++ sx.h	2007/05/04 10:26:16
@@ -99,9 +99,9 @@
 	uintptr_t _tid = (uintptr_t)(tid);				\
 									\
 	if (!atomic_cmpset_acq_ptr(&(sx)->sx_lock, SX_LOCK_UNLOCKED,	\
-	    _tid)) {							\
+	    _tid))							\
 		_sx_xlock_hard((sx), _tid, (file), (line));		\
-	} else								\
+	else								\
 		lock_profile_obtain_lock_success(&(sx)->lock_object, 0,	\
 		    0, (file), (line));					\
 } while (0)
@@ -121,9 +121,9 @@
 									\
 	if (!(x & SX_LOCK_SHARED) ||					\
 	    !atomic_cmpset_acq_ptr(&(sx)->sx_lock, x,			\
-	    x + SX_ONE_SHARER)) {					\
+	    x + SX_ONE_SHARER))						\
 		_sx_slock_hard((sx), (file), (line));			\
-	} else								\
+	else								\
 		lock_profile_obtain_lock_success(&(sx)->lock_object, 0,	\
 		    0, (file), (line));					\
 } while (0)
