git: 7977edb76560 - main - unix: split unp_connectat() in two

Mark Johnston <[email protected]>
Newsgroups gmane.os.freebsd.devel.cvs.src
Message-ID <6a7a0d0f.3f93f.49cb6403__21416.2405159854$1786383738$gmane$org@gitrepo.freebsd.org>
The branch main has been updated by markj:

URL: https://cgit.FreeBSD.org/src/commit/?id=7977edb7656082d90a539b85bd2a750b383602da

commit 7977edb7656082d90a539b85bd2a750b383602da
Author:     John Ericson <[email protected]>
AuthorDate: 2026-08-10 15:04:18 +0000
Commit:     Mark Johnston <[email protected]>
CommitDate: 2026-08-10 17:31:21 +0000

    unix: split unp_connectat() in two
    
    Factor the second half — connecting to an already-resolved peer PCB —
    out into a new `unp_connect_peer()`, leaving `unp_connectat()` with the
    connection state machine and pathname resolution.  No functional change.
    
    The helper's contract: the caller guarantees stability of the peer PCB
    (vnode lock plus `unp_vp_mtxpool` lock for peers found via
    `VOP_UNP_CONNECT()`), has set `UNP_CONNECTING` on the connecting socket,
    and clears it again on error; the helper clears it on success.
    
    This prepares for connecting to a peer named by something other than a
    pathname.
    
    Signed-off-by: John Ericson <[email protected]>
    
    Reviewed by:    markj
    MFC after:      2 weeks
    Differential Revision:  https://reviews.freebsd.org/D58404
---
 sys/kern/uipc_usrreq.c | 102 +++++++++++++++++++++++++++++--------------------
 1 file changed, 61 insertions(+), 41 deletions(-)

diff --git a/sys/kern/uipc_usrreq.c b/sys/kern/uipc_usrreq.c
index 0e3f0d13c12d..c1d00e66f614 100644
--- a/sys/kern/uipc_usrreq.c
+++ b/sys/kern/uipc_usrreq.c
@@ -294,6 +294,8 @@ static int	unp_connect(struct socket *, struct sockaddr *,
 		    struct thread *);
 static int	unp_connectat(int, struct socket *, struct sockaddr *,
 		    struct thread *, bool);
+static int	unp_connect_peer(struct socket *, struct unpcb *,
+		    struct sockaddr **, struct thread *, bool);
 static void	unp_connect2(struct socket *, struct socket *, bool);
 static void	unp_disconnect(struct unpcb *unp, struct unpcb *unp2);
 static void	unp_dispose(struct socket *so);
@@ -2889,8 +2891,7 @@ unp_connectat(int fd, struct socket *so, struct sockaddr *nam,
 	struct mtx *vplock;
 	struct sockaddr_un *soun;
 	struct vnode *vp;
-	struct socket *so2;
-	struct unpcb *unp, *unp2, *unp3;
+	struct unpcb *unp, *unp2;
 	struct nameidata nd;
 	char buf[SOCK_MAXADDRLEN];
 	struct sockaddr *sa;
@@ -2979,40 +2980,80 @@ unp_connectat(int fd, struct socket *so, struct sockaddr *nam,
 	if (error)
 		goto bad;
 
-	unp = sotounpcb(so);
-	KASSERT(unp != NULL, ("unp_connect: unp == NULL"));
-
 	vplock = mtx_pool_find(unp_vp_mtxpool, vp);
 	mtx_lock(vplock);
 	VOP_UNP_CONNECT(vp, &unp2);
-	if (unp2 == NULL) {
+	if (unp2 == NULL)
 		error = ECONNREFUSED;
-		goto bad2;
+	else
+		error = unp_connect_peer(so, unp2, &sa, td, return_locked);
+	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);
 	}
-	so2 = unp2->unp_socket;
-	if (so->so_type != so2->so_type) {
-		error = EPROTOTYPE;
-		goto bad2;
+	free(sa, M_SONAME);
+	if (__predict_false(error)) {
+		UNP_PCB_LOCK(unp);
+		KASSERT((unp->unp_flags & UNP_CONNECTING) != 0,
+		    ("%s: unp %p has UNP_CONNECTING clear", __func__, unp));
+		unp->unp_flags &= ~UNP_CONNECTING;
+		UNP_PCB_UNLOCK(unp);
 	}
+	return (error);
+}
+
+/*
+ * Second half of connecting a unix socket: 'so' is our connecting socket,
+ * with UNP_CONNECTING set, and 'unp2' is the PCB of the peer named by the
+ * caller, which must guarantee its stability (by holding a reference on the
+ * peer socket, or the vnode lock plus unp_vp_mtxpool lock for a peer found
+ * via VOP_UNP_CONNECT()).
+ *
+ * For connection-oriented sockets '*sap' points to a buffer to hold the
+ * listener's address; it is consumed (set to NULL) if used.  On success
+ * UNP_CONNECTING is cleared; on error the caller must clear it.
+ */
+static int
+unp_connect_peer(struct socket *so, struct unpcb *unp2, struct sockaddr **sap,
+    struct thread *td, bool return_locked)
+{
+	struct socket *so2;
+	struct unpcb *unp, *unp3;
+	int error;
+	bool connreq;
+
+	unp = sotounpcb(so);
+	KASSERT(unp != NULL, ("%s: unp == NULL", __func__));
+	connreq = (so->so_proto->pr_flags & PR_CONNREQUIRED) != 0;
+
+	so2 = unp2->unp_socket;
+	if (so->so_type != so2->so_type)
+		return (EPROTOTYPE);
 	if (connreq) {
 		if (SOLISTENING(so2))
 			so2 = solisten_clone(so2);
 		else
 			so2 = NULL;
-		if (so2 == NULL) {
-			error = ECONNREFUSED;
-			goto bad2;
-		}
+		if (so2 == NULL)
+			return (ECONNREFUSED);
 		if ((error = uipc_attach(so2, 0, NULL)) != 0) {
 			sodealloc(so2);
-			goto bad2;
+			return (error);
 		}
 		unp3 = sotounpcb(so2);
 		unp_pcb_lock_pair(unp2, unp3);
 		if (unp2->unp_addr != NULL) {
-			bcopy(unp2->unp_addr, sa, unp2->unp_addr->sun_len);
-			unp3->unp_addr = (struct sockaddr_un *) sa;
-			sa = NULL;
+			bcopy(unp2->unp_addr, *sap, unp2->unp_addr->sun_len);
+			unp3->unp_addr = (struct sockaddr_un *)*sap;
+			*sap = NULL;
 		}
 
 		unp_copy_peercred(td, unp3, unp, unp2);
@@ -3043,28 +3084,7 @@ unp_connectat(int fd, struct socket *so, struct sockaddr *nam,
 	unp->unp_flags &= ~UNP_CONNECTING;
 	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);
-	if (__predict_false(error)) {
-		UNP_PCB_LOCK(unp);
-		KASSERT((unp->unp_flags & UNP_CONNECTING) != 0,
-		    ("%s: unp %p has UNP_CONNECTING clear", __func__, unp));
-		unp->unp_flags &= ~UNP_CONNECTING;
-		UNP_PCB_UNLOCK(unp);
-	}
-	return (error);
+	return (0);
 }
 
 /*
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.