git: 4c4bad4421fb - main - kqueue: avoid closing a file under the knlist lock

Adrian Chadd <[email protected]>
Newsgroups gmane.os.freebsd.devel.cvs.src
Message-ID <6a76649f.3628b.44c639c6__13088.4233441734$1786143926$gmane$org@gitrepo.freebsd.org>
The branch main has been updated by adrian:

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

commit 4c4bad4421fb1a300178767f71215cc5f5e0bfb6
Author:     Abdelkader Boudih <[email protected]>
AuthorDate: 2026-08-07 22:57:07 +0000
Commit:     Adrian Chadd <[email protected]>
CommitDate: 2026-08-07 22:57:11 +0000

    kqueue: avoid closing a file under the knlist lock
    
    Killing a knote releases its file reference, and releasing the last one
    runs the close path inline.
     panic: _mtx_lock_sleep: recursed on non-recursive mutex ttymtx
    
    Revoking a controlling tty during exit reaches this whenever a knote is
    still registered on it.
    
    Released the knlist lock around the drop and restart the walk.
    The knote stays valid while the lock is released.
    
    MFC: 1 week
    
    Reviewed by:    kib
    Differential Revision:  https://reviews.freebsd.org/D58681
---
 sys/kern/kern_event.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/sys/kern/kern_event.c b/sys/kern/kern_event.c
index 507451ce4492..734f8a408f4d 100644
--- a/sys/kern/kern_event.c
+++ b/sys/kern/kern_event.c
@@ -2793,6 +2793,7 @@ knlist_cleardel(struct knlist *knl, struct thread *td, int islocked, int killkn)
 {
 	struct knote *kn, *kn2;
 	struct kqueue *kq;
+	bool dropped;
 
 	KASSERT(!knl->kl_autodestroy, ("cleardel for autodestroy %p", knl));
 	if (islocked)
@@ -2809,6 +2810,7 @@ knlist_cleardel(struct knlist *knl, struct thread *td, int islocked, int killkn)
 		 * freed or converted to one-shot, as the attached subject is
 		 * essentially disappearing.
 		 */
+		dropped = false;
 		SLIST_FOREACH_SAFE(kn, &knl->kl_list, kn_selnext, kn2) {
 			kq = kn->kn_kq;
 			KQ_LOCK(kq);
@@ -2820,7 +2822,11 @@ knlist_cleardel(struct knlist *knl, struct thread *td, int islocked, int killkn)
 			if (killkn) {
 				kn_enter_flux(kn);
 				KQ_UNLOCK(kq);
+				knl->kl_unlock(knl->kl_lockarg);
 				knote_drop_detached(kn, td);
+				knl->kl_lock(knl->kl_lockarg);
+				dropped = true;
+				break;
 			} else {
 				/* Make sure cleared knotes disappear soon */
 				kn->kn_flags |= EV_EOF | EV_ONESHOT;
@@ -2828,6 +2834,8 @@ knlist_cleardel(struct knlist *knl, struct thread *td, int islocked, int killkn)
 			}
 			kq = NULL;
 		}
+		if (dropped)
+			continue;
 
 		if (SLIST_EMPTY(&knl->kl_list))
 			break;
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.