aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/nfs/nfs4xdr.c100
-rw-r--r--include/linux/nfs4.h1
-rw-r--r--include/linux/nfs_xdr.h7
3 files changed, 108 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);
365 encode_delegreturn_maxsz) 365 encode_delegreturn_maxsz)
366#define NFS4_dec_delegreturn_sz (compound_decode_hdr_maxsz + \ 366#define NFS4_dec_delegreturn_sz (compound_decode_hdr_maxsz + \
367 decode_delegreturn_maxsz) 367 decode_delegreturn_maxsz)
368#define NFS4_enc_getacl_sz (compound_encode_hdr_maxsz + \
369 encode_putfh_maxsz + \
370 encode_getattr_maxsz)
371#define NFS4_dec_getacl_sz (compound_decode_hdr_maxsz + \
372 decode_putfh_maxsz + \
373 op_decode_hdr_maxsz + \
374 nfs4_fattr_bitmap_maxsz + 1)
368 375
369static struct { 376static struct {
370 unsigned int mode; 377 unsigned int mode;
@@ -1632,6 +1639,34 @@ out:
1632} 1639}
1633 1640
1634/* 1641/*
1642 * Encode a GETACL request
1643 */
1644static int
1645nfs4_xdr_enc_getacl(struct rpc_rqst *req, uint32_t *p,
1646 struct nfs_getaclargs *args)
1647{
1648 struct xdr_stream xdr;
1649 struct rpc_auth *auth = req->rq_task->tk_auth;
1650 struct compound_hdr hdr = {
1651 .nops = 2,
1652 };
1653 int replen, status;
1654
1655 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1656 encode_compound_hdr(&xdr, &hdr);
1657 status = encode_putfh(&xdr, args->fh);
1658 if (status)
1659 goto out;
1660 status = encode_getattr_two(&xdr, FATTR4_WORD0_ACL, 0);
1661 /* set up reply buffer: */
1662 replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS4_dec_getacl_sz) << 2;
1663 xdr_inline_pages(&req->rq_rcv_buf, replen,
1664 args->acl_pages, args->acl_pgbase, args->acl_len);
1665out:
1666 return status;
1667}
1668
1669/*
1635 * Encode a WRITE request 1670 * Encode a WRITE request
1636 */ 1671 */
1637static int nfs4_xdr_enc_write(struct rpc_rqst *req, uint32_t *p, struct nfs_writeargs *args) 1672static 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)
3125 return decode_op_hdr(xdr, OP_RENEW); 3160 return decode_op_hdr(xdr, OP_RENEW);
3126} 3161}
3127 3162
3163static int decode_getacl(struct xdr_stream *xdr, struct rpc_rqst *req,
3164 size_t *acl_len)
3165{
3166 uint32_t *savep;
3167 uint32_t attrlen,
3168 bitmap[2] = {0};
3169 struct kvec *iov = req->rq_rcv_buf.head;
3170 int status;
3171
3172 *acl_len = 0;
3173 if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0)
3174 goto out;
3175 if ((status = decode_attr_bitmap(xdr, bitmap)) != 0)
3176 goto out;
3177 if ((status = decode_attr_length(xdr, &attrlen, &savep)) != 0)
3178 goto out;
3179
3180 if (unlikely(bitmap[0] & (FATTR4_WORD0_ACL - 1U)))
3181 return -EIO;
3182 if (likely(bitmap[0] & FATTR4_WORD0_ACL)) {
3183 int hdrlen, recvd;
3184
3185 /* We ignore &savep and don't do consistency checks on
3186 * the attr length. Let userspace figure it out.... */
3187 hdrlen = (u8 *)xdr->p - (u8 *)iov->iov_base;
3188 recvd = req->rq_rcv_buf.len - hdrlen;
3189 if (attrlen > recvd) {
3190 printk(KERN_WARNING "NFS: server cheating in getattr"
3191 " acl reply: attrlen %u > recvd %u\n",
3192 attrlen, recvd);
3193 return -EINVAL;
3194 }
3195 if (attrlen <= *acl_len)
3196 xdr_read_pages(xdr, attrlen);
3197 *acl_len = attrlen;
3198 }
3199
3200out:
3201 return status;
3202}
3203
3128static int 3204static int
3129decode_savefh(struct xdr_stream *xdr) 3205decode_savefh(struct xdr_stream *xdr)
3130{ 3206{
@@ -3418,6 +3494,29 @@ out:
3418 3494
3419 3495
3420/* 3496/*
3497 * Decode GETACL response
3498 */
3499static int
3500nfs4_xdr_dec_getacl(struct rpc_rqst *rqstp, uint32_t *p, size_t *acl_len)
3501{
3502 struct xdr_stream xdr;
3503 struct compound_hdr hdr;
3504 int status;
3505
3506 xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
3507 status = decode_compound_hdr(&xdr, &hdr);
3508 if (status)
3509 goto out;
3510 status = decode_putfh(&xdr);
3511 if (status)
3512 goto out;
3513 status = decode_getacl(&xdr, rqstp, acl_len);
3514
3515out:
3516 return status;
3517}
3518
3519/*
3421 * Decode CLOSE response 3520 * Decode CLOSE response
3422 */ 3521 */
3423static int nfs4_xdr_dec_close(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_closeres *res) 3522static 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[] = {
4017 PROC(READDIR, enc_readdir, dec_readdir), 4116 PROC(READDIR, enc_readdir, dec_readdir),
4018 PROC(SERVER_CAPS, enc_server_caps, dec_server_caps), 4117 PROC(SERVER_CAPS, enc_server_caps, dec_server_caps),
4019 PROC(DELEGRETURN, enc_delegreturn, dec_delegreturn), 4118 PROC(DELEGRETURN, enc_delegreturn, dec_delegreturn),
4119 PROC(GETACL, enc_getacl, dec_getacl),
4020}; 4120};
4021 4121
4022struct rpc_version nfs_version4 = { 4122struct rpc_version nfs_version4 = {
diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h
index 5ca8a8d8ccdf..6ee7e2585af5 100644
--- a/include/linux/nfs4.h
+++ b/include/linux/nfs4.h
@@ -382,6 +382,7 @@ enum {
382 NFSPROC4_CLNT_READDIR, 382 NFSPROC4_CLNT_READDIR,
383 NFSPROC4_CLNT_SERVER_CAPS, 383 NFSPROC4_CLNT_SERVER_CAPS,
384 NFSPROC4_CLNT_DELEGRETURN, 384 NFSPROC4_CLNT_DELEGRETURN,
385 NFSPROC4_CLNT_GETACL,
385}; 386};
386 387
387#endif 388#endif
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
index cf38db59f347..9f5e1d407c7b 100644
--- a/include/linux/nfs_xdr.h
+++ b/include/linux/nfs_xdr.h
@@ -326,6 +326,13 @@ struct nfs_setattrargs {
326 const u32 * bitmask; 326 const u32 * bitmask;
327}; 327};
328 328
329struct nfs_getaclargs {
330 struct nfs_fh * fh;
331 size_t acl_len;
332 unsigned int acl_pgbase;
333 struct page ** acl_pages;
334};
335
329struct nfs_setattrres { 336struct nfs_setattrres {
330 struct nfs_fattr * fattr; 337 struct nfs_fattr * fattr;
331 const struct nfs_server * server; 338 const struct nfs_server * server;