From b1937dd1ca9254e6022a2a427ee20661b7aa285b Mon Sep 17 00:00:00 2001
From: Poul-Henning Kamp <phk@FreeBSD.org>
Date: Fri, 27 Sep 2002 21:24:40 +0000
Subject: [PATCH] Make the UP/DOWN threads hold on to their own private mutex
 while doing work.

This prevents people from sleeping in the UP/DOWN I/O path by mistake
or design (doing so almost invariably result in deadlocks since it
stalls all I/O processing in the given direction.

Sponsored by:   DARPA & NAI Labs.
---
 sys/geom/geom_kern.c | 28 ++++++++++++++++++++++++++--
 1 file changed, 26 insertions(+), 2 deletions(-)

diff --git a/sys/geom/geom_kern.c b/sys/geom/geom_kern.c
index 8eceb3c04cd5..c68271eaf7a4 100644
--- a/sys/geom/geom_kern.c
+++ b/sys/geom/geom_kern.c
@@ -59,16 +59,37 @@ static struct proc *g_up_proc;
 
 int g_debugflags;
 
+/*
+ * G_UP and G_DOWN are the two threads which push I/O through the
+ * stack.
+ *
+ * Things are procesed in a FIFO order, but these threads could be
+ * part of I/O prioritization by deciding which bios/bioqs to service
+ * in what order.
+ *
+ * We have only one thread in each direction, it is belived that until
+ * a very non-trivial workload in the UP/DOWN path this will be enough,
+ * but more than one can actually be run without problems.
+ *
+ * Holding the "mymutex" is a debugging feature:  It prevents people
+ * from sleeping in the UP/DOWN I/O path by mistake or design (doing
+ * so almost invariably result in deadlocks since it stalls all I/O
+ * processing in the given direction.
+ */
+
 static void
 g_up_procbody(void)
 {
 	struct proc *p = g_up_proc;
 	struct thread *tp = FIRST_THREAD_IN_PROC(p);
+	struct mtx mymutex;
 
+	mtx_init(&mymutex, "g_up", MTX_DEF, 0);
+	mtx_lock(&mymutex);
 	curthread->td_base_pri = PRIBIO;
 	for(;;) {
 		g_io_schedule_up(tp);
-		tsleep(&g_wait_up, PRIBIO, "g_up", hz/10);
+		msleep(&g_wait_up, &mymutex, PRIBIO, "g_up", hz/10);
 	}
 }
 
@@ -85,11 +106,14 @@ g_down_procbody(void)
 {
 	struct proc *p = g_down_proc;
 	struct thread *tp = FIRST_THREAD_IN_PROC(p);
+	struct mtx mymutex;
 
+	mtx_init(&mymutex, "g_down", MTX_DEF, 0);
+	mtx_lock(&mymutex);
 	curthread->td_base_pri = PRIBIO;
 	for(;;) {
 		g_io_schedule_down(tp);
-		tsleep(&g_wait_down, PRIBIO, "g_down", hz/10);
+		msleep(&g_wait_down, &mymutex, PRIBIO, "g_down", hz/10);
 	}
 }