From 104c0a839baf7bd73dd7cb6df3321bb307c53da5 Mon Sep 17 00:00:00 2001 From: mvs Date: Sat, 3 Feb 2024 22:50:08 +0000 Subject: [PATCH] Rework socket buffers locking for shared netlock. 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. --- sys/kern/uipc_socket.c | 187 ++++++++++++++++++--------------- sys/kern/uipc_socket2.c | 70 +++++++++--- sys/kern/uipc_syscalls.c | 4 +- sys/miscfs/fifofs/fifo_vnops.c | 61 +++++++++-- sys/netinet/ip_divert.c | 11 +- sys/netinet/ip_divert.h | 3 +- sys/netinet/ip_var.h | 3 +- sys/netinet/raw_ip.c | 11 +- sys/netinet/udp_usrreq.c | 12 ++- sys/netinet/udp_var.h | 3 +- sys/netinet6/ip6_divert.c | 3 +- sys/netinet6/ip6_mroute.c | 8 +- sys/netinet6/ip6_var.h | 3 +- sys/netinet6/raw_ip6.c | 11 +- sys/sys/mutex.h | 5 +- sys/sys/protosw.h | 11 +- sys/sys/socketvar.h | 22 +++- 17 files changed, 296 insertions(+), 132 deletions(-) diff --git a/sys/kern/uipc_socket.c b/sys/kern/uipc_socket.c index 41a6bd7045d..aa28062e180 100644 --- a/sys/kern/uipc_socket.c +++ b/sys/kern/uipc_socket.c @@ -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 diff --git a/sys/kern/uipc_socket2.c b/sys/kern/uipc_socket2.c index 5b55090dd71..a86dd7d8632 100644 --- a/sys/kern/uipc_socket2.c +++ b/sys/kern/uipc_socket2.c @@ -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); } /* diff --git a/sys/kern/uipc_syscalls.c b/sys/kern/uipc_syscalls.c index c258936d774..c57950af2ea 100644 --- a/sys/kern/uipc_syscalls.c +++ b/sys/kern/uipc_syscalls.c @@ -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); diff --git a/sys/miscfs/fifofs/fifo_vnops.c b/sys/miscfs/fifofs/fifo_vnops.c index 985b0e4cab4..54583728236 100644 --- a/sys/miscfs/fifofs/fifo_vnops.c +++ b/sys/miscfs/fifofs/fifo_vnops.c @@ -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); diff --git a/sys/netinet/ip_divert.c b/sys/netinet/ip_divert.c index b21569e7205..593bfcfbc11 100644 --- a/sys/netinet/ip_divert.c +++ b/sys/netinet/ip_divert.c @@ -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 @@ -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) { diff --git a/sys/netinet/ip_divert.h b/sys/netinet/ip_divert.h index 14188641599..2c09d517559 100644 --- a/sys/netinet/ip_divert.h +++ b/sys/netinet/ip_divert.h @@ -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 @@ -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 *, diff --git a/sys/netinet/ip_var.h b/sys/netinet/ip_var.h index 789796633e3..663671d1a26 100644 --- a/sys/netinet/ip_var.h +++ b/sys/netinet/ip_var.h @@ -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 *); diff --git a/sys/netinet/raw_ip.c b/sys/netinet/raw_ip.c index ae9ddb52185..5f8047c77e7 100644 --- a/sys/netinet/raw_ip.c +++ b/sys/netinet/raw_ip.c @@ -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) { diff --git a/sys/netinet/udp_usrreq.c b/sys/netinet/udp_usrreq.c index 6a58bb91671..18b0ae983bc 100644 --- a/sys/netinet/udp_usrreq.c +++ b/sys/netinet/udp_usrreq.c @@ -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) { diff --git a/sys/netinet/udp_var.h b/sys/netinet/udp_var.h index 80df3318fe4..5731cf4ef1a 100644 --- a/sys/netinet/udp_var.h +++ b/sys/netinet/udp_var.h @@ -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 *); diff --git a/sys/netinet6/ip6_divert.c b/sys/netinet6/ip6_divert.c index 89644174285..551df0e5012 100644 --- a/sys/netinet6/ip6_divert.c +++ b/sys/netinet6/ip6_divert.c @@ -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 @@ -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, diff --git a/sys/netinet6/ip6_mroute.c b/sys/netinet6/ip6_mroute.c index 5b02315f921..759a677b30e 100644 --- a/sys/netinet6/ip6_mroute.c +++ b/sys/netinet6/ip6_mroute.c @@ -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; diff --git a/sys/netinet6/ip6_var.h b/sys/netinet6/ip6_var.h index ebfde734480..887bd95fe18 100644 --- a/sys/netinet6/ip6_var.h +++ b/sys/netinet6/ip6_var.h @@ -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 *); diff --git a/sys/netinet6/raw_ip6.c b/sys/netinet6/raw_ip6.c index 1b784248f3f..4ae5ff2ba1a 100644 --- a/sys/netinet6/raw_ip6.c +++ b/sys/netinet6/raw_ip6.c @@ -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) { diff --git a/sys/sys/mutex.h b/sys/sys/mutex.h index 8bb039aeb54..a90714c82b1 100644 --- a/sys/sys/mutex.h +++ b/sys/sys/mutex.h @@ -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 @@ -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, diff --git a/sys/sys/protosw.h b/sys/sys/protosw.h index 03ade942c03..c6af33751fc 100644 --- a/sys/sys/protosw.h +++ b/sys/sys/protosw.h @@ -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) { diff --git a/sys/sys/socketvar.h b/sys/sys/socketvar.h index 41403c00da1..f57773e63b8 100644 --- a/sys/sys/socketvar.h +++ b/sys/sys/socketvar.h @@ -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 /* for struct sigio_ref */ #include #include +#include #include #include @@ -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 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)) || -- 2.20.1