Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 029d105e authored by J. Bruce Fields's avatar J. Bruce Fields Committed by Trond Myklebust
Browse files

[PATCH] NFSv4: Client-side xdr for reading NFSv4 acls



 Client-side support for NFSv4 acls: xdr encoding and decoding routines for
 reading acls

 Signed-off-by: default avatarJ. Bruce Fields <bfields@citi.umich.edu>
 Signed-off-by: default avatarTrond Myklebust <Trond.Myklebust@netapp.com>
parent 96928206
Loading
Loading
Loading
Loading
+100 −0
Original line number Original line Diff line number Diff line
@@ -365,6 +365,13 @@ static int nfs_stat_to_errno(int);
				encode_delegreturn_maxsz)
				encode_delegreturn_maxsz)
#define NFS4_dec_delegreturn_sz (compound_decode_hdr_maxsz + \
#define NFS4_dec_delegreturn_sz (compound_decode_hdr_maxsz + \
				decode_delegreturn_maxsz)
				decode_delegreturn_maxsz)
#define NFS4_enc_getacl_sz	(compound_encode_hdr_maxsz + \
				encode_putfh_maxsz + \
				encode_getattr_maxsz)
#define NFS4_dec_getacl_sz	(compound_decode_hdr_maxsz + \
				decode_putfh_maxsz + \
				op_decode_hdr_maxsz + \
				nfs4_fattr_bitmap_maxsz + 1)


static struct {
static struct {
	unsigned int	mode;
	unsigned int	mode;
@@ -1631,6 +1638,34 @@ static int nfs4_xdr_enc_setattr(struct rpc_rqst *req, uint32_t *p, struct nfs_se
        return status;
        return status;
}
}


/*
 * Encode a GETACL request
 */
static int
nfs4_xdr_enc_getacl(struct rpc_rqst *req, uint32_t *p,
		struct nfs_getaclargs *args)
{
	struct xdr_stream xdr;
	struct rpc_auth *auth = req->rq_task->tk_auth;
	struct compound_hdr hdr = {
		.nops   = 2,
	};
	int replen, status;

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
	encode_compound_hdr(&xdr, &hdr);
	status = encode_putfh(&xdr, args->fh);
	if (status)
		goto out;
	status = encode_getattr_two(&xdr, FATTR4_WORD0_ACL, 0);
	/* set up reply buffer: */
	replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS4_dec_getacl_sz) << 2;
	xdr_inline_pages(&req->rq_rcv_buf, replen,
		args->acl_pages, args->acl_pgbase, args->acl_len);
out:
	return status;
}

/*
/*
 * Encode a WRITE request
 * Encode a WRITE request
 */
 */
@@ -3125,6 +3160,47 @@ static int decode_renew(struct xdr_stream *xdr)
	return decode_op_hdr(xdr, OP_RENEW);
	return decode_op_hdr(xdr, OP_RENEW);
}
}


static int decode_getacl(struct xdr_stream *xdr, struct rpc_rqst *req,
		size_t *acl_len)
{
	uint32_t *savep;
	uint32_t attrlen,
		 bitmap[2] = {0};
	struct kvec *iov = req->rq_rcv_buf.head;
	int status;

	*acl_len = 0;
	if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0)
		goto out;
	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)) {
		int hdrlen, recvd;

		/* 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;
		recvd = req->rq_rcv_buf.len - hdrlen;
		if (attrlen > recvd) {
			printk(KERN_WARNING "NFS: server cheating in getattr"
					" acl reply: attrlen %u > recvd %u\n",
					attrlen, recvd);
			return -EINVAL;
		}
		if (attrlen <= *acl_len)
			xdr_read_pages(xdr, attrlen);
		*acl_len = attrlen;
	}

out:
	return status;
}

static int
static int
decode_savefh(struct xdr_stream *xdr)
decode_savefh(struct xdr_stream *xdr)
{
{
@@ -3417,6 +3493,29 @@ static int nfs4_xdr_dec_getattr(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4
}
}




/*
 * Decode GETACL response
 */
static int
nfs4_xdr_dec_getacl(struct rpc_rqst *rqstp, uint32_t *p, size_t *acl_len)
{
	struct xdr_stream xdr;
	struct compound_hdr hdr;
	int status;

	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
	status = decode_compound_hdr(&xdr, &hdr);
	if (status)
		goto out;
	status = decode_putfh(&xdr);
	if (status)
		goto out;
	status = decode_getacl(&xdr, rqstp, acl_len);

out:
	return status;
}

/*
/*
 * Decode CLOSE response
 * Decode CLOSE response
 */
 */
@@ -4017,6 +4116,7 @@ struct rpc_procinfo nfs4_procedures[] = {
  PROC(READDIR,		enc_readdir,	dec_readdir),
  PROC(READDIR,		enc_readdir,	dec_readdir),
  PROC(SERVER_CAPS,	enc_server_caps, dec_server_caps),
  PROC(SERVER_CAPS,	enc_server_caps, dec_server_caps),
  PROC(DELEGRETURN,	enc_delegreturn, dec_delegreturn),
  PROC(DELEGRETURN,	enc_delegreturn, dec_delegreturn),
  PROC(GETACL,		enc_getacl,	dec_getacl),
};
};


struct rpc_version		nfs_version4 = {
struct rpc_version		nfs_version4 = {
+1 −0
Original line number Original line Diff line number Diff line
@@ -382,6 +382,7 @@ enum {
	NFSPROC4_CLNT_READDIR,
	NFSPROC4_CLNT_READDIR,
	NFSPROC4_CLNT_SERVER_CAPS,
	NFSPROC4_CLNT_SERVER_CAPS,
	NFSPROC4_CLNT_DELEGRETURN,
	NFSPROC4_CLNT_DELEGRETURN,
	NFSPROC4_CLNT_GETACL,
};
};


#endif
#endif
+7 −0
Original line number Original line Diff line number Diff line
@@ -326,6 +326,13 @@ struct nfs_setattrargs {
	const u32 *			bitmask;
	const u32 *			bitmask;
};
};


struct nfs_getaclargs {
	struct nfs_fh *			fh;
	size_t				acl_len;
	unsigned int			acl_pgbase;
	struct page **			acl_pages;
};

struct nfs_setattrres {
struct nfs_setattrres {
	struct nfs_fattr *              fattr;
	struct nfs_fattr *              fattr;
	const struct nfs_server *	server;
	const struct nfs_server *	server;