nfsd: Make the pNFS server update Change for Setxattr/Rmxattr

When the NFS server does the Setxattr or Rmxattr operation,
the Change attribute (va_filerev) needs to be updated.

Without this patch, that was not happening for the
pNFS server configuration.  This patch does a Setattr
against the DS file to make the Change attribute
change.

This bug was discovered during a recent IETF NFSv4 testing
event, where the Change attribute wasn't changed in the
operation reply.

MFC after:	1 month
This commit is contained in:
Rick Macklem 2022-10-18 15:47:07 -07:00
parent a4ee0edc4a
commit ae7816576e

View File

@ -101,6 +101,7 @@ struct callout nfsd_callout;
static int nfssvc_srvcall(struct thread *, struct nfssvc_args *,
struct ucred *);
static void nfsvno_updateds(struct vnode *, struct ucred *, struct thread *);
int nfsrv_enable_crossmntpt = 1;
static int nfs_commit_blks;
@ -6776,8 +6777,11 @@ nfsvno_setxattr(struct vnode *vp, char *name, int len, struct mbuf *m,
if (error == 0) {
error = VOP_SETEXTATTR(vp, EXTATTR_NAMESPACE_USER, name, uiop,
cred, p);
if (error == 0)
if (error == 0) {
if (vp->v_type == VREG && nfsrv_devidcnt != 0)
nfsvno_updateds(vp, cred, p);
error = VOP_FSYNC(vp, MNT_WAIT, p);
}
free(iv, M_TEMP);
}
@ -6786,6 +6790,44 @@ nfsvno_setxattr(struct vnode *vp, char *name, int len, struct mbuf *m,
return (error);
}
/*
* For a pNFS server, the DS file's ctime and
* va_filerev (TimeMetadata and Change) needs to
* be updated. This is a hack, but works by
* flipping the S_ISGID bit in va_mode and then
* flipping it back.
* It does result in two MDS->DS RPCs, but creating
* a custom RPC just to do this seems overkill, since
* Setxattr/Rmxattr will not be done that frequently.
* If it fails part way through, that is not too
* serious, since the DS file is never executed.
*/
static void
nfsvno_updateds(struct vnode *vp, struct ucred *cred, NFSPROC_T *p)
{
struct nfsvattr nva;
int ret;
u_short tmode;
ret = VOP_GETATTR(vp, &nva.na_vattr, cred);
if (ret == 0) {
tmode = nva.na_mode;
NFSVNO_ATTRINIT(&nva);
tmode ^= S_ISGID;
NFSVNO_SETATTRVAL(&nva, mode, tmode);
ret = nfsrv_proxyds(vp, 0, 0, cred, p,
NFSPROC_SETATTR, NULL, NULL, NULL, &nva,
NULL, NULL, 0, NULL);
if (ret == 0) {
tmode ^= S_ISGID;
NFSVNO_SETATTRVAL(&nva, mode, tmode);
ret = nfsrv_proxyds(vp, 0, 0, cred, p,
NFSPROC_SETATTR, NULL, NULL, NULL,
&nva, NULL, NULL, 0, NULL);
}
}
}
/*
* Remove Extended attribute vnode op.
*/
@ -6813,8 +6855,11 @@ nfsvno_rmxattr(struct nfsrv_descript *nd, struct vnode *vp, char *name,
if (error == EOPNOTSUPP)
error = VOP_SETEXTATTR(vp, EXTATTR_NAMESPACE_USER, name, NULL,
cred, p);
if (error == 0)
if (error == 0) {
if (vp->v_type == VREG && nfsrv_devidcnt != 0)
nfsvno_updateds(vp, cred, p);
error = VOP_FSYNC(vp, MNT_WAIT, p);
}
out:
NFSEXITCODE(error);
return (error);