aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/kern/kern_kthread.c40
-rw-r--r--sys/kern/kern_shutdown.c32
-rw-r--r--sys/kern/vfs_bio.c31
-rw-r--r--sys/kern/vfs_export.c21
-rw-r--r--sys/kern/vfs_subr.c21
-rw-r--r--sys/sys/kthread.h5
6 files changed, 126 insertions, 24 deletions
diff --git a/sys/kern/kern_kthread.c b/sys/kern/kern_kthread.c
index b375fbb3e129..5efe90c83d15 100644
--- a/sys/kern/kern_kthread.c
+++ b/sys/kern/kern_kthread.c
@@ -30,6 +30,7 @@
#include <sys/systm.h>
#include <sys/proc.h>
#include <sys/kthread.h>
+#include <sys/signalvar.h>
#include <sys/unistd.h>
#include <sys/wait.h>
@@ -97,3 +98,42 @@ kthread_exit(int ecode)
exit1(curproc, W_EXITCODE(ecode, 0));
}
+/*
+ * Advise a kernel process to suspend (or resume) in its main loop.
+ * Participation is voluntary.
+ */
+int
+suspend_kproc(struct proc *p, int timo)
+{
+ /*
+ * Make sure this is indeed a system process and we can safely
+ * use the p_siglist field.
+ */
+ if ((p->p_flag & P_SYSTEM) == 0)
+ return (EINVAL);
+ SIGADDSET(p->p_siglist, SIGSTOP);
+ return tsleep((caddr_t)&p->p_siglist, PPAUSE, "suspkp", timo);
+}
+
+int
+resume_kproc(struct proc *p)
+{
+ /*
+ * Make sure this is indeed a system process and we can safely
+ * use the p_siglist field.
+ */
+ if ((p->p_flag & P_SYSTEM) == 0)
+ return (EINVAL);
+ SIGDELSET(p->p_siglist, SIGSTOP);
+ wakeup((caddr_t)&p->p_siglist);
+ return (0);
+}
+
+void
+kproc_suspend_loop(struct proc *p)
+{
+ while (SIGISMEMBER(p->p_siglist, SIGSTOP)) {
+ wakeup((caddr_t)&p->p_siglist);
+ tsleep((caddr_t)&p->p_siglist, PPAUSE, "kpsusp", 0);
+ }
+}
diff --git a/sys/kern/kern_shutdown.c b/sys/kern/kern_shutdown.c
index adf02b672826..d66cfbd1ceff 100644
--- a/sys/kern/kern_shutdown.c
+++ b/sys/kern/kern_shutdown.c
@@ -52,6 +52,7 @@
#include <sys/proc.h>
#include <sys/vnode.h>
#include <sys/kernel.h>
+#include <sys/kthread.h>
#include <sys/mount.h>
#include <sys/queue.h>
#include <sys/sysctl.h>
@@ -571,3 +572,34 @@ poweroff_wait(void *junk, int howto)
return;
DELAY(poweroff_delay * 1000);
}
+
+/*
+ * Some system processes (e.g. syncer) need to be stopped at appropriate
+ * points in their main loops prior to a system shutdown, so that they
+ * won't interfere with the shutdown process (e.g. by holding a disk buf
+ * to cause sync to fail). For each of these system processes, register
+ * shutdown_kproc() as a handler for one of shutdown events.
+ */
+static int kproc_shutdown_wait = 60;
+SYSCTL_INT(_kern_shutdown, OID_AUTO, kproc_shutdown_wait, CTLFLAG_RW,
+ &kproc_shutdown_wait, 0, "");
+
+void
+shutdown_kproc(void *arg, int howto)
+{
+ struct proc *p;
+ int error;
+
+ if (panicstr)
+ return;
+
+ p = (struct proc *)arg;
+ printf("Waiting (max %d seconds) for system process `%s' to stop...",
+ kproc_shutdown_wait * hz, p->p_comm);
+ error = suspend_kproc(p, kproc_shutdown_wait);
+
+ if (error == EWOULDBLOCK)
+ printf("timed out\n");
+ else
+ printf("stopped\n");
+}
diff --git a/sys/kern/vfs_bio.c b/sys/kern/vfs_bio.c
index c24a4e00f607..9d2b5c27f978 100644
--- a/sys/kern/vfs_bio.c
+++ b/sys/kern/vfs_bio.c
@@ -29,13 +29,20 @@
#include <sys/param.h>
#include <sys/systm.h>
+#include <sys/buf.h>
+#include <sys/conf.h>
+#include <sys/eventhandler.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/mount.h>
#include <sys/kernel.h>
-#include <sys/sysctl.h>
-#include <sys/proc.h>
#include <sys/kthread.h>
-#include <sys/vnode.h>
+#include <sys/proc.h>
+#include <sys/reboot.h>
+#include <sys/resourcevar.h>
+#include <sys/sysctl.h>
#include <sys/vmmeter.h>
-#include <sys/lock.h>
+#include <sys/vnode.h>
#include <vm/vm.h>
#include <vm/vm_param.h>
#include <vm/vm_kern.h>
@@ -44,11 +51,6 @@
#include <vm/vm_object.h>
#include <vm/vm_extern.h>
#include <vm/vm_map.h>
-#include <sys/buf.h>
-#include <sys/mount.h>
-#include <sys/malloc.h>
-#include <sys/resourcevar.h>
-#include <sys/conf.h>
static MALLOC_DEFINE(M_BIOBUF, "BIO buffer", "BIO buffer");
@@ -1666,6 +1668,13 @@ static void
buf_daemon()
{
int s;
+
+ /*
+ * This process needs to be suspended prior to shutdown sync.
+ */
+ EVENTHANDLER_REGISTER(shutdown_pre_sync, shutdown_kproc, bufdaemonproc,
+ SHUTDOWN_PRI_LAST);
+
/*
* This process is allowed to take the buffer cache to the limit
*/
@@ -1676,7 +1685,9 @@ buf_daemon()
bd_flushto = hidirtybuffers; /* dynamically adjusted */
bd_flushinc = 1;
- while (TRUE) {
+ for (;;) {
+ kproc_suspend_loop(bufdaemonproc);
+
bd_request = 0;
/*
diff --git a/sys/kern/vfs_export.c b/sys/kern/vfs_export.c
index 059ca2a4787a..f59d819f2000 100644
--- a/sys/kern/vfs_export.c
+++ b/sys/kern/vfs_export.c
@@ -46,20 +46,23 @@
#include <sys/param.h>
#include <sys/systm.h>
+#include <sys/buf.h>
+#include <sys/conf.h>
+#include <sys/dirent.h>
+#include <sys/domain.h>
+#include <sys/eventhandler.h>
#include <sys/fcntl.h>
#include <sys/kernel.h>
-#include <sys/proc.h>
#include <sys/kthread.h>
#include <sys/malloc.h>
#include <sys/mount.h>
+#include <sys/proc.h>
+#include <sys/reboot.h>
#include <sys/socket.h>
-#include <sys/vnode.h>
#include <sys/stat.h>
-#include <sys/buf.h>
-#include <sys/domain.h>
-#include <sys/dirent.h>
+#include <sys/sysctl.h>
#include <sys/vmmeter.h>
-#include <sys/conf.h>
+#include <sys/vnode.h>
#include <machine/limits.h>
@@ -72,7 +75,6 @@
#include <vm/vm_pager.h>
#include <vm/vnode_pager.h>
#include <vm/vm_zone.h>
-#include <sys/sysctl.h>
static MALLOC_DEFINE(M_NETADDR, "Export Host", "Export host address structure");
@@ -975,9 +977,14 @@ sched_sync(void)
int s;
struct proc *p = updateproc;
+ EVENTHANDLER_REGISTER(shutdown_pre_sync, shutdown_kproc, p,
+ SHUTDOWN_PRI_LAST);
+
p->p_flag |= P_BUFEXHAUST;
for (;;) {
+ kproc_suspend_loop(p);
+
starttime = time_second;
/*
diff --git a/sys/kern/vfs_subr.c b/sys/kern/vfs_subr.c
index 059ca2a4787a..f59d819f2000 100644
--- a/sys/kern/vfs_subr.c
+++ b/sys/kern/vfs_subr.c
@@ -46,20 +46,23 @@
#include <sys/param.h>
#include <sys/systm.h>
+#include <sys/buf.h>
+#include <sys/conf.h>
+#include <sys/dirent.h>
+#include <sys/domain.h>
+#include <sys/eventhandler.h>
#include <sys/fcntl.h>
#include <sys/kernel.h>
-#include <sys/proc.h>
#include <sys/kthread.h>
#include <sys/malloc.h>
#include <sys/mount.h>
+#include <sys/proc.h>
+#include <sys/reboot.h>
#include <sys/socket.h>
-#include <sys/vnode.h>
#include <sys/stat.h>
-#include <sys/buf.h>
-#include <sys/domain.h>
-#include <sys/dirent.h>
+#include <sys/sysctl.h>
#include <sys/vmmeter.h>
-#include <sys/conf.h>
+#include <sys/vnode.h>
#include <machine/limits.h>
@@ -72,7 +75,6 @@
#include <vm/vm_pager.h>
#include <vm/vnode_pager.h>
#include <vm/vm_zone.h>
-#include <sys/sysctl.h>
static MALLOC_DEFINE(M_NETADDR, "Export Host", "Export host address structure");
@@ -975,9 +977,14 @@ sched_sync(void)
int s;
struct proc *p = updateproc;
+ EVENTHANDLER_REGISTER(shutdown_pre_sync, shutdown_kproc, p,
+ SHUTDOWN_PRI_LAST);
+
p->p_flag |= P_BUFEXHAUST;
for (;;) {
+ kproc_suspend_loop(p);
+
starttime = time_second;
/*
diff --git a/sys/sys/kthread.h b/sys/sys/kthread.h
index afea3c67f17d..fb0d3f995cbe 100644
--- a/sys/sys/kthread.h
+++ b/sys/sys/kthread.h
@@ -47,4 +47,9 @@ int kthread_create __P((void (*)(void *), void *, struct proc **,
const char *, ...)) __printflike(4, 5);
void kthread_exit __P((int)) __dead2;
+int suspend_kproc __P((struct proc *, int));
+int resume_kproc __P((struct proc *));
+void kproc_suspend_loop __P((struct proc *));
+void shutdown_kproc __P((void *, int));
+
#endif