static int decode_getacl(struct xdr_stream *xdr, struct rpc_rqst *req,
			 struct nfs_getaclres *res)
{
	__be32 *savep, *bm_p;
	uint32_t attrlen,
		 bitmap[3] = {0};
	struct kvec *iov = req->rq_rcv_buf.head;
	int status;

	res->acl_len = 0;
	if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0)
		goto out;
	bm_p = xdr->p;
	if ((status = decode_attr_bitmap(xdr, bitmap)) != 0)
		goto out;
	if ((status = decode_attr_length(xdr, &attrlen, &savep)) != 0)
		goto out;

	if (unlikely(bitmap[0] & (FATTR4_WORD0_ACL - 1U)))
		return -EIO;
	if (likely(bitmap[0] & FATTR4_WORD0_ACL)) {
		size_t hdrlen;
		u32 recvd;

		/* The bitmap (xdr len + bitmaps) and the attr xdr len words
		 * are stored with the acl data to handle the problem of
		 * variable length bitmaps.*/
		xdr->p = bm_p;
		res->acl_data_offset = be32_to_cpup(bm_p) + 2;
		res->acl_data_offset <<= 2;

		/* We ignore &savep and don't do consistency checks on
		 * the attr length.  Let userspace figure it out.... */
		hdrlen = (u8 *)xdr->p - (u8 *)iov->iov_base;
		attrlen += res->acl_data_offset;
		recvd = req->rq_rcv_buf.len - hdrlen;
		if (attrlen > recvd) {
			if (res->acl_flags & NFS4_ACL_LEN_REQUEST) {
				/* getxattr interface called with a NULL buf */
				res->acl_len = attrlen;
				goto out;
			}
			dprintk("NFS: acl reply: attrlen %u > recvd %u\n",
					attrlen, recvd);
			return -EINVAL;
		}
		xdr_read_pages(xdr, attrlen);
		res->acl_len = attrlen;
	} else
		status = -EOPNOTSUPP;

out:
	return status;
}
static int decode_getacl(struct xdr_stream *xdr, struct rpc_rqst *req,
			 struct nfs_getaclres *res)
{
	__be32 *savep, *bm_p;
	uint32_t attrlen,
		 bitmap[3] = {0};
	struct kvec *iov = req->rq_rcv_buf.head;
	int status;

	res->acl_len = 0;
	if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0)
		goto out;
	bm_p = xdr->p;
	if ((status = decode_attr_bitmap(xdr, bitmap)) != 0)
		goto out;
	if ((status = decode_attr_length(xdr, &attrlen, &savep)) != 0)
		goto out;

	if (unlikely(bitmap[0] & (FATTR4_WORD0_ACL - 1U)))
		return -EIO;
	if (likely(bitmap[0] & FATTR4_WORD0_ACL)) {
		size_t hdrlen;
		u32 recvd;

		 
		xdr->p = bm_p;
		res->acl_data_offset = be32_to_cpup(bm_p) + 2;
		res->acl_data_offset <<= 2;

		 
		hdrlen = (u8 *)xdr->p - (u8 *)iov->iov_base;
		attrlen += res->acl_data_offset;
		recvd = req->rq_rcv_buf.len - hdrlen;
		if (attrlen > recvd) {
			if (res->acl_flags & NFS4_ACL_LEN_REQUEST) {
				 
				res->acl_len = attrlen;
				goto out;
			}
			dprintk("NFS: acl reply: attrlen %u > recvd %u\n",
					attrlen, recvd);
			return -EINVAL;
		}
		xdr_read_pages(xdr, attrlen);
		res->acl_len = attrlen;
	} else
		status = -EOPNOTSUPP;

out:
	return status;
}