The branch main has been updated by glebius:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=315167c0de1a066614a936aa2c8954acb1a909eb

commit 315167c0de1a066614a936aa2c8954acb1a909eb
Author:     Gleb Smirnoff <[email protected]>
AuthorDate: 2022-06-24 16:09:10 +0000
Commit:     Gleb Smirnoff <[email protected]>
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);

Reply via email to