From 61067bc2145a0b64b9e72a0e463c57a4c3c505ca Mon Sep 17 00:00:00 2001 From: Oscar Zhao Date: Tue, 5 May 2020 04:14:30 -0400 Subject: [PATCH] release processing KN only when kq_scan has >0 max events. Because calling kevent with =0 max events doesn't mean all events are processed. This results in a subtle race of pre-releasing unprocessed knotes. --- sys/kern/kern_event.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/sys/kern/kern_event.c b/sys/kern/kern_event.c index 2f7b6372361a..ae26b103819e 100644 --- a/sys/kern/kern_event.c +++ b/sys/kern/kern_event.c @@ -2044,6 +2044,7 @@ kqueue_register(struct kqueue *kq, struct kevq *kevq, struct kevent *kev, struct KQ_UNLOCK(kq); knote_drop(kn, td); + CTR3(KTR_KQ, "kqueue_register: kq %p deleted kn %p, fd %d", kq, kn, kev->ident); goto done; } @@ -3068,11 +3069,6 @@ kqueue_scan(struct kevq *kevq, int maxevents, struct kevent_copyops *k_ops, error = 0; haskqglobal = 0; - KEVQ_LOCK(kevq); - /* release processing knotes first */ - kevq_rel_proc_kn(kevq); - KEVQ_UNLOCK(kevq); - // it's important that this is done before activate if (maxevents == 0) goto done_nl; @@ -3082,6 +3078,11 @@ kqueue_scan(struct kevq *kevq, int maxevents, struct kevent_copyops *k_ops, kevq_activate(kevq, td); } + KEVQ_LOCK(kevq); + /* release processing knotes first */ + kevq_rel_proc_kn(kevq); + KEVQ_UNLOCK(kevq); + /* adjust max events according to the target frequency */ if ((kq->kq_flags & KQ_FLAG_MULTI) && kq->kq_tfreq > 0 && kevq->kevq_avg_lat > 0) { /* expected events per syscall @@ -4199,7 +4200,7 @@ knote_activate(struct knote *kn) KQ_NOTOWNED(kq); - CTR2(KTR_KQ, "knote_activate: kn %p, flags %d", kn, kn->kn_status); + CTR3(KTR_KQ, "knote_activate: kn %p, fd %d, flags %d", kn, kn->kn_id, kn->kn_status); KN_FLUX_NOTOWNED(kn); KASSERT(kn_in_flux(kn), ("knote %p not in flux", kn));