struct nfsd_attrs attrs = {
                .na_iattr       = &argp->attrs,
        };
+       const struct timespec64 *guardtime = NULL;
 
        dprintk("nfsd: SETATTR(3)  %s\n",
                                SVCFH_fmt(&argp->fh));
 
        fh_copy(&resp->fh, &argp->fh);
-       resp->status = nfsd_setattr(rqstp, &resp->fh, &attrs,
-                                   argp->check_guard, argp->guardtime);
+       if (argp->check_guard)
+               guardtime = &argp->guardtime;
+       resp->status = nfsd_setattr(rqstp, &resp->fh, &attrs, guardtime);
        return rpc_success;
 }
 
 
 static bool
 svcxdr_decode_sattrguard3(struct xdr_stream *xdr, struct nfsd3_sattrargs *args)
 {
-       __be32 *p;
        u32 check;
 
        if (xdr_stream_decode_bool(xdr, &check) < 0)
                return false;
        if (check) {
-               p = xdr_inline_decode(xdr, XDR_UNIT * 2);
-               if (!p)
+               if (!svcxdr_decode_nfstime3(xdr, &args->guardtime))
                        return false;
                args->check_guard = 1;
-               args->guardtime = be32_to_cpup(p);
        } else
                args->check_guard = 0;
 
 
                goto out;
        save_no_wcc = cstate->current_fh.fh_no_wcc;
        cstate->current_fh.fh_no_wcc = true;
-       status = nfsd_setattr(rqstp, &cstate->current_fh, &attrs,
-                               0, (time64_t)0);
+       status = nfsd_setattr(rqstp, &cstate->current_fh, &attrs, NULL);
        cstate->current_fh.fh_no_wcc = save_no_wcc;
        if (!status)
                status = nfserrno(attrs.na_labelerr);
 
                return 0;
        if (!(open->op_share_access & NFS4_SHARE_ACCESS_WRITE))
                return nfserr_inval;
-       return nfsd_setattr(rqstp, fh, &attrs, 0, (time64_t)0);
+       return nfsd_setattr(rqstp, fh, &attrs, NULL);
 }
 
 static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file *fp,
 
                }
        }
 
-       resp->status = nfsd_setattr(rqstp, fhp, &attrs, 0, (time64_t)0);
+       resp->status = nfsd_setattr(rqstp, fhp, &attrs, NULL);
        if (resp->status != nfs_ok)
                goto out;
 
                 */
                attr->ia_valid &= ATTR_SIZE;
                if (attr->ia_valid)
-                       resp->status = nfsd_setattr(rqstp, newfhp, &attrs, 0,
-                                                   (time64_t)0);
+                       resp->status = nfsd_setattr(rqstp, newfhp, &attrs,
+                                                   NULL);
        }
 
 out_unlock:
 
  * @rqstp: controlling RPC transaction
  * @fhp: filehandle of target
  * @attr: attributes to set
- * @check_guard: set to 1 if guardtime is a valid timestamp
  * @guardtime: do not act if ctime.tv_sec does not match this timestamp
  *
  * This call may adjust the contents of @attr (in particular, this
  */
 __be32
 nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp,
-            struct nfsd_attrs *attr,
-            int check_guard, time64_t guardtime)
+            struct nfsd_attrs *attr, const struct timespec64 *guardtime)
 {
        struct dentry   *dentry;
        struct inode    *inode;
 
        nfsd_sanitize_attrs(inode, iap);
 
-       if (check_guard && guardtime != inode_get_ctime_sec(inode))
-               return nfserr_notsync;
-
        /*
         * The size case is special, it changes the file in addition to the
         * attributes, and file systems don't expect it to be mixed with
        err = fh_fill_pre_attrs(fhp);
        if (err)
                goto out_unlock;
+
+       if (guardtime) {
+               struct timespec64 ctime = inode_get_ctime(inode);
+               if ((u32)guardtime->tv_sec != (u32)ctime.tv_sec ||
+                   guardtime->tv_nsec != ctime.tv_nsec) {
+                       err = nfserr_notsync;
+                       goto out_fill_attrs;
+               }
+       }
+
        for (retries = 1;;) {
                struct iattr attrs;
 
                attr->na_aclerr = set_posix_acl(&nop_mnt_idmap,
                                                dentry, ACL_TYPE_DEFAULT,
                                                attr->na_dpacl);
+out_fill_attrs:
        fh_fill_post_attrs(fhp);
 out_unlock:
        inode_unlock(inode);
         * if the attributes have not changed.
         */
        if (iap->ia_valid)
-               status = nfsd_setattr(rqstp, resfhp, attrs, 0, (time64_t)0);
+               status = nfsd_setattr(rqstp, resfhp, attrs, NULL);
        else
                status = nfserrno(commit_metadata(resfhp));
 
 
                                const char *, unsigned int,
                                struct svc_export **, struct dentry **);
 __be32         nfsd_setattr(struct svc_rqst *, struct svc_fh *,
-                               struct nfsd_attrs *, int, time64_t);
+                            struct nfsd_attrs *, const struct timespec64 *);
 int nfsd_mountpoint(struct dentry *, struct svc_export *);
 #ifdef CONFIG_NFSD_V4
 __be32         nfsd4_vfs_fallocate(struct svc_rqst *, struct svc_fh *,
 
        struct svc_fh           fh;
        struct iattr            attrs;
        int                     check_guard;
-       time64_t                guardtime;
+       struct timespec64       guardtime;
 };
 
 struct nfsd3_diropargs {