summaryrefslogtreecommitdiff
path: root/sys/kern
diff options
context:
space:
mode:
authorVisa Hankala <visa@cvs.openbsd.org>2021-10-24 07:02:48 +0000
committerVisa Hankala <visa@cvs.openbsd.org>2021-10-24 07:02:48 +0000
commit5c59fd748e54b73743cd348940723ae3ae61a903 (patch)
treed658047149ce21a3131a02a3435316fd54474e2c /sys/kern
parent50bf60990b76f89bcfab0921ae44a6bc9f04d3b1 (diff)
Set klist lock for sockets to make socket event filters MP-safe
The filterops instances already provide f_modify and f_process callbacks with proper internal locking. Locking of socket klists has been the missing detail for MP-safety. OK mpi@
Diffstat (limited to 'sys/kern')
-rw-r--r--sys/kern/uipc_socket.c58
-rw-r--r--sys/kern/uipc_socket2.c6
2 files changed, 50 insertions, 14 deletions
diff --git a/sys/kern/uipc_socket.c b/sys/kern/uipc_socket.c
index afab85de1ee..f0d7046c40c 100644
--- a/sys/kern/uipc_socket.c
+++ b/sys/kern/uipc_socket.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: uipc_socket.c,v 1.266 2021/10/22 15:11:32 mpi Exp $ */
+/* $OpenBSD: uipc_socket.c,v 1.267 2021/10/24 07:02:47 visa Exp $ */
/* $NetBSD: uipc_socket.c,v 1.21 1996/02/04 02:17:52 christos Exp $ */
/*
@@ -88,7 +88,7 @@ int filt_solistenprocess(struct knote *kn, struct kevent *kev);
int filt_solisten_common(struct knote *kn, struct socket *so);
const struct filterops solisten_filtops = {
- .f_flags = FILTEROP_ISFD,
+ .f_flags = FILTEROP_ISFD | FILTEROP_MPSAFE,
.f_attach = NULL,
.f_detach = filt_sordetach,
.f_event = filt_solisten,
@@ -97,7 +97,7 @@ const struct filterops solisten_filtops = {
};
const struct filterops soread_filtops = {
- .f_flags = FILTEROP_ISFD,
+ .f_flags = FILTEROP_ISFD | FILTEROP_MPSAFE,
.f_attach = NULL,
.f_detach = filt_sordetach,
.f_event = filt_soread,
@@ -106,7 +106,7 @@ const struct filterops soread_filtops = {
};
const struct filterops sowrite_filtops = {
- .f_flags = FILTEROP_ISFD,
+ .f_flags = FILTEROP_ISFD | FILTEROP_MPSAFE,
.f_attach = NULL,
.f_detach = filt_sowdetach,
.f_event = filt_sowrite,
@@ -115,7 +115,7 @@ const struct filterops sowrite_filtops = {
};
const struct filterops soexcept_filtops = {
- .f_flags = FILTEROP_ISFD,
+ .f_flags = FILTEROP_ISFD | FILTEROP_MPSAFE,
.f_attach = NULL,
.f_detach = filt_sordetach,
.f_event = filt_soexcept,
@@ -173,6 +173,8 @@ socreate(int dom, struct socket **aso, int type, int proto)
return (EPROTOTYPE);
so = pool_get(&socket_pool, PR_WAITOK | PR_ZERO);
rw_init(&so->so_lock, "solock");
+ klist_init(&so->so_rcv.sb_sel.si_note, &socket_klistops, so);
+ klist_init(&so->so_snd.sb_sel.si_note, &socket_klistops, so);
sigio_init(&so->so_sigio);
TAILQ_INIT(&so->so_q0);
TAILQ_INIT(&so->so_q);
@@ -262,6 +264,8 @@ sofree(struct socket *so, int s)
}
}
sigio_free(&so->so_sigio);
+ klist_free(&so->so_rcv.sb_sel.si_note);
+ klist_free(&so->so_snd.sb_sel.si_note);
#ifdef SOCKET_SPLICE
if (so->so_sp) {
if (issplicedback(so)) {
@@ -2042,9 +2046,9 @@ soo_kqfilter(struct file *fp, struct knote *kn)
{
struct socket *so = kn->kn_fp->f_data;
struct sockbuf *sb;
+ int s;
- KERNEL_ASSERT_LOCKED();
-
+ s = solock(so);
switch (kn->kn_filter) {
case EVFILT_READ:
if (so->so_options & SO_ACCEPTCONN)
@@ -2062,10 +2066,12 @@ soo_kqfilter(struct file *fp, struct knote *kn)
sb = &so->so_rcv;
break;
default:
+ sounlock(so, s);
return (EINVAL);
}
klist_insert_locked(&sb->sb_sel.si_note, kn);
+ sounlock(so, s);
return (0);
}
@@ -2075,9 +2081,7 @@ filt_sordetach(struct knote *kn)
{
struct socket *so = kn->kn_fp->f_data;
- KERNEL_ASSERT_LOCKED();
-
- klist_remove_locked(&so->so_rcv.sb_sel.si_note, kn);
+ klist_remove(&so->so_rcv.sb_sel.si_note, kn);
}
int
@@ -2157,9 +2161,7 @@ filt_sowdetach(struct knote *kn)
{
struct socket *so = kn->kn_fp->f_data;
- KERNEL_ASSERT_LOCKED();
-
- klist_remove_locked(&so->so_snd.sb_sel.si_note, kn);
+ klist_remove(&so->so_snd.sb_sel.si_note, kn);
}
int
@@ -2353,6 +2355,36 @@ filt_solistenprocess(struct knote *kn, struct kevent *kev)
return (rv);
}
+void
+klist_soassertlk(void *arg)
+{
+ struct socket *so = arg;
+
+ soassertlocked(so);
+}
+
+int
+klist_solock(void *arg)
+{
+ struct socket *so = arg;
+
+ return (solock(so));
+}
+
+void
+klist_sounlock(void *arg, int ls)
+{
+ struct socket *so = arg;
+
+ sounlock(so, ls);
+}
+
+const struct klistops socket_klistops = {
+ .klo_assertlk = klist_soassertlk,
+ .klo_lock = klist_solock,
+ .klo_unlock = klist_sounlock,
+};
+
#ifdef DDB
void
sobuf_print(struct sockbuf *,
diff --git a/sys/kern/uipc_socket2.c b/sys/kern/uipc_socket2.c
index e387e4705f7..59229ef936d 100644
--- a/sys/kern/uipc_socket2.c
+++ b/sys/kern/uipc_socket2.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: uipc_socket2.c,v 1.113 2021/07/26 05:51:13 mpi Exp $ */
+/* $OpenBSD: uipc_socket2.c,v 1.114 2021/10/24 07:02:47 visa Exp $ */
/* $NetBSD: uipc_socket2.c,v 1.11 1996/02/04 02:17:55 christos Exp $ */
/*
@@ -189,6 +189,8 @@ sonewconn(struct socket *head, int connstatus)
so->so_rcv.sb_lowat = head->so_rcv.sb_lowat;
so->so_rcv.sb_timeo_nsecs = head->so_rcv.sb_timeo_nsecs;
+ klist_init(&so->so_rcv.sb_sel.si_note, &socket_klistops, so);
+ klist_init(&so->so_snd.sb_sel.si_note, &socket_klistops, so);
sigio_init(&so->so_sigio);
sigio_copy(&so->so_sigio, &head->so_sigio);
@@ -196,6 +198,8 @@ sonewconn(struct socket *head, int connstatus)
if ((*so->so_proto->pr_attach)(so, 0)) {
(void) soqremque(so, soqueue);
sigio_free(&so->so_sigio);
+ klist_free(&so->so_rcv.sb_sel.si_note);
+ klist_free(&so->so_snd.sb_sel.si_note);
pool_put(&socket_pool, so);
return (NULL);
}