git: f1933eda43e6 - stable/14 - jail: Handle jail removal in a dedicated thread

From: Mark Johnston <markj_at_FreeBSD.org>
Date: Sat, 04 Jan 2025 14:08:16 UTC
The branch stable/14 has been updated by markj:

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

commit f1933eda43e6d15bc237a63741bda56bfed953e0
Author:     Mark Johnston <markj@FreeBSD.org>
AuthorDate: 2024-12-21 19:23:51 +0000
Commit:     Mark Johnston <markj@FreeBSD.org>
CommitDate: 2025-01-04 13:56:37 +0000

    jail: Handle jail removal in a dedicated thread
    
    Otherwise a deadlock is possible: the system taskqueue thread removes a
    prison and calls vnet_destroy(), vnet_vlan_uninit() destroys the if_vlan
    cloner, the vlan_clone_destroy() callback calls taskqueue_drain() on the
    thread taskqueue.
    
    Fix the problem by introducing a new thread for jail removals.
    
    Ideally, the taskqueue interface would let consumers define queues
    without having to map them to threads, as that'd make it possible to
    avoid such deadlocks without extra threads; for now, this is the only
    solution.
    
    Reviewed by:    jamie
    MFC after:      2 weeks
    Differential Revision:  https://reviews.freebsd.org/D47991
    
    (cherry picked from commit 8cf955f3f48a45db22a3cc3ad89a22b543fa38ce)
---
 sys/kern/kern_jail.c | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/sys/kern/kern_jail.c b/sys/kern/kern_jail.c
index c4e89774f18b..6f2b4f7fc336 100644
--- a/sys/kern/kern_jail.c
+++ b/sys/kern/kern_jail.c
@@ -130,6 +130,12 @@ struct jailsys_flags {
 	unsigned	 new;
 };
 
+/*
+ * Handle jail teardown in a dedicated thread to avoid deadlocks from
+ * vnet_destroy().
+ */
+TASKQUEUE_DEFINE_THREAD(jail_remove);
+
 /* allprison, allprison_racct and lastprid are protected by allprison_lock. */
 struct	sx allprison_lock;
 SX_SYSINIT(allprison_lock, &allprison_lock, "allprison");
@@ -2868,7 +2874,7 @@ prison_free(struct prison *pr)
 		 * Don't remove the last reference in this context,
 		 * in case there are locks held.
 		 */
-		taskqueue_enqueue(taskqueue_thread, &pr->pr_task);
+		taskqueue_enqueue(taskqueue_jail_remove, &pr->pr_task);
 	}
 }
 
@@ -2942,7 +2948,7 @@ prison_proc_free(struct prison *pr)
 		     pr->pr_id));
 		pr->pr_flags |= PR_COMPLETE_PROC;
 		mtx_unlock(&pr->pr_mtx);
-		taskqueue_enqueue(taskqueue_thread, &pr->pr_task);
+		taskqueue_enqueue(taskqueue_jail_remove, &pr->pr_task);
 	}
 }