git: 315167c0de1a - main - unix: provide an option to return locked from unp_connectat()
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Fri, 24 Jun 2022 16:10:34 UTC
The branch main has been updated by glebius: URL: https://cgit.FreeBSD.org/src/commit/?id=315167c0de1a066614a936aa2c8954acb1a909eb commit 315167c0de1a066614a936aa2c8954acb1a909eb Author: Gleb Smirnoff <glebius@FreeBSD.org> AuthorDate: 2022-06-24 16:09:10 +0000 Commit: Gleb Smirnoff <glebius@FreeBSD.org> CommitDate: 2022-06-24 16:09:10 +0000 unix: provide an option to return locked from unp_connectat() Use this new version in unix/dgram socket when sending to a target address. This removes extra lock release/acquisition and possible counter-intuitive ENOTCONN. Reviewed by: markj Differential revision: https://reviews.freebsd.org/D35298 --- sys/kern/uipc_usrreq.c | 48 +++++++++++++++++++++++++++--------------------- 1 file changed, 27 insertions(+), 21 deletions(-) diff --git a/sys/kern/uipc_usrreq.c b/sys/kern/uipc_usrreq.c index 2872e28aef3a..594cc35af57d 100644 --- a/sys/kern/uipc_usrreq.c +++ b/sys/kern/uipc_usrreq.c @@ -292,7 +292,7 @@ static int uipc_ctloutput(struct socket *, struct sockopt *); static int unp_connect(struct socket *, struct sockaddr *, struct thread *); static int unp_connectat(int, struct socket *, struct sockaddr *, - struct thread *); + struct thread *, bool); static void unp_connect2(struct socket *so, struct socket *so2, int); static void unp_disconnect(struct unpcb *unp, struct unpcb *unp2); static void unp_dispose(struct socket *so); @@ -721,7 +721,7 @@ uipc_connectat(int fd, struct socket *so, struct sockaddr *nam, int error; KASSERT(td == curthread, ("uipc_connectat: td != curthread")); - error = unp_connectat(fd, so, nam, td); + error = unp_connectat(fd, so, nam, td, false); return (error); } @@ -1212,22 +1212,20 @@ uipc_sosend_dgram(struct socket *so, struct sockaddr *addr, struct uio *uio, } SOCKBUF_UNLOCK(&so->so_snd); - if (addr != NULL && (error = unp_connect(so, addr, td))) - goto out3; - - UNP_PCB_LOCK(unp); - /* - * Because connect() and send() are non-atomic in a sendto() with a - * target address, it's possible that the socket will have disconnected - * before the send() can run. In that case return the slightly - * counter-intuitive but otherwise correct error that the socket is not - * connected. - */ - unp2 = unp_pcb_lock_peer(unp); - if (unp2 == NULL) { - UNP_PCB_UNLOCK(unp); - error = ENOTCONN; - goto out3; + if (addr != NULL) { + if ((error = unp_connectat(AT_FDCWD, so, addr, td, true))) + goto out3; + UNP_PCB_LOCK_ASSERT(unp); + unp2 = unp->unp_conn; + UNP_PCB_LOCK_ASSERT(unp2); + } else { + UNP_PCB_LOCK(unp); + unp2 = unp_pcb_lock_peer(unp); + if (unp2 == NULL) { + UNP_PCB_UNLOCK(unp); + error = ENOTCONN; + goto out3; + } } if (unp2->unp_flags & UNP_WANTCRED_MASK) @@ -1828,12 +1826,12 @@ static int unp_connect(struct socket *so, struct sockaddr *nam, struct thread *td) { - return (unp_connectat(AT_FDCWD, so, nam, td)); + return (unp_connectat(AT_FDCWD, so, nam, td, false)); } static int unp_connectat(int fd, struct socket *so, struct sockaddr *nam, - struct thread *td) + struct thread *td, bool return_locked) { struct mtx *vplock; struct sockaddr_un *soun; @@ -1983,11 +1981,19 @@ unp_connectat(int fd, struct socket *so, struct sockaddr *nam, KASSERT((unp->unp_flags & UNP_CONNECTING) != 0, ("%s: unp %p has UNP_CONNECTING clear", __func__, unp)); unp->unp_flags &= ~UNP_CONNECTING; - unp_pcb_unlock_pair(unp, unp2); + if (!return_locked) + unp_pcb_unlock_pair(unp, unp2); bad2: mtx_unlock(vplock); bad: if (vp != NULL) { + /* + * If we are returning locked (called via uipc_sosend_dgram()), + * we need to be sure that vput() won't sleep. This is + * guaranteed by VOP_UNP_CONNECT() call above and unp2 lock. + * SOCK_STREAM/SEQPACKET can't request return_locked (yet). + */ + MPASS(!(return_locked && connreq)); vput(vp); } free(sa, M_SONAME);