diff options
author | Visa Hankala <visa@cvs.openbsd.org> | 2021-06-16 14:26:31 +0000 |
---|---|---|
committer | Visa Hankala <visa@cvs.openbsd.org> | 2021-06-16 14:26:31 +0000 |
commit | 44303148a05134db193d7d2f08bf7e7edbe5df85 (patch) | |
tree | c9c35290a7f3c2be7f42c08403588ab9bac4703e | |
parent | 51a59ecb2adb43b8c60352ad01917f33a3100e0a (diff) |
kqueue: kq_lock is needed when updating kn_status
The kn_status field of struct knote is part of kqueue's internal state.
When kn_status is being updated, kq_lock has to be locked. This is true
even with MP-unsafe event filters.
OK mpi@
-rw-r--r-- | sys/kern/kern_event.c | 19 | ||||
-rw-r--r-- | sys/sys/event.h | 5 |
2 files changed, 17 insertions, 7 deletions
diff --git a/sys/kern/kern_event.c b/sys/kern/kern_event.c index 48d3400613a..ed2b1d16f8e 100644 --- a/sys/kern/kern_event.c +++ b/sys/kern/kern_event.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kern_event.c,v 1.166 2021/06/11 04:29:54 visa Exp $ */ +/* $OpenBSD: kern_event.c,v 1.167 2021/06/16 14:26:30 visa Exp $ */ /*- * Copyright (c) 1999,2000,2001 Jonathan Lemon <jlemon@FreeBSD.org> @@ -328,10 +328,15 @@ filt_procattach(struct knote *kn) void filt_procdetach(struct knote *kn) { + struct kqueue *kq = kn->kn_kq; struct process *pr = kn->kn_ptr.p_process; - int s; + int s, status; + + mtx_enter(&kq->kq_lock); + status = kn->kn_status; + mtx_leave(&kq->kq_lock); - if (kn->kn_status & KN_DETACHED) + if (status & KN_DETACHED) return; s = splhigh(); @@ -342,6 +347,7 @@ filt_procdetach(struct knote *kn) int filt_proc(struct knote *kn, long hint) { + struct kqueue *kq = kn->kn_kq; u_int event; /* @@ -363,8 +369,11 @@ filt_proc(struct knote *kn, long hint) struct process *pr = kn->kn_ptr.p_process; int s; - s = splhigh(); + mtx_enter(&kq->kq_lock); kn->kn_status |= KN_DETACHED; + mtx_leave(&kq->kq_lock); + + s = splhigh(); kn->kn_flags |= (EV_EOF | EV_ONESHOT); kn->kn_data = W_EXITCODE(pr->ps_xexit, pr->ps_xsig); klist_remove_locked(&pr->ps_klist, kn); @@ -391,7 +400,7 @@ filt_proc(struct knote *kn, long hint) kev.fflags = kn->kn_sfflags; kev.data = kn->kn_id; /* parent */ kev.udata = kn->kn_udata; /* preserve udata */ - error = kqueue_register(kn->kn_kq, &kev, NULL); + error = kqueue_register(kq, &kev, NULL); if (error) kn->kn_fflags |= NOTE_TRACKERR; } diff --git a/sys/sys/event.h b/sys/sys/event.h index 27e9d974efc..4df0d934ed0 100644 --- a/sys/sys/event.h +++ b/sys/sys/event.h @@ -1,4 +1,4 @@ -/* $OpenBSD: event.h,v 1.55 2021/06/02 13:56:28 visa Exp $ */ +/* $OpenBSD: event.h,v 1.56 2021/06/16 14:26:30 visa Exp $ */ /*- * Copyright (c) 1999,2000,2001 Jonathan Lemon <jlemon@FreeBSD.org> @@ -228,6 +228,7 @@ struct filterops { * Locking: * I immutable after creation * o object lock + * q kn_kq->kq_lock */ struct knote { SLIST_ENTRY(knote) kn_link; /* for fd */ @@ -235,7 +236,7 @@ struct knote { TAILQ_ENTRY(knote) kn_tqe; struct kqueue *kn_kq; /* [I] which queue we are on */ struct kevent kn_kevent; - int kn_status; + int kn_status; /* [q] */ int kn_sfflags; /* [o] saved filter flags */ __int64_t kn_sdata; /* [o] saved data field */ union { |