diff options
| author | Mark Johnston <markj@FreeBSD.org> | 2025-11-18 14:22:04 +0000 |
|---|---|---|
| committer | Mark Johnston <markj@FreeBSD.org> | 2025-11-18 16:24:21 +0000 |
| commit | d795c753e262b97a93dc353aa66b858e1b1969d1 (patch) | |
| tree | f3701146f54f9823de910237741620b4457eb458 | |
| parent | 39ee24182b92114d006abc2b8095334a1d8a083c (diff) | |
kevent: Hold the knlist mutex when invoking f_event(NOTE_FORK)
In general f_event is supposed to be called with the knlist mutex held,
so lock it earlier to follow this protocol. Also make sure that the
update to kn_fflags is synchronized.
Lock the kqueue itself earlier in the case where the knote is activated,
to avoid locking and unlocking the kqueue twice.
PR: 291005
Reported by: Qiu-ji Chen <chenqiuji666@gmail.com>
Reviewed by: kib
MFC after: 1 week
Differential Revision: https://reviews.freebsd.org/D53762
| -rw-r--r-- | sys/kern/kern_event.c | 16 |
1 files changed, 12 insertions, 4 deletions
diff --git a/sys/kern/kern_event.c b/sys/kern/kern_event.c index 1baa24d278bf..a48408fd482a 100644 --- a/sys/kern/kern_event.c +++ b/sys/kern/kern_event.c @@ -627,12 +627,20 @@ knote_fork(struct knlist *list, int pid) kev.data = kn->kn_id; /* parent */ kev.udata = kn->kn_kevent.udata;/* preserve udata */ error = kqueue_register(kq, &kev, NULL, M_NOWAIT); + + /* + * Serialize updates to the kn_kevent fields with threads + * scanning the queue. + */ + list->kl_lock(list->kl_lockarg); if (error) kn->kn_fflags |= NOTE_TRACKERR; - if (kn->kn_fop->f_event(kn, NOTE_FORK)) - KNOTE_ACTIVATE(kn, 0); - list->kl_lock(list->kl_lockarg); - KQ_LOCK(kq); + if (kn->kn_fop->f_event(kn, NOTE_FORK)) { + KQ_LOCK(kq); + KNOTE_ACTIVATE(kn, 1); + } else { + KQ_LOCK(kq); + } kn_leave_flux(kn); KQ_UNLOCK_FLUX(kq); } |
