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().

Reported by:	Christoper Iler <ciler@volexity.com>
Tested by:	Christoper Iler <ciler@volexity.com>
MFC after:	2 weeks
This commit is contained in:
Rick Macklem 2025-06-04 16:09:01 -07:00
parent 6b6542ec84
commit 1749465947

View file

@ -2857,7 +2857,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;
@ -3107,11 +3107,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;
}
@ -3201,16 +3213,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.
*/