Hi, The next small step towards parallel network stack is to use shared netlock in soreceive(). The UDP and IP divert layer provide locking of the PCB. If that is possible, use shared instead of exclusive netlock in soreceive(). The PCB mutex provides a per socket lock against multiple soreceive() running in parallel.
The solock_shared() is a bit hacky. Especially where we have to release and regrab both locks in sosleep_nsec(). But it does what we need. The udp_input() keeps exclusive lock for now. Socket splicing and IP header chains are not completely MP safe yet. Also udp_input() has some tentacles that need more testing. Ok to procceed with soreceive() unlocking before release? I think udp_input() has to wait post 7.2. bluhm Index: kern/uipc_socket.c =================================================================== RCS file: /data/mirror/openbsd/cvs/src/sys/kern/uipc_socket.c,v retrieving revision 1.287 diff -u -p -r1.287 uipc_socket.c --- kern/uipc_socket.c 3 Sep 2022 13:29:33 -0000 1.287 +++ kern/uipc_socket.c 3 Sep 2022 19:23:43 -0000 @@ -822,10 +822,10 @@ bad: if (mp) *mp = NULL; - solock(so); + solock_shared(so); restart: if ((error = sblock(so, &so->so_rcv, SBLOCKWAIT(flags))) != 0) { - sounlock(so); + sounlock_shared(so); return (error); } @@ -893,7 +893,7 @@ restart: sbunlock(so, &so->so_rcv); error = sbwait(so, &so->so_rcv); if (error) { - sounlock(so); + sounlock_shared(so); return (error); } goto restart; @@ -962,11 +962,11 @@ dontblock: sbsync(&so->so_rcv, nextrecord); if (controlp) { if (pr->pr_domain->dom_externalize) { - sounlock(so); + sounlock_shared(so); error = (*pr->pr_domain->dom_externalize) (cm, controllen, flags); - solock(so); + solock_shared(so); } *controlp = cm; } else { @@ -1040,9 +1040,9 @@ dontblock: SBLASTRECORDCHK(&so->so_rcv, "soreceive uiomove"); SBLASTMBUFCHK(&so->so_rcv, "soreceive uiomove"); resid = uio->uio_resid; - sounlock(so); + sounlock_shared(so); uio_error = uiomove(mtod(m, caddr_t) + moff, len, uio); - solock(so); + solock_shared(so); if (uio_error) uio->uio_resid = resid - len; } else @@ -1126,7 +1126,7 @@ dontblock: error = sbwait(so, &so->so_rcv); if (error) { sbunlock(so, &so->so_rcv); - sounlock(so); + sounlock_shared(so); return (0); } if ((m = so->so_rcv.sb_mb) != NULL) @@ -1171,7 +1171,7 @@ dontblock: *flagsp |= flags; release: sbunlock(so, &so->so_rcv); - sounlock(so); + sounlock_shared(so); return (error); } Index: kern/uipc_socket2.c =================================================================== RCS file: /data/mirror/openbsd/cvs/src/sys/kern/uipc_socket2.c,v retrieving revision 1.127 diff -u -p -r1.127 uipc_socket2.c --- kern/uipc_socket2.c 13 Aug 2022 21:01:46 -0000 1.127 +++ kern/uipc_socket2.c 3 Sep 2022 19:23:43 -0000 @@ -360,6 +360,24 @@ solock(struct socket *so) } } +void +solock_shared(struct socket *so) +{ + switch (so->so_proto->pr_domain->dom_family) { + case PF_INET: + case PF_INET6: + if (so->so_proto->pr_usrreqs->pru_lock != NULL) { + NET_LOCK_SHARED(); + pru_lock(so); + } else + NET_LOCK(); + break; + default: + rw_enter_write(&so->so_lock); + break; + } +} + int solock_persocket(struct socket *so) { @@ -403,6 +421,24 @@ sounlock(struct socket *so) } void +sounlock_shared(struct socket *so) +{ + switch (so->so_proto->pr_domain->dom_family) { + case PF_INET: + case PF_INET6: + if (so->so_proto->pr_usrreqs->pru_unlock != NULL) { + pru_unlock(so); + NET_UNLOCK_SHARED(); + } else + NET_UNLOCK(); + break; + default: + rw_exit_write(&so->so_lock); + break; + } +} + +void soassertlocked(struct socket *so) { switch (so->so_proto->pr_domain->dom_family) { @@ -425,7 +461,15 @@ sosleep_nsec(struct socket *so, void *id switch (so->so_proto->pr_domain->dom_family) { case PF_INET: case PF_INET6: + if (so->so_proto->pr_usrreqs->pru_unlock != NULL && + rw_status(&netlock) == RW_READ) { + pru_unlock(so); + } ret = rwsleep_nsec(ident, &netlock, prio, wmesg, nsecs); + if (so->so_proto->pr_usrreqs->pru_lock != NULL && + rw_status(&netlock) == RW_READ) { + pru_lock(so); + } break; default: ret = rwsleep_nsec(ident, &so->so_lock, prio, wmesg, nsecs); Index: netinet/ip_divert.c =================================================================== RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/ip_divert.c,v retrieving revision 1.85 diff -u -p -r1.85 ip_divert.c --- netinet/ip_divert.c 3 Sep 2022 18:48:50 -0000 1.85 +++ netinet/ip_divert.c 3 Sep 2022 19:23:43 -0000 @@ -66,6 +66,8 @@ const struct pr_usrreqs divert_usrreqs = .pru_usrreq = divert_usrreq, .pru_attach = divert_attach, .pru_detach = divert_detach, + .pru_lock = divert_lock, + .pru_unlock = divert_unlock, .pru_bind = divert_bind, .pru_shutdown = divert_shutdown, .pru_send = divert_send, @@ -325,6 +327,24 @@ divert_detach(struct socket *so) in_pcbdetach(inp); return (0); +} + +void +divert_lock(struct socket *so) +{ + struct inpcb *inp = sotoinpcb(so); + + NET_ASSERT_LOCKED(); + mtx_enter(&inp->inp_mtx); +} + +void +divert_unlock(struct socket *so) +{ + struct inpcb *inp = sotoinpcb(so); + + NET_ASSERT_LOCKED(); + mtx_leave(&inp->inp_mtx); } int Index: netinet/ip_divert.h =================================================================== RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/ip_divert.h,v retrieving revision 1.20 diff -u -p -r1.20 ip_divert.h --- netinet/ip_divert.h 28 Aug 2022 18:44:16 -0000 1.20 +++ netinet/ip_divert.h 3 Sep 2022 19:23:43 -0000 @@ -74,6 +74,8 @@ int divert_usrreq(struct socket *, int, struct mbuf *, struct mbuf *, struct mbuf *, struct proc *); int divert_attach(struct socket *, int); int divert_detach(struct socket *); +void divert_lock(struct socket *); +void divert_unlock(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: netinet/udp_usrreq.c =================================================================== RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/udp_usrreq.c,v retrieving revision 1.300 diff -u -p -r1.300 udp_usrreq.c --- netinet/udp_usrreq.c 3 Sep 2022 18:48:50 -0000 1.300 +++ netinet/udp_usrreq.c 3 Sep 2022 19:23:43 -0000 @@ -126,6 +126,8 @@ const struct pr_usrreqs udp_usrreqs = { .pru_usrreq = udp_usrreq, .pru_attach = udp_attach, .pru_detach = udp_detach, + .pru_lock = udp_lock, + .pru_unlock = udp_unlock, .pru_bind = udp_bind, .pru_connect = udp_connect, .pru_disconnect = udp_disconnect, @@ -141,6 +143,8 @@ const struct pr_usrreqs udp6_usrreqs = { .pru_usrreq = udp_usrreq, .pru_attach = udp_attach, .pru_detach = udp_detach, + .pru_lock = udp_lock, + .pru_unlock = udp_unlock, .pru_bind = udp_bind, .pru_connect = udp_connect, .pru_disconnect = udp_disconnect, @@ -1159,6 +1163,24 @@ udp_detach(struct socket *so) in_pcbdetach(inp); return (0); +} + +void +udp_lock(struct socket *so) +{ + struct inpcb *inp = sotoinpcb(so); + + NET_ASSERT_LOCKED(); + mtx_enter(&inp->inp_mtx); +} + +void +udp_unlock(struct socket *so) +{ + struct inpcb *inp = sotoinpcb(so); + + NET_ASSERT_LOCKED(); + mtx_leave(&inp->inp_mtx); } int Index: netinet/udp_var.h =================================================================== RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/udp_var.h,v retrieving revision 1.45 diff -u -p -r1.45 udp_var.h --- netinet/udp_var.h 2 Sep 2022 13:12:32 -0000 1.45 +++ netinet/udp_var.h 3 Sep 2022 19:23:43 -0000 @@ -147,6 +147,8 @@ int udp_usrreq(struct socket *, int, struct mbuf *, struct mbuf *, struct mbuf *, struct proc *); int udp_attach(struct socket *, int); int udp_detach(struct socket *); +void udp_lock(struct socket *); +void udp_unlock(struct socket *); int udp_bind(struct socket *, struct mbuf *, struct proc *); int udp_connect(struct socket *, struct mbuf *); int udp_disconnect(struct socket *); Index: netinet6/ip6_divert.c =================================================================== RCS file: /data/mirror/openbsd/cvs/src/sys/netinet6/ip6_divert.c,v retrieving revision 1.84 diff -u -p -r1.84 ip6_divert.c --- netinet6/ip6_divert.c 3 Sep 2022 18:48:50 -0000 1.84 +++ netinet6/ip6_divert.c 3 Sep 2022 19:23:43 -0000 @@ -67,6 +67,8 @@ const struct pr_usrreqs divert6_usrreqs .pru_usrreq = divert6_usrreq, .pru_attach = divert6_attach, .pru_detach = divert6_detach, + .pru_lock = divert6_lock, + .pru_unlock = divert6_unlock, .pru_bind = divert6_bind, .pru_shutdown = divert6_shutdown, .pru_send = divert6_send, @@ -332,6 +334,24 @@ divert6_detach(struct socket *so) in_pcbdetach(inp); return (0); +} + +void +divert6_lock(struct socket *so) +{ + struct inpcb *inp = sotoinpcb(so); + + NET_ASSERT_LOCKED(); + mtx_enter(&inp->inp_mtx); +} + +void +divert6_unlock(struct socket *so) +{ + struct inpcb *inp = sotoinpcb(so); + + NET_ASSERT_LOCKED(); + mtx_leave(&inp->inp_mtx); } int Index: netinet6/ip6_divert.h =================================================================== RCS file: /data/mirror/openbsd/cvs/src/sys/netinet6/ip6_divert.h,v retrieving revision 1.18 diff -u -p -r1.18 ip6_divert.h --- netinet6/ip6_divert.h 28 Aug 2022 18:44:17 -0000 1.18 +++ netinet6/ip6_divert.h 3 Sep 2022 19:23:43 -0000 @@ -74,6 +74,8 @@ int divert6_usrreq(struct socket *, int, struct mbuf *, struct mbuf *, struct mbuf *, struct proc *); int divert6_attach(struct socket *, int); int divert6_detach(struct socket *); +void divert6_lock(struct socket *); +void divert6_unlock(struct socket *); int divert6_bind(struct socket *, struct mbuf *, struct proc *); int divert6_shutdown(struct socket *); int divert6_send(struct socket *, struct mbuf *, struct mbuf *, Index: sys/protosw.h =================================================================== RCS file: /data/mirror/openbsd/cvs/src/sys/sys/protosw.h,v retrieving revision 1.53 diff -u -p -r1.53 protosw.h --- sys/protosw.h 3 Sep 2022 18:48:50 -0000 1.53 +++ sys/protosw.h 3 Sep 2022 19:23:43 -0000 @@ -68,6 +68,8 @@ struct pr_usrreqs { int (*pru_attach)(struct socket *, int); int (*pru_detach)(struct socket *); + void (*pru_lock)(struct socket *); + void (*pru_unlock)(struct socket *); int (*pru_bind)(struct socket *, struct mbuf *, struct proc *); int (*pru_listen)(struct socket *); int (*pru_connect)(struct socket *, struct mbuf *); @@ -277,6 +279,18 @@ static inline int pru_detach(struct socket *so) { return (*so->so_proto->pr_usrreqs->pru_detach)(so); +} + +static inline void +pru_lock(struct socket *so) +{ + (*so->so_proto->pr_usrreqs->pru_lock)(so); +} + +static inline void +pru_unlock(struct socket *so) +{ + (*so->so_proto->pr_usrreqs->pru_unlock)(so); } static inline int Index: sys/socketvar.h =================================================================== RCS file: /data/mirror/openbsd/cvs/src/sys/sys/socketvar.h,v retrieving revision 1.109 diff -u -p -r1.109 socketvar.h --- sys/socketvar.h 1 Sep 2022 05:31:49 -0000 1.109 +++ sys/socketvar.h 3 Sep 2022 19:23:43 -0000 @@ -348,9 +348,11 @@ int sockargs(struct mbuf **, const void int sosleep_nsec(struct socket *, void *, int, const char *, uint64_t); void solock(struct socket *); +void solock_shared(struct socket *); int solock_persocket(struct socket *); void solock_pair(struct socket *, struct socket *); void sounlock(struct socket *); +void sounlock_shared(struct socket *); int sendit(struct proc *, int, struct msghdr *, int, register_t *); int recvit(struct proc *, int, struct msghdr *, caddr_t, register_t *);