Rework socket buffers locking for shared netlock.
authormvs <mvs@openbsd.org>
Sat, 3 Feb 2024 22:50:08 +0000 (22:50 +0000)
committermvs <mvs@openbsd.org>
Sat, 3 Feb 2024 22:50:08 +0000 (22:50 +0000)
Shared netlock is not sufficient to call so{r,w}wakeup(). The following
sowakeup() modifies `sb_flags' and knote(9) stuff. Unfortunately, we
can't call so{r,w}wakeup() with `inp_mtx' mutex(9) because sowakeup()
also calls pgsigio() which grabs kernel lock.

However, `so*_filtops' callbacks only perform read-only access to the
socket stuff, so it is enough to hold shared netlock only, but the klist
stuff needs to be protected.

This diff introduces `sb_mtx' mutex(9) to protect sockbuf. This time
`sb_mtx' used to protect only `sb_flags' and `sb_klist'.

Now we have soassertlocked_readonly() and soassertlocked(). The first
one is happy if only shared netlock is held, meanwhile the second wants
`so_lock' or pru_lock() be held together with shared netlock.

To keep soassertlocked*() assertions soft, we need to know mutex(9)
state, so new mtx_owned() macro was introduces. Also, the new optional
(*pru_locked)() handler brings the state of pru_lock().

Tests and ok from bluhm.

17 files changed:
sys/kern/uipc_socket.c
sys/kern/uipc_socket2.c
sys/kern/uipc_syscalls.c
sys/miscfs/fifofs/fifo_vnops.c
sys/netinet/ip_divert.c
sys/netinet/ip_divert.h
sys/netinet/ip_var.h
sys/netinet/raw_ip.c
sys/netinet/udp_usrreq.c
sys/netinet/udp_var.h
sys/netinet6/ip6_divert.c
sys/netinet6/ip6_mroute.c
sys/netinet6/ip6_var.h
sys/netinet6/raw_ip6.c
sys/sys/mutex.h
sys/sys/protosw.h
sys/sys/socketvar.h

index 41a6bd7..aa28062 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: uipc_socket.c,v 1.315 2024/01/26 18:24:23 mvs Exp $   */
+/*     $OpenBSD: uipc_socket.c,v 1.316 2024/02/03 22:50:08 mvs Exp $   */
 /*     $NetBSD: uipc_socket.c,v 1.21 1996/02/04 02:17:52 christos Exp $        */
 
 /*
@@ -72,26 +72,20 @@ int filt_soread(struct knote *kn, long hint);
 void   filt_sowdetach(struct knote *kn);
 int    filt_sowrite(struct knote *kn, long hint);
 int    filt_soexcept(struct knote *kn, long hint);
-int    filt_solisten(struct knote *kn, long hint);
-int    filt_somodify(struct kevent *kev, struct knote *kn);
-int    filt_soprocess(struct knote *kn, struct kevent *kev);
 
-const struct filterops solisten_filtops = {
-       .f_flags        = FILTEROP_ISFD | FILTEROP_MPSAFE,
-       .f_attach       = NULL,
-       .f_detach       = filt_sordetach,
-       .f_event        = filt_solisten,
-       .f_modify       = filt_somodify,
-       .f_process      = filt_soprocess,
-};
+int    filt_sowmodify(struct kevent *kev, struct knote *kn);
+int    filt_sowprocess(struct knote *kn, struct kevent *kev);
+
+int    filt_sormodify(struct kevent *kev, struct knote *kn);
+int    filt_sorprocess(struct knote *kn, struct kevent *kev);
 
 const struct filterops soread_filtops = {
        .f_flags        = FILTEROP_ISFD | FILTEROP_MPSAFE,
        .f_attach       = NULL,
        .f_detach       = filt_sordetach,
        .f_event        = filt_soread,
-       .f_modify       = filt_somodify,
-       .f_process      = filt_soprocess,
+       .f_modify       = filt_sormodify,
+       .f_process      = filt_sorprocess,
 };
 
 const struct filterops sowrite_filtops = {
@@ -99,8 +93,8 @@ const struct filterops sowrite_filtops = {
        .f_attach       = NULL,
        .f_detach       = filt_sowdetach,
        .f_event        = filt_sowrite,
-       .f_modify       = filt_somodify,
-       .f_process      = filt_soprocess,
+       .f_modify       = filt_sowmodify,
+       .f_process      = filt_sowprocess,
 };
 
 const struct filterops soexcept_filtops = {
@@ -108,18 +102,8 @@ const struct filterops soexcept_filtops = {
        .f_attach       = NULL,
        .f_detach       = filt_sordetach,
        .f_event        = filt_soexcept,
-       .f_modify       = filt_somodify,
-       .f_process      = filt_soprocess,
-};
-
-void   klist_soassertlk(void *);
-int    klist_solock(void *);
-void   klist_sounlock(void *, int);
-
-const struct klistops socket_klistops = {
-       .klo_assertlk   = klist_soassertlk,
-       .klo_lock       = klist_solock,
-       .klo_unlock     = klist_sounlock,
+       .f_modify       = filt_sormodify,
+       .f_process      = filt_sorprocess,
 };
 
 #ifndef SOMINCONN
@@ -158,8 +142,10 @@ soalloc(const struct domain *dp, int wait)
                return (NULL);
        rw_init_flags(&so->so_lock, dp->dom_name, RWL_DUPOK);
        refcnt_init(&so->so_refcnt);
-       klist_init(&so->so_rcv.sb_klist, &socket_klistops, so);
-       klist_init(&so->so_snd.sb_klist, &socket_klistops, so);
+       mtx_init(&so->so_rcv.sb_mtx, IPL_MPFLOOR);
+       mtx_init(&so->so_snd.sb_mtx, IPL_MPFLOOR);
+       klist_init_mutex(&so->so_rcv.sb_klist, &so->so_rcv.sb_mtx);
+       klist_init_mutex(&so->so_snd.sb_klist, &so->so_snd.sb_mtx);
        sigio_init(&so->so_sigio);
        TAILQ_INIT(&so->so_q0);
        TAILQ_INIT(&so->so_q);
@@ -1757,7 +1743,7 @@ somove(struct socket *so, int wait)
 void
 sorwakeup(struct socket *so)
 {
-       soassertlocked(so);
+       soassertlocked_readonly(so);
 
 #ifdef SOCKET_SPLICE
        if (so->so_rcv.sb_flags & SB_SPLICE) {
@@ -1785,7 +1771,7 @@ sorwakeup(struct socket *so)
 void
 sowwakeup(struct socket *so)
 {
-       soassertlocked(so);
+       soassertlocked_readonly(so);
 
 #ifdef SOCKET_SPLICE
        if (so->so_snd.sb_flags & SB_SPLICE)
@@ -2134,7 +2120,46 @@ void
 sohasoutofband(struct socket *so)
 {
        pgsigio(&so->so_sigio, SIGURG, 0);
-       knote_locked(&so->so_rcv.sb_klist, 0);
+       knote(&so->so_rcv.sb_klist, 0);
+}
+
+void
+sofilt_lock(struct socket *so, struct sockbuf *sb)
+{
+       switch (so->so_proto->pr_domain->dom_family) {
+       case PF_INET:
+       case PF_INET6:
+               NET_LOCK_SHARED();
+               break;
+       default:
+               rw_enter_write(&so->so_lock);
+               break;
+       }
+
+       mtx_enter(&sb->sb_mtx);
+}
+
+void
+sofilt_unlock(struct socket *so, struct sockbuf *sb)
+{
+       mtx_leave(&sb->sb_mtx);
+
+       switch (so->so_proto->pr_domain->dom_family) {
+       case PF_INET:
+       case PF_INET6:
+               NET_UNLOCK_SHARED();
+               break;
+       default:
+               rw_exit_write(&so->so_lock);
+               break;
+       }
+}
+
+static inline void
+sofilt_assert_locked(struct socket *so, struct sockbuf *sb)
+{
+       MUTEX_ASSERT_LOCKED(&sb->sb_mtx);
+       soassertlocked_readonly(so);
 }
 
 int
@@ -2143,13 +2168,9 @@ soo_kqfilter(struct file *fp, struct knote *kn)
        struct socket *so = kn->kn_fp->f_data;
        struct sockbuf *sb;
 
-       solock(so);
        switch (kn->kn_filter) {
        case EVFILT_READ:
-               if (so->so_options & SO_ACCEPTCONN)
-                       kn->kn_fop = &solisten_filtops;
-               else
-                       kn->kn_fop = &soread_filtops;
+               kn->kn_fop = &soread_filtops;
                sb = &so->so_rcv;
                break;
        case EVFILT_WRITE:
@@ -2161,12 +2182,10 @@ soo_kqfilter(struct file *fp, struct knote *kn)
                sb = &so->so_rcv;
                break;
        default:
-               sounlock(so);
                return (EINVAL);
        }
 
-       klist_insert_locked(&sb->sb_klist, kn);
-       sounlock(so);
+       klist_insert(&sb->sb_klist, kn);
 
        return (0);
 }
@@ -2185,7 +2204,23 @@ filt_soread(struct knote *kn, long hint)
        struct socket *so = kn->kn_fp->f_data;
        int rv = 0;
 
-       soassertlocked(so);
+       sofilt_assert_locked(so, &so->so_rcv);
+
+       if (so->so_options & SO_ACCEPTCONN) {
+               kn->kn_data = so->so_qlen;
+               rv = (kn->kn_data != 0);
+
+               if (kn->kn_flags & (__EV_POLL | __EV_SELECT)) {
+                       if (so->so_state & SS_ISDISCONNECTED) {
+                               kn->kn_flags |= __EV_HUP;
+                               rv = 1;
+                       } else {
+                               rv = soreadable(so);
+                       }
+               }
+
+               return rv;
+       }
 
        kn->kn_data = so->so_rcv.sb_cc;
 #ifdef SOCKET_SPLICE
@@ -2226,7 +2261,7 @@ filt_sowrite(struct knote *kn, long hint)
        struct socket *so = kn->kn_fp->f_data;
        int rv;
 
-       soassertlocked(so);
+       sofilt_assert_locked(so, &so->so_snd);
 
        kn->kn_data = sbspace(so, &so->so_snd);
        if (so->so_snd.sb_state & SS_CANTSENDMORE) {
@@ -2257,7 +2292,7 @@ filt_soexcept(struct knote *kn, long hint)
        struct socket *so = kn->kn_fp->f_data;
        int rv = 0;
 
-       soassertlocked(so);
+       sofilt_assert_locked(so, &so->so_rcv);
 
 #ifdef SOCKET_SPLICE
        if (isspliced(so)) {
@@ -2283,77 +2318,55 @@ filt_soexcept(struct knote *kn, long hint)
 }
 
 int
-filt_solisten(struct knote *kn, long hint)
+filt_sowmodify(struct kevent *kev, struct knote *kn)
 {
        struct socket *so = kn->kn_fp->f_data;
-       int active;
-
-       soassertlocked(so);
-
-       kn->kn_data = so->so_qlen;
-       active = (kn->kn_data != 0);
+       int rv;
 
-       if (kn->kn_flags & (__EV_POLL | __EV_SELECT)) {
-               if (so->so_state & SS_ISDISCONNECTED) {
-                       kn->kn_flags |= __EV_HUP;
-                       active = 1;
-               } else {
-                       active = soreadable(so);
-               }
-       }
+       sofilt_lock(so, &so->so_snd);
+       rv = knote_modify(kev, kn);
+       sofilt_unlock(so, &so->so_snd);
 
-       return (active);
+       return (rv);
 }
 
 int
-filt_somodify(struct kevent *kev, struct knote *kn)
+filt_sowprocess(struct knote *kn, struct kevent *kev)
 {
        struct socket *so = kn->kn_fp->f_data;
        int rv;
 
-       solock(so);
-       rv = knote_modify(kev, kn);
-       sounlock(so);
+       sofilt_lock(so, &so->so_snd);
+       rv = knote_process(kn, kev);
+       sofilt_unlock(so, &so->so_snd);
 
        return (rv);
 }
 
 int
-filt_soprocess(struct knote *kn, struct kevent *kev)
+filt_sormodify(struct kevent *kev, struct knote *kn)
 {
        struct socket *so = kn->kn_fp->f_data;
        int rv;
 
-       solock(so);
-       rv = knote_process(kn, kev);
-       sounlock(so);
+       sofilt_lock(so, &so->so_rcv);
+       rv = knote_modify(kev, kn);
+       sofilt_unlock(so, &so->so_rcv);
 
        return (rv);
 }
 
-void
-klist_soassertlk(void *arg)
-{
-       struct socket *so = arg;
-
-       soassertlocked(so);
-}
-
 int
-klist_solock(void *arg)
+filt_sorprocess(struct knote *kn, struct kevent *kev)
 {
-       struct socket *so = arg;
-
-       solock(so);
-       return (1);
-}
+       struct socket *so = kn->kn_fp->f_data;
+       int rv;
 
-void
-klist_sounlock(void *arg, int ls)
-{
-       struct socket *so = arg;
+       sofilt_lock(so, &so->so_rcv);
+       rv = knote_process(kn, kev);
+       sofilt_unlock(so, &so->so_rcv);
 
-       sounlock(so);
+       return (rv);
 }
 
 #ifdef DDB
index 5b55090..a86dd7d 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: uipc_socket2.c,v 1.140 2024/01/11 14:15:11 bluhm Exp $        */
+/*     $OpenBSD: uipc_socket2.c,v 1.141 2024/02/03 22:50:08 mvs Exp $  */
 /*     $NetBSD: uipc_socket2.c,v 1.11 1996/02/04 02:17:55 christos Exp $       */
 
 /*
@@ -439,7 +439,7 @@ sounlock_shared(struct socket *so)
 }
 
 void
-soassertlocked(struct socket *so)
+soassertlocked_readonly(struct socket *so)
 {
        switch (so->so_proto->pr_domain->dom_family) {
        case PF_INET:
@@ -452,6 +452,27 @@ soassertlocked(struct socket *so)
        }
 }
 
+void
+soassertlocked(struct socket *so)
+{
+       switch (so->so_proto->pr_domain->dom_family) {
+       case PF_INET:
+       case PF_INET6:
+               if (rw_status(&netlock) == RW_READ) {
+                       NET_ASSERT_LOCKED();
+
+                       if (splassert_ctl > 0 && pru_locked(so) == 0 &&
+                           rw_status(&so->so_lock) != RW_WRITE)
+                               splassert_fail(0, RW_WRITE, __func__);
+               } else
+                       NET_ASSERT_LOCKED_EXCLUSIVE();
+               break;
+       default:
+               rw_assert_wrlock(&so->so_lock);
+               break;
+       }
+}
+
 int
 sosleep_nsec(struct socket *so, void *ident, int prio, const char *wmesg,
     uint64_t nsecs)
@@ -489,46 +510,62 @@ sbwait(struct socket *so, struct sockbuf *sb)
 
        soassertlocked(so);
 
+       mtx_enter(&sb->sb_mtx);
        sb->sb_flags |= SB_WAIT;
+       mtx_leave(&sb->sb_mtx);
+
        return sosleep_nsec(so, &sb->sb_cc, prio, "netio", sb->sb_timeo_nsecs);
 }
 
 int
 sblock(struct socket *so, struct sockbuf *sb, int flags)
 {
-       int error, prio = PSOCK;
+       int error = 0, prio = PSOCK;
 
        soassertlocked(so);
 
+       mtx_enter(&sb->sb_mtx);
        if ((sb->sb_flags & SB_LOCK) == 0) {
                sb->sb_flags |= SB_LOCK;
-               return (0);
+               goto out;
+       }
+       if ((flags & SBL_WAIT) == 0) {
+               error = EWOULDBLOCK;
+               goto out;
        }
-       if ((flags & SBL_WAIT) == 0)
-               return (EWOULDBLOCK);
        if (!(flags & SBL_NOINTR || sb->sb_flags & SB_NOINTR))
                prio |= PCATCH;
 
        while (sb->sb_flags & SB_LOCK) {
                sb->sb_flags |= SB_WANT;
+               mtx_leave(&sb->sb_mtx);
                error = sosleep_nsec(so, &sb->sb_flags, prio, "netlck", INFSLP);
                if (error)
                        return (error);
+               mtx_enter(&sb->sb_mtx);
        }
        sb->sb_flags |= SB_LOCK;
-       return (0);
+out:
+       mtx_leave(&sb->sb_mtx);
+
+       return (error);
 }
 
 void
 sbunlock(struct socket *so, struct sockbuf *sb)
 {
-       soassertlocked(so);
+       int dowakeup = 0;
 
+       mtx_enter(&sb->sb_mtx);
        sb->sb_flags &= ~SB_LOCK;
        if (sb->sb_flags & SB_WANT) {
                sb->sb_flags &= ~SB_WANT;
-               wakeup(&sb->sb_flags);
+               dowakeup = 1;
        }
+       mtx_leave(&sb->sb_mtx);
+
+       if (dowakeup)
+               wakeup(&sb->sb_flags);
 }
 
 /*
@@ -539,15 +576,24 @@ sbunlock(struct socket *so, struct sockbuf *sb)
 void
 sowakeup(struct socket *so, struct sockbuf *sb)
 {
-       soassertlocked(so);
+       int dowakeup = 0, dopgsigio = 0;
 
+       mtx_enter(&sb->sb_mtx);
        if (sb->sb_flags & SB_WAIT) {
                sb->sb_flags &= ~SB_WAIT;
-               wakeup(&sb->sb_cc);
+               dowakeup = 1;
        }
        if (sb->sb_flags & SB_ASYNC)
-               pgsigio(&so->so_sigio, SIGIO, 0);
+               dopgsigio = 1;
+
        knote_locked(&sb->sb_klist, 0);
+       mtx_leave(&sb->sb_mtx);
+
+       if (dowakeup)
+               wakeup(&sb->sb_cc);
+
+       if (dopgsigio)
+               pgsigio(&so->so_sigio, SIGIO, 0);
 }
 
 /*
index c258936..c57950a 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: uipc_syscalls.c,v 1.216 2024/01/03 11:07:04 bluhm Exp $       */
+/*     $OpenBSD: uipc_syscalls.c,v 1.217 2024/02/03 22:50:09 mvs Exp $ */
 /*     $NetBSD: uipc_syscalls.c,v 1.19 1996/02/09 19:00:48 christos Exp $      */
 
 /*
@@ -326,7 +326,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_locked(&head->so_rcv.sb_klist, 0);
+       knote(&head->so_rcv.sb_klist, 0);
 
        if (persocket)
                sounlock(head);
index 985b0e4..5458372 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: fifo_vnops.c,v 1.102 2023/03/08 04:43:08 guenther Exp $       */
+/*     $OpenBSD: fifo_vnops.c,v 1.103 2024/02/03 22:50:09 mvs Exp $    */
 /*     $NetBSD: fifo_vnops.c,v 1.18 1996/03/16 23:52:42 christos Exp $ */
 
 /*
@@ -105,16 +105,18 @@ int       filt_fiforead(struct knote *kn, long hint);
 void   filt_fifowdetach(struct knote *kn);
 int    filt_fifowrite(struct knote *kn, long hint);
 int    filt_fifoexcept(struct knote *kn, long hint);
-int    filt_fifomodify(struct kevent *kev, struct knote *kn);
-int    filt_fifoprocess(struct knote *kn, struct kevent *kev);
+int    filt_fiformodify(struct kevent *kev, struct knote *kn);
+int    filt_fiforprocess(struct knote *kn, struct kevent *kev);
+int    filt_fifowmodify(struct kevent *kev, struct knote *kn);
+int    filt_fifowprocess(struct knote *kn, struct kevent *kev);
 
 const struct filterops fiforead_filtops = {
        .f_flags        = FILTEROP_ISFD | FILTEROP_MPSAFE,
        .f_attach       = NULL,
        .f_detach       = filt_fifordetach,
        .f_event        = filt_fiforead,
-       .f_modify       = filt_fifomodify,
-       .f_process      = filt_fifoprocess,
+       .f_modify       = filt_fiformodify,
+       .f_process      = filt_fiforprocess,
 };
 
 const struct filterops fifowrite_filtops = {
@@ -122,8 +124,8 @@ const struct filterops fifowrite_filtops = {
        .f_attach       = NULL,
        .f_detach       = filt_fifowdetach,
        .f_event        = filt_fifowrite,
-       .f_modify       = filt_fifomodify,
-       .f_process      = filt_fifoprocess,
+       .f_modify       = filt_fifowmodify,
+       .f_process      = filt_fifowprocess,
 };
 
 const struct filterops fifoexcept_filtops = {
@@ -131,8 +133,8 @@ const struct filterops fifoexcept_filtops = {
        .f_attach       = NULL,
        .f_detach       = filt_fifordetach,
        .f_event        = filt_fifoexcept,
-       .f_modify       = filt_fifomodify,
-       .f_process      = filt_fifoprocess,
+       .f_modify       = filt_fiformodify,
+       .f_process      = filt_fiforprocess,
 };
 
 /*
@@ -517,6 +519,7 @@ filt_fiforead(struct knote *kn, long hint)
        int rv;
 
        soassertlocked(so);
+       MUTEX_ASSERT_LOCKED(&so->so_rcv.sb_mtx);
 
        kn->kn_data = so->so_rcv.sb_cc;
        if (so->so_rcv.sb_state & SS_CANTRCVMORE) {
@@ -551,6 +554,7 @@ filt_fifowrite(struct knote *kn, long hint)
        int rv;
 
        soassertlocked(so);
+       MUTEX_ASSERT_LOCKED(&so->so_snd.sb_mtx);
 
        kn->kn_data = sbspace(so, &so->so_snd);
        if (so->so_snd.sb_state & SS_CANTSENDMORE) {
@@ -571,6 +575,7 @@ filt_fifoexcept(struct knote *kn, long hint)
        int rv = 0;
 
        soassertlocked(so);
+       MUTEX_ASSERT_LOCKED(&so->so_rcv.sb_mtx);
 
        if (kn->kn_flags & __EV_POLL) {
                if (so->so_state & SS_ISDISCONNECTED) {
@@ -585,26 +590,60 @@ filt_fifoexcept(struct knote *kn, long hint)
 }
 
 int
-filt_fifomodify(struct kevent *kev, struct knote *kn)
+filt_fiformodify(struct kevent *kev, struct knote *kn)
 {
        struct socket *so = kn->kn_hook;
        int rv;
 
        solock(so);
+       mtx_enter(&so->so_rcv.sb_mtx);
        rv = knote_modify(kev, kn);
+       mtx_leave(&so->so_rcv.sb_mtx);
        sounlock(so);
 
        return (rv);
 }
 
 int
-filt_fifoprocess(struct knote *kn, struct kevent *kev)
+filt_fiforprocess(struct knote *kn, struct kevent *kev)
 {
        struct socket *so = kn->kn_hook;
        int rv;
 
        solock(so);
+       mtx_enter(&so->so_rcv.sb_mtx);
        rv = knote_process(kn, kev);
+       mtx_leave(&so->so_rcv.sb_mtx);
+       sounlock(so);
+
+       return (rv);
+}
+
+int
+filt_fifowmodify(struct kevent *kev, struct knote *kn)
+{
+       struct socket *so = kn->kn_hook;
+       int rv;
+
+       solock(so);
+       mtx_enter(&so->so_snd.sb_mtx);
+       rv = knote_modify(kev, kn);
+       mtx_leave(&so->so_snd.sb_mtx);
+       sounlock(so);
+
+       return (rv);
+}
+
+int
+filt_fifowprocess(struct knote *kn, struct kevent *kev)
+{
+       struct socket *so = kn->kn_hook;
+       int rv;
+
+       solock(so);
+       mtx_enter(&so->so_snd.sb_mtx);
+       rv = knote_process(kn, kev);
+       mtx_leave(&so->so_snd.sb_mtx);
        sounlock(so);
 
        return (rv);
index b21569e..593bfcf 100644 (file)
@@ -1,4 +1,4 @@
-/*      $OpenBSD: ip_divert.c,v 1.92 2023/09/16 09:33:27 mpi Exp $ */
+/*      $OpenBSD: ip_divert.c,v 1.93 2024/02/03 22:50:09 mvs Exp $ */
 
 /*
  * Copyright (c) 2009 Michele Marchetto <michele@openbsd.org>
@@ -67,6 +67,7 @@ const struct pr_usrreqs divert_usrreqs = {
        .pru_detach     = divert_detach,
        .pru_lock       = divert_lock,
        .pru_unlock     = divert_unlock,
+       .pru_locked     = divert_locked,
        .pru_bind       = divert_bind,
        .pru_shutdown   = divert_shutdown,
        .pru_send       = divert_send,
@@ -313,6 +314,14 @@ divert_unlock(struct socket *so)
        mtx_leave(&inp->inp_mtx);
 }
 
+int
+divert_locked(struct socket *so)
+{
+       struct inpcb *inp = sotoinpcb(so);
+
+       return mtx_owned(&inp->inp_mtx);
+}
+
 int
 divert_bind(struct socket *so, struct mbuf *addr, struct proc *p)
 {
index 1418864..2c09d51 100644 (file)
@@ -1,4 +1,4 @@
-/*      $OpenBSD: ip_divert.h,v 1.24 2022/10/17 14:49:02 mvs Exp $ */
+/*      $OpenBSD: ip_divert.h,v 1.25 2024/02/03 22:50:09 mvs Exp $ */
 
 /*
  * Copyright (c) 2009 Michele Marchetto <michele@openbsd.org>
@@ -74,6 +74,7 @@ int    divert_attach(struct socket *, int, int);
 int     divert_detach(struct socket *);
 void    divert_lock(struct socket *);
 void    divert_unlock(struct socket *);
+int     divert_locked(struct socket *);
 int     divert_bind(struct socket *, struct mbuf *, struct proc *);
 int     divert_shutdown(struct socket *);
 int     divert_send(struct socket *, struct mbuf *, struct mbuf *,
index 7897966..663671d 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: ip_var.h,v 1.110 2023/11/26 22:08:10 bluhm Exp $      */
+/*     $OpenBSD: ip_var.h,v 1.111 2024/02/03 22:50:09 mvs Exp $        */
 /*     $NetBSD: ip_var.h,v 1.16 1996/02/13 23:43:20 christos Exp $     */
 
 /*
@@ -260,6 +260,7 @@ int  rip_attach(struct socket *, int, int);
 int     rip_detach(struct socket *);
 void    rip_lock(struct socket *);
 void    rip_unlock(struct socket *);
+int     rip_locked(struct socket *);
 int     rip_bind(struct socket *, struct mbuf *, struct proc *);
 int     rip_connect(struct socket *, struct mbuf *);
 int     rip_disconnect(struct socket *);
index ae9ddb5..5f8047c 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: raw_ip.c,v 1.154 2024/01/21 01:17:20 bluhm Exp $      */
+/*     $OpenBSD: raw_ip.c,v 1.155 2024/02/03 22:50:09 mvs Exp $        */
 /*     $NetBSD: raw_ip.c,v 1.25 1996/02/18 18:58:33 christos Exp $     */
 
 /*
@@ -108,6 +108,7 @@ const struct pr_usrreqs rip_usrreqs = {
        .pru_detach     = rip_detach,
        .pru_lock       = rip_lock,
        .pru_unlock     = rip_unlock,
+       .pru_locked     = rip_locked,
        .pru_bind       = rip_bind,
        .pru_connect    = rip_connect,
        .pru_disconnect = rip_disconnect,
@@ -524,6 +525,14 @@ rip_unlock(struct socket *so)
        mtx_leave(&inp->inp_mtx);
 }
 
+int
+rip_locked(struct socket *so)
+{
+       struct inpcb *inp = sotoinpcb(so);
+
+       return mtx_owned(&inp->inp_mtx);
+}
+
 int
 rip_bind(struct socket *so, struct mbuf *nam, struct proc *p)
 {
index 6a58bb9..18b0ae9 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: udp_usrreq.c,v 1.316 2024/01/28 20:34:25 bluhm Exp $  */
+/*     $OpenBSD: udp_usrreq.c,v 1.317 2024/02/03 22:50:09 mvs Exp $    */
 /*     $NetBSD: udp_usrreq.c,v 1.28 1996/03/16 23:54:03 christos Exp $ */
 
 /*
@@ -127,6 +127,7 @@ const struct pr_usrreqs udp_usrreqs = {
        .pru_detach     = udp_detach,
        .pru_lock       = udp_lock,
        .pru_unlock     = udp_unlock,
+       .pru_locked     = udp_locked,
        .pru_bind       = udp_bind,
        .pru_connect    = udp_connect,
        .pru_disconnect = udp_disconnect,
@@ -143,6 +144,7 @@ const struct pr_usrreqs udp6_usrreqs = {
        .pru_detach     = udp_detach,
        .pru_lock       = udp_lock,
        .pru_unlock     = udp_unlock,
+       .pru_locked     = udp_locked,
        .pru_bind       = udp_bind,
        .pru_connect    = udp_connect,
        .pru_disconnect = udp_disconnect,
@@ -1156,6 +1158,14 @@ udp_unlock(struct socket *so)
        mtx_leave(&inp->inp_mtx);
 }
 
+int
+udp_locked(struct socket *so)
+{
+       struct inpcb *inp = sotoinpcb(so);
+
+       return mtx_owned(&inp->inp_mtx);
+}
+
 int
 udp_bind(struct socket *so, struct mbuf *addr, struct proc *p)
 {
index 80df331..5731cf4 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: udp_var.h,v 1.50 2024/01/10 16:44:30 bluhm Exp $      */
+/*     $OpenBSD: udp_var.h,v 1.51 2024/02/03 22:50:09 mvs Exp $        */
 /*     $NetBSD: udp_var.h,v 1.12 1996/02/13 23:44:41 christos Exp $    */
 
 /*
@@ -147,6 +147,7 @@ int  udp_attach(struct socket *, int, int);
 int     udp_detach(struct socket *);
 void    udp_lock(struct socket *);
 void    udp_unlock(struct socket *);
+int     udp_locked(struct socket *);
 int     udp_bind(struct socket *, struct mbuf *, struct proc *);
 int     udp_connect(struct socket *, struct mbuf *);
 int     udp_disconnect(struct socket *);
index 8964417..551df0e 100644 (file)
@@ -1,4 +1,4 @@
-/*      $OpenBSD: ip6_divert.c,v 1.91 2024/01/01 18:52:09 bluhm Exp $ */
+/*      $OpenBSD: ip6_divert.c,v 1.92 2024/02/03 22:50:09 mvs Exp $ */
 
 /*
  * Copyright (c) 2009 Michele Marchetto <michele@openbsd.org>
@@ -69,6 +69,7 @@ const struct pr_usrreqs divert6_usrreqs = {
        .pru_detach     = divert_detach,
        .pru_lock       = divert_lock,
        .pru_unlock     = divert_unlock,
+       .pru_locked     = divert_locked,
        .pru_bind       = divert_bind,
        .pru_shutdown   = divert_shutdown,
        .pru_send       = divert6_send,
index 5b02315..759a677 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: ip6_mroute.c,v 1.138 2023/12/06 09:27:17 bluhm Exp $  */
+/*     $OpenBSD: ip6_mroute.c,v 1.139 2024/02/03 22:50:09 mvs Exp $    */
 /*     $NetBSD: ip6_mroute.c,v 1.59 2003/12/10 09:28:38 itojun Exp $   */
 /*     $KAME: ip6_mroute.c,v 1.45 2001/03/25 08:38:51 itojun Exp $     */
 
@@ -861,12 +861,12 @@ socket6_send(struct socket *so, struct mbuf *mm, struct sockaddr_in6 *src)
 
                mtx_enter(&inp->inp_mtx);
                ret = sbappendaddr(so, &so->so_rcv, sin6tosa(src), mm, NULL);
+               if (ret != 0)
+                       sorwakeup(so);
                mtx_leave(&inp->inp_mtx);
 
-               if (ret != 0) {
-                       sorwakeup(so);
+               if (ret != 0)
                        return 0;
-               }
        }
        m_freem(mm);
        return -1;
index ebfde73..887bd95 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: ip6_var.h,v 1.109 2023/12/03 20:36:24 bluhm Exp $     */
+/*     $OpenBSD: ip6_var.h,v 1.110 2024/02/03 22:50:09 mvs Exp $       */
 /*     $KAME: ip6_var.h,v 1.33 2000/06/11 14:59:20 jinmei Exp $        */
 
 /*
@@ -353,6 +353,7 @@ int rip6_attach(struct socket *, int, int);
 int    rip6_detach(struct socket *);
 void   rip6_lock(struct socket *);
 void   rip6_unlock(struct socket *);
+int    rip6_locked(struct socket *);
 int    rip6_bind(struct socket *, struct mbuf *, struct proc *);
 int    rip6_connect(struct socket *, struct mbuf *);
 int    rip6_disconnect(struct socket *);
index 1b78424..4ae5ff2 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: raw_ip6.c,v 1.179 2024/01/21 01:17:20 bluhm Exp $     */
+/*     $OpenBSD: raw_ip6.c,v 1.180 2024/02/03 22:50:09 mvs Exp $       */
 /*     $KAME: raw_ip6.c,v 1.69 2001/03/04 15:55:44 itojun Exp $        */
 
 /*
@@ -110,6 +110,7 @@ const struct pr_usrreqs rip6_usrreqs = {
        .pru_detach     = rip6_detach,
        .pru_lock       = rip6_lock,
        .pru_unlock     = rip6_unlock,
+       .pru_locked     = rip6_locked,
        .pru_bind       = rip6_bind,
        .pru_connect    = rip6_connect,
        .pru_disconnect = rip6_disconnect,
@@ -653,6 +654,14 @@ rip6_unlock(struct socket *so)
        mtx_leave(&inp->inp_mtx);
 }
 
+int
+rip6_locked(struct socket *so)
+{
+       struct inpcb *inp = sotoinpcb(so);
+
+       return mtx_owned(&inp->inp_mtx);
+}
+
 int
 rip6_bind(struct socket *so, struct mbuf *nam, struct proc *p)
 {
index 8bb039a..a90714c 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: mutex.h,v 1.19 2023/12/01 14:37:22 bluhm Exp $        */
+/*     $OpenBSD: mutex.h,v 1.20 2024/02/03 22:50:09 mvs Exp $  */
 
 /*
  * Copyright (c) 2004 Artur Grabowski <art@openbsd.org>
@@ -127,6 +127,9 @@ void        mtx_leave(struct mutex *);
 
 #define mtx_init(m, ipl)       mtx_init_flags(m, ipl, NULL, 0)
 
+#define mtx_owned(mtx) \
+       (((mtx)->mtx_owner == curcpu()) || panicstr || db_active)
+
 #ifdef WITNESS
 
 void   _mtx_init_flags(struct mutex *, int, const char *, int,
index 03ade94..c6af337 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: protosw.h,v 1.64 2024/01/11 14:15:12 bluhm Exp $      */
+/*     $OpenBSD: protosw.h,v 1.65 2024/02/03 22:50:09 mvs Exp $        */
 /*     $NetBSD: protosw.h,v 1.10 1996/04/09 20:55:32 cgd Exp $ */
 
 /*-
@@ -69,6 +69,7 @@ struct pr_usrreqs {
        int     (*pru_detach)(struct socket *);
        void    (*pru_lock)(struct socket *);
        void    (*pru_unlock)(struct socket *);
+       int     (*pru_locked)(struct socket *so);
        int     (*pru_bind)(struct socket *, struct mbuf *, struct proc *);
        int     (*pru_listen)(struct socket *);
        int     (*pru_connect)(struct socket *, struct mbuf *);
@@ -296,6 +297,14 @@ pru_unlock(struct socket *so)
                (*so->so_proto->pr_usrreqs->pru_unlock)(so);
 }
 
+static inline int
+pru_locked(struct socket *so)
+{
+       if (so->so_proto->pr_usrreqs->pru_locked)
+               return (*so->so_proto->pr_usrreqs->pru_locked)(so);
+       return (0);
+}
+
 static inline int
 pru_bind(struct socket *so, struct mbuf *nam, struct proc *p)
 {
index 41403c0..f57773e 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: socketvar.h,v 1.121 2024/01/11 14:15:12 bluhm Exp $   */
+/*     $OpenBSD: socketvar.h,v 1.122 2024/02/03 22:50:09 mvs Exp $     */
 /*     $NetBSD: socketvar.h,v 1.18 1996/02/09 18:25:38 christos Exp $  */
 
 /*-
@@ -40,6 +40,7 @@
 #include <sys/sigio.h>                         /* for struct sigio_ref */
 #include <sys/task.h>
 #include <sys/timeout.h>
+#include <sys/mutex.h>
 #include <sys/rwlock.h>
 #include <sys/refcnt.h>
 
@@ -105,6 +106,7 @@ struct socket {
  * Variables for socket buffering.
  */
        struct  sockbuf {
+               struct mutex sb_mtx;
 /* The following fields are all zeroed on flush. */
 #define        sb_startzero    sb_cc
                u_long  sb_cc;          /* actual chars in buffer */
@@ -174,6 +176,7 @@ struct socket {
 #include <lib/libkern/libkern.h>
 
 void   soassertlocked(struct socket *);
+void   soassertlocked_readonly(struct socket *);
 
 static inline void
 soref(struct socket *so)
@@ -200,9 +203,16 @@ sorele(struct socket *so)
 static inline int
 sb_notify(struct socket *so, struct sockbuf *sb)
 {
+       int rv;
+
        soassertlocked(so);
-       return ((sb->sb_flags & (SB_WAIT|SB_ASYNC|SB_SPLICE)) != 0 ||
+
+       mtx_enter(&sb->sb_mtx);
+       rv = ((sb->sb_flags & (SB_WAIT|SB_ASYNC|SB_SPLICE)) != 0 ||
            !klist_empty(&sb->sb_klist));
+       mtx_leave(&sb->sb_mtx);
+
+       return rv;
 }
 
 /*
@@ -211,10 +221,12 @@ sb_notify(struct socket *so, struct sockbuf *sb)
  * still be negative (cc > hiwat or mbcnt > mbmax).  Should detect
  * overflow and return 0.
  */
+
 static inline long
 sbspace(struct socket *so, struct sockbuf *sb)
 {
-       soassertlocked(so);
+       soassertlocked_readonly(so);
+
        return lmin(sb->sb_hiwat - sb->sb_cc, sb->sb_mbmax - sb->sb_mbcnt);
 }
 
@@ -230,7 +242,7 @@ sbspace(struct socket *so, struct sockbuf *sb)
 static inline int
 soreadable(struct socket *so)
 {
-       soassertlocked(so);
+       soassertlocked_readonly(so);
        if (isspliced(so))
                return 0;
        return (so->so_rcv.sb_state & SS_CANTRCVMORE) || so->so_qlen ||
@@ -241,7 +253,7 @@ soreadable(struct socket *so)
 static inline int
 sowriteable(struct socket *so)
 {
-       soassertlocked(so);
+       soassertlocked_readonly(so);
        return ((sbspace(so, &so->so_snd) >= so->so_snd.sb_lowat &&
            ((so->so_state & SS_ISCONNECTED) ||
            (so->so_proto->pr_flags & PR_CONNREQUIRED)==0)) ||