Commit 7e13f4f8 authored by Jeff Layton's avatar Jeff Layton Committed by Chuck Lever
Browse files

nfsd: handle delegated timestamps in SETATTR



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: default avatarJeff Layton <jlayton@kernel.org>
Signed-off-by: default avatarChuck Lever <chuck.lever@oracle.com>
parent 6ae30d6e
Loading
Loading
Loading
Loading
+28 −3
Original line number Diff line number Diff line
@@ -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);
+1 −1
Original line number Diff line number Diff line
@@ -5595,7 +5595,7 @@ nfsd4_process_open1(struct nfsd4_compound_state *cstate,
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;
+20 −0
Original line number Diff line number Diff line
@@ -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)
+4 −1
Original line number Diff line number Diff line
@@ -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