git: a2408c4e976a - stable/14 - nfsd: Fix accumulating nfslockfile structures

From: Rick Macklem <rmacklem_at_FreeBSD.org>
Date: Wed, 18 Jun 2025 20:12:41 UTC
The branch stable/14 has been updated by rmacklem:

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

commit a2408c4e976a9499358e40cc326cb1ce4bd6de7a
Author:     Rick Macklem <rmacklem@FreeBSD.org>
AuthorDate: 2025-06-04 23:09:01 +0000
Commit:     Rick Macklem <rmacklem@FreeBSD.org>
CommitDate: 2025-06-18 20:09:54 +0000

    nfsd: Fix accumulating nfslockfile structures
    
    If a NFSv4 client does an exclusive open where the file
    already exists, the server returns EEXIST.  However,
    without this patch, a partially filled in nfslockfile
    structure is allocated, but is not referenced by any open
    and, as such, never gets freed.
    
    This patch fixes the bug by checking for EEXIST before
    calling nfsvno_open().
    
    (cherry picked from commit 1749465947a807caa53ce09b90a30b820eaab62e)
---
 sys/fs/nfsserver/nfs_nfsdserv.c | 28 ++++++++++++++++------------
 1 file changed, 16 insertions(+), 12 deletions(-)

diff --git a/sys/fs/nfsserver/nfs_nfsdserv.c b/sys/fs/nfsserver/nfs_nfsdserv.c
index a38ef3d47946..7ac5b61b0ae9 100644
--- a/sys/fs/nfsserver/nfs_nfsdserv.c
+++ b/sys/fs/nfsserver/nfs_nfsdserv.c
@@ -2829,7 +2829,7 @@ nfsrvd_open(struct nfsrv_descript *nd, __unused int isdgram,
 	int how = NFSCREATE_UNCHECKED;
 	int32_t cverf[2], tverf[2] = { 0, 0 };
 	vnode_t vp = NULL, dirp = NULL;
-	struct nfsvattr nva, dirfor, diraft;
+	struct nfsvattr nva, dirfor, diraft, nva2;
 	struct nameidata named;
 	nfsv4stateid_t stateid, delegstateid;
 	nfsattrbit_t attrbits;
@@ -3076,11 +3076,23 @@ nfsrvd_open(struct nfsrv_descript *nd, __unused int isdgram,
 			}
 			break;
 		    case NFSCREATE_EXCLUSIVE:
-			exclusive_flag = 1;
 			if (nd->nd_repstat == 0 && named.ni_vp == NULL)
 				nva.na_mode = 0;
-			break;
+			/* FALLTHROUGH */
 		    case NFSCREATE_EXCLUSIVE41:
+			if (nd->nd_repstat == 0 && named.ni_vp != NULL) {
+				nd->nd_repstat = nfsvno_getattr(named.ni_vp,
+				    &nva2, nd, p, 1, NULL);
+				if (nd->nd_repstat == 0) {
+					tverf[0] = nva2.na_atime.tv_sec;
+					tverf[1] = nva2.na_atime.tv_nsec;
+					if (cverf[0] != tverf[0] ||
+					     cverf[1] != tverf[1]))
+						nd->nd_repstat = EEXIST;
+				}
+				if (nd->nd_repstat != 0)
+					done_namei = true;
+			}
 			exclusive_flag = 1;
 			break;
 		    }
@@ -3170,16 +3182,8 @@ nfsrvd_open(struct nfsrv_descript *nd, __unused int isdgram,
 		    NFSACCCHK_VPISLOCKED, NULL);
 	}
 
-	if (!nd->nd_repstat) {
+	if (!nd->nd_repstat)
 		nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
-		if (!nd->nd_repstat) {
-			tverf[0] = nva.na_atime.tv_sec;
-			tverf[1] = nva.na_atime.tv_nsec;
-		}
-	}
-	if (!nd->nd_repstat && exclusive_flag && (cverf[0] != tverf[0] ||
-	    cverf[1] != tverf[1]))
-		nd->nd_repstat = EEXIST;
 	/*
 	 * Do the open locking/delegation stuff.
 	 */