git: 2c01d10f67b3 - main - unix: factor unp_vnode_peer() out of unp_connectat()
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Mon, 10 Aug 2026 17:40:34 UTC
The branch main has been updated by markj:
URL: https://cgit.FreeBSD.org/src/commit/?id=2c01d10f67b343254fd4e747f822a8cdcc326f9d
commit 2c01d10f67b343254fd4e747f822a8cdcc326f9d
Author: John Ericson <John.Ericson@Obsidian.Systems>
AuthorDate: 2026-08-10 15:04:25 +0000
Commit: Mark Johnston <markj@FreeBSD.org>
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 <John.Ericson@Obsidian.Systems>
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