git: 4fc11c92d324 - main - nfsd: Fix handling of attributes during Open/Create/Exclusive_41
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Thu, 15 Jan 2026 23:30:47 UTC
The branch main has been updated by rmacklem:
URL: https://cgit.FreeBSD.org/src/commit/?id=4fc11c92d324c9099ecc28f25a96591a2ff6105c
commit 4fc11c92d324c9099ecc28f25a96591a2ff6105c
Author: Rick Macklem <rmacklem@FreeBSD.org>
AuthorDate: 2026-01-15 23:27:22 +0000
Commit: Rick Macklem <rmacklem@FreeBSD.org>
CommitDate: 2026-01-15 23:27:22 +0000
nfsd: Fix handling of attributes during Open/Create/Exclusive_41
When an NFSv4.n client specifies settings for attributes other
mode during a Open/Create/Exclusive_41, these other attributes
were not being set.
This patch resolves the problem by calling nfsrv_fixsattr()
after the VOP_CREATE() call in nfsvno_open() for this case.
There is no extant NFSv4.n client that currently does this,
as far as I know.
MFC after: 2 weeks
---
sys/fs/nfs/nfs.h | 5 +++++
sys/fs/nfs/nfs_var.h | 2 +-
sys/fs/nfs/nfsdport.h | 2 ++
sys/fs/nfsserver/nfs_nfsdport.c | 46 ++++++++++++++++++++++++++++++++++-------
sys/fs/nfsserver/nfs_nfsdserv.c | 13 +++++++-----
sys/fs/nfsserver/nfs_nfsdsubs.c | 6 +++---
6 files changed, 57 insertions(+), 17 deletions(-)
diff --git a/sys/fs/nfs/nfs.h b/sys/fs/nfs/nfs.h
index ecff9b8e6849..7903542be91d 100644
--- a/sys/fs/nfs/nfs.h
+++ b/sys/fs/nfs/nfs.h
@@ -872,6 +872,11 @@ typedef enum { UNKNOWN=0, DELETED=1, NLINK_ZERO=2, VALID=3 } nfsremove_status;
#define SUPPACL_NFSV4 1
#define SUPPACL_POSIX 2
+/* Values NFSv4 uses for exclusive_flag. */
+#define NFSV4_EXCLUSIVE_NONE 0
+#define NFSV4_EXCLUSIVE 1
+#define NFSV4_EXCLUSIVE_41 2
+
#endif /* _KERNEL */
#endif /* _NFS_NFS_H */
diff --git a/sys/fs/nfs/nfs_var.h b/sys/fs/nfs/nfs_var.h
index 0211acf7f00b..28088c12d7e7 100644
--- a/sys/fs/nfs/nfs_var.h
+++ b/sys/fs/nfs/nfs_var.h
@@ -410,7 +410,7 @@ int nfsv4_strtogid(struct nfsrv_descript *, u_char *, int, gid_t *);
int nfsrv_checkuidgid(struct nfsrv_descript *, struct nfsvattr *);
void nfsrv_fixattr(struct nfsrv_descript *, vnode_t,
struct nfsvattr *, NFSACL_T *, NFSACL_T *, NFSPROC_T *, nfsattrbit_t *,
- struct nfsexstuff *);
+ bool);
int nfsrv_errmoved(int);
int nfsrv_putreferralattr(struct nfsrv_descript *, nfsattrbit_t *,
struct nfsreferral *, int, int *);
diff --git a/sys/fs/nfs/nfsdport.h b/sys/fs/nfs/nfsdport.h
index c863741746c5..6439ef921d29 100644
--- a/sys/fs/nfs/nfsdport.h
+++ b/sys/fs/nfs/nfsdport.h
@@ -46,6 +46,8 @@
#define NFSVNO_ISSETATIME(n) ((n)->na_atime.tv_sec != VNOVAL)
#define NFSVNO_NOTSETMTIME(n) ((n)->na_mtime.tv_sec == VNOVAL)
#define NFSVNO_ISSETMTIME(n) ((n)->na_mtime.tv_sec != VNOVAL)
+#define NFSVNO_NOTSETFLAGS(n) ((n)->na_flags == VNOVAL)
+#define NFSVNO_ISSETFLAGS(n) ((n)->na_flags != VNOVAL)
/*
* This structure acts as a "catch-all" for information that
diff --git a/sys/fs/nfsserver/nfs_nfsdport.c b/sys/fs/nfsserver/nfs_nfsdport.c
index 1e215b52e835..833203cd86fc 100644
--- a/sys/fs/nfsserver/nfs_nfsdport.c
+++ b/sys/fs/nfsserver/nfs_nfsdport.c
@@ -1972,6 +1972,7 @@ nfsvno_open(struct nfsrv_descript *nd, struct nameidata *ndp,
NFSACL_T *aclp, NFSACL_T *daclp, nfsattrbit_t *attrbitp, struct ucred *cred,
bool done_namei, struct nfsexstuff *exp, struct vnode **vpp)
{
+ struct vattr va;
struct vnode *vp = NULL;
u_quad_t tempsize;
struct nfsexstuff nes;
@@ -2018,23 +2019,52 @@ nfsvno_open(struct nfsrv_descript *nd, struct nameidata *ndp,
&ndp->ni_vp : NULL, false);
nfsvno_relpathbuf(ndp);
if (!nd->nd_repstat) {
- if (*exclusive_flagp) {
- *exclusive_flagp = 0;
- NFSVNO_ATTRINIT(nvap);
- nvap->na_atime.tv_sec = cverf[0];
- nvap->na_atime.tv_nsec = cverf[1];
+ if (*exclusive_flagp != NFSV4_EXCLUSIVE_NONE) {
+ VATTR_NULL(&va);
+ va.va_atime.tv_sec = cverf[0];
+ va.va_atime.tv_nsec = cverf[1];
nd->nd_repstat = VOP_SETATTR(ndp->ni_vp,
- &nvap->na_vattr, cred);
+ &va, cred);
if (nd->nd_repstat != 0) {
vput(ndp->ni_vp);
ndp->ni_vp = NULL;
nd->nd_repstat = NFSERR_NOTSUPP;
- } else
+ } else {
+ /*
+ * Few clients set these
+ * attributes in Open/Create
+ * Exclusive_41. If this
+ * changes, this should include
+ * setting atime, instead of
+ * the above.
+ */
+ if (*exclusive_flagp ==
+ NFSV4_EXCLUSIVE_41 &&
+ (NFSISSET_ATTRBIT(attrbitp,
+ NFSATTRBIT_OWNER) ||
+ NFSISSET_ATTRBIT(attrbitp,
+ NFSATTRBIT_OWNERGROUP) ||
+ NFSISSET_ATTRBIT(attrbitp,
+ NFSATTRBIT_TIMEMODIFYSET)||
+ NFSISSET_ATTRBIT(attrbitp,
+ NFSATTRBIT_ARCHIVE) ||
+ NFSISSET_ATTRBIT(attrbitp,
+ NFSATTRBIT_HIDDEN) ||
+ NFSISSET_ATTRBIT(attrbitp,
+ NFSATTRBIT_SYSTEM) ||
+ aclp != NULL ||
+ daclp != NULL))
+ nfsrv_fixattr(nd,
+ ndp->ni_vp, nvap,
+ aclp, daclp, p,
+ attrbitp, true);
NFSSETBIT_ATTRBIT(attrbitp,
NFSATTRBIT_TIMEACCESS);
+ }
+ *exclusive_flagp = NFSV4_EXCLUSIVE_NONE;
} else {
nfsrv_fixattr(nd, ndp->ni_vp, nvap,
- aclp, daclp, p, attrbitp, exp);
+ aclp, daclp, p, attrbitp, false);
}
}
vp = ndp->ni_vp;
diff --git a/sys/fs/nfsserver/nfs_nfsdserv.c b/sys/fs/nfsserver/nfs_nfsdserv.c
index 3eb3471d9ac9..b5f5b9bec9fc 100644
--- a/sys/fs/nfsserver/nfs_nfsdserv.c
+++ b/sys/fs/nfsserver/nfs_nfsdserv.c
@@ -1608,7 +1608,7 @@ nfsrvd_mknod(struct nfsrv_descript *nd, __unused int isdgram,
nd->nd_repstat = nfsvno_mknod(&named, &nva, nd->nd_cred, p);
if (!nd->nd_repstat) {
vp = named.ni_vp;
- nfsrv_fixattr(nd, vp, &nva, aclp, daclp, p, &attrbits, exp);
+ nfsrv_fixattr(nd, vp, &nva, aclp, daclp, p, &attrbits, false);
nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
if ((nd->nd_flag & ND_NFSV3) && !nd->nd_repstat)
nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1,
@@ -2120,7 +2120,7 @@ nfsrvd_symlinksub(struct nfsrv_descript *nd, struct nameidata *ndp,
!(nd->nd_flag & ND_NFSV2), nd->nd_saveduid, nd->nd_cred, p, exp);
if (!nd->nd_repstat && !(nd->nd_flag & ND_NFSV2)) {
nfsrv_fixattr(nd, ndp->ni_vp, nvap, aclp, NULL, p, attrbitp,
- exp);
+ false);
if (nd->nd_flag & ND_NFSV3) {
nd->nd_repstat = nfsvno_getfh(ndp->ni_vp, fhp, p);
if (!nd->nd_repstat)
@@ -2255,7 +2255,7 @@ nfsrvd_mkdirsub(struct nfsrv_descript *nd, struct nameidata *ndp,
nd->nd_cred, p, exp);
if (!nd->nd_repstat) {
vp = ndp->ni_vp;
- nfsrv_fixattr(nd, vp, nvap, aclp, daclp, p, attrbitp, exp);
+ nfsrv_fixattr(nd, vp, nvap, aclp, daclp, p, attrbitp, false);
nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
if (!(nd->nd_flag & ND_NFSV4) && !nd->nd_repstat)
nd->nd_repstat = nfsvno_getattr(vp, nvap, nd, p, 1,
@@ -2964,7 +2964,8 @@ nfsrvd_open(struct nfsrv_descript *nd, __unused int isdgram,
u_int32_t *tl;
int i, retext;
struct nfsstate *stp = NULL;
- int error = 0, create, claim, exclusive_flag = 0, override;
+ int error = 0, create, claim, override;
+ int exclusive_flag = NFSV4_EXCLUSIVE_NONE;
u_int32_t rflags = NFSV4OPEN_LOCKTYPEPOSIX, acemask;
int how = NFSCREATE_UNCHECKED;
int32_t cverf[2], tverf[2] = { 0, 0 };
@@ -3229,6 +3230,7 @@ nfsrvd_open(struct nfsrv_descript *nd, __unused int isdgram,
case NFSCREATE_EXCLUSIVE:
if (nd->nd_repstat == 0 && named.ni_vp == NULL)
nva.na_mode = 0;
+ exclusive_flag = NFSV4_EXCLUSIVE;
/* FALLTHROUGH */
case NFSCREATE_EXCLUSIVE41:
if (nd->nd_repstat == 0 && named.ni_vp != NULL) {
@@ -3244,7 +3246,8 @@ nfsrvd_open(struct nfsrv_descript *nd, __unused int isdgram,
if (nd->nd_repstat != 0)
done_namei = true;
}
- exclusive_flag = 1;
+ if (how == NFSCREATE_EXCLUSIVE41)
+ exclusive_flag = NFSV4_EXCLUSIVE_41;
break;
}
}
diff --git a/sys/fs/nfsserver/nfs_nfsdsubs.c b/sys/fs/nfsserver/nfs_nfsdsubs.c
index c8c78d98be72..fdedf959f0e5 100644
--- a/sys/fs/nfsserver/nfs_nfsdsubs.c
+++ b/sys/fs/nfsserver/nfs_nfsdsubs.c
@@ -1645,7 +1645,7 @@ out:
void
nfsrv_fixattr(struct nfsrv_descript *nd, vnode_t vp,
struct nfsvattr *nvap, NFSACL_T *aclp, NFSACL_T *daclp, NFSPROC_T *p,
- nfsattrbit_t *attrbitp, struct nfsexstuff *exp)
+ nfsattrbit_t *attrbitp, bool atime_done)
{
int change = 0;
struct nfsvattr nva;
@@ -1675,7 +1675,7 @@ nfsrv_fixattr(struct nfsrv_descript *nd, vnode_t vp,
}
}
if (NFSISSET_ATTRBIT(attrbitp, NFSATTRBIT_TIMEACCESSSET) &&
- NFSVNO_ISSETATIME(nvap)) {
+ !atime_done && NFSVNO_ISSETATIME(nvap)) {
nva.na_atime = nvap->na_atime;
change++;
NFSSETBIT_ATTRBIT(&nattrbits, NFSATTRBIT_TIMEACCESSSET);
@@ -1736,7 +1736,7 @@ nfsrv_fixattr(struct nfsrv_descript *nd, vnode_t vp,
}
}
if (change) {
- error = nfsvno_setattr(vp, &nva, nd->nd_cred, p, exp);
+ error = nfsvno_setattr(vp, &nva, nd->nd_cred, p, NULL);
if (error) {
NFSCLRALL_ATTRBIT(attrbitp, &nattrbits);
}