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