git: 4c4bad4421fb - main - kqueue: avoid closing a file under the knlist lock
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Fri, 07 Aug 2026 23:05:03 UTC
The branch main has been updated by adrian:
URL: https://cgit.FreeBSD.org/src/commit/?id=4c4bad4421fb1a300178767f71215cc5f5e0bfb6
commit 4c4bad4421fb1a300178767f71215cc5f5e0bfb6
Author: Abdelkader Boudih <freebsd@seuros.com>
AuthorDate: 2026-08-07 22:57:07 +0000
Commit: Adrian Chadd <adrian@FreeBSD.org>
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;