summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVisa Hankala <visa@cvs.openbsd.org>2021-06-16 14:26:31 +0000
committerVisa Hankala <visa@cvs.openbsd.org>2021-06-16 14:26:31 +0000
commit44303148a05134db193d7d2f08bf7e7edbe5df85 (patch)
treec9c35290a7f3c2be7f42c08403588ab9bac4703e
parent51a59ecb2adb43b8c60352ad01917f33a3100e0a (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.c19
-rw-r--r--sys/sys/event.h5
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 {