git: c37d95826ab5 - releng/15.0 - jail: fix a regression that creates zombies when removing dying jails

From: Colin Percival <cperciva_at_FreeBSD.org>
Date: Thu, 30 Oct 2025 04:23:53 UTC
The branch releng/15.0 has been updated by cperciva:

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

commit c37d95826ab5a9becb491396a6522f442680d25f
Author:     Jamie Gritton <jamie@FreeBSD.org>
AuthorDate: 2025-10-20 16:49:14 +0000
Commit:     Colin Percival <cperciva@FreeBSD.org>
CommitDate: 2025-10-30 04:23:18 +0000

    jail: fix a regression that creates zombies when removing dying jails
    
    When adding jail descriptors, I split sys_jail remove in two, and
    didn't properly track jail held between them when a jail was dying.
    This fixes that as well as cleaning up the logic behind it.
    
    Approved by:    re (cperciva)
    PR:             290217
    Reported by:    David 'equinox' Lamparter <equinox at diac24.net>
    Reviewed by:    markj
    MFC after:      3 days
    Differential Revision:  https://reviews.freebsd.org/D53200
    
    (cherry picked from commit 78f70d4ff9dd4af2318b25023a7f55be7402ec60)
    (cherry picked from commit 2d3c6a06edc3919455d1152f4ffaa60697e2c4f2)
---
 sys/kern/kern_jail.c | 21 ++++++++++-----------
 1 file changed, 10 insertions(+), 11 deletions(-)

diff --git a/sys/kern/kern_jail.c b/sys/kern/kern_jail.c
index a0a200caefc6..267b60ffb5bc 100644
--- a/sys/kern/kern_jail.c
+++ b/sys/kern/kern_jail.c
@@ -2911,12 +2911,6 @@ prison_remove(struct prison *pr)
 {
 	sx_assert(&allprison_lock, SA_XLOCKED);
 	mtx_assert(&pr->pr_mtx, MA_OWNED);
-	if (!prison_isalive(pr)) {
-		/* Silently ignore already-dying prisons. */
-		mtx_unlock(&pr->pr_mtx);
-		sx_xunlock(&allprison_lock);
-		return;
-	}
 	prison_deref(pr, PD_KILL | PD_DEREF | PD_LOCKED | PD_LIST_XLOCKED);
 }
 
@@ -3463,12 +3457,17 @@ prison_deref(struct prison *pr, int flags)
 			/* Kill the prison and its descendents. */
 			KASSERT(pr != &prison0,
 			    ("prison_deref trying to kill prison0"));
-			if (!(flags & PD_DEREF)) {
-				prison_hold(pr);
-				flags |= PD_DEREF;
+			if (!prison_isalive(pr)) {
+				/* Silently ignore already-dying prisons. */
+				flags &= ~PD_KILL;
+			} else {
+				if (!(flags & PD_DEREF)) {
+					prison_hold(pr);
+					flags |= PD_DEREF;
+				}
+				flags = prison_lock_xlock(pr, flags);
+				prison_deref_kill(pr, &freeprison);
 			}
-			flags = prison_lock_xlock(pr, flags);
-			prison_deref_kill(pr, &freeprison);
 		}
 		if (flags & PD_DEUREF) {
 			/* Drop a user reference. */