From nobody Sat Jul 25 01:31:49 2026 X-Original-To: dev-commits-src-all@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 4h6S520kkHz6lcDc for ; Sat, 25 Jul 2026 01:31:50 +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 4h6S514n45z3MKC for ; Sat, 25 Jul 2026 01:31:49 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1784943109; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=MSvlscVn/jAI9aXahHPeXeBOV4i+ssbdmKAUY0y3qtY=; b=br2U9lER//47X5cxmYKBxuoPuROODzw8fJxIC0GGnXQS+lr6Fp86troto3EMrOpN88u/zE Dc8H51Q/aeT7OPJyCPmpPSVXQEo5xPPJIiTcObKUbF7T8T8GtCIRMn1EPCqUBYuICwbIUs RwMypY1BaXZQ8jY9lHqilWJSDuDXuaqRG06amrOASbCjtk5rFAa1Vm2GFNLeigffjYwKGS 5BUrRK2kvNP8ErkubQtyxXEAWlsfXpS2TVV2yfBexrg1vAWBjJwljjfCeuqenzMxprs3n0 bGGgNYRK6x3mPUJHPyKZ/2oB/oXF/GZDLiCy32JkhaZtXUaSBpOz3xmEKF0DKQ== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1784943109; a=rsa-sha256; cv=none; b=KemFTcycqqvK3eMjIf6d/oxdtXTJKoMqAiYsfqU1MIl1vidmPhwVyAfyt22EC43g5mK+OW 3WtW5xgIf3gsYk+2lEnkQtMErLOEuS/GVQpzIP/2wJWwJBlwBQ8ysF6f59DLFfNTK6e8Nv Ow1ENIvdA6tnJCcjmg6vbMvnJCbarWfpZiMKWwJjogwReomdEaJrHPkYUGff+3FoJcVDfU hDjqsiaF1t96wXM4QEt6GNSNNMYpw9I2XYGmGliKiPJegOk373OF+gn6Qt3O6hkk8lF/dq /Y6r2QMmPJT4EOFrpX52yoLHhKNk8zOdQj4ur9kQ9J2XpCR9X2U4tmr2mKfQWg== 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=1784943109; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=MSvlscVn/jAI9aXahHPeXeBOV4i+ssbdmKAUY0y3qtY=; b=Jsaul7ghgghKBdcjzLHzYdRzQSGIG5jdvixL2lLp/Nr/b5rF2qIg0F7tJPg7GyAuIMdcj/ YFtA4LlfSapMV6l+GMU2yyU+JiS94usrXfHUGMV7BxzPr5pbnf/kXUKJ0DVE+uXdWmQBFj CFQjefglP8CvgNJZfrwbKH2iLt3kMtuxgdYbbz0IH8B5uGd4ykLvnHNxKMm+tv9MwqPim/ Oywl40UMNA12GOd4hI4iny8gKBTJQxLNNuiOTEsa99TYIdgdKCry+V0sTVGnTftYhb3KD2 cXxCp9IEO6Q5x0mgOAhID+zytaMKtmAeJpUkSqr8foMFOMy2UjcCTMHehSZ06g== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) by mxrelay.nyi.freebsd.org (Postfix) with ESMTP id 4h6S513k5jz1hh for ; Sat, 25 Jul 2026 01:31:49 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from git (uid 1279) (envelope-from git@FreeBSD.org) id 34a87 by gitrepo.freebsd.org (DragonFly Mail Agent v0.13+ on gitrepo.freebsd.org); Sat, 25 Jul 2026 01:31:49 +0000 To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org From: Rick Macklem Subject: git: 5d5b759f4cb7 - stable/14 - nfsd: Garbage collect stray NFSv4 state List-Id: Commit messages for all branches of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-all List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-all@freebsd.org Sender: owner-dev-commits-src-all@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: rmacklem X-Git-Repository: src X-Git-Refname: refs/heads/stable/14 X-Git-Reftype: branch X-Git-Commit: 5d5b759f4cb76884c9c2455dadbc498e6edebe0c Auto-Submitted: auto-generated Date: Sat, 25 Jul 2026 01:31:49 +0000 Message-Id: <6a641205.34a87.73867ad6@gitrepo.freebsd.org> The branch stable/14 has been updated by rmacklem: URL: https://cgit.FreeBSD.org/src/commit/?id=5d5b759f4cb76884c9c2455dadbc498e6edebe0c commit 5d5b759f4cb76884c9c2455dadbc498e6edebe0c Author: Rick Macklem AuthorDate: 2026-07-11 15:49:12 +0000 Commit: Rick Macklem CommitDate: 2026-07-25 01:28:09 +0000 nfsd: Garbage collect stray NFSv4 state When a file is deleted on the NFS server by another client, any NFSv4 state related to that file is left stranded. This happens because the NFSv4 operations that free the state use a CFH, which is set by a PutFH operation. However, the PutFH fails with ESTALE because the file has been deleted. This patch adds a function called nfsrv_freestrandedstate() that frees all the NFSv4 state related to a file and calls this function when PutFH will be replying ESTALE. While here, a helper function was defined to handle free'ng of the nfslockfile structure and replaces the two places where nearly identical code does this. (cherry picked from commit c52bcd09c2a6736fe841fd72e3cfb74de5a35b03) --- sys/fs/nfsserver/nfs_nfsdstate.c | 89 +++++++++++++++++++++++++++++++++------- 1 file changed, 75 insertions(+), 14 deletions(-) diff --git a/sys/fs/nfsserver/nfs_nfsdstate.c b/sys/fs/nfsserver/nfs_nfsdstate.c index cb957698bce9..4446c830175c 100644 --- a/sys/fs/nfsserver/nfs_nfsdstate.c +++ b/sys/fs/nfsserver/nfs_nfsdstate.c @@ -247,6 +247,7 @@ static void nfsrv_issuedelegation(struct vnode *vp, struct nfsclient *clp, nfsv4stateid_t *delegstateidp); static void nfsrv_clientlock(bool mlocked); static void nfsrv_clientunlock(bool mlocked); +static void nfsrv_freelockifnotinuse(struct nfslockfile *lfp); /* * Lock the client structure, either with the mutex or the exclusive nfsd lock. @@ -1530,20 +1531,13 @@ nfsrv_freedeleglist(struct nfsstatehead *sthp) static void nfsrv_freedeleg(struct nfsstate *stp) { - struct nfslockfile *lfp; LIST_REMOVE(stp, ls_hash); LIST_REMOVE(stp, ls_list); LIST_REMOVE(stp, ls_file); if ((stp->ls_flags & NFSLCK_DELEGWRITE) != 0) nfsrv_writedelegcnt--; - lfp = stp->ls_lfp; - if (LIST_EMPTY(&lfp->lf_open) && - LIST_EMPTY(&lfp->lf_lock) && LIST_EMPTY(&lfp->lf_deleg) && - LIST_EMPTY(&lfp->lf_locallock) && LIST_EMPTY(&lfp->lf_rollback) && - lfp->lf_usecount == 0 && - nfsv4_testlock(&lfp->lf_locallock_lck) == 0) - nfsrv_freenfslockfile(lfp); + nfsrv_freelockifnotinuse(stp->ls_lfp); free(stp, M_NFSDSTATE); NFSD_VNET(nfsstatsv1_p)->srvdelegates--; nfsrv_openpluslock--; @@ -1625,12 +1619,7 @@ nfsrv_freeopen(struct nfsstate *stp, vnode_t vp, int cansleep, NFSPROC_T *p) * If there are locks associated with the open, the * nfslockfile structure can be freed via nfsrv_freelockowner(). */ - if (lfp != NULL && LIST_EMPTY(&lfp->lf_open) && - LIST_EMPTY(&lfp->lf_deleg) && LIST_EMPTY(&lfp->lf_lock) && - LIST_EMPTY(&lfp->lf_locallock) && LIST_EMPTY(&lfp->lf_rollback) && - lfp->lf_usecount == 0 && - nfsv4_testlock(&lfp->lf_locallock_lck) == 0) - nfsrv_freenfslockfile(lfp); + nfsrv_freelockifnotinuse(lfp); free(stp, M_NFSDSTATE); NFSD_VNET(nfsstatsv1_p)->srvopens--; nfsrv_openpluslock--; @@ -9022,3 +9011,75 @@ nfsrv_issuedelegation(struct vnode *vp, struct nfsclient *clp, nfsrv_delegatecnt++; } } + +/* + * Free the nfslockfile structure if not in use. + */ +static void +nfsrv_freelockifnotinuse(struct nfslockfile *lfp) +{ + + /* + * The nfslockfile is freed here if there are no locks + * associated with the open. + * If there are locks associated with the open, the + * nfslockfile structure can be freed via nfsrv_freelockowner(). + */ + if (lfp != NULL && LIST_EMPTY(&lfp->lf_open) && + LIST_EMPTY(&lfp->lf_deleg) && LIST_EMPTY(&lfp->lf_lock) && + LIST_EMPTY(&lfp->lf_locallock) && LIST_EMPTY(&lfp->lf_rollback) && + lfp->lf_usecount == 0 && + nfsv4_testlock(&lfp->lf_locallock_lck) == 0) + nfsrv_freenfslockfile(lfp); +} + +/* + * Free stranded open/lock/delegation/layouts. + * (These become stranded if the file has been deleted.) + */ +void +nfsrv_freestrandedstate(struct nfsrvfh *nfp) +{ + struct nfslockfile *lfp; + struct nfsstate *stp, *nstp; + struct nfslayouthash *lhyp; + struct nfslayout *lyp, *nlyp; + fhandle_t *fhp; + + if (nfp->nfsrvfh_len != NFSX_MYFH) + return; + fhp = (fhandle_t *)nfp->nfsrvfh_data; + NFSLOCKSTATE(); + if (nfsrv_getlockfile(0, NULL, &lfp, fhp, 0) < 0) { + NFSUNLOCKSTATE(); + return; + } + lfp->lf_usecount++; /* So nfsrv_freeopen() does not free it. */ + /* Note that nfsrv_freeopen() will also free the byte range locks. */ + LIST_FOREACH_SAFE(stp, &lfp->lf_open, ls_file, nstp) + nfsrv_freeopen(stp, NULL, 0, curthread); + + /* + * Normally, a delegation will have been recalled when the file is + * removed. However, get rid of any that have somehow been + * left stranded. + */ + LIST_FOREACH_SAFE(stp, &lfp->lf_deleg, ls_file, nstp) + nfsrv_freedeleg(stp); + + /* Get rid of the nfslockfile, if no longer in use. */ + lfp->lf_usecount--; + nfsrv_freelockifnotinuse(lfp); + NFSUNLOCKSTATE(); + + /* Free any layouts for the pNFS server case. */ + if (nfsrv_devidcnt == 0) + return; + lhyp = NFSLAYOUTHASH(fhp); + NFSLOCKLAYOUT(lhyp); + TAILQ_FOREACH_SAFE(lyp, &lhyp->list, lay_list, nlyp) { + if (NFSBCMP(&lyp->lay_fh, fhp, sizeof(*fhp)) == 0) + nfsrv_freelayout(&lhyp->list, lyp); + } + NFSUNLOCKLAYOUT(lhyp); +}