git: b8534da5ee54 - stable/13 - REAP_KILL_PROC: kill processes in the threaded taskqueue context
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Sat, 03 Sep 2022 01:29:24 UTC
The branch stable/13 has been updated by kib: URL: https://cgit.FreeBSD.org/src/commit/?id=b8534da5ee54c75259dbbf8b5e54b0f261940714 commit b8534da5ee54c75259dbbf8b5e54b0f261940714 Author: Konstantin Belousov <kib@FreeBSD.org> AuthorDate: 2022-08-12 19:37:08 +0000 Commit: Konstantin Belousov <kib@FreeBSD.org> CommitDate: 2022-09-03 01:17:36 +0000 REAP_KILL_PROC: kill processes in the threaded taskqueue context (cherry picked from commit 2842ec6d99ce3590eabb34d23eff5b0fed24eb98) --- sys/kern/kern_procctl.c | 183 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 124 insertions(+), 59 deletions(-) diff --git a/sys/kern/kern_procctl.c b/sys/kern/kern_procctl.c index 36372fd31bd4..1fb1183741d6 100644 --- a/sys/kern/kern_procctl.c +++ b/sys/kern/kern_procctl.c @@ -43,6 +43,7 @@ __FBSDID("$FreeBSD$"); #include <sys/sx.h> #include <sys/syscallsubr.h> #include <sys/sysproto.h> +#include <sys/taskqueue.h> #include <sys/wait.h> #include <vm/vm.h> @@ -243,32 +244,29 @@ reap_getpids(struct thread *td, struct proc *p, void *data) return (error); } -static void -reap_kill_proc_relock(struct proc *p, int xlocked) -{ - PROC_UNLOCK(p); - if (xlocked) - sx_xlock(&proctree_lock); - else - sx_slock(&proctree_lock); - PROC_LOCK(p); -} +struct reap_kill_proc_work { + struct ucred *cr; + struct proc *target; + ksiginfo_t *ksi; + struct procctl_reaper_kill *rk; + int *error; + struct task t; +}; static void -reap_kill_proc_locked(struct thread *td, struct proc *p2, - ksiginfo_t *ksi, struct procctl_reaper_kill *rk, int *error) +reap_kill_proc_locked(struct reap_kill_proc_work *w) { - int error1, r, xlocked; + int error1; bool need_stop; - PROC_LOCK_ASSERT(p2, MA_OWNED); - PROC_ASSERT_HELD(p2); + PROC_LOCK_ASSERT(w->target, MA_OWNED); + PROC_ASSERT_HELD(w->target); - error1 = p_cansignal(td, p2, rk->rk_sig); + error1 = cr_cansignal(w->cr, w->target, w->rk->rk_sig); if (error1 != 0) { - if (*error == ESRCH) { - rk->rk_fpid = p2->p_pid; - *error = error1; + if (*w->error == ESRCH) { + w->rk->rk_fpid = w->target->p_pid; + *w->error = error1; } return; } @@ -286,39 +284,34 @@ reap_kill_proc_locked(struct thread *td, struct proc *p2, * thread signals the whole subtree, it is an application * race. */ - need_stop = p2 != td->td_proc && - (td->td_proc->p_flag2 & P2_WEXIT) == 0 && - (p2->p_flag & (P_KPROC | P_SYSTEM | P_STOPPED)) == 0 && - (rk->rk_flags & REAPER_KILL_CHILDREN) == 0; - - if (need_stop) { - xlocked = sx_xlocked(&proctree_lock); - sx_unlock(&proctree_lock); - r = thread_single(p2, SINGLE_ALLPROC); - reap_kill_proc_relock(p2, xlocked); - if (r != 0) - need_stop = false; - } + if ((w->target->p_flag & (P_KPROC | P_SYSTEM | P_STOPPED)) == 0) + need_stop = thread_single(w->target, SINGLE_ALLPROC) == 0; + else + need_stop = false; - pksignal(p2, rk->rk_sig, ksi); - rk->rk_killed++; - *error = error1; + (void)pksignal(w->target, w->rk->rk_sig, w->ksi); + w->rk->rk_killed++; + *w->error = error1; if (need_stop) - thread_single_end(p2, SINGLE_ALLPROC); + thread_single_end(w->target, SINGLE_ALLPROC); } static void -reap_kill_proc(struct thread *td, struct proc *p2, ksiginfo_t *ksi, - struct procctl_reaper_kill *rk, int *error) +reap_kill_proc_work(void *arg, int pending __unused) { - PROC_LOCK(p2); - if ((p2->p_flag2 & P2_WEXIT) == 0) { - _PHOLD_LITE(p2); - reap_kill_proc_locked(td, p2, ksi, rk, error); - _PRELE(p2); - } - PROC_UNLOCK(p2); + struct reap_kill_proc_work *w; + + w = arg; + PROC_LOCK(w->target); + if ((w->target->p_flag2 & P2_WEXIT) == 0) + reap_kill_proc_locked(w); + PROC_UNLOCK(w->target); + + sx_xlock(&proctree_lock); + w->target = NULL; + wakeup(&w->target); + sx_xunlock(&proctree_lock); } struct reap_kill_tracker { @@ -357,25 +350,40 @@ reap_kill_children(struct thread *td, struct proc *reaper, struct procctl_reaper_kill *rk, ksiginfo_t *ksi, int *error) { struct proc *p2; + int error1; LIST_FOREACH(p2, &reaper->p_children, p_sibling) { - (void)reap_kill_proc(td, p2, ksi, rk, error); - /* - * Do not end the loop on error, signal everything we - * can. - */ + PROC_LOCK(p2); + if ((p2->p_flag2 & P2_WEXIT) == 0) { + error1 = p_cansignal(td, p2, rk->rk_sig); + if (error1 != 0) { + if (*error == ESRCH) { + rk->rk_fpid = p2->p_pid; + *error = error1; + } + + /* + * Do not end the loop on error, + * signal everything we can. + */ + } else { + (void)pksignal(p2, rk->rk_sig, ksi); + rk->rk_killed++; + } + } + PROC_UNLOCK(p2); } } static bool reap_kill_subtree_once(struct thread *td, struct proc *p, struct proc *reaper, - struct procctl_reaper_kill *rk, ksiginfo_t *ksi, int *error, - struct unrhdr *pids) + struct unrhdr *pids, struct reap_kill_proc_work *w) { struct reap_kill_tracker_head tracker; struct reap_kill_tracker *t; struct proc *p2; - bool res; + int r, xlocked; + bool res, st; res = false; TAILQ_INIT(&tracker); @@ -397,14 +405,54 @@ reap_kill_subtree_once(struct thread *td, struct proc *p, struct proc *reaper, LIST_FOREACH(p2, &t->parent->p_reaplist, p_reapsibling) { if (t->parent == reaper && - (rk->rk_flags & REAPER_KILL_SUBTREE) != 0 && - p2->p_reapsubtree != rk->rk_subtree) + (w->rk->rk_flags & REAPER_KILL_SUBTREE) != 0 && + p2->p_reapsubtree != w->rk->rk_subtree) continue; if ((p2->p_treeflag & P_TREE_REAPER) != 0) reap_kill_sched(&tracker, p2); if (alloc_unr_specific(pids, p2->p_pid) != p2->p_pid) continue; - reap_kill_proc(td, p2, ksi, rk, error); + if (p2 == td->td_proc) { + if ((p2->p_flag & P_HADTHREADS) != 0 && + (p2->p_flag2 & P2_WEXIT) == 0) { + xlocked = sx_xlocked(&proctree_lock); + sx_unlock(&proctree_lock); + st = true; + } else { + st = false; + } + PROC_LOCK(p2); + if (st) + r = thread_single(p2, SINGLE_NO_EXIT); + (void)pksignal(p2, w->rk->rk_sig, w->ksi); + w->rk->rk_killed++; + if (st && r == 0) + thread_single_end(p2, SINGLE_NO_EXIT); + PROC_UNLOCK(p2); + if (st) { + if (xlocked) + sx_xlock(&proctree_lock); + else + sx_slock(&proctree_lock); + } + } else { + PROC_LOCK(p2); + if ((p2->p_flag2 & P2_WEXIT) == 0) { + _PHOLD_LITE(p2); + PROC_UNLOCK(p2); + w->target = p2; + taskqueue_enqueue(taskqueue_thread, + &w->t); + while (w->target != NULL) { + sx_sleep(&w->target, + &proctree_lock, PWAIT, + "reapst", 0); + } + PROC_LOCK(p2); + _PRELE(p2); + } + PROC_UNLOCK(p2); + } res = true; } reap_kill_sched_free(t); @@ -414,7 +462,7 @@ reap_kill_subtree_once(struct thread *td, struct proc *p, struct proc *reaper, static void reap_kill_subtree(struct thread *td, struct proc *p, struct proc *reaper, - struct procctl_reaper_kill *rk, ksiginfo_t *ksi, int *error) + struct reap_kill_proc_work *w) { struct unrhdr pids; @@ -431,7 +479,7 @@ reap_kill_subtree(struct thread *td, struct proc *p, struct proc *reaper, } td->td_proc->p_singlethr++; PROC_UNLOCK(td->td_proc); - while (reap_kill_subtree_once(td, p, reaper, rk, ksi, error, &pids)) + while (reap_kill_subtree_once(td, p, reaper, &pids, w)) ; PROC_LOCK(td->td_proc); td->td_proc->p_singlethr--; @@ -455,6 +503,7 @@ reap_kill_sapblk(struct thread *td __unused, void *data) static int reap_kill(struct thread *td, struct proc *p, void *data) { + struct reap_kill_proc_work w; struct proc *reaper; ksiginfo_t ksi; struct procctl_reaper_kill *rk; @@ -483,7 +532,23 @@ reap_kill(struct thread *td, struct proc *p, void *data) if ((rk->rk_flags & REAPER_KILL_CHILDREN) != 0) { reap_kill_children(td, reaper, rk, &ksi, &error); } else { - reap_kill_subtree(td, p, reaper, rk, &ksi, &error); + w.cr = crhold(td->td_ucred); + w.ksi = &ksi; + w.rk = rk; + w.error = &error; + TASK_INIT(&w.t, 0, reap_kill_proc_work, &w); + + /* + * Prevent swapout, since w, ksi, and possibly rk, are + * allocated on the stack. We sleep in + * reap_kill_subtree_once() waiting for task to + * complete single-threading. + */ + PHOLD(td->td_proc); + + reap_kill_subtree(td, p, reaper, &w); + PRELE(td->td_proc); + crfree(w.cr); } PROC_LOCK(p); return (error);