dtucker@ reported an interesting recursion [0]. His trace shows that a thread executing unp_detach() MUST NOT be holding the NET_LOCK().
So here's a new version of my SOCKET_LOCK() diff that does exactly that. That means sofree(9) won't grab the NET_LOCK() for unix sockets which makes uipc_usrreq() completely NET_LOCK() free. Please test and report back. [0] https://marc.info/?l=openbsd-misc&m=148661605114230&w=2 Index: kern/sys_socket.c =================================================================== RCS file: /cvs/src/sys/kern/sys_socket.c,v retrieving revision 1.28 diff -u -p -r1.28 sys_socket.c --- kern/sys_socket.c 31 Jan 2017 12:16:20 -0000 1.28 +++ kern/sys_socket.c 9 Feb 2017 11:21:44 -0000 @@ -38,6 +38,7 @@ #include <sys/proc.h> #include <sys/mbuf.h> #include <sys/protosw.h> +#include <sys/domain.h> #include <sys/socket.h> #include <sys/socketvar.h> #include <sys/ioctl.h> @@ -127,10 +128,10 @@ soo_ioctl(struct file *fp, u_long cmd, c } if (IOCGROUP(cmd) == 'r') return (EOPNOTSUPP); - NET_LOCK(s); + SOCKET_LOCK(so, s); error = ((*so->so_proto->pr_usrreq)(so, PRU_CONTROL, (struct mbuf *)cmd, (struct mbuf *)data, (struct mbuf *)NULL, p)); - NET_UNLOCK(s); + SOCKET_UNLOCK(s); return (error); } @@ -187,10 +188,10 @@ soo_stat(struct file *fp, struct stat *u ub->st_mode |= S_IWUSR | S_IWGRP | S_IWOTH; ub->st_uid = so->so_euid; ub->st_gid = so->so_egid; - NET_LOCK(s); + SOCKET_LOCK(so, s); (void) ((*so->so_proto->pr_usrreq)(so, PRU_SENSE, (struct mbuf *)ub, NULL, NULL, p)); - NET_UNLOCK(s); + SOCKET_UNLOCK(s); return (0); } Index: kern/uipc_socket.c =================================================================== RCS file: /cvs/src/sys/kern/uipc_socket.c,v retrieving revision 1.176 diff -u -p -r1.176 uipc_socket.c --- kern/uipc_socket.c 1 Feb 2017 20:59:47 -0000 1.176 +++ kern/uipc_socket.c 9 Feb 2017 11:21:44 -0000 @@ -135,16 +135,16 @@ socreate(int dom, struct socket **aso, i so->so_egid = p->p_ucred->cr_gid; so->so_cpid = p->p_p->ps_pid; so->so_proto = prp; - NET_LOCK(s); + SOCKET_LOCK(so, s); error = (*prp->pr_usrreq)(so, PRU_ATTACH, NULL, (struct mbuf *)(long)proto, NULL, p); if (error) { so->so_state |= SS_NOFDREF; sofree(so); - NET_UNLOCK(s); + SOCKET_UNLOCK(s); return (error); } - NET_UNLOCK(s); + SOCKET_UNLOCK(s); *aso = so; return (0); } @@ -154,9 +154,9 @@ sobind(struct socket *so, struct mbuf *n { int s, error; - NET_LOCK(s); + SOCKET_LOCK(so, s); error = (*so->so_proto->pr_usrreq)(so, PRU_BIND, NULL, nam, NULL, p); - NET_UNLOCK(s); + SOCKET_UNLOCK(s); return (error); } @@ -171,11 +171,11 @@ solisten(struct socket *so, int backlog) if (isspliced(so) || issplicedback(so)) return (EOPNOTSUPP); #endif /* SOCKET_SPLICE */ - NET_LOCK(s); + SOCKET_LOCK(so, s); error = (*so->so_proto->pr_usrreq)(so, PRU_LISTEN, NULL, NULL, NULL, curproc); if (error) { - NET_UNLOCK(s); + SOCKET_UNLOCK(s); return (error); } if (TAILQ_FIRST(&so->so_q) == NULL) @@ -185,15 +185,13 @@ solisten(struct socket *so, int backlog) if (backlog < sominconn) backlog = sominconn; so->so_qlimit = backlog; - NET_UNLOCK(s); + SOCKET_UNLOCK(s); return (0); } void sofree(struct socket *so) { - NET_ASSERT_LOCKED(); - if (so->so_pcb || (so->so_state & SS_NOFDREF) == 0) return; if (so->so_head) { @@ -232,7 +230,7 @@ soclose(struct socket *so) struct socket *so2; int s, error = 0; - NET_LOCK(s); + SOCKET_LOCK(so, s); if (so->so_options & SO_ACCEPTCONN) { while ((so2 = TAILQ_FIRST(&so->so_q0)) != NULL) { (void) soqremque(so2, 0); @@ -256,7 +254,7 @@ soclose(struct socket *so) (so->so_state & SS_NBIO)) goto drop; while (so->so_state & SS_ISCONNECTED) { - error = rwsleep(&so->so_timeo, &netlock, + error = sosleep(so, &so->so_timeo, PSOCK | PCATCH, "netcls", so->so_linger * hz); if (error) @@ -276,7 +274,7 @@ discard: panic("soclose NOFDREF: so %p, so_type %d", so, so->so_type); so->so_state |= SS_NOFDREF; sofree(so); - NET_UNLOCK(s); + SOCKET_UNLOCK(s); return (error); } @@ -294,7 +292,7 @@ soaccept(struct socket *so, struct mbuf { int error = 0; - NET_ASSERT_LOCKED(); + SOCKET_ASSERT_LOCKED(so); if ((so->so_state & SS_NOFDREF) == 0) panic("soaccept !NOFDREF: so %p, so_type %d", so, so->so_type); @@ -315,7 +313,7 @@ soconnect(struct socket *so, struct mbuf if (so->so_options & SO_ACCEPTCONN) return (EOPNOTSUPP); - NET_LOCK(s); + SOCKET_LOCK(so, s); /* * If protocol is connection-based, can only connect once. * Otherwise, if connected, try to disconnect first. @@ -329,7 +327,7 @@ soconnect(struct socket *so, struct mbuf else error = (*so->so_proto->pr_usrreq)(so, PRU_CONNECT, NULL, nam, NULL, curproc); - NET_UNLOCK(s); + SOCKET_UNLOCK(s); return (error); } @@ -338,10 +336,10 @@ soconnect2(struct socket *so1, struct so { int s, error; - NET_LOCK(s); + SOCKET_LOCK(so1, s); error = (*so1->so_proto->pr_usrreq)(so1, PRU_CONNECT2, NULL, (struct mbuf *)so2, NULL, curproc); - NET_UNLOCK(s); + SOCKET_UNLOCK(s); return (error); } @@ -350,7 +348,7 @@ sodisconnect(struct socket *so) { int error; - NET_ASSERT_LOCKED(); + SOCKET_ASSERT_LOCKED(so); if ((so->so_state & SS_ISCONNECTED) == 0) return (ENOTCONN); @@ -418,14 +416,14 @@ sosend(struct socket *so, struct mbuf *a (sizeof(struct fdpass) / sizeof(int))); } -#define snderr(errno) { error = errno; NET_UNLOCK(s); goto release; } +#define snderr(errno) { error = errno; SOCKET_UNLOCK(s); goto release; } restart: if ((error = sblock(&so->so_snd, SBLOCKWAIT(flags), NULL)) != 0) goto out; so->so_state |= SS_ISSENDING; do { - NET_LOCK(s); + SOCKET_LOCK(so, s); if (so->so_state & SS_CANTSENDMORE) snderr(EPIPE); if (so->so_error) { @@ -453,14 +451,14 @@ restart: if ((so->so_state & SS_NBIO) || (flags & MSG_DONTWAIT)) snderr(EWOULDBLOCK); sbunlock(&so->so_snd); - error = sbwait(&so->so_snd); + error = sbwait(so, &so->so_snd); so->so_state &= ~SS_ISSENDING; - NET_UNLOCK(s); + SOCKET_UNLOCK(s); if (error) goto out; goto restart; } - NET_UNLOCK(s); + SOCKET_UNLOCK(s); space -= clen; do { if (uio == NULL) { @@ -480,13 +478,13 @@ restart: if (flags & MSG_EOR) top->m_flags |= M_EOR; } - NET_LOCK(s); + SOCKET_LOCK(so, s); if (resid == 0) so->so_state &= ~SS_ISSENDING; error = (*so->so_proto->pr_usrreq)(so, (flags & MSG_OOB) ? PRU_SENDOOB : PRU_SEND, top, addr, control, curproc); - NET_UNLOCK(s); + SOCKET_UNLOCK(s); clen = 0; control = NULL; top = NULL; @@ -615,7 +613,7 @@ sbsync(struct sockbuf *sb, struct mbuf * * followed by an optional mbuf or mbufs containing ancillary data, * and then zero or more mbufs of data. * In order to avoid blocking network for the entire time here, we release - * the NET_LOCK() while doing the actual copy to user space. + * the SOCKET_LOCK() while doing the actual copy to user space. * Although the sockbuf is locked, new data may still be appended, * and thus we must maintain consistency of the sockbuf during that time. * @@ -649,10 +647,10 @@ soreceive(struct socket *so, struct mbuf flags |= MSG_DONTWAIT; if (flags & MSG_OOB) { m = m_get(M_WAIT, MT_DATA); - NET_LOCK(s); + SOCKET_LOCK(so, s); error = (*pr->pr_usrreq)(so, PRU_RCVOOB, m, (struct mbuf *)(long)(flags & MSG_PEEK), NULL, curproc); - NET_UNLOCK(s); + SOCKET_UNLOCK(s); if (error) goto bad; do { @@ -670,7 +668,7 @@ bad: restart: if ((error = sblock(&so->so_rcv, SBLOCKWAIT(flags), NULL)) != 0) return (error); - NET_LOCK(s); + SOCKET_LOCK(so, s); m = so->so_rcv.sb_mb; #ifdef SOCKET_SPLICE @@ -734,8 +732,8 @@ restart: SBLASTRECORDCHK(&so->so_rcv, "soreceive sbwait 1"); SBLASTMBUFCHK(&so->so_rcv, "soreceive sbwait 1"); sbunlock(&so->so_rcv); - error = sbwait(&so->so_rcv); - NET_UNLOCK(s); + error = sbwait(so, &so->so_rcv); + SOCKET_UNLOCK(s); if (error) return (error); goto restart; @@ -801,11 +799,9 @@ dontblock: if (pr->pr_domain->dom_externalize && mtod(cm, struct cmsghdr *)->cmsg_type == SCM_RIGHTS) { - NET_UNLOCK(s); error = (*pr->pr_domain->dom_externalize) (cm, controllen, flags); - NET_LOCK(s); } *controlp = cm; } else { @@ -873,9 +869,9 @@ dontblock: SBLASTRECORDCHK(&so->so_rcv, "soreceive uiomove"); SBLASTMBUFCHK(&so->so_rcv, "soreceive uiomove"); resid = uio->uio_resid; - NET_UNLOCK(s); + SOCKET_UNLOCK(s); uio_error = uiomove(mtod(m, caddr_t) + moff, len, uio); - NET_LOCK(s); + SOCKET_LOCK(so, s); if (uio_error) uio->uio_resid = resid - len; } else @@ -954,10 +950,10 @@ dontblock: break; SBLASTRECORDCHK(&so->so_rcv, "soreceive sbwait 2"); SBLASTMBUFCHK(&so->so_rcv, "soreceive sbwait 2"); - error = sbwait(&so->so_rcv); + error = sbwait(so, &so->so_rcv); if (error) { sbunlock(&so->so_rcv); - NET_UNLOCK(s); + SOCKET_UNLOCK(s); return (0); } if ((m = so->so_rcv.sb_mb) != NULL) @@ -993,7 +989,7 @@ dontblock: if (orig_resid == uio->uio_resid && orig_resid && (flags & MSG_EOR) == 0 && (so->so_state & SS_CANTRCVMORE) == 0) { sbunlock(&so->so_rcv); - NET_UNLOCK(s); + SOCKET_UNLOCK(s); goto restart; } @@ -1004,7 +1000,7 @@ dontblock: *flagsp |= flags; release: sbunlock(&so->so_rcv); - NET_UNLOCK(s); + SOCKET_UNLOCK(s); return (error); } @@ -1014,7 +1010,7 @@ soshutdown(struct socket *so, int how) struct protosw *pr = so->so_proto; int s, error = 0; - NET_LOCK(s); + SOCKET_LOCK(so, s); switch (how) { case SHUT_RD: case SHUT_RDWR: @@ -1030,7 +1026,7 @@ soshutdown(struct socket *so, int how) error = EINVAL; break; } - NET_UNLOCK(s); + SOCKET_UNLOCK(s); return (error); } @@ -1043,7 +1039,8 @@ sorflush(struct socket *so) struct sockbuf asb; sb->sb_flags |= SB_NOINTR; - (void) sblock(sb, M_WAITOK, &netlock); + sblock(sb, M_WAITOK, + (pr->pr_domain->dom_family != PF_LOCAL) ? &netlock : NULL); socantrcvmore(so); sbunlock(sb); asb = *sb; @@ -1094,10 +1091,10 @@ sosplice(struct socket *so, int fd, off_ if ((error = sblock(&so->so_rcv, (so->so_state & SS_NBIO) ? M_NOWAIT : M_WAITOK, NULL)) != 0) return (error); - NET_LOCK(s); + SOCKET_LOCK(so, s); if (so->so_sp->ssp_socket) sounsplice(so, so->so_sp->ssp_socket, 1); - NET_UNLOCK(s); + SOCKET_UNLOCK(s); sbunlock(&so->so_rcv); return (0); } @@ -1126,7 +1123,7 @@ sosplice(struct socket *so, int fd, off_ FRELE(fp, curproc); return (error); } - NET_LOCK(s); + SOCKET_LOCK(so, s); if (so->so_sp->ssp_socket || sosp->so_sp->ssp_soback) { error = EBUSY; @@ -1167,7 +1164,7 @@ sosplice(struct socket *so, int fd, off_ } release: - NET_UNLOCK(s); + SOCKET_UNLOCK(s); sbunlock(&sosp->so_snd); sbunlock(&so->so_rcv); FRELE(fp, curproc); @@ -1177,7 +1174,7 @@ sosplice(struct socket *so, int fd, off_ void sounsplice(struct socket *so, struct socket *sosp, int wakeup) { - NET_ASSERT_LOCKED(); + SOCKET_ASSERT_LOCKED(so); task_del(sosplice_taskq, &so->so_splicetask); timeout_del(&so->so_idleto); @@ -1194,12 +1191,12 @@ soidle(void *arg) struct socket *so = arg; int s; - NET_LOCK(s); + SOCKET_LOCK(so, s); if (so->so_rcv.sb_flagsintr & SB_SPLICE) { so->so_error = ETIMEDOUT; sounsplice(so, so->so_sp->ssp_socket, 1); } - NET_UNLOCK(s); + SOCKET_UNLOCK(s); } void @@ -1208,7 +1205,7 @@ sotask(void *arg) struct socket *so = arg; int s; - NET_LOCK(s); + SOCKET_LOCK(so, s); if (so->so_rcv.sb_flagsintr & SB_SPLICE) { /* * We may not sleep here as sofree() and unsplice() may be @@ -1217,7 +1214,7 @@ sotask(void *arg) */ somove(so, M_DONTWAIT); } - NET_UNLOCK(s); + SOCKET_UNLOCK(s); /* Avoid user land starvation. */ yield(); @@ -1239,7 +1236,7 @@ somove(struct socket *so, int wait) int error = 0, maxreached = 0; short state; - NET_ASSERT_LOCKED(); + SOCKET_ASSERT_LOCKED(so); nextpkt: if (so->so_error) { @@ -1509,7 +1506,7 @@ somove(struct socket *so, int wait) void sorwakeup(struct socket *so) { - NET_ASSERT_LOCKED(); + SOCKET_ASSERT_LOCKED(so); #ifdef SOCKET_SPLICE if (so->so_rcv.sb_flagsintr & SB_SPLICE) { @@ -1541,7 +1538,7 @@ sorwakeup(struct socket *so) void sowwakeup(struct socket *so) { - NET_ASSERT_LOCKED(); + SOCKET_ASSERT_LOCKED(so); #ifdef SOCKET_SPLICE if (so->so_snd.sb_flagsintr & SB_SPLICE) @@ -1558,10 +1555,10 @@ sosetopt(struct socket *so, int level, i if (level != SOL_SOCKET) { if (so->so_proto && so->so_proto->pr_ctloutput) { - NET_LOCK(s); + SOCKET_LOCK(so, s); error = (*so->so_proto->pr_ctloutput)(PRCO_SETOPT, so, level, optname, m0); - NET_UNLOCK(s); + SOCKET_UNLOCK(s); return (error); } error = ENOPROTOOPT; @@ -1705,10 +1702,10 @@ sosetopt(struct socket *so, int level, i struct domain *dom = so->so_proto->pr_domain; level = dom->dom_protosw->pr_protocol; - NET_LOCK(s); + SOCKET_LOCK(so, s); error = (*so->so_proto->pr_ctloutput) (PRCO_SETOPT, so, level, optname, m0); - NET_UNLOCK(s); + SOCKET_UNLOCK(s); return (error); } error = ENOPROTOOPT; @@ -1737,10 +1734,10 @@ sosetopt(struct socket *so, int level, i break; } if (error == 0 && so->so_proto && so->so_proto->pr_ctloutput) { - NET_LOCK(s); + SOCKET_LOCK(so, s); (*so->so_proto->pr_ctloutput)(PRCO_SETOPT, so, level, optname, m0); - NET_UNLOCK(s); + SOCKET_UNLOCK(s); m = NULL; /* freed by protocol */ } } @@ -1761,10 +1758,10 @@ sogetopt(struct socket *so, int level, i m = m_get(M_WAIT, MT_SOOPTS); m->m_len = 0; - NET_LOCK(s); + SOCKET_LOCK(so, s); error = (*so->so_proto->pr_ctloutput)(PRCO_GETOPT, so, level, optname, m); - NET_UNLOCK(s); + SOCKET_UNLOCK(s); if (error) { m_free(m); return (error); @@ -1849,10 +1846,10 @@ sogetopt(struct socket *so, int level, i struct domain *dom = so->so_proto->pr_domain; level = dom->dom_protosw->pr_protocol; - NET_LOCK(s); + SOCKET_LOCK(so, s); error = (*so->so_proto->pr_ctloutput) (PRCO_GETOPT, so, level, optname, m); - NET_UNLOCK(s); + SOCKET_UNLOCK(s); if (error) { (void)m_free(m); return (error); Index: kern/uipc_socket2.c =================================================================== RCS file: /cvs/src/sys/kern/uipc_socket2.c,v retrieving revision 1.71 diff -u -p -r1.71 uipc_socket2.c --- kern/uipc_socket2.c 25 Jan 2017 06:15:50 -0000 1.71 +++ kern/uipc_socket2.c 9 Feb 2017 11:21:45 -0000 @@ -38,6 +38,7 @@ #include <sys/malloc.h> #include <sys/mbuf.h> #include <sys/protosw.h> +#include <sys/domain.h> #include <sys/socket.h> #include <sys/socketvar.h> #include <sys/signalvar.h> @@ -147,7 +148,7 @@ sonewconn(struct socket *head, int conns struct socket *so; int soqueue = connstatus ? 1 : 0; - NET_ASSERT_LOCKED(); + SOCKET_ASSERT_LOCKED(head); if (mclpools[0].pr_nout > mclpools[0].pr_hardlimit * 95 / 100) return (NULL); @@ -267,16 +268,25 @@ socantrcvmore(struct socket *so) sorwakeup(so); } +int +sosleep(struct socket *so, void *ident, int prio, const char *wmesg, int timo) +{ + if (so->so_proto->pr_protocol != PF_LOCAL) + return rwsleep(ident, &netlock, prio, wmesg, timo); + else + return tsleep(ident, prio, wmesg, timo); +} + /* * Wait for data to arrive at/drain from a socket buffer. */ int -sbwait(struct sockbuf *sb) +sbwait(struct socket *so, struct sockbuf *sb) { - NET_ASSERT_LOCKED(); + SOCKET_ASSERT_LOCKED(so); sb->sb_flagsintr |= SB_WAIT; - return (rwsleep(&sb->sb_cc, &netlock, + return (sosleep(so, &sb->sb_cc, (sb->sb_flags & SB_NOINTR) ? PSOCK : PSOCK | PCATCH, "netio", sb->sb_timeo)); } @@ -338,7 +348,7 @@ sbunlock(struct sockbuf *sb) void sowakeup(struct socket *so, struct sockbuf *sb) { - NET_ASSERT_LOCKED(); + SOCKET_ASSERT_LOCKED(so); selwakeup(&sb->sb_sel); sb->sb_flagsintr &= ~SB_SEL; Index: kern/uipc_syscalls.c =================================================================== RCS file: /cvs/src/sys/kern/uipc_syscalls.c,v retrieving revision 1.148 diff -u -p -r1.148 uipc_syscalls.c --- kern/uipc_syscalls.c 26 Jan 2017 01:58:00 -0000 1.148 +++ kern/uipc_syscalls.c 9 Feb 2017 11:21:45 -0000 @@ -289,9 +289,9 @@ doaccept(struct proc *p, int sock, struc } nam = m_get(M_WAIT, MT_SONAME); - - NET_LOCK(s); + head = headfp->f_data; + SOCKET_LOCK(head, s); if (isdnssocket(head) || (head->so_options & SO_ACCEPTCONN) == 0) { error = EINVAL; goto out; @@ -308,8 +308,8 @@ doaccept(struct proc *p, int sock, struc head->so_error = ECONNABORTED; break; } - error = rwsleep(&head->so_timeo, &netlock, PSOCK | PCATCH, - "netcon", 0); + error = sosleep(head, &head->so_timeo, PSOCK | PCATCH, "netcon", + 0); if (error) goto out; } @@ -346,7 +346,7 @@ doaccept(struct proc *p, int sock, struc *retval = tmpfd; } out: - NET_UNLOCK(s); + SOCKET_UNLOCK(s); m_freem(nam); if (error) { fdplock(fdp); @@ -410,9 +410,9 @@ sys_connect(struct proc *p, void *v, reg m_freem(nam); return (EINPROGRESS); } - NET_LOCK(s); + SOCKET_LOCK(so, s); while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) { - error = rwsleep(&so->so_timeo, &netlock, PSOCK | PCATCH, + error = sosleep(so, &so->so_timeo, PSOCK | PCATCH, "netcon2", 0); if (error) { if (error == EINTR || error == ERESTART) @@ -424,7 +424,7 @@ sys_connect(struct proc *p, void *v, reg error = so->so_error; so->so_error = 0; } - NET_UNLOCK(s); + SOCKET_UNLOCK(s); bad: if (!interrupted) so->so_state &= ~SS_ISCONNECTING; @@ -1051,9 +1051,9 @@ sys_getsockname(struct proc *p, void *v, if (error) goto bad; m = m_getclr(M_WAIT, MT_SONAME); - NET_LOCK(s); + SOCKET_LOCK(so, s); error = (*so->so_proto->pr_usrreq)(so, PRU_SOCKADDR, 0, m, 0, p); - NET_UNLOCK(s); + SOCKET_UNLOCK(s); if (error) goto bad; error = copyaddrout(p, m, SCARG(uap, asa), len, SCARG(uap, alen)); @@ -1094,9 +1094,9 @@ sys_getpeername(struct proc *p, void *v, if (error) goto bad; m = m_getclr(M_WAIT, MT_SONAME); - NET_LOCK(s); + SOCKET_LOCK(so, s); error = (*so->so_proto->pr_usrreq)(so, PRU_PEERADDR, 0, m, 0, p); - NET_UNLOCK(s); + SOCKET_UNLOCK(s); if (error) goto bad; error = copyaddrout(p, m, SCARG(uap, asa), len, SCARG(uap, alen)); Index: kern/uipc_usrreq.c =================================================================== RCS file: /cvs/src/sys/kern/uipc_usrreq.c,v retrieving revision 1.115 diff -u -p -r1.115 uipc_usrreq.c --- kern/uipc_usrreq.c 9 Feb 2017 11:18:55 -0000 1.115 +++ kern/uipc_usrreq.c 9 Feb 2017 11:21:46 -0000 @@ -121,6 +121,9 @@ uipc_usrreq(struct socket *so, int req, error = EINVAL; goto release; } + + NET_ASSERT_UNLOCKED(); + switch (req) { case PRU_ATTACH: @@ -132,17 +135,12 @@ uipc_usrreq(struct socket *so, int req, break; case PRU_DETACH: - /* XXXSMP breaks atomicity */ - rw_exit_write(&netlock); unp_detach(unp); - rw_enter_write(&netlock); break; case PRU_BIND: - /* XXXSMP breaks atomicity */ - rw_exit_write(&netlock); + NET_ASSERT_UNLOCKED(); error = unp_bind(unp, nam, p); - rw_enter_write(&netlock); break; case PRU_LISTEN: @@ -151,10 +149,7 @@ uipc_usrreq(struct socket *so, int req, break; case PRU_CONNECT: - /* XXXSMP breaks atomicity */ - rw_exit_write(&netlock); error = unp_connect(so, nam, p); - rw_enter_write(&netlock); break; case PRU_CONNECT2: @@ -222,10 +217,7 @@ uipc_usrreq(struct socket *so, int req, error = EISCONN; break; } - /* XXXSMP breaks atomicity */ - rw_exit_write(&netlock); error = unp_connect(so, nam, p); - rw_enter_write(&netlock); if (error) break; } else { @@ -397,9 +389,7 @@ void unp_detach(struct unpcb *unp) { struct vnode *vp; - - NET_ASSERT_UNLOCKED(); - + LIST_REMOVE(unp, unp_link); if (unp->unp_vnode) { unp->unp_vnode->v_socket = NULL; @@ -411,10 +401,7 @@ unp_detach(struct unpcb *unp) unp_disconnect(unp); while (!SLIST_EMPTY(&unp->unp_refs)) unp_drop(SLIST_FIRST(&unp->unp_refs), ECONNRESET); - /* XXXSMP The assert is wrong */ - rw_enter_write(&netlock); soisdisconnected(unp->unp_socket); - rw_exit_write(&netlock); unp->unp_socket->so_pcb = NULL; m_freem(unp->unp_addr); free(unp, M_PCB, sizeof *unp); @@ -539,7 +526,7 @@ unp_connect(struct socket *so, struct mb error = EPROTOTYPE; goto bad; } - NET_LOCK(s); + SOCKET_LOCK(so, s); if (so->so_proto->pr_flags & PR_CONNREQUIRED) { if ((so2->so_options & SO_ACCEPTCONN) == 0 || (so3 = sonewconn(so2, 0)) == 0) { @@ -564,7 +551,7 @@ unp_connect(struct socket *so, struct mb } error = unp_connect2(so, so2); unlock: - NET_UNLOCK(s); + SOCKET_UNLOCK(s); bad: vput(vp); return (error); Index: sys/socketvar.h =================================================================== RCS file: /cvs/src/sys/sys/socketvar.h,v retrieving revision 1.67 diff -u -p -r1.67 socketvar.h --- sys/socketvar.h 19 Dec 2016 08:36:50 -0000 1.67 +++ sys/socketvar.h 9 Feb 2017 11:21:46 -0000 @@ -278,7 +278,7 @@ void sbrelease(struct sockbuf *sb); int sbcheckreserve(u_long cnt, u_long defcnt); int sbchecklowmem(void); int sbreserve(struct sockbuf *sb, u_long cc); -int sbwait(struct sockbuf *sb); +int sbwait(struct socket *, struct sockbuf *sb); int sb_lock(struct sockbuf *sb); void soinit(void); int soabort(struct socket *so); @@ -313,6 +313,7 @@ int sosend(struct socket *so, struct mbu int sosetopt(struct socket *so, int level, int optname, struct mbuf *m0); int soshutdown(struct socket *so, int how); +int sosleep(struct socket *, void *, int, const char *, int); void sowakeup(struct socket *so, struct sockbuf *sb); void sorwakeup(struct socket *); void sowwakeup(struct socket *); Index: sys/systm.h =================================================================== RCS file: /cvs/src/sys/sys/systm.h,v retrieving revision 1.123 diff -u -p -r1.123 systm.h --- sys/systm.h 25 Jan 2017 06:15:50 -0000 1.123 +++ sys/systm.h 9 Feb 2017 11:21:46 -0000 @@ -301,7 +301,7 @@ do { \ s = splsoftnet(); \ } while (0) -#define NET_UNLOCK(s) \ +#define NET_UNLOCK(s) \ do { \ splx(s); \ rw_exit_write(&netlock); \ @@ -318,6 +318,27 @@ do { \ do { \ if (rw_status(&netlock) == RW_WRITE) \ splassert_fail(0, rw_status(&netlock), __func__); \ +} while (0) + + +#define SOCKET_LOCK(so, s) \ +do { \ + if (so->so_proto->pr_domain->dom_family != PF_LOCAL) \ + NET_LOCK(s); \ + else \ + s = -42; \ +} while (0) + +#define SOCKET_UNLOCK(s) \ +do { \ + if (s != -42) \ + NET_UNLOCK(s); \ +} while (0) + +#define SOCKET_ASSERT_LOCKED(so) \ +do { \ + if (so->so_proto->pr_domain->dom_family != PF_LOCAL) \ + NET_ASSERT_LOCKED(); \ } while (0) __returns_twice int setjmp(label_t *);