Commit c0aa1913 authored by Chuck Lever's avatar Chuck Lever
Browse files

NFSD: Refactor nfsd_setattr()



Move code that will be retried (in a subsequent patch) into a helper
function.

Signed-off-by: default avatarChuck Lever <chuck.lever@oracle.com>
Reviewed-by: default avatarJeff Layton <jlayton@kernel.org>
parent c035362e
Loading
Loading
Loading
Loading
+57 −40
Original line number Diff line number Diff line
@@ -343,8 +343,61 @@ nfsd_get_write_access(struct svc_rqst *rqstp, struct svc_fh *fhp,
	return nfserrno(get_write_access(inode));
}

static int __nfsd_setattr(struct dentry *dentry, struct iattr *iap)
{
	int host_err;

	if (iap->ia_valid & ATTR_SIZE) {
		/*
 * Set various file attributes.  After this call fhp needs an fh_put.
		 * RFC5661, Section 18.30.4:
		 *   Changing the size of a file with SETATTR indirectly
		 *   changes the time_modify and change attributes.
		 *
		 * (and similar for the older RFCs)
		 */
		struct iattr size_attr = {
			.ia_valid	= ATTR_SIZE | ATTR_CTIME | ATTR_MTIME,
			.ia_size	= iap->ia_size,
		};

		if (iap->ia_size < 0)
			return -EFBIG;

		host_err = notify_change(&init_user_ns, dentry, &size_attr, NULL);
		if (host_err)
			return host_err;
		iap->ia_valid &= ~ATTR_SIZE;

		/*
		 * Avoid the additional setattr call below if the only other
		 * attribute that the client sends is the mtime, as we update
		 * it as part of the size change above.
		 */
		if ((iap->ia_valid & ~ATTR_MTIME) == 0)
			return 0;
	}

	if (!iap->ia_valid)
		return 0;

	iap->ia_valid |= ATTR_CTIME;
	return notify_change(&init_user_ns, dentry, iap, NULL);
}

/**
 * nfsd_setattr - Set various file attributes.
 * @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
 * call may change the bits in the na_iattr.ia_valid field).
 *
 * Returns nfs_ok on success, otherwise an NFS status code is
 * returned. Caller must release @fhp by calling fh_put in either
 * case.
 */
__be32
nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp,
@@ -357,7 +410,7 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp,
	int		accmode = NFSD_MAY_SATTR;
	umode_t		ftype = 0;
	__be32		err;
	int		host_err = 0;
	int		host_err;
	bool		get_write_count;
	bool		size_change = (iap->ia_valid & ATTR_SIZE);

@@ -414,43 +467,7 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp,
	}

	inode_lock(inode);
	if (size_change) {
		/*
		 * RFC5661, Section 18.30.4:
		 *   Changing the size of a file with SETATTR indirectly
		 *   changes the time_modify and change attributes.
		 *
		 * (and similar for the older RFCs)
		 */
		struct iattr size_attr = {
			.ia_valid	= ATTR_SIZE | ATTR_CTIME | ATTR_MTIME,
			.ia_size	= iap->ia_size,
		};

		host_err = -EFBIG;
		if (iap->ia_size < 0)
			goto out_unlock;

		host_err = notify_change(&init_user_ns, dentry, &size_attr, NULL);
		if (host_err)
			goto out_unlock;
		iap->ia_valid &= ~ATTR_SIZE;

		/*
		 * Avoid the additional setattr call below if the only other
		 * attribute that the client sends is the mtime, as we update
		 * it as part of the size change above.
		 */
		if ((iap->ia_valid & ~ATTR_MTIME) == 0)
			goto out_unlock;
	}

	if (iap->ia_valid) {
		iap->ia_valid |= ATTR_CTIME;
		host_err = notify_change(&init_user_ns, dentry, iap, NULL);
	}

out_unlock:
	host_err = __nfsd_setattr(dentry, iap);
	if (attr->na_seclabel && attr->na_seclabel->len)
		attr->na_labelerr = security_inode_setsecctx(dentry,
			attr->na_seclabel->data, attr->na_seclabel->len);