From e905407d906dc115a8fdbe37c027f67c0954cc6b Mon Sep 17 00:00:00 2001 From: visa Date: Fri, 28 May 2021 16:24:53 +0000 Subject: [PATCH] Add f_modify and f_process callbacks to socket filterops. This makes kqueue use the extended callback interface with socket event filters. Now one level of nested kernel locking is avoided, and the callbacks run without splhigh(). The filterops no longer check NOTE_SUBMIT, and use a fixed locking pattern instead. The f_event routines are always called with solock(), whereas f_modify and f_process are always called without the lock. OK mpi@ --- sys/kern/uipc_socket.c | 168 ++++++++++++++++++++++++++++++++++----- sys/kern/uipc_syscalls.c | 4 +- 2 files changed, 149 insertions(+), 23 deletions(-) diff --git a/sys/kern/uipc_socket.c b/sys/kern/uipc_socket.c index f194fae1707..dce20208828 100644 --- a/sys/kern/uipc_socket.c +++ b/sys/kern/uipc_socket.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uipc_socket.c,v 1.262 2021/05/25 22:45:09 bluhm Exp $ */ +/* $OpenBSD: uipc_socket.c,v 1.263 2021/05/28 16:24:53 visa Exp $ */ /* $NetBSD: uipc_socket.c,v 1.21 1996/02/04 02:17:52 christos Exp $ */ /* @@ -70,15 +70,26 @@ void sorflush(struct socket *); void filt_sordetach(struct knote *kn); int filt_soread(struct knote *kn, long hint); +int filt_soreadmodify(struct kevent *kev, struct knote *kn); +int filt_soreadprocess(struct knote *kn, struct kevent *kev); +int filt_soread_common(struct knote *kn, struct socket *so); void filt_sowdetach(struct knote *kn); int filt_sowrite(struct knote *kn, long hint); +int filt_sowritemodify(struct kevent *kev, struct knote *kn); +int filt_sowriteprocess(struct knote *kn, struct kevent *kev); +int filt_sowrite_common(struct knote *kn, struct socket *so); int filt_solisten(struct knote *kn, long hint); +int filt_solistenmodify(struct kevent *kev, struct knote *kn); +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_attach = NULL, .f_detach = filt_sordetach, .f_event = filt_solisten, + .f_modify = filt_solistenmodify, + .f_process = filt_solistenprocess, }; const struct filterops soread_filtops = { @@ -86,6 +97,8 @@ const struct filterops soread_filtops = { .f_attach = NULL, .f_detach = filt_sordetach, .f_event = filt_soread, + .f_modify = filt_soreadmodify, + .f_process = filt_soreadprocess, }; const struct filterops sowrite_filtops = { @@ -93,6 +106,8 @@ const struct filterops sowrite_filtops = { .f_attach = NULL, .f_detach = filt_sowdetach, .f_event = filt_sowrite, + .f_modify = filt_sowritemodify, + .f_process = filt_sowriteprocess, }; const struct filterops soexcept_filtops = { @@ -100,6 +115,8 @@ const struct filterops soexcept_filtops = { .f_attach = NULL, .f_detach = filt_sordetach, .f_event = filt_soread, + .f_modify = filt_soreadmodify, + .f_process = filt_soreadprocess, }; #ifndef SOMINCONN @@ -2058,13 +2075,12 @@ filt_sordetach(struct knote *kn) } int -filt_soread(struct knote *kn, long hint) +filt_soread_common(struct knote *kn, struct socket *so) { - struct socket *so = kn->kn_fp->f_data; - int s, rv = 0; + int rv = 0; + + soassertlocked(so); - if ((hint & NOTE_SUBMIT) == 0) - s = solock(so); kn->kn_data = so->so_rcv.sb_cc; #ifdef SOCKET_SPLICE if (isspliced(so)) { @@ -2092,12 +2108,50 @@ filt_soread(struct knote *kn, long hint) } else { rv = (kn->kn_data >= so->so_rcv.sb_lowat); } - if ((hint & NOTE_SUBMIT) == 0) - sounlock(so, s); return rv; } +int +filt_soread(struct knote *kn, long hint) +{ + struct socket *so = kn->kn_fp->f_data; + + return (filt_soread_common(kn, so)); +} + +int +filt_soreadmodify(struct kevent *kev, struct knote *kn) +{ + struct socket *so = kn->kn_fp->f_data; + int rv, s; + + s = solock(so); + knote_modify(kev, kn); + rv = filt_soread_common(kn, so); + sounlock(so, s); + + return (rv); +} + +int +filt_soreadprocess(struct knote *kn, struct kevent *kev) +{ + struct socket *so = kn->kn_fp->f_data; + int rv, s; + + s = solock(so); + if (kev != NULL && (kn->kn_flags & EV_ONESHOT)) + rv = 1; + else + rv = filt_soread_common(kn, so); + if (rv != 0) + knote_submit(kn, kev); + sounlock(so, s); + + return (rv); +} + void filt_sowdetach(struct knote *kn) { @@ -2109,13 +2163,12 @@ filt_sowdetach(struct knote *kn) } int -filt_sowrite(struct knote *kn, long hint) +filt_sowrite_common(struct knote *kn, struct socket *so) { - struct socket *so = kn->kn_fp->f_data; - int s, rv; + int rv; + + soassertlocked(so); - if ((hint & NOTE_SUBMIT) == 0) - s = solock(so); kn->kn_data = sbspace(so, &so->so_snd); if (so->so_state & SS_CANTSENDMORE) { kn->kn_flags |= EV_EOF; @@ -2135,27 +2188,100 @@ filt_sowrite(struct knote *kn, long hint) } else { rv = (kn->kn_data >= so->so_snd.sb_lowat); } - if ((hint & NOTE_SUBMIT) == 0) - sounlock(so, s); return (rv); } int -filt_solisten(struct knote *kn, long hint) +filt_sowrite(struct knote *kn, long hint) { struct socket *so = kn->kn_fp->f_data; - int s; - if ((hint & NOTE_SUBMIT) == 0) - s = solock(so); + return (filt_sowrite_common(kn, so)); +} + +int +filt_sowritemodify(struct kevent *kev, struct knote *kn) +{ + struct socket *so = kn->kn_fp->f_data; + int rv, s; + + s = solock(so); + knote_modify(kev, kn); + rv = filt_sowrite_common(kn, so); + sounlock(so, s); + + return (rv); +} + +int +filt_sowriteprocess(struct knote *kn, struct kevent *kev) +{ + struct socket *so = kn->kn_fp->f_data; + int rv, s; + + s = solock(so); + if (kev != NULL && (kn->kn_flags & EV_ONESHOT)) + rv = 1; + else + rv = filt_sowrite_common(kn, so); + if (rv != 0) + knote_submit(kn, kev); + sounlock(so, s); + + return (rv); +} + +int +filt_solisten_common(struct knote *kn, struct socket *so) +{ + soassertlocked(so); + kn->kn_data = so->so_qlen; - if ((hint & NOTE_SUBMIT) == 0) - sounlock(so, s); return (kn->kn_data != 0); } +int +filt_solisten(struct knote *kn, long hint) +{ + struct socket *so = kn->kn_fp->f_data; + + return (filt_solisten_common(kn, so)); +} + +int +filt_solistenmodify(struct kevent *kev, struct knote *kn) +{ + struct socket *so = kn->kn_fp->f_data; + int rv, s; + + s = solock(so); + knote_modify(kev, kn); + rv = filt_solisten_common(kn, so); + sounlock(so, s); + + return (rv); +} + +int +filt_solistenprocess(struct knote *kn, struct kevent *kev) +{ + struct socket *so = kn->kn_fp->f_data; + int rv, s; + + s = solock(so); + if (kev != NULL && (kn->kn_flags & EV_ONESHOT)) + rv = 1; + else + rv = filt_solisten_common(kn, so); + if (rv != 0) + knote_submit(kn, kev); + sounlock(so, s); + + return (rv); +} + #ifdef DDB void sobuf_print(struct sockbuf *, diff --git a/sys/kern/uipc_syscalls.c b/sys/kern/uipc_syscalls.c index 67b9baf441b..b28c66ac69b 100644 --- a/sys/kern/uipc_syscalls.c +++ b/sys/kern/uipc_syscalls.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uipc_syscalls.c,v 1.190 2021/05/13 17:31:59 mvs Exp $ */ +/* $OpenBSD: uipc_syscalls.c,v 1.191 2021/05/28 16:24:53 visa Exp $ */ /* $NetBSD: uipc_syscalls.c,v 1.19 1996/02/09 19:00:48 christos Exp $ */ /* @@ -308,7 +308,7 @@ doaccept(struct proc *p, int sock, struct sockaddr *name, socklen_t *anamelen, : (flags & SOCK_NONBLOCK ? FNONBLOCK : 0); /* connection has been removed from the listen queue */ - KNOTE(&head->so_rcv.sb_sel.si_note, NOTE_SUBMIT); + KNOTE(&head->so_rcv.sb_sel.si_note, 0); fp->f_type = DTYPE_SOCKET; fp->f_flag = FREAD | FWRITE | nflag; -- 2.20.1