From nobody Mon Aug 10 17:40:33 2026 X-Original-To: dev-commits-src-main@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4hJhqQ4NmPz6X2kn for ; Mon, 10 Aug 2026 17:40:34 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "YR1" (not verified)) by mx1.freebsd.org (Postfix) with ESMTPS id 4hJhqP3zY6z48tb for ; Mon, 10 Aug 2026 17:40:33 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1786383633; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=NU+DtEdEwbbQLlAp9AJOO4y1i/kTa1EcPipUoX9g8O0=; b=K93cMv8yOczbRxCRHgyNq7CBSQmwB+Mam+gIUyFHLEJAgb6tAHCRASquOYf7j/oYF/5EAd vQK9A5d+l2uO46cNN2g+5VzgAaY6Ka41seEBHu2+X3EQPJYNbBKsmszWXQGO7/cdPXk43c f6OU2QYgFb8/QhRp/j26ZyytwMJTAgn2BETmTkI0jpSdgEOIv/jJ1DHIJlvK0psIlFyn00 AZnYtJLsr3WInjJYVT0RaOI3Yl5ogyZfBvHgnL/eBPdDe+nxoUctCU4y9SPiJYPRBbvLM9 UKJYwL8/UoCtGXd/HIHKxMvp1rELkcplqyvRFHdiQjwFaXeY9ufO7qrE2sprVg== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1786383633; a=rsa-sha256; cv=none; b=Z85XJPxs1kV3PW/lqL9/EPnBWN6NgfSMxdWK0dM94FLDy/JN1yHHfoDpL31aqIKnPyJy40 eab4t6F9OzjXSw9tdRr1VTWrPZc5sAN72WP0HSfG4CCocdrty0fKkyYi4YB/XbMz7S2WWH 1XLNd2JhORtY8i5KpumngCA9+kmN9xXHmL7RUjhBoYk4GR1+kEZmukBhFvn7qzMe9R/sO6 M0eSVek53q751/7s+BVqDHxySlb4EjP8w3o/TFyRCoIlJR80htMBUIdCF07B1K/ttZN9rk bafMphdCN2FSzuMtUefqBGz32hHtpVoMw4xIXfTX68cfPlbJ9Z/aUMlFNy3vdw== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1786383633; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=NU+DtEdEwbbQLlAp9AJOO4y1i/kTa1EcPipUoX9g8O0=; b=ExglTSxJGthbJH+YjLeeP29iSGtdAsLuWCb0cvaOp519EikwcwhUHY1iA9AXGfgvcaSC/+ i18PJ/M7w0EOrjXNbTkCbj7BMfTByB7T9WlumRXN76/xUhbuaN9PGvNO9huWscrK1qbUhw cj9Ergg5kI9yNqrsYE7r6K3NvsFzIcPIQPdaolKlCzUXXGs6W4g0JuJZ27jA36ghXHE0Fq U+A66rJT2o6wUXVEONcD955+1hh3zDo4c/V8Yjdd5xlJwXsNCedk1oJ+KrdOEND1uX2eLj 09t1BtZ/xIq1BRMoNQiZ0Gt8TAiyShsxZbLdm9aR01TnN2cy63MmV1DRemKSfQ== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) by mxrelay.nyi.freebsd.org (Postfix) with ESMTP id 4hJhqP2mNqz3qk for ; Mon, 10 Aug 2026 17:40:33 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from git (uid 1279) (envelope-from git@FreeBSD.org) id 40fca by gitrepo.freebsd.org (DragonFly Mail Agent v0.13+ on gitrepo.freebsd.org); Mon, 10 Aug 2026 17:40:33 +0000 To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org Cc: John Ericson From: Mark Johnston Subject: git: 26147c51546e - main - unix: pin the pathname peer by reference across the connect List-Id: Commit messages for the main branch of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-main List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-main@freebsd.org Sender: owner-dev-commits-src-main@FreeBSD.org List-Id: List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: markj X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: 26147c51546ecc98791db66fa4d948348bf4ec7b Auto-Submitted: auto-generated Date: Mon, 10 Aug 2026 17:40:33 +0000 Message-Id: <6a7a0d11.40fca.623b892@gitrepo.freebsd.org> The branch main has been updated by markj: URL: https://cgit.FreeBSD.org/src/commit/?id=26147c51546ecc98791db66fa4d948348bf4ec7b commit 26147c51546ecc98791db66fa4d948348bf4ec7b Author: John Ericson AuthorDate: 2026-08-10 15:04:23 +0000 Commit: Mark Johnston CommitDate: 2026-08-10 17:31:21 +0000 unix: pin the pathname peer by reference across the connect In the pathname path of `unp_connectat()`, take a reference on the peer socket under the per-vnode `unp_vp_mtxpool` lock, drop that lock, and `vput()` the vnode *before* calling `unp_connect_peer()`, rather than holding the vnode lock across the connect. `unp_connect_peer()` already accepts "a reference on the peer socket" as a stability guarantee (it is exactly what the descriptor path relies on), so this is behaviour-preserving. The payoff is that no vnode lock is held across the connect, which removes the delicate `MPASS(!(return_locked && connreq))` "vput() must not sleep while the peer is locked" invariant on the datagram fast path. That reference then has to be released, and for the reasons described in the code, this can only safely happen *after* the PCB is unlocked. The boolean flag is replaced with a nullable out pointer to return the reference to the caller so that it can carry out this responsibility. No functional change intended. Signed-off-by: John Ericson Assisted-by: Claude Code (Claude Opus 4.8 and Fable 5) Reviewed by: markj MFC after: 2 weeks Differential Revision: https://reviews.freebsd.org/D58460 --- sys/kern/uipc_usrreq.c | 84 +++++++++++++++++++++++++++++++++----------------- 1 file changed, 55 insertions(+), 29 deletions(-) diff --git a/sys/kern/uipc_usrreq.c b/sys/kern/uipc_usrreq.c index d198f8732a93..ac8de59b57b2 100644 --- a/sys/kern/uipc_usrreq.c +++ b/sys/kern/uipc_usrreq.c @@ -293,7 +293,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 *, bool); + struct thread *, struct socket **); static int unp_connect_peer(struct socket *, struct unpcb *, struct sockaddr **, struct thread *, bool); static void unp_connect2(struct socket *, struct socket *, bool); @@ -738,7 +738,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, false); + error = unp_connectat(fd, so, nam, td, NULL); return (error); } @@ -2000,7 +2000,7 @@ uipc_sosend_dgram(struct socket *so, struct sockaddr *addr, struct uio *uio, { struct unpcb *unp, *unp2; const struct sockaddr *from; - struct socket *so2; + struct socket *so2, *peer; struct sockbuf *sb; struct mchain cmc = MCHAIN_INITIALIZER(&cmc); struct mbuf *f; @@ -2082,7 +2082,7 @@ uipc_sosend_dgram(struct socket *so, struct sockaddr *addr, struct uio *uio, SOCK_SENDBUF_UNLOCK(so); if (addr != NULL) { - if ((error = unp_connectat(AT_FDCWD, so, addr, td, true))) + if ((error = unp_connectat(AT_FDCWD, so, addr, td, &peer))) goto out3; UNP_PCB_LOCK_ASSERT(unp); unp2 = unp->unp_conn; @@ -2198,9 +2198,10 @@ uipc_sosend_dgram(struct socket *so, struct sockaddr *addr, struct uio *uio, } out4: - if (addr != NULL) + if (addr != NULL) { unp_disconnect(unp, unp2); - else + sorele(peer); + } else unp_pcb_unlock_pair(unp, unp2); td->td_ru.ru_msgsnd++; @@ -2904,14 +2905,33 @@ static int unp_connect(struct socket *so, struct sockaddr *nam, struct thread *td) { - return (unp_connectat(AT_FDCWD, so, nam, td, false)); + return (unp_connectat(AT_FDCWD, so, nam, td, NULL)); } +/* + * Connect socket 'so' to the unix-domain peer named by 'nam', resolved + * relative to descriptor 'fd' (AT_FDCWD for connect(2)). + * + * 'referenced_peerp' selects how the peer is returned. If NULL, on exit the + * peer's PCB is unlocked and the peer is unreferenced, symmetrically releasing + * the resources acquired within the function. If non-NULL, the peer's PCB is + * returned locked and '*referenced_peerp' receives the referenced peer socket; + * the caller is then responsible for first unlocking the peer's PCB and + * afterwards releasing the socket. + * + * The reference is handed back rather than released in the return-unlocked + * case, because releasing the last one under the PCB lock could cause + * uipc_close() to try to re-acquire that lock. + * + * Note: the referenced_peerp mechanism is here only for the datagram fast-send + * path, which enqueues under the peer's PCB lock. + */ static int unp_connectat(int fd, struct socket *so, struct sockaddr *nam, - struct thread *td, bool return_locked) + struct thread *td, struct socket **referenced_peerp) { struct mtx *vplock; + struct socket *so2; struct vnode *vp; struct unpcb *unp, *unp2; struct nameidata nd; @@ -2979,26 +2999,31 @@ unp_connectat(int fd, struct socket *so, struct sockaddr *nam, cap_rights_init_one(&rights, CAP_CONNECTAT)); error = namei(&nd); if (error) - vp = NULL; - else - vp = nd.ni_vp; - ASSERT_VOP_LOCKED(vp, "unp_connect"); - if (error) - goto bad; + 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. + */ if (vp->v_type != VSOCK) { error = ENOTSOCK; - goto bad; + goto drop_vp; } #ifdef MAC error = mac_vnode_check_open(td->td_ucred, vp, VWRITE | VREAD); if (error) - goto bad; + goto drop_vp; #endif error = VOP_ACCESS(vp, VWRITE, td->td_ucred, td); if (error) - goto bad; + goto drop_vp; vplock = mtx_pool_find(unp_vp_mtxpool, vp); mtx_lock(vplock); @@ -3006,19 +3031,20 @@ unp_connectat(int fd, struct socket *so, struct sockaddr *nam, if (unp2 == NULL) error = ECONNREFUSED; else - error = unp_connect_peer(so, unp2, &sa, td, return_locked); + soref(so2 = unp2->unp_socket); 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); - } +drop_vp: + vput(vp); + if (error != 0) + goto out; + error = unp_connect_peer(so, sotounpcb(so2), &sa, td, + referenced_peerp != NULL); + /* Transfer the reference; the caller releases it after unlocking. */ + if (error == 0 && referenced_peerp != NULL) + *referenced_peerp = so2; + else + sorele(so2); +out: free(sa, M_SONAME); if (__predict_false(error)) { UNP_PCB_LOCK(unp);