git: 2c01d10f67b3 - main - unix: factor unp_vnode_peer() out of unp_connectat()

Mark Johnston <[email protected]>
Newsgroups gmane.os.freebsd.devel.cvs.src
Message-ID <6a7a0d12.40b32.14ac1239__43015.9738565393$1786383774$gmane$org@gitrepo.freebsd.org>
The branch main has been updated by markj:

URL: https://cgit.FreeBSD.org/src/commit/?id=2c01d10f67b343254fd4e747f822a8cdcc326f9d

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

    unix: factor unp_vnode_peer() out of unp_connectat()
    
    Move the "resolve a locked vnode to the referenced peer socket it names"
    block into a helper.  Pure code motion: the caller now calls
    `unp_vnode_peer()` and keeps the `vput()`/connect/`sorele()` sequence.
    
    No functional change intended.
    
    Note: This refactor isn't really necessary as `unp_vnode_peer()` will
    only be called once throughout this entire patch series. I am just
    including it out of my personal preferences for decomposing tasks into
    smaller functions --- we can skip this patch if the reviewers don't like
    this.
    
    Signed-off-by: John Ericson <[email protected]>
    Assisted-by: Claude Code (Claude Opus 4.8 and Fable 5)
    
    Reviewed by:    markj
    MFC after:      2 weeks
    Differential Revision:  https://reviews.freebsd.org/D58461
---
 sys/kern/uipc_usrreq.c | 85 ++++++++++++++++++++++++++++++--------------------
 1 file changed, 51 insertions(+), 34 deletions(-)

diff --git a/sys/kern/uipc_usrreq.c b/sys/kern/uipc_usrreq.c
index ac8de59b57b2..418c43a8ac85 100644
--- a/sys/kern/uipc_usrreq.c
+++ b/sys/kern/uipc_usrreq.c
@@ -296,6 +296,8 @@ static int	unp_connectat(int, struct socket *, struct sockaddr *,
 		    struct thread *, struct socket **);
 static int	unp_connect_peer(struct socket *, struct unpcb *,
 		    struct sockaddr **, struct thread *, bool);
+static int	unp_vnode_peer(struct vnode *, struct thread *,
+		    struct socket **);
 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);
@@ -2930,10 +2932,8 @@ static int
 unp_connectat(int fd, struct socket *so, struct sockaddr *nam,
     struct thread *td, struct socket **referenced_peerp)
 {
-	struct mtx *vplock;
 	struct socket *so2;
-	struct vnode *vp;
-	struct unpcb *unp, *unp2;
+	struct unpcb *unp;
 	struct nameidata nd;
 	char buf[SOCK_MAXADDRLEN];
 	struct sockaddr *sa;
@@ -3001,40 +3001,15 @@ unp_connectat(int fd, struct socket *so, struct sockaddr *nam,
 	if (error)
 		goto out;
 	NDFREE_PNBUF(&nd);
-	vp = nd.ni_vp;
-	ASSERT_VOP_LOCKED(vp, "unp_connect");
 
 	/*
-	 * Resolve the vnode to a referenced peer socket, then drop the vnode
-	 * before connecting.  Holding a reference on the peer keeps it stable
-	 * in place of the per-vnode unp_vp_mtxpool lock, so no vnode lock is
-	 * held across unp_connect_peer() -- which is what the return_locked
-	 * datagram fast path needs, since vput() must not sleep while the peer
-	 * is locked.
+	 * Resolve the vnode to a referenced peer socket and drop the vnode
+	 * before connecting: the reference keeps the peer stable, so no vnode
+	 * lock is held across unp_connect_peer() (which matters for the
+	 * return_locked datagram fast path).
 	 */
-	if (vp->v_type != VSOCK) {
-		error = ENOTSOCK;
-		goto drop_vp;
-	}
-#ifdef MAC
-	error = mac_vnode_check_open(td->td_ucred, vp, VWRITE | VREAD);
-	if (error)
-		goto drop_vp;
-#endif
-	error = VOP_ACCESS(vp, VWRITE, td->td_ucred, td);
-	if (error)
-		goto drop_vp;
-
-	vplock = mtx_pool_find(unp_vp_mtxpool, vp);
-	mtx_lock(vplock);
-	VOP_UNP_CONNECT(vp, &unp2);
-	if (unp2 == NULL)
-		error = ECONNREFUSED;
-	else
-		soref(so2 = unp2->unp_socket);
-	mtx_unlock(vplock);
-drop_vp:
-	vput(vp);
+	error = unp_vnode_peer(nd.ni_vp, td, &so2);
+	vput(nd.ni_vp);
 	if (error != 0)
 		goto out;
 	error = unp_connect_peer(so, sotounpcb(so2), &sa, td,
@@ -3056,6 +3031,48 @@ out:
 	return (error);
 }
 
+/*
+ * Resolve locked vnode 'vp' to the unix-domain socket it names and return a
+ * referenced peer socket in '*so2p'.  As the connect(2)-time resolution, this
+ * enforces the caller's authorization to reach the socket -- filesystem
+ * permission (VOP_ACCESS) and MAC (mac_vnode_check_open) -- which bare readers
+ * of the vnode->pcb binding, such as vfs_unp_reclaim(), deliberately skip.
+ *
+ * The returned reference keeps the peer stable for unp_connect_peer() once vp's
+ * per-vnode binding lock is dropped, so the caller must release it with
+ * sorele().  Does not consume 'vp'.
+ */
+static int
+unp_vnode_peer(struct vnode *vp, struct thread *td, struct socket **so2p)
+{
+	struct mtx *vplock;
+	struct unpcb *unp2;
+	int error;
+
+	ASSERT_VOP_LOCKED(vp, __func__);
+
+	if (vp->v_type != VSOCK)
+		return (ENOTSOCK);
+#ifdef MAC
+	error = mac_vnode_check_open(td->td_ucred, vp, VWRITE | VREAD);
+	if (error != 0)
+		return (error);
+#endif
+	error = VOP_ACCESS(vp, VWRITE, td->td_ucred, td);
+	if (error != 0)
+		return (error);
+
+	vplock = mtx_pool_find(unp_vp_mtxpool, vp);
+	mtx_lock(vplock);
+	VOP_UNP_CONNECT(vp, &unp2);
+	if (unp2 == NULL)
+		error = ECONNREFUSED;
+	else
+		soref(*so2p = unp2->unp_socket);
+	mtx_unlock(vplock);
+	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
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.