]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
nfsd: handle delegated timestamps in SETATTR
authorJeff Layton <jlayton@kernel.org>
Mon, 9 Dec 2024 21:14:01 +0000 (16:14 -0500)
committerChuck Lever <chuck.lever@oracle.com>
Tue, 21 Jan 2025 20:30:01 +0000 (15:30 -0500)
Allow SETATTR to handle delegated timestamps. This patch assumes that
only the delegation holder has the ability to set the timestamps in this
way, so we allow this only if the SETATTR stateid refers to a
*_ATTRS_DELEG delegation.

Signed-off-by: Jeff Layton <jlayton@kernel.org>
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
fs/nfsd/nfs4proc.c
fs/nfsd/nfs4state.c
fs/nfsd/nfs4xdr.c
fs/nfsd/nfsd.h

index ad44ad49274f035707fa648d12011844b1c79a44..f6e06c779d09dacdcea81fb3b4135bf600f6cc63 100644 (file)
@@ -1135,18 +1135,43 @@ nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
                .na_iattr       = &setattr->sa_iattr,
                .na_seclabel    = &setattr->sa_label,
        };
+       bool save_no_wcc, deleg_attrs;
+       struct nfs4_stid *st = NULL;
        struct inode *inode;
        __be32 status = nfs_ok;
-       bool save_no_wcc;
        int err;
 
-       if (setattr->sa_iattr.ia_valid & ATTR_SIZE) {
+       deleg_attrs = setattr->sa_bmval[2] & (FATTR4_WORD2_TIME_DELEG_ACCESS |
+                                             FATTR4_WORD2_TIME_DELEG_MODIFY);
+
+       if (deleg_attrs || (setattr->sa_iattr.ia_valid & ATTR_SIZE)) {
+               int flags = WR_STATE;
+
+               if (setattr->sa_bmval[2] & FATTR4_WORD2_TIME_DELEG_ACCESS)
+                       flags |= RD_STATE;
+
                status = nfs4_preprocess_stateid_op(rqstp, cstate,
                                &cstate->current_fh, &setattr->sa_stateid,
-                               WR_STATE, NULL, NULL);
+                               flags, NULL, &st);
                if (status)
                        return status;
        }
+
+       if (deleg_attrs) {
+               status = nfserr_bad_stateid;
+               if (st->sc_type & SC_TYPE_DELEG) {
+                       struct nfs4_delegation *dp = delegstateid(st);
+
+                       /* Only for *_ATTRS_DELEG flavors */
+                       if (deleg_attrs_deleg(dp->dl_type))
+                               status = nfs_ok;
+               }
+       }
+       if (st)
+               nfs4_put_stid(st);
+       if (status)
+               return status;
+
        err = fh_want_write(&cstate->current_fh);
        if (err)
                return nfserrno(err);
index 5e1d30b917385975d9d7026cd23eeffb7ee0f416..ab19ac7b232912d495f2af212a0ba24eff8b7ecc 100644 (file)
@@ -5595,7 +5595,7 @@ retry:
 static inline __be32
 nfs4_check_delegmode(struct nfs4_delegation *dp, int flags)
 {
-       if ((flags & WR_STATE) && deleg_is_read(dp->dl_type))
+       if (!(flags & RD_STATE) && deleg_is_read(dp->dl_type))
                return nfserr_openmode;
        else
                return nfs_ok;
index 2c5c288064b00fc76d3505b4ddc7982c9ca18113..178325fcb6cbf6adbb79f9aa0de535b87a547a24 100644 (file)
@@ -521,6 +521,26 @@ nfsd4_decode_fattr4(struct nfsd4_compoundargs *argp, u32 *bmval, u32 bmlen,
                *umask = mask & S_IRWXUGO;
                iattr->ia_valid |= ATTR_MODE;
        }
+       if (bmval[2] & FATTR4_WORD2_TIME_DELEG_ACCESS) {
+               fattr4_time_deleg_access access;
+
+               if (!xdrgen_decode_fattr4_time_deleg_access(argp->xdr, &access))
+                       return nfserr_bad_xdr;
+               iattr->ia_atime.tv_sec = access.seconds;
+               iattr->ia_atime.tv_nsec = access.nseconds;
+               iattr->ia_valid |= ATTR_ATIME | ATTR_ATIME_SET | ATTR_DELEG;
+       }
+       if (bmval[2] & FATTR4_WORD2_TIME_DELEG_MODIFY) {
+               fattr4_time_deleg_modify modify;
+
+               if (!xdrgen_decode_fattr4_time_deleg_modify(argp->xdr, &modify))
+                       return nfserr_bad_xdr;
+               iattr->ia_mtime.tv_sec = modify.seconds;
+               iattr->ia_mtime.tv_nsec = modify.nseconds;
+               iattr->ia_ctime.tv_sec = modify.seconds;
+               iattr->ia_ctime.tv_nsec = modify.seconds;
+               iattr->ia_valid |= ATTR_CTIME | ATTR_MTIME | ATTR_MTIME_SET | ATTR_DELEG;
+       }
 
        /* request sanity: did attrlist4 contain the expected number of words? */
        if (attrlist4_count != xdr_stream_pos(argp->xdr) - starting_pos)
index 4c101c8be95f5855543b71a6e8fc3d7ee9511443..e2997f0ffbc537fcbd9e9da004ab0b6ad6164cbb 100644 (file)
@@ -528,7 +528,10 @@ static inline bool nfsd_attrs_supported(u32 minorversion, const u32 *bmval)
 #endif
 #define NFSD_WRITEABLE_ATTRS_WORD2 \
        (FATTR4_WORD2_MODE_UMASK \
-       | MAYBE_FATTR4_WORD2_SECURITY_LABEL)
+       | MAYBE_FATTR4_WORD2_SECURITY_LABEL \
+       | FATTR4_WORD2_TIME_DELEG_ACCESS \
+       | FATTR4_WORD2_TIME_DELEG_MODIFY \
+       )
 
 #define NFSD_SUPPATTR_EXCLCREAT_WORD0 \
        NFSD_WRITEABLE_ATTRS_WORD0