git: 0e67c3f675ea - main - reap_kill_subtree_once(): reap_kill_proc_work() might drop proctree_lock

From: Konstantin Belousov <kib_at_FreeBSD.org>
Date: Sat, 21 Feb 2026 10:07:57 UTC
The branch main has been updated by kib:

URL: https://cgit.FreeBSD.org/src/commit/?id=0e67c3f675eab3a9c00b76e3886ace7700ef1bd4

commit 0e67c3f675eab3a9c00b76e3886ace7700ef1bd4
Author:     Konstantin Belousov <kib@FreeBSD.org>
AuthorDate: 2026-02-16 15:20:02 +0000
Commit:     Konstantin Belousov <kib@FreeBSD.org>
CommitDate: 2026-02-21 09:45:47 +0000

    reap_kill_subtree_once(): reap_kill_proc_work() might drop proctree_lock
    
    Due to this, restart the iteration over the p_reapsiblings if the lock
    was dropped.
    
    Reviewed by:    markj
    Tested by:      pho
    Sponsored by:   The FreeBSD Foundation
    MFC after:      1 week
    Differential revision:  https://reviews.freebsd.org/D55288
---
 sys/kern/kern_procctl.c | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/sys/kern/kern_procctl.c b/sys/kern/kern_procctl.c
index 04c47d086677..30ab37d56877 100644
--- a/sys/kern/kern_procctl.c
+++ b/sys/kern/kern_procctl.c
@@ -280,7 +280,7 @@ reap_kill_proc_locked(struct reap_kill_proc_work *w)
 }
 
 static void
-reap_kill_proc(struct reap_kill_proc_work *w)
+reap_kill_proc(struct reap_kill_proc_work *w, bool *proctree_dropped)
 {
 	struct pgrp *pgrp;
 	int xlocked;
@@ -311,6 +311,7 @@ reap_kill_proc(struct reap_kill_proc_work *w)
 		/* This is safe because pgrp zone is nofree. */
 		sx_xlock(&pgrp->pg_killsx);
 		sx_xunlock(&pgrp->pg_killsx);
+		*proctree_dropped = true;
 		if (xlocked)
 			sx_xlock(&proctree_lock);
 		else
@@ -392,7 +393,7 @@ reap_kill_subtree_once(struct thread *td, struct proc *p, struct proc *reaper,
 	struct reap_kill_tracker_head tracker;
 	struct reap_kill_tracker *t;
 	struct proc *p2;
-	bool res;
+	bool proctree_dropped, res;
 
 	res = false;
 	TAILQ_INIT(&tracker);
@@ -400,6 +401,7 @@ reap_kill_subtree_once(struct thread *td, struct proc *p, struct proc *reaper,
 	while ((t = TAILQ_FIRST(&tracker)) != NULL) {
 		TAILQ_REMOVE(&tracker, t, link);
 
+again:
 		/*
 		 * Since reap_kill_proc() drops proctree_lock sx, it
 		 * is possible that the tracked reaper is no longer.
@@ -435,6 +437,7 @@ reap_kill_subtree_once(struct thread *td, struct proc *p, struct proc *reaper,
 			    (P2_REAPKILLED | P2_WEXIT)) != 0)
 				continue;
 
+			proctree_dropped = false;
 			PROC_LOCK(p2);
 			if ((p2->p_flag2 & P2_WEXIT) == 0) {
 				_PHOLD(p2);
@@ -446,11 +449,13 @@ reap_kill_subtree_once(struct thread *td, struct proc *p, struct proc *reaper,
 				p2->p_flag2 |= P2_REAPKILLED;
 
 				w->target = p2;
-				reap_kill_proc(w);
+				reap_kill_proc(w, &proctree_dropped);
 				_PRELE(p2);
 			}
 			PROC_UNLOCK(p2);
 			res = true;
+			if (proctree_dropped)
+				goto again;
 		}
 		reap_kill_sched_free(t);
 	}