Subject: tsleep() in vfs_shutdown (update)
To: None <tech-kern@netbsd.org>
From: Manuel Bouyer <bouyer@antioche.lip6.fr>
List: tech-kern
Date: 08/27/2000 22:21:21
--envbJBWh7q8WU6mo
Content-Type: text/plain; charset=us-ascii

Hi,
attached is an updated patch to allow tsleep() in vfs_shutdown() instead of
delay(). Per Jason's comments, setrunnable() & friends now mark processes
SHOLD instead of SRUN when needed. I also renamed stopsched() to
suspendsched() and added a resumesched(), to put back SHOLD processes in the
run queue.

suspendsched()/resumesched() uses a counter, so that it's possible to call
suspendsched() from different places without special care. I added a new
p_flag, P_HOLD, set for processes which should be set SHOLD rather than
SRUN when they become runnable again.
suspendsched() asserts P_HOLD for all processes but curproc and P_SYSTEM
processes. P_HOLD is tested before marking a process SRUN again (can now
be marked SRUN or SHOLD).
I'm not sure about the semantic resumesched() should have when it's called
but the suspend counter is greather than 1 (that is, more than one process
have suspended the sheduler, see the XXX in the code). For now the current
process will keep running but this may not be rigth. Maybe we should tsleep(),
waiting to the suspend counter to be back to 0 ?

I'm waiting for comments. If I don't hear anything before Thursday, 31 I'll
commit this and ask for a pull up (I want this to be in 1.5_BETA, it's really
important for RAIDframe users).

--
Manuel Bouyer, LIP6, Universite Paris VI.           Manuel.Bouyer@lip6.fr
--

--envbJBWh7q8WU6mo
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="diff-1.5"

Index: compat/svr4/svr4_lwp.c
===================================================================
RCS file: /cvsroot/syssrc/sys/compat/svr4/svr4_lwp.c,v
retrieving revision 1.3
diff -u -r1.3 svr4_lwp.c
--- compat/svr4/svr4_lwp.c	2000/05/28 05:49:05	1.3
+++ compat/svr4/svr4_lwp.c	2000/08/27 19:16:16
@@ -253,7 +253,7 @@
 	if (!CANSIGNAL(p, p->p_cred, pt, 0))
 		return EPERM;
 
-	pt->p_stat = SRUN;
+	pt->p_stat = (pt->p_flag & P_HOLD) ? SHOLD : SRUN;
 	return 0;
 }
 
Index: kern/kern_fork.c
===================================================================
RCS file: /cvsroot/syssrc/sys/kern/kern_fork.c,v
retrieving revision 1.66.2.1
diff -u -r1.66.2.1 kern_fork.c
--- kern/kern_fork.c	2000/07/04 16:05:34	1.66.2.1
+++ kern/kern_fork.c	2000/08/27 19:16:17
@@ -290,7 +290,7 @@
 	 * Increase reference counts on shared objects.
 	 * The p_stats and p_sigacts substructs are set in vm_fork.
 	 */
-	p2->p_flag = P_INMEM | (p1->p_flag & P_SUGID);
+	p2->p_flag = P_INMEM | (p1->p_flag & (P_SUGID | P_HOLD));
 	p2->p_emul = p1->p_emul;
 	if (p1->p_flag & P_PROFIL)
 		startprofclock(p2);
@@ -382,8 +382,11 @@
 	s = splstatclock();
 	p2->p_stats->p_start = time;
 	p2->p_acflag = AFORK;
-	p2->p_stat = SRUN;
-	setrunqueue(p2);
+	if ((p2->p_flag & P_HOLD) == 0) {
+		p2->p_stat = SRUN;
+		setrunqueue(p2);
+	} else 
+		p2->p_stat = SHOLD;
 	splx(s);
 
 	/*
Index: kern/kern_synch.c
===================================================================
RCS file: /cvsroot/syssrc/sys/kern/kern_synch.c,v
retrieving revision 1.78.2.2
diff -u -r1.78.2.2 kern_synch.c
--- kern/kern_synch.c	2000/08/11 23:10:15	1.78.2.2
+++ kern/kern_synch.c	2000/08/27 19:16:17
@@ -119,6 +119,8 @@
 struct callout roundrobin_ch = CALLOUT_INITIALIZER;
 struct callout schedcpu_ch = CALLOUT_INITIALIZER;
 
+int sched_suspended = 0;
+
 /*
  * Force switch among equal priority processes every 100ms.
  */
@@ -591,17 +593,20 @@
 	if (p->p_slptime > 1)
 		updatepri(p);
 	p->p_slptime = 0;
-	p->p_stat = SRUN;
-
-	/*
-	 * Since curpriority is a user priority, p->p_priority
-	 * is always better than curpriority.
-	 */
-	if (p->p_flag & P_INMEM) {
-		setrunqueue(p);
-		need_resched();
-	} else
-		wakeup(&proc0);
+	if ((p->p_flag & P_HOLD) == 0) {
+		p->p_stat = SRUN;
+		/*
+		 * Since curpriority is a user priority, p->p_priority
+		 * is always better than curpriority.
+		 */
+		if (p->p_flag & P_INMEM) {
+			setrunqueue(p);
+			need_resched();
+		} else
+			wakeup(&proc0);
+	} else {
+		p->p_stat = SHOLD;
+	}
 }
 
 /*
@@ -715,8 +720,11 @@
 
 	s = splstatclock();
 	p->p_priority = p->p_usrpri;
-	p->p_stat = SRUN;
-	setrunqueue(p);
+	if ((p->p_flag & P_HOLD) == 0) {
+		p->p_stat = SRUN;
+		setrunqueue(p);
+	} else
+		p->p_stat = SHOLD;
 	p->p_stats->p_ru.ru_nvcsw++;
 	mi_switch(p);
 	splx(s);
@@ -742,8 +750,11 @@
 
 	s = splstatclock(); 
 	p->p_priority = p->p_usrpri;
-	p->p_stat = SRUN;
-	setrunqueue(p);
+	if ((p->p_flag & P_HOLD) == 0) {
+		p->p_stat = SRUN;
+		setrunqueue(p);
+	} else 
+		p->p_stat = SHOLD;
 	p->p_stats->p_ru.ru_nivcsw++;
 	mi_switch(p);
 	splx(s);
@@ -862,6 +873,7 @@
 	switch (p->p_stat) {
 	case 0:
 	case SRUN:
+	case SHOLD:
 	case SONPROC:
 	case SZOMB:
 	case SDEAD:
@@ -883,9 +895,12 @@
 	case SIDL:
 		break;
 	}
-	p->p_stat = SRUN;
-	if (p->p_flag & P_INMEM)
-		setrunqueue(p);
+	if ((p->p_flag & P_HOLD) == 0) {
+		p->p_stat = SRUN;
+		if (p->p_flag & P_INMEM)
+			setrunqueue(p);
+	} else
+		p->p_stat = SHOLD;
 	splx(s);
 	if (p->p_slptime > 1)
 		updatepri(p);
@@ -959,4 +974,69 @@
 	resetpriority(p);
 	if (p->p_priority >= PUSER)
 		p->p_priority = p->p_usrpri;
+}
+
+/*
+ * Mark all non-system processes as non-runnable, and remove from run queue.
+ */
+void
+suspendsched()
+{
+	int s, i;
+	struct proc *p, *next;
+	s = splclock();
+
+	sched_suspended++;
+	if (sched_suspended > 1) {
+		/* sheduling was already suspended */
+		splx(s);
+		return;
+	}
+	/* mark P_HOLD all processes that aren't P_SYSTEM or curproc */
+	for (p = LIST_FIRST(&allproc); p != NULL; p = next) {
+		next = LIST_NEXT(p, p_list);
+		if (p == curproc || (p->p_flag & P_SYSTEM) != 0)
+			continue;
+		p->p_flag |= P_HOLD;
+	}
+	/* go through the run queues, remove P_HOLD processes */
+	for (i = 0; i < RUNQUE_NQS; i++) {
+		for (p = (struct proc *)&sched_qs[i];
+		    p->p_forw != (struct proc *)&sched_qs[i]; p = next) {
+			next = p->p_forw;
+			if ((p->p_flag & P_HOLD) != 0) {
+				remrunqueue(p);
+				p->p_stat = SHOLD;
+			}
+		}
+	}
+	splx(s);
+}
+
+/* resume scheduling, replace all suspended processes on a run queue */
+void
+resumesched()
+{
+	int s;
+	struct proc *p, *next;
+	s = splclock();
+
+	sched_suspended--;
+	if (sched_suspended < 0)
+		panic("resumesched");
+	if (sched_suspended > 0) {
+		/* someone still wants the sheduling to be suspended */
+		/* XXX should we mark curproc P_HOLD as well ? */
+		splx(s);
+		return;
+	}
+	for (p = LIST_FIRST(&allproc); p != NULL; p = next) {
+		next = LIST_NEXT(p, p_list);
+		p->p_flag &= ~P_HOLD;
+		if (p->p_stat == SHOLD) {
+			p->p_stat = SRUN;
+			setrunqueue(p);
+		}
+	}
+	splx(s);
 }
Index: kern/vfs_subr.c
===================================================================
RCS file: /cvsroot/syssrc/sys/kern/vfs_subr.c,v
retrieving revision 1.128.2.3
diff -u -r1.128.2.3 vfs_subr.c
--- kern/vfs_subr.c	2000/07/20 00:14:40	1.128.2.3
+++ kern/vfs_subr.c	2000/08/27 19:16:17
@@ -88,6 +88,7 @@
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/proc.h>
+#include <sys/kernel.h>
 #include <sys/mount.h>
 #include <sys/time.h>
 #include <sys/fcntl.h>
@@ -2352,7 +2353,7 @@
 vfs_shutdown()
 {
 	struct buf *bp;
-	int iter, nbusy, dcount, s;
+	int iter, nbusy, nbusy_prev = 0, dcount, s;
 	struct proc *p = curproc;
 
 	/* XXX we're certainly not running in proc0's context! */
@@ -2361,7 +2362,8 @@
 	
 	printf("syncing disks... ");
 
-	/* XXX Should suspend scheduling. */
+	/* remove user process from run queue */
+	suspendsched();
 	(void) spl0();
 
 	/* avoid coming back this way again if we panic. */
@@ -2371,7 +2373,7 @@
 
 	/* Wait for sync to finish. */
 	dcount = 10000;
-	for (iter = 0; iter < 20; iter++) {
+	for (iter = 0; iter < 20;) {
 		nbusy = 0;
 		for (bp = &buf[nbuf]; --bp >= buf; ) {
 			if ((bp->b_flags & (B_BUSY|B_INVAL|B_READ)) == B_BUSY)
@@ -2398,8 +2400,15 @@
 		}
 		if (nbusy == 0)
 			break;
+		if (nbusy_prev == 0)
+			nbusy_prev = nbusy;
 		printf("%d ", nbusy);
-		DELAY(40000 * iter);
+		tsleep(&nbusy, PRIBIO, "bflush",
+		    (iter == 0) ? 1 : hz / 25 * iter);
+		if (nbusy >= nbusy_prev) /* we didn't flush anything */
+			iter++;
+		else
+			nbusy_prev = nbusy;
 	}
 	if (nbusy) {
 fail:
Index: sys/proc.h
===================================================================
RCS file: /cvsroot/syssrc/sys/sys/proc.h,v
retrieving revision 1.98.2.1
diff -u -r1.98.2.1 proc.h
--- sys/proc.h	2000/08/11 23:07:41	1.98.2.1
+++ sys/proc.h	2000/08/27 19:16:17
@@ -238,29 +238,31 @@
 #define	SZOMB	5		/* Awaiting collection by parent. */
 #define	SDEAD	6		/* Process is almost a zombie. */
 #define	SONPROC	7		/* Process is currently on a CPU */
+#define SHOLD	8		/* Process is runnable but suspended */
 
 #define	P_ZOMBIE(p)	((p)->p_stat == SZOMB || (p)->p_stat == SDEAD)
 
 /* These flags are kept in p_flag. */
-#define	P_ADVLOCK	0x00001	/* Process may hold a POSIX advisory lock. */
-#define	P_CONTROLT	0x00002	/* Has a controlling terminal. */
-#define	P_INMEM		0x00004	/* Loaded into memory. */
-#define	P_NOCLDSTOP	0x00008	/* No SIGCHLD when children stop. */
-#define	P_PPWAIT	0x00010	/* Parent is waiting for child to exec/exit. */
-#define	P_PROFIL	0x00020	/* Has started profiling. */
-#define	P_SELECT	0x00040	/* Selecting; wakeup/waiting danger. */
-#define	P_SINTR		0x00080	/* Sleep is interruptible. */
-#define	P_SUGID		0x00100	/* Had set id privileges since last exec. */
-#define	P_SYSTEM	0x00200	/* System proc: no sigs, stats or swapping. */
-#define	P_TIMEOUT	0x00400	/* Timing out during sleep. */
-#define	P_TRACED	0x00800	/* Debugged process being traced. */
-#define	P_WAITED	0x01000	/* Debugging process has waited for child. */
-#define	P_WEXIT		0x02000	/* Working on exiting. */
-#define	P_EXEC		0x04000	/* Process called exec. */
-#define	P_OWEUPC	0x08000	/* Owe process an addupc() call at next ast. */
-#define	P_FSTRACE	0x10000	/* Debugger process being traced by procfs */
-#define	P_NOCLDWAIT	0x20000	/* No zombies if child dies */
-#define	P_32		0x40000	/* 32-bit process -- only used on 64-bit kernels */
+#define	P_ADVLOCK	0x000001 /* Process may hold a POSIX advisory lock. */
+#define	P_CONTROLT	0x000002 /* Has a controlling terminal. */
+#define	P_INMEM		0x000004 /* Loaded into memory. */
+#define	P_NOCLDSTOP	0x000008 /* No SIGCHLD when children stop. */
+#define	P_PPWAIT	0x000010 /* Parent is waiting for child to exec/exit. */
+#define	P_PROFIL	0x000020 /* Has started profiling. */
+#define	P_SELECT	0x000040 /* Selecting; wakeup/waiting danger. */
+#define	P_SINTR		0x000080 /* Sleep is interruptible. */
+#define	P_SUGID		0x000100 /* Had set id privileges since last exec. */
+#define	P_SYSTEM	0x000200 /* System proc: no sigs, stats or swapping. */
+#define	P_TIMEOUT	0x000400 /* Timing out during sleep. */
+#define	P_TRACED	0x000800 /* Debugged process being traced. */
+#define	P_WAITED	0x001000 /* Debugging process has waited for child. */
+#define	P_WEXIT		0x002000 /* Working on exiting. */
+#define	P_EXEC		0x004000 /* Process called exec. */
+#define	P_OWEUPC	0x008000 /* Owe process an addupc() call at next ast. */
+#define	P_FSTRACE	0x010000 /* Debugger process being traced by procfs */
+#define	P_NOCLDWAIT	0x020000 /* No zombies if child dies */
+#define	P_32		0x040000 /* 32-bit process -- only used on 64-bit kernels */
+#define	P_HOLD		0x100000 /* process scheduling is suspended */
 
 /*
  * Macro to compute the exit signal to be delivered.
@@ -386,6 +388,8 @@
 void	resetpriority __P((struct proc *));
 void	setrunnable __P((struct proc *));
 void	setrunqueue __P((struct proc *));
+void	suspendsched __P((void));
+void	resumesched __P((void));
 int	ltsleep __P((void *chan, int pri, const char *wmesg, int timo,
 	    __volatile struct simplelock *));
 void	unsleep __P((struct proc *));

--envbJBWh7q8WU6mo
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename=diff-current

Index: compat/svr4/svr4_lwp.c
===================================================================
RCS file: /cvsroot/syssrc/sys/compat/svr4/svr4_lwp.c,v
retrieving revision 1.3
diff -u -r1.3 svr4_lwp.c
--- compat/svr4/svr4_lwp.c	2000/05/28 05:49:05	1.3
+++ compat/svr4/svr4_lwp.c	2000/08/27 20:04:40
@@ -253,7 +253,7 @@
 	if (!CANSIGNAL(p, p->p_cred, pt, 0))
 		return EPERM;
 
-	pt->p_stat = SRUN;
+	pt->p_stat = (pt->p_flag & P_HOLD) ? SHOLD : SRUN;
 	return 0;
 }
 
Index: kern/kern_fork.c
===================================================================
RCS file: /cvsroot/syssrc/sys/kern/kern_fork.c,v
retrieving revision 1.72
diff -u -r1.72 kern_fork.c
--- kern/kern_fork.c	2000/08/25 02:55:49	1.72
+++ kern/kern_fork.c	2000/08/27 20:04:40
@@ -276,7 +276,7 @@
 	 * Increase reference counts on shared objects.
 	 * The p_stats and p_sigacts substructs are set in vm_fork.
 	 */
-	p2->p_flag = P_INMEM | (p1->p_flag & P_SUGID);
+	p2->p_flag = P_INMEM | (p1->p_flag & (P_SUGID | P_HOLD));
 	p2->p_emul = p1->p_emul;
 	if (p1->p_flag & P_PROFIL)
 		startprofclock(p2);
@@ -368,8 +368,11 @@
 	s = splstatclock();
 	p2->p_stats->p_start = time;
 	p2->p_acflag = AFORK;
-	p2->p_stat = SRUN;
-	setrunqueue(p2);
+	if ((p2->p_flag & P_HOLD) == 0) {
+		p2->p_stat = SRUN;
+		setrunqueue(p2);
+	} else 
+		p2->p_stat = SHOLD;
 	splx(s);
 
 	/*
Index: kern/kern_synch.c
===================================================================
RCS file: /cvsroot/syssrc/sys/kern/kern_synch.c,v
retrieving revision 1.90
diff -u -r1.90 kern_synch.c
--- kern/kern_synch.c	2000/08/26 19:26:43	1.90
+++ kern/kern_synch.c	2000/08/27 20:04:40
@@ -123,6 +123,8 @@
 
 struct callout schedcpu_ch = CALLOUT_INITIALIZER;
 
+int sched_suspended = 0;
+
 /*
  * Force switch among equal priority processes every 100ms.
  * Called from hardclock every hz/10 == rrticks hardclock ticks.
@@ -570,18 +572,21 @@
 	if (p->p_slptime > 1)
 		updatepri(p);
 	p->p_slptime = 0;
-	p->p_stat = SRUN;
-
-	/*
-	 * Since curpriority is a user priority, p->p_priority
-	 * is always better than curpriority.
-	 */
-	if (p->p_flag & P_INMEM) {
-		setrunqueue(p);
-		KASSERT(p->p_cpu != NULL);
-		need_resched(p->p_cpu);
-	} else
-		sched_wakeup(&proc0);
+	if ((p->p_flag & P_HOLD) == 0) {
+		p->p_stat = SRUN;
+		/*
+		 * Since curpriority is a user priority, p->p_priority
+		 * is always better than curpriority.
+		 */
+		if (p->p_flag & P_INMEM) {
+			setrunqueue(p);
+			KASSERT(p->p_cpu != NULL);
+			need_resched(p->p_cpu);
+		} else
+			wakeup(&proc0);
+	} else {
+		p->p_stat = SHOLD;
+	}
 }
 
 #if defined(MULTIPROCESSOR) || defined(LOCKDEBUG)
@@ -722,8 +727,11 @@
 
 	SCHED_LOCK(s);
 	p->p_priority = p->p_usrpri;
-	p->p_stat = SRUN;
-	setrunqueue(p);
+	if ((p->p_flag & P_HOLD) == 0) {
+		p->p_stat = SRUN;
+		setrunqueue(p);
+	} else
+		p->p_stat = SHOLD;
 	p->p_stats->p_ru.ru_nvcsw++;
 	mi_switch(p);
 	SCHED_ASSERT_UNLOCKED();
@@ -750,8 +758,11 @@
 
 	SCHED_LOCK(s);
 	p->p_priority = p->p_usrpri;
-	p->p_stat = SRUN;
-	setrunqueue(p);
+	if ((p->p_flag & P_HOLD) == 0) {
+		p->p_stat = SRUN;
+		setrunqueue(p);
+	} else 
+		p->p_stat = SHOLD;
 	p->p_stats->p_ru.ru_nivcsw++;
 	mi_switch(p);
 	SCHED_ASSERT_UNLOCKED();
@@ -903,6 +914,7 @@
 	switch (p->p_stat) {
 	case 0:
 	case SRUN:
+	case SHOLD:
 	case SONPROC:
 	case SZOMB:
 	case SDEAD:
@@ -924,10 +936,12 @@
 	case SIDL:
 		break;
 	}
-	p->p_stat = SRUN;
-	if (p->p_flag & P_INMEM)
-		setrunqueue(p);
-
+	if ((p->p_flag & P_HOLD) == 0) {
+		p->p_stat = SRUN;
+		if (p->p_flag & P_INMEM)
+			setrunqueue(p);
+	} else
+		p->p_stat = SHOLD;
 	if (p->p_slptime > 1)
 		updatepri(p);
 	p->p_slptime = 0;
@@ -998,4 +1012,69 @@
 
 	if (p->p_priority >= PUSER)
 		p->p_priority = p->p_usrpri;
+}
+
+/*
+ * Mark all non-system processes as non-runnable, and remove from run queue.
+ */
+void
+suspendsched()
+{
+	int s, i;
+	struct proc *p, *next;
+
+	SCHED_LOCK(s);
+	sched_suspended++;
+	if (sched_suspended > 1) {
+		/* sheduling was already suspended */
+		SCHED_UNLOCK(s);
+		return;
+	}
+	/* mark P_HOLD all processes that aren't P_SYSTEM or curproc */
+	for (p = LIST_FIRST(&allproc); p != NULL; p = next) {
+		next = LIST_NEXT(p, p_list);
+		if (p == curproc || (p->p_flag & P_SYSTEM) != 0)
+			continue;
+		p->p_flag |= P_HOLD;
+	}
+	/* go through the run queues, remove P_HOLD processes */
+	for (i = 0; i < RUNQUE_NQS; i++) {
+		for (p = (struct proc *)&sched_qs[i];
+		    p->p_forw != (struct proc *)&sched_qs[i]; p = next) {
+			next = p->p_forw;
+			if ((p->p_flag & P_HOLD) != 0) {
+				remrunqueue(p);
+				p->p_stat = SHOLD;
+			}
+		}
+	}
+	SCHED_UNLOCK(s);
+}
+
+/* resume scheduling, replace all suspended processes on a run queue */
+void
+resumesched()
+{
+	int s;
+	struct proc *p, *next;
+
+	SCHED_LOCK(s);
+	sched_suspended--;
+	if (sched_suspended < 0)
+		panic("resumesched");
+	if (sched_suspended > 0) {
+		/* someone still wants the sheduling to be suspended */
+		/* XXX should we mark curproc P_HOLD as well ? */
+		SCHED_UNLOCK(s);
+		return;
+	}
+	for (p = LIST_FIRST(&allproc); p != NULL; p = next) {
+		next = LIST_NEXT(p, p_list);
+		p->p_flag &= ~P_HOLD;
+		if (p->p_stat == SHOLD) {
+			p->p_stat = SRUN;
+			setrunqueue(p);
+		}
+	}
+	SCHED_UNLOCK(s);
 }
Index: kern/vfs_subr.c
===================================================================
RCS file: /cvsroot/syssrc/sys/kern/vfs_subr.c,v
retrieving revision 1.137
diff -u -r1.137 vfs_subr.c
--- kern/vfs_subr.c	2000/08/21 06:42:57	1.137
+++ kern/vfs_subr.c	2000/08/27 20:04:42
@@ -88,6 +88,7 @@
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/proc.h>
+#include <sys/kernel.h>
 #include <sys/mount.h>
 #include <sys/time.h>
 #include <sys/fcntl.h>
@@ -2347,7 +2348,7 @@
 vfs_shutdown()
 {
 	struct buf *bp;
-	int iter, nbusy, dcount, s;
+	int iter, nbusy, nbusy_prev = 0, dcount, s;
 	struct proc *p = curproc;
 
 	/* XXX we're certainly not running in proc0's context! */
@@ -2356,7 +2357,8 @@
 	
 	printf("syncing disks... ");
 
-	/* XXX Should suspend scheduling. */
+	/* remove user process from run queue */
+	suspendsched();
 	(void) spl0();
 
 	/* avoid coming back this way again if we panic. */
@@ -2366,7 +2368,7 @@
 
 	/* Wait for sync to finish. */
 	dcount = 10000;
-	for (iter = 0; iter < 20; iter++) {
+	for (iter = 0; iter < 20;) {
 		nbusy = 0;
 		for (bp = &buf[nbuf]; --bp >= buf; ) {
 			if ((bp->b_flags & (B_BUSY|B_INVAL|B_READ)) == B_BUSY)
@@ -2393,8 +2395,15 @@
 		}
 		if (nbusy == 0)
 			break;
+		if (nbusy_prev == 0)
+			nbusy_prev = nbusy;
 		printf("%d ", nbusy);
-		DELAY(40000 * iter);
+		tsleep(&nbusy, PRIBIO, "bflush",
+		    (iter == 0) ? 1 : hz / 25 * iter);
+		if (nbusy >= nbusy_prev) /* we didn't flush anything */
+			iter++;
+		else
+			nbusy_prev = nbusy;
 	}
 	if (nbusy) {
 fail:
Index: sys/proc.h
===================================================================
RCS file: /cvsroot/syssrc/sys/sys/proc.h,v
retrieving revision 1.102
diff -u -r1.102 proc.h
--- sys/proc.h	2000/08/22 17:28:29	1.102
+++ sys/proc.h	2000/08/27 20:04:42
@@ -238,30 +238,32 @@
 #define	SZOMB	5		/* Awaiting collection by parent. */
 #define	SDEAD	6		/* Process is almost a zombie. */
 #define	SONPROC	7		/* Process is currently on a CPU */
+#define	SHOLD	8		/* Process is runnable but suspended */
 
 #define	P_ZOMBIE(p)	((p)->p_stat == SZOMB || (p)->p_stat == SDEAD)
 
 /* These flags are kept in p_flag. */
-#define	P_ADVLOCK	0x00001	/* Process may hold a POSIX advisory lock. */
-#define	P_CONTROLT	0x00002	/* Has a controlling terminal. */
-#define	P_INMEM		0x00004	/* Loaded into memory. */
-#define	P_NOCLDSTOP	0x00008	/* No SIGCHLD when children stop. */
-#define	P_PPWAIT	0x00010	/* Parent is waiting for child to exec/exit. */
-#define	P_PROFIL	0x00020	/* Has started profiling. */
-#define	P_SELECT	0x00040	/* Selecting; wakeup/waiting danger. */
-#define	P_SINTR		0x00080	/* Sleep is interruptible. */
-#define	P_SUGID		0x00100	/* Had set id privileges since last exec. */
-#define	P_SYSTEM	0x00200	/* System proc: no sigs, stats or swapping. */
-#define	P_TIMEOUT	0x00400	/* Timing out during sleep. */
-#define	P_TRACED	0x00800	/* Debugged process being traced. */
-#define	P_WAITED	0x01000	/* Debugging process has waited for child. */
-#define	P_WEXIT		0x02000	/* Working on exiting. */
-#define	P_EXEC		0x04000	/* Process called exec. */
-#define	P_OWEUPC	0x08000	/* Owe process an addupc() call at next ast. */
-#define	P_FSTRACE	0x10000	/* Debugger process being traced by procfs */
-#define	P_NOCLDWAIT	0x20000	/* No zombies if child dies */
-#define	P_32		0x40000	/* 32-bit process (used on 64-bit kernels) */
-#define P_BIGLOCK	0x80000 /* Process needs kernel "big lock" to run */
+#define	P_ADVLOCK	0x000001 /* Process may hold a POSIX advisory lock. */
+#define	P_CONTROLT	0x000002 /* Has a controlling terminal. */
+#define	P_INMEM		0x000004 /* Loaded into memory. */
+#define	P_NOCLDSTOP	0x000008 /* No SIGCHLD when children stop. */
+#define	P_PPWAIT	0x000010 /* Parent is waiting for child to exec/exit. */
+#define	P_PROFIL	0x000020 /* Has started profiling. */
+#define	P_SELECT	0x000040 /* Selecting; wakeup/waiting danger. */
+#define	P_SINTR		0x000080 /* Sleep is interruptible. */
+#define	P_SUGID		0x000100 /* Had set id privileges since last exec. */
+#define	P_SYSTEM	0x000200 /* System proc: no sigs, stats or swapping. */
+#define	P_TIMEOUT	0x000400 /* Timing out during sleep. */
+#define	P_TRACED	0x000800 /* Debugged process being traced. */
+#define	P_WAITED	0x001000 /* Debugging process has waited for child. */
+#define	P_WEXIT		0x002000 /* Working on exiting. */
+#define	P_EXEC		0x004000 /* Process called exec. */
+#define	P_OWEUPC	0x008000 /* Owe process an addupc() call at next ast. */
+#define	P_FSTRACE	0x010000 /* Debugger process being traced by procfs */
+#define	P_NOCLDWAIT	0x020000 /* No zombies if child dies */
+#define	P_32		0x040000 /* 32-bit process (used on 64-bit kernels) */
+#define P_BIGLOCK	0x080000 /* Process needs kernel "big lock" to run */
+#define	P_HOLD		0x100000 /* process scheduling is suspended */
 
 
 /*
@@ -388,6 +390,8 @@
 void	resetpriority __P((struct proc *));
 void	setrunnable __P((struct proc *));
 void	setrunqueue __P((struct proc *));
+void	suspendsched __P((void));
+void	resumesched __P((void));
 int	ltsleep __P((void *chan, int pri, const char *wmesg, int timo,
 	    __volatile struct simplelock *));
 void	unsleep __P((struct proc *));

--envbJBWh7q8WU6mo--