diff options
-rw-r--r-- | sys/kern/kern_kthread.c | 40 | ||||
-rw-r--r-- | sys/kern/kern_shutdown.c | 32 | ||||
-rw-r--r-- | sys/kern/vfs_bio.c | 31 | ||||
-rw-r--r-- | sys/kern/vfs_export.c | 21 | ||||
-rw-r--r-- | sys/kern/vfs_subr.c | 21 | ||||
-rw-r--r-- | sys/sys/kthread.h | 5 |
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 |