==== //depot/user/tanimura/inodezone_uma/kern/kern_sx.c#1 - /home/carrots/tanimura/silver4/p4-freefall/inodezone_uma/kern/kern_sx.c ====
--- /tmp/tmp.89710.0	Sat Mar 16 18:50:40 2002
+++ /home/carrots/tanimura/silver4/p4-freefall/inodezone_uma/kern/kern_sx.c	Sat Mar 16 17:56:00 2002
@@ -72,6 +72,7 @@
 	cv_init(&sx->sx_excl_cv, description);
 	sx->sx_excl_wcnt = 0;
 	sx->sx_xholder = NULL;
+	sx->sx_upgrader = NULL;
 
 	LOCK_LOG_INIT(lock, 0);
 
@@ -215,7 +216,15 @@
 	 * there are exclusive lock waiters.
 	 */
 	if (sx->sx_excl_wcnt > 0) {
-		if (sx->sx_cnt == 0)
+		/*
+		 * The upgrader beats any other exclusive lockers.
+		 * Note that the upgrader holds the last shared lock.
+		 */
+		if (sx->sx_upgrader != NULL && sx->sx_cnt == 1) {
+			KASSERT(td->td_flags & TDF_CVWAITQ != 0,
+				("_sx_sunlock: the upgrader is not waiting for sx_excl_cv"));
+			cv_waitq_remove(sx->sx_upgrader);
+		} else if (sx->sx_cnt == 0)
 			cv_signal(&sx->sx_excl_cv);
 	} else if (sx->sx_shrd_wcnt > 0)
 		cv_broadcast(&sx->sx_shrd_cv);
@@ -250,6 +259,45 @@
 	LOCK_LOG_LOCK("XUNLOCK", &sx->sx_object, 0, 0, file, line);
 
 	mtx_unlock(sx->sx_lock);
+}
+
+int
+_sx_upgrade(struct sx *sx, const char *file, int line)
+{
+
+	_sx_assert(sx, SX_SLOCKED, file, line);
+	mtx_lock(sx->sx_lock);
+
+	/*
+	 * If another thread is waiting for lock upgrade,
+	 * the curtherad must unlock this sx.
+	 */
+	if (sx->sx_upgrader != NULL) {
+		mtx_unlock(sx->sx_lock);
+		return (0);
+	}
+	sx->sx_upgrader = curthread;
+
+	/* Loop in case we lose the race for lock acquisition. */
+	while (sx->sx_cnt != 1) {
+		sx->sx_excl_wcnt++;
+		cv_wait(&sx->sx_excl_cv, sx->sx_lock);
+		sx->sx_excl_wcnt--;
+	}
+
+	/* We must be the sole thread slocking this sx. */
+	MPASS(sx->sx_cnt == 1);
+
+	/* Acquire an exclusive lock. */
+	sx->sx_cnt = -1;
+	sx->sx_xholder = curthread;
+	sx->sx_upgrader = NULL;
+
+	LOCK_LOG_LOCK("XUPGRADE", &sx->sx_object, 0, 1, file, line);
+	WITNESS_UPGRADE(&sx->sx_object, LOP_EXCLUSIVE, file, line);
+
+	mtx_unlock(sx->sx_lock);
+	return (1);
 }
 
 int
==== //depot/user/tanimura/inodezone_uma/kern/subr_witness.c#1 - /home/carrots/tanimura/silver4/p4-freefall/inodezone_uma/kern/subr_witness.c ====
--- /tmp/tmp.89710.1	Sat Mar 16 18:50:41 2002
+++ /home/carrots/tanimura/silver4/p4-freefall/inodezone_uma/kern/subr_witness.c	Sat Mar 16 18:02:38 2002
@@ -717,9 +717,9 @@
 	if ((lock->lo_flags & LO_UPGRADABLE) == 0)
 		panic("upgrade of non-upgradable lock (%s) %s @ %s:%d",
 		    class->lc_name, lock->lo_name, file, line);
-	if ((flags & LOP_TRYLOCK) == 0)
-		panic("non-try upgrade of lock (%s) %s @ %s:%d", class->lc_name,
-		    lock->lo_name, file, line);
+	if ((flags & LOP_TRYLOCK) == 0) {
+		/* TODO: check for lock order reversal. */
+	}
 	if ((lock->lo_class->lc_flags & LC_SLEEPLOCK) == 0)
 		panic("upgrade of non-sleep lock (%s) %s @ %s:%d",
 		    class->lc_name, lock->lo_name, file, line);
==== //depot/user/tanimura/inodezone_uma/sys/sx.h#1 - /home/carrots/tanimura/silver4/p4-freefall/inodezone_uma/sys/sx.h ====
--- /tmp/tmp.89710.2	Sat Mar 16 18:50:41 2002
+++ /home/carrots/tanimura/silver4/p4-freefall/inodezone_uma/sys/sx.h	Sat Mar 16 17:33:09 2002
@@ -44,6 +44,7 @@
 	struct cv	sx_excl_cv;	/* xlock waiters. */
 	int		sx_excl_wcnt;	/* Number of xlock waiters. */
 	struct thread	*sx_xholder;	/* Thread presently holding xlock. */
+	struct thread	*sx_upgrader;	/* Thread presently waiting for lock upgrade. */
 };
 
 #ifdef _KERNEL
@@ -55,6 +56,7 @@
 int	_sx_try_xlock(struct sx *sx, const char *file, int line);
 void	_sx_sunlock(struct sx *sx, const char *file, int line);
 void	_sx_xunlock(struct sx *sx, const char *file, int line);
+int	_sx_upgrade(struct sx *sx, const char *file, int line);
 int	_sx_try_upgrade(struct sx *sx, const char *file, int line);
 void	_sx_downgrade(struct sx *sx, const char *file, int line);
 #ifdef INVARIANT_SUPPORT
@@ -67,6 +69,7 @@
 #define	sx_try_xlock(sx)	_sx_try_xlock((sx), LOCK_FILE, LOCK_LINE)
 #define	sx_sunlock(sx)		_sx_sunlock((sx), LOCK_FILE, LOCK_LINE)
 #define	sx_xunlock(sx)		_sx_xunlock((sx), LOCK_FILE, LOCK_LINE)
+#define	sx_upgrade(sx)		_sx_upgrade((sx), LOCK_FILE, LOCK_LINE)
 #define	sx_try_upgrade(sx)	_sx_try_upgrade((sx), LOCK_FILE, LOCK_LINE)
 #define	sx_downgrade(sx)	_sx_downgrade((sx), LOCK_FILE, LOCK_LINE)
 
