diff options
-rw-r--r-- | fs/nfs/nfs4xdr.c | 100 | ||||
-rw-r--r-- | include/linux/nfs4.h | 1 | ||||
-rw-r--r-- | include/linux/nfs_xdr.h | 7 |
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 | ||
369 | static struct { | 376 | static 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 | */ | ||
1644 | static int | ||
1645 | nfs4_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); | ||
1665 | out: | ||
1666 | return status; | ||
1667 | } | ||
1668 | |||
1669 | /* | ||
1635 | * Encode a WRITE request | 1670 | * Encode a WRITE request |
1636 | */ | 1671 | */ |
1637 | static int nfs4_xdr_enc_write(struct rpc_rqst *req, uint32_t *p, struct nfs_writeargs *args) | 1672 | 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) | |||
3125 | return decode_op_hdr(xdr, OP_RENEW); | 3160 | return decode_op_hdr(xdr, OP_RENEW); |
3126 | } | 3161 | } |
3127 | 3162 | ||
3163 | static 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 | |||
3200 | out: | ||
3201 | return status; | ||
3202 | } | ||
3203 | |||
3128 | static int | 3204 | static int |
3129 | decode_savefh(struct xdr_stream *xdr) | 3205 | decode_savefh(struct xdr_stream *xdr) |
3130 | { | 3206 | { |
@@ -3418,6 +3494,29 @@ out: | |||
3418 | 3494 | ||
3419 | 3495 | ||
3420 | /* | 3496 | /* |
3497 | * Decode GETACL response | ||
3498 | */ | ||
3499 | static int | ||
3500 | nfs4_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 | |||
3515 | out: | ||
3516 | return status; | ||
3517 | } | ||
3518 | |||
3519 | /* | ||
3421 | * Decode CLOSE response | 3520 | * Decode CLOSE response |
3422 | */ | 3521 | */ |
3423 | static int nfs4_xdr_dec_close(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_closeres *res) | 3522 | 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[] = { | |||
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 | ||
4022 | struct rpc_version nfs_version4 = { | 4122 | struct 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 | ||
329 | struct nfs_getaclargs { | ||
330 | struct nfs_fh * fh; | ||
331 | size_t acl_len; | ||
332 | unsigned int acl_pgbase; | ||
333 | struct page ** acl_pages; | ||
334 | }; | ||
335 | |||
329 | struct nfs_setattrres { | 336 | struct nfs_setattrres { |
330 | struct nfs_fattr * fattr; | 337 | struct nfs_fattr * fattr; |
331 | const struct nfs_server * server; | 338 | const struct nfs_server * server; |