Commit 04b4c9fb authored by Anna Schumaker's avatar Anna Schumaker Committed by Trond Myklebust
Browse files

NFSv4.2: Clean up: move decode_*xattr() functions



Move them out of the encode_*() section and into the decode_*() section
where it belongs.

Signed-off-by: default avatarAnna Schumaker <Anna.Schumaker@Netapp.com>
Signed-off-by: default avatarTrond Myklebust <trond.myklebust@hammerspace.com>
parent fd42ba82
Loading
Loading
Loading
Loading
+162 −164
Original line number Diff line number Diff line
@@ -464,20 +464,6 @@ static void encode_setxattr(struct xdr_stream *xdr,
		xdr_write_pages(xdr, arg->xattr_pages, 0, arg->xattr_len);
}

static int decode_setxattr(struct xdr_stream *xdr,
			   struct nfs4_change_info *cinfo)
{
	int status;

	status = decode_op_hdr(xdr, OP_SETXATTR);
	if (status)
		goto out;
	status = decode_change_info(xdr, cinfo);
out:
	return status;
}


static void encode_getxattr(struct xdr_stream *xdr, const char *name,
			    struct compound_hdr *hdr)
{
@@ -485,43 +471,6 @@ static void encode_getxattr(struct xdr_stream *xdr, const char *name,
	encode_string(xdr, strlen(name), name);
}

static int decode_getxattr(struct xdr_stream *xdr,
			   struct nfs42_getxattrres *res,
			   struct rpc_rqst *req)
{
	int status;
	__be32 *p;
	u32 len, rdlen;

	status = decode_op_hdr(xdr, OP_GETXATTR);
	if (status)
		return status;

	p = xdr_inline_decode(xdr, 4);
	if (unlikely(!p))
		return -EIO;

	len = be32_to_cpup(p);

	/*
	 * Only check against the page length here. The actual
	 * requested length may be smaller, but that is only
	 * checked against after possibly caching a valid reply.
	 */
	if (len > req->rq_rcv_buf.page_len)
		return -ERANGE;

	res->xattr_len = len;

	if (len > 0) {
		rdlen = xdr_read_pages(xdr, len);
		if (rdlen < len)
			return -EIO;
	}

	return 0;
}

static void encode_removexattr(struct xdr_stream *xdr, const char *name,
			       struct compound_hdr *hdr)
{
@@ -529,21 +478,6 @@ static void encode_removexattr(struct xdr_stream *xdr, const char *name,
	encode_string(xdr, strlen(name), name);
}


static int decode_removexattr(struct xdr_stream *xdr,
			   struct nfs4_change_info *cinfo)
{
	int status;

	status = decode_op_hdr(xdr, OP_REMOVEXATTR);
	if (status)
		goto out;

	status = decode_change_info(xdr, cinfo);
out:
	return status;
}

static void encode_listxattrs(struct xdr_stream *xdr,
			     const struct nfs42_listxattrsargs *arg,
			     struct compound_hdr *hdr)
@@ -565,104 +499,6 @@ static void encode_listxattrs(struct xdr_stream *xdr,
	*p = cpu_to_be32(arg->count + 8 + 4);
}

static int decode_listxattrs(struct xdr_stream *xdr,
			    struct nfs42_listxattrsres *res)
{
	int status;
	__be32 *p;
	u32 count, len, ulen;
	size_t left, copied;
	char *buf;

	status = decode_op_hdr(xdr, OP_LISTXATTRS);
	if (status) {
		/*
		 * Special case: for LISTXATTRS, NFS4ERR_TOOSMALL
		 * should be translated to ERANGE.
		 */
		if (status == -ETOOSMALL)
			status = -ERANGE;
		/*
		 * Special case: for LISTXATTRS, NFS4ERR_NOXATTR
		 * should be translated to success with zero-length reply.
		 */
		if (status == -ENODATA) {
			res->eof = true;
			status = 0;
		}
		goto out;
	}

	p = xdr_inline_decode(xdr, 8);
	if (unlikely(!p))
		return -EIO;

	xdr_decode_hyper(p, &res->cookie);

	p = xdr_inline_decode(xdr, 4);
	if (unlikely(!p))
		return -EIO;

	left = res->xattr_len;
	buf = res->xattr_buf;

	count = be32_to_cpup(p);
	copied = 0;

	/*
	 * We have asked for enough room to encode the maximum number
	 * of possible attribute names, so everything should fit.
	 *
	 * But, don't rely on that assumption. Just decode entries
	 * until they don't fit anymore, just in case the server did
	 * something odd.
	 */
	while (count--) {
		p = xdr_inline_decode(xdr, 4);
		if (unlikely(!p))
			return -EIO;

		len = be32_to_cpup(p);
		if (len > (XATTR_NAME_MAX - XATTR_USER_PREFIX_LEN)) {
			status = -ERANGE;
			goto out;
		}

		p = xdr_inline_decode(xdr, len);
		if (unlikely(!p))
			return -EIO;

		ulen = len + XATTR_USER_PREFIX_LEN + 1;
		if (buf) {
			if (ulen > left) {
				status = -ERANGE;
				goto out;
			}

			memcpy(buf, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN);
			memcpy(buf + XATTR_USER_PREFIX_LEN, p, len);

			buf[ulen - 1] = 0;
			buf += ulen;
			left -= ulen;
		}
		copied += ulen;
	}

	p = xdr_inline_decode(xdr, 4);
	if (unlikely(!p))
		return -EIO;

	res->eof = be32_to_cpup(p);
	res->copied = copied;

out:
	if (status == -ERANGE && res->xattr_len == XATTR_LIST_MAX)
		status = -E2BIG;

	return status;
}

/*
 * Encode ALLOCATE request
 */
@@ -1192,6 +1028,168 @@ static int decode_layouterror(struct xdr_stream *xdr)
	return decode_op_hdr(xdr, OP_LAYOUTERROR);
}

static int decode_setxattr(struct xdr_stream *xdr,
			   struct nfs4_change_info *cinfo)
{
	int status;

	status = decode_op_hdr(xdr, OP_SETXATTR);
	if (status)
		goto out;
	status = decode_change_info(xdr, cinfo);
out:
	return status;
}

static int decode_getxattr(struct xdr_stream *xdr,
			   struct nfs42_getxattrres *res,
			   struct rpc_rqst *req)
{
	int status;
	__be32 *p;
	u32 len, rdlen;

	status = decode_op_hdr(xdr, OP_GETXATTR);
	if (status)
		return status;

	p = xdr_inline_decode(xdr, 4);
	if (unlikely(!p))
		return -EIO;

	len = be32_to_cpup(p);

	/*
	 * Only check against the page length here. The actual
	 * requested length may be smaller, but that is only
	 * checked against after possibly caching a valid reply.
	 */
	if (len > req->rq_rcv_buf.page_len)
		return -ERANGE;

	res->xattr_len = len;

	if (len > 0) {
		rdlen = xdr_read_pages(xdr, len);
		if (rdlen < len)
			return -EIO;
	}

	return 0;
}

static int decode_removexattr(struct xdr_stream *xdr,
			   struct nfs4_change_info *cinfo)
{
	int status;

	status = decode_op_hdr(xdr, OP_REMOVEXATTR);
	if (status)
		goto out;

	status = decode_change_info(xdr, cinfo);
out:
	return status;
}

static int decode_listxattrs(struct xdr_stream *xdr,
			    struct nfs42_listxattrsres *res)
{
	int status;
	__be32 *p;
	u32 count, len, ulen;
	size_t left, copied;
	char *buf;

	status = decode_op_hdr(xdr, OP_LISTXATTRS);
	if (status) {
		/*
		 * Special case: for LISTXATTRS, NFS4ERR_TOOSMALL
		 * should be translated to ERANGE.
		 */
		if (status == -ETOOSMALL)
			status = -ERANGE;
		/*
		 * Special case: for LISTXATTRS, NFS4ERR_NOXATTR
		 * should be translated to success with zero-length reply.
		 */
		if (status == -ENODATA) {
			res->eof = true;
			status = 0;
		}
		goto out;
	}

	p = xdr_inline_decode(xdr, 8);
	if (unlikely(!p))
		return -EIO;

	xdr_decode_hyper(p, &res->cookie);

	p = xdr_inline_decode(xdr, 4);
	if (unlikely(!p))
		return -EIO;

	left = res->xattr_len;
	buf = res->xattr_buf;

	count = be32_to_cpup(p);
	copied = 0;

	/*
	 * We have asked for enough room to encode the maximum number
	 * of possible attribute names, so everything should fit.
	 *
	 * But, don't rely on that assumption. Just decode entries
	 * until they don't fit anymore, just in case the server did
	 * something odd.
	 */
	while (count--) {
		p = xdr_inline_decode(xdr, 4);
		if (unlikely(!p))
			return -EIO;

		len = be32_to_cpup(p);
		if (len > (XATTR_NAME_MAX - XATTR_USER_PREFIX_LEN)) {
			status = -ERANGE;
			goto out;
		}

		p = xdr_inline_decode(xdr, len);
		if (unlikely(!p))
			return -EIO;

		ulen = len + XATTR_USER_PREFIX_LEN + 1;
		if (buf) {
			if (ulen > left) {
				status = -ERANGE;
				goto out;
			}

			memcpy(buf, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN);
			memcpy(buf + XATTR_USER_PREFIX_LEN, p, len);

			buf[ulen - 1] = 0;
			buf += ulen;
			left -= ulen;
		}
		copied += ulen;
	}

	p = xdr_inline_decode(xdr, 4);
	if (unlikely(!p))
		return -EIO;

	res->eof = be32_to_cpup(p);
	res->copied = copied;

out:
	if (status == -ERANGE && res->xattr_len == XATTR_LIST_MAX)
		status = -E2BIG;

	return status;
}

/*
 * Decode ALLOCATE request
 */