git: 53d691cacae6 - stable/15 - reap_kill_subtree_once: when proctree_lock is dropped, reaper might change

From: Konstantin Belousov <kib_at_FreeBSD.org>
Date: Sat, 13 Jun 2026 01:03:58 UTC
The branch stable/15 has been updated by kib:

URL: https://cgit.FreeBSD.org/src/commit/?id=53d691cacae602f96a80a656ec8f508b65ace81c

commit 53d691cacae602f96a80a656ec8f508b65ace81c
Author:     Konstantin Belousov <kib@FreeBSD.org>
AuthorDate: 2026-06-05 23:57:16 +0000
Commit:     Konstantin Belousov <kib@FreeBSD.org>
CommitDate: 2026-06-13 00:58:38 +0000

    reap_kill_subtree_once: when proctree_lock is dropped, reaper might change
    
    (cherry picked from commit 44970244e6d872103f36eae34218b672b69579dd)
---
 sys/kern/kern_procctl.c | 43 +++++++++++++++++++++++++++++--------------
 1 file changed, 29 insertions(+), 14 deletions(-)

diff --git a/sys/kern/kern_procctl.c b/sys/kern/kern_procctl.c
index 1ff1b15767b5..c8d14aa2f2f6 100644
--- a/sys/kern/kern_procctl.c
+++ b/sys/kern/kern_procctl.c
@@ -49,6 +49,7 @@
 #include <vm/pmap.h>
 #include <vm/vm_map.h>
 #include <vm/vm_extern.h>
+#include <vm/uma.h>
 
 static int
 protect_setchild(struct thread *td, struct proc *p, int flags)
@@ -366,13 +367,7 @@ reap_kill_sched(struct reap_kill_tracker_head *tracker, struct proc *p2)
 {
 	struct reap_kill_tracker *t;
 
-	PROC_LOCK(p2);
-	if ((p2->p_flag2 & P2_WEXIT) != 0) {
-		PROC_UNLOCK(p2);
-		return;
-	}
-	_PHOLD(p2);
-	PROC_UNLOCK(p2);
+	PROC_TREE_REF(p2);
 	t = malloc(sizeof(struct reap_kill_tracker), M_TEMP, M_WAITOK);
 	t->parent = p2;
 	TAILQ_INSERT_TAIL(tracker, t, link);
@@ -381,7 +376,7 @@ reap_kill_sched(struct reap_kill_tracker_head *tracker, struct proc *p2)
 static void
 reap_kill_sched_free(struct reap_kill_tracker *t)
 {
-	PRELE(t->parent);
+	PROC_TREE_UNREF(t->parent);
 	free(t, M_TEMP);
 }
 
@@ -416,16 +411,17 @@ reap_kill_children(struct thread *td, struct proc *reaper,
 }
 
 static bool
-reap_kill_subtree_once(struct thread *td, struct proc *p, struct proc *reaper,
+reap_kill_subtree_once(struct thread *td, struct proc *p, struct proc **reaperp,
     struct unrhdr *pids, struct reap_kill_proc_work *w)
 {
 	struct reap_kill_tracker_head tracker;
 	struct reap_kill_tracker *t;
-	struct proc *p2;
+	struct proc *p2, *reaper, *old_reaper;
 	bool proctree_dropped, res;
 
 	res = false;
 	TAILQ_INIT(&tracker);
+	reaper = *reaperp;
 	reap_kill_sched(&tracker, reaper);
 	while ((t = TAILQ_FIRST(&tracker)) != NULL) {
 		TAILQ_REMOVE(&tracker, t, link);
@@ -483,8 +479,24 @@ again:
 			}
 			PROC_UNLOCK(p2);
 			res = true;
-			if (proctree_dropped)
+			if (proctree_dropped) {
+				old_reaper = reaper;
+				reaper = get_reaper_or_p(p);
+				if (old_reaper != reaper) {
+					*reaperp = reaper;
+					PROC_TREE_REF(reaper);
+					PROC_TREE_UNREF(old_reaper);
+					reap_kill_sched(&tracker, reaper);
+					/*
+					 * Already scheduled kill
+					 * actions should be kept on
+					 * the schedule, the processes
+					 * are inherited by the new
+					 * reaper.
+					 */
+				}
 				goto again;
+			}
 		}
 		reap_kill_sched_free(t);
 	}
@@ -492,7 +504,7 @@ again:
 }
 
 static void
-reap_kill_subtree(struct thread *td, struct proc *p, struct proc *reaper,
+reap_kill_subtree(struct thread *td, struct proc *p, struct proc **reaperp,
     struct reap_kill_proc_work *w)
 {
 	struct unrhdr pids;
@@ -512,7 +524,7 @@ reap_kill_subtree(struct thread *td, struct proc *p, struct proc *reaper,
 		goto out;
 	}
 	PROC_UNLOCK(td->td_proc);
-	while (reap_kill_subtree_once(td, p, reaper, &pids, w))
+	while (reap_kill_subtree_once(td, p, reaperp, &pids, w))
 	       ;
 
 	ihandle = create_iter_unr(&pids);
@@ -562,6 +574,7 @@ reap_kill(struct thread *td, struct proc *p, void *data)
 		return (EINVAL);
 	PROC_UNLOCK(p);
 	reaper = get_reaper_or_p(p);
+
 	ksiginfo_init(&ksi);
 	ksi.ksi_signo = rk->rk_sig;
 	ksi.ksi_code = SI_USER;
@@ -577,7 +590,9 @@ reap_kill(struct thread *td, struct proc *p, void *data)
 		w.ksi = &ksi;
 		w.rk = rk;
 		w.error = &error;
-		reap_kill_subtree(td, p, reaper, &w);
+		PROC_TREE_REF(reaper);
+		reap_kill_subtree(td, p, &reaper, &w);
+		PROC_TREE_UNREF(reaper);
 		crfree(w.cr);
 	}
 	PROC_LOCK(p);