The branch stable/13 has been updated by rmacklem:

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

commit 5971781ee78b0c5879c2696437b1f7629d140c30
Author:     Rick Macklem <rmack...@freebsd.org>
AuthorDate: 2022-10-18 22:47:07 +0000
Commit:     Rick Macklem <rmack...@freebsd.org>
CommitDate: 2022-11-16 20:09:33 +0000

    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.
    
    (cherry picked from commit ae7816576e44412a8ae9daa92c210a6ba4f269dc)
---
 sys/fs/nfsserver/nfs_nfsdport.c | 49 +++++++++++++++++++++++++++++++++++++++--
 1 file changed, 47 insertions(+), 2 deletions(-)

diff --git a/sys/fs/nfsserver/nfs_nfsdport.c b/sys/fs/nfsserver/nfs_nfsdport.c
index 258642bb1060..51c4d59e5380 100644
--- a/sys/fs/nfsserver/nfs_nfsdport.c
+++ b/sys/fs/nfsserver/nfs_nfsdport.c
@@ -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;
@@ -6568,8 +6569,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);
        }
 
@@ -6578,6 +6582,44 @@ out:
        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.
  */
@@ -6605,8 +6647,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);

Reply via email to