summaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
Diffstat (limited to 'fs')
-rw-r--r--fs/nfs/nfs4xdr.c100
1 files changed, 100 insertions, 0 deletions
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
index 8204926bb467..6f1c003ee33a 100644
--- a/fs/nfs/nfs4xdr.c
+++ b/fs/nfs/nfs4xdr.c
@@ -365,6 +365,13 @@ static int nfs_stat_to_errno(int);
encode_delegreturn_maxsz)
#define NFS4_dec_delegreturn_sz (compound_decode_hdr_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 {
unsigned int mode;
@@ -1632,6 +1639,34 @@ out:
}
/*
+ * 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
*/
static int nfs4_xdr_enc_write(struct rpc_rqst *req, uint32_t *p, struct nfs_writeargs *args)
@@ -3125,6 +3160,47 @@ static int decode_renew(struct xdr_stream *xdr)
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
decode_savefh(struct xdr_stream *xdr)
{
@@ -3418,6 +3494,29 @@ out:
/*
+ * 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
*/
static int nfs4_xdr_dec_close(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_closeres *res)
@@ -4017,6 +4116,7 @@ struct rpc_procinfo nfs4_procedures[] = {
PROC(READDIR, enc_readdir, dec_readdir),
PROC(SERVER_CAPS, enc_server_caps, dec_server_caps),
PROC(DELEGRETURN, enc_delegreturn, dec_delegreturn),
+ PROC(GETACL, enc_getacl, dec_getacl),
};
struct rpc_version nfs_version4 = {
OpenPOWER on IntegriCloud