Add f_modify and f_process callbacks to socket filterops.
authorvisa <visa@openbsd.org>
Fri, 28 May 2021 16:24:53 +0000 (16:24 +0000)
committervisa <visa@openbsd.org>
Fri, 28 May 2021 16:24:53 +0000 (16:24 +0000)
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
sys/kern/uipc_syscalls.c

index f194fae..dce2020 100644 (file)
@@ -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 *,
index 67b9baf..b28c66a 100644 (file)
@@ -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;