aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs/callback_xdr.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/nfs/callback_xdr.c')
-rw-r--r--fs/nfs/callback_xdr.c137
1 files changed, 106 insertions, 31 deletions
diff --git a/fs/nfs/callback_xdr.c b/fs/nfs/callback_xdr.c
index 76b0aa0f73bf..05af212f0edf 100644
--- a/fs/nfs/callback_xdr.c
+++ b/fs/nfs/callback_xdr.c
@@ -9,6 +9,7 @@
9#include <linux/sunrpc/svc.h> 9#include <linux/sunrpc/svc.h>
10#include <linux/nfs4.h> 10#include <linux/nfs4.h>
11#include <linux/nfs_fs.h> 11#include <linux/nfs_fs.h>
12#include <linux/slab.h>
12#include "nfs4_fs.h" 13#include "nfs4_fs.h"
13#include "callback.h" 14#include "callback.h"
14 15
@@ -23,10 +24,15 @@
23#if defined(CONFIG_NFS_V4_1) 24#if defined(CONFIG_NFS_V4_1)
24#define CB_OP_SEQUENCE_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ + \ 25#define CB_OP_SEQUENCE_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ + \
25 4 + 1 + 3) 26 4 + 1 + 3)
27#define CB_OP_RECALLANY_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ)
28#define CB_OP_RECALLSLOT_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ)
26#endif /* CONFIG_NFS_V4_1 */ 29#endif /* CONFIG_NFS_V4_1 */
27 30
28#define NFSDBG_FACILITY NFSDBG_CALLBACK 31#define NFSDBG_FACILITY NFSDBG_CALLBACK
29 32
33/* Internal error code */
34#define NFS4ERR_RESOURCE_HDR 11050
35
30typedef __be32 (*callback_process_op_t)(void *, void *); 36typedef __be32 (*callback_process_op_t)(void *, void *);
31typedef __be32 (*callback_decode_arg_t)(struct svc_rqst *, struct xdr_stream *, void *); 37typedef __be32 (*callback_decode_arg_t)(struct svc_rqst *, struct xdr_stream *, void *);
32typedef __be32 (*callback_encode_res_t)(struct svc_rqst *, struct xdr_stream *, void *); 38typedef __be32 (*callback_encode_res_t)(struct svc_rqst *, struct xdr_stream *, void *);
@@ -172,7 +178,7 @@ static __be32 decode_op_hdr(struct xdr_stream *xdr, unsigned int *op)
172 __be32 *p; 178 __be32 *p;
173 p = read_buf(xdr, 4); 179 p = read_buf(xdr, 4);
174 if (unlikely(p == NULL)) 180 if (unlikely(p == NULL))
175 return htonl(NFS4ERR_RESOURCE); 181 return htonl(NFS4ERR_RESOURCE_HDR);
176 *op = ntohl(*p); 182 *op = ntohl(*p);
177 return 0; 183 return 0;
178} 184}
@@ -214,10 +220,10 @@ out:
214 220
215#if defined(CONFIG_NFS_V4_1) 221#if defined(CONFIG_NFS_V4_1)
216 222
217static unsigned decode_sessionid(struct xdr_stream *xdr, 223static __be32 decode_sessionid(struct xdr_stream *xdr,
218 struct nfs4_sessionid *sid) 224 struct nfs4_sessionid *sid)
219{ 225{
220 uint32_t *p; 226 __be32 *p;
221 int len = NFS4_MAX_SESSIONID_LEN; 227 int len = NFS4_MAX_SESSIONID_LEN;
222 228
223 p = read_buf(xdr, len); 229 p = read_buf(xdr, len);
@@ -228,12 +234,12 @@ static unsigned decode_sessionid(struct xdr_stream *xdr,
228 return 0; 234 return 0;
229} 235}
230 236
231static unsigned decode_rc_list(struct xdr_stream *xdr, 237static __be32 decode_rc_list(struct xdr_stream *xdr,
232 struct referring_call_list *rc_list) 238 struct referring_call_list *rc_list)
233{ 239{
234 uint32_t *p; 240 __be32 *p;
235 int i; 241 int i;
236 unsigned status; 242 __be32 status;
237 243
238 status = decode_sessionid(xdr, &rc_list->rcl_sessionid); 244 status = decode_sessionid(xdr, &rc_list->rcl_sessionid);
239 if (status) 245 if (status)
@@ -266,13 +272,13 @@ out:
266 return status; 272 return status;
267} 273}
268 274
269static unsigned decode_cb_sequence_args(struct svc_rqst *rqstp, 275static __be32 decode_cb_sequence_args(struct svc_rqst *rqstp,
270 struct xdr_stream *xdr, 276 struct xdr_stream *xdr,
271 struct cb_sequenceargs *args) 277 struct cb_sequenceargs *args)
272{ 278{
273 uint32_t *p; 279 __be32 *p;
274 int i; 280 int i;
275 unsigned status; 281 __be32 status;
276 282
277 status = decode_sessionid(xdr, &args->csa_sessionid); 283 status = decode_sessionid(xdr, &args->csa_sessionid);
278 if (status) 284 if (status)
@@ -326,6 +332,39 @@ out_free:
326 goto out; 332 goto out;
327} 333}
328 334
335static __be32 decode_recallany_args(struct svc_rqst *rqstp,
336 struct xdr_stream *xdr,
337 struct cb_recallanyargs *args)
338{
339 __be32 *p;
340
341 args->craa_addr = svc_addr(rqstp);
342 p = read_buf(xdr, 4);
343 if (unlikely(p == NULL))
344 return htonl(NFS4ERR_BADXDR);
345 args->craa_objs_to_keep = ntohl(*p++);
346 p = read_buf(xdr, 4);
347 if (unlikely(p == NULL))
348 return htonl(NFS4ERR_BADXDR);
349 args->craa_type_mask = ntohl(*p);
350
351 return 0;
352}
353
354static __be32 decode_recallslot_args(struct svc_rqst *rqstp,
355 struct xdr_stream *xdr,
356 struct cb_recallslotargs *args)
357{
358 __be32 *p;
359
360 args->crsa_addr = svc_addr(rqstp);
361 p = read_buf(xdr, 4);
362 if (unlikely(p == NULL))
363 return htonl(NFS4ERR_BADXDR);
364 args->crsa_target_max_slots = ntohl(*p++);
365 return 0;
366}
367
329#endif /* CONFIG_NFS_V4_1 */ 368#endif /* CONFIG_NFS_V4_1 */
330 369
331static __be32 encode_string(struct xdr_stream *xdr, unsigned int len, const char *str) 370static __be32 encode_string(struct xdr_stream *xdr, unsigned int len, const char *str)
@@ -445,7 +484,7 @@ static __be32 encode_op_hdr(struct xdr_stream *xdr, uint32_t op, __be32 res)
445 484
446 p = xdr_reserve_space(xdr, 8); 485 p = xdr_reserve_space(xdr, 8);
447 if (unlikely(p == NULL)) 486 if (unlikely(p == NULL))
448 return htonl(NFS4ERR_RESOURCE); 487 return htonl(NFS4ERR_RESOURCE_HDR);
449 *p++ = htonl(op); 488 *p++ = htonl(op);
450 *p = res; 489 *p = res;
451 return 0; 490 return 0;
@@ -479,10 +518,10 @@ out:
479 518
480#if defined(CONFIG_NFS_V4_1) 519#if defined(CONFIG_NFS_V4_1)
481 520
482static unsigned encode_sessionid(struct xdr_stream *xdr, 521static __be32 encode_sessionid(struct xdr_stream *xdr,
483 const struct nfs4_sessionid *sid) 522 const struct nfs4_sessionid *sid)
484{ 523{
485 uint32_t *p; 524 __be32 *p;
486 int len = NFS4_MAX_SESSIONID_LEN; 525 int len = NFS4_MAX_SESSIONID_LEN;
487 526
488 p = xdr_reserve_space(xdr, len); 527 p = xdr_reserve_space(xdr, len);
@@ -493,11 +532,11 @@ static unsigned encode_sessionid(struct xdr_stream *xdr,
493 return 0; 532 return 0;
494} 533}
495 534
496static unsigned encode_cb_sequence_res(struct svc_rqst *rqstp, 535static __be32 encode_cb_sequence_res(struct svc_rqst *rqstp,
497 struct xdr_stream *xdr, 536 struct xdr_stream *xdr,
498 const struct cb_sequenceres *res) 537 const struct cb_sequenceres *res)
499{ 538{
500 uint32_t *p; 539 __be32 *p;
501 unsigned status = res->csr_status; 540 unsigned status = res->csr_status;
502 541
503 if (unlikely(status != 0)) 542 if (unlikely(status != 0))
@@ -533,6 +572,8 @@ preprocess_nfs41_op(int nop, unsigned int op_nr, struct callback_op **op)
533 case OP_CB_GETATTR: 572 case OP_CB_GETATTR:
534 case OP_CB_RECALL: 573 case OP_CB_RECALL:
535 case OP_CB_SEQUENCE: 574 case OP_CB_SEQUENCE:
575 case OP_CB_RECALL_ANY:
576 case OP_CB_RECALL_SLOT:
536 *op = &callback_ops[op_nr]; 577 *op = &callback_ops[op_nr];
537 break; 578 break;
538 579
@@ -540,9 +581,7 @@ preprocess_nfs41_op(int nop, unsigned int op_nr, struct callback_op **op)
540 case OP_CB_NOTIFY_DEVICEID: 581 case OP_CB_NOTIFY_DEVICEID:
541 case OP_CB_NOTIFY: 582 case OP_CB_NOTIFY:
542 case OP_CB_PUSH_DELEG: 583 case OP_CB_PUSH_DELEG:
543 case OP_CB_RECALL_ANY:
544 case OP_CB_RECALLABLE_OBJ_AVAIL: 584 case OP_CB_RECALLABLE_OBJ_AVAIL:
545 case OP_CB_RECALL_SLOT:
546 case OP_CB_WANTS_CANCELLED: 585 case OP_CB_WANTS_CANCELLED:
547 case OP_CB_NOTIFY_LOCK: 586 case OP_CB_NOTIFY_LOCK:
548 return htonl(NFS4ERR_NOTSUPP); 587 return htonl(NFS4ERR_NOTSUPP);
@@ -582,20 +621,18 @@ preprocess_nfs4_op(unsigned int op_nr, struct callback_op **op)
582static __be32 process_op(uint32_t minorversion, int nop, 621static __be32 process_op(uint32_t minorversion, int nop,
583 struct svc_rqst *rqstp, 622 struct svc_rqst *rqstp,
584 struct xdr_stream *xdr_in, void *argp, 623 struct xdr_stream *xdr_in, void *argp,
585 struct xdr_stream *xdr_out, void *resp) 624 struct xdr_stream *xdr_out, void *resp, int* drc_status)
586{ 625{
587 struct callback_op *op = &callback_ops[0]; 626 struct callback_op *op = &callback_ops[0];
588 unsigned int op_nr = OP_CB_ILLEGAL; 627 unsigned int op_nr;
589 __be32 status; 628 __be32 status;
590 long maxlen; 629 long maxlen;
591 __be32 res; 630 __be32 res;
592 631
593 dprintk("%s: start\n", __func__); 632 dprintk("%s: start\n", __func__);
594 status = decode_op_hdr(xdr_in, &op_nr); 633 status = decode_op_hdr(xdr_in, &op_nr);
595 if (unlikely(status)) { 634 if (unlikely(status))
596 status = htonl(NFS4ERR_OP_ILLEGAL); 635 return status;
597 goto out;
598 }
599 636
600 dprintk("%s: minorversion=%d nop=%d op_nr=%u\n", 637 dprintk("%s: minorversion=%d nop=%d op_nr=%u\n",
601 __func__, minorversion, nop, op_nr); 638 __func__, minorversion, nop, op_nr);
@@ -604,19 +641,32 @@ static __be32 process_op(uint32_t minorversion, int nop,
604 preprocess_nfs4_op(op_nr, &op); 641 preprocess_nfs4_op(op_nr, &op);
605 if (status == htonl(NFS4ERR_OP_ILLEGAL)) 642 if (status == htonl(NFS4ERR_OP_ILLEGAL))
606 op_nr = OP_CB_ILLEGAL; 643 op_nr = OP_CB_ILLEGAL;
607out: 644 if (status)
645 goto encode_hdr;
646
647 if (*drc_status) {
648 status = *drc_status;
649 goto encode_hdr;
650 }
651
608 maxlen = xdr_out->end - xdr_out->p; 652 maxlen = xdr_out->end - xdr_out->p;
609 if (maxlen > 0 && maxlen < PAGE_SIZE) { 653 if (maxlen > 0 && maxlen < PAGE_SIZE) {
610 if (likely(status == 0 && op->decode_args != NULL)) 654 status = op->decode_args(rqstp, xdr_in, argp);
611 status = op->decode_args(rqstp, xdr_in, argp); 655 if (likely(status == 0))
612 if (likely(status == 0 && op->process_op != NULL))
613 status = op->process_op(argp, resp); 656 status = op->process_op(argp, resp);
614 } else 657 } else
615 status = htonl(NFS4ERR_RESOURCE); 658 status = htonl(NFS4ERR_RESOURCE);
616 659
660 /* Only set by OP_CB_SEQUENCE processing */
661 if (status == htonl(NFS4ERR_RETRY_UNCACHED_REP)) {
662 *drc_status = status;
663 status = 0;
664 }
665
666encode_hdr:
617 res = encode_op_hdr(xdr_out, op_nr, status); 667 res = encode_op_hdr(xdr_out, op_nr, status);
618 if (status == 0) 668 if (unlikely(res))
619 status = res; 669 return res;
620 if (op->encode_res != NULL && status == 0) 670 if (op->encode_res != NULL && status == 0)
621 status = op->encode_res(rqstp, xdr_out, resp); 671 status = op->encode_res(rqstp, xdr_out, resp);
622 dprintk("%s: done, status = %d\n", __func__, ntohl(status)); 672 dprintk("%s: done, status = %d\n", __func__, ntohl(status));
@@ -632,7 +682,7 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *r
632 struct cb_compound_hdr_res hdr_res = { NULL }; 682 struct cb_compound_hdr_res hdr_res = { NULL };
633 struct xdr_stream xdr_in, xdr_out; 683 struct xdr_stream xdr_in, xdr_out;
634 __be32 *p; 684 __be32 *p;
635 __be32 status; 685 __be32 status, drc_status = 0;
636 unsigned int nops = 0; 686 unsigned int nops = 0;
637 687
638 dprintk("%s: start\n", __func__); 688 dprintk("%s: start\n", __func__);
@@ -652,11 +702,18 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *r
652 return rpc_system_err; 702 return rpc_system_err;
653 703
654 while (status == 0 && nops != hdr_arg.nops) { 704 while (status == 0 && nops != hdr_arg.nops) {
655 status = process_op(hdr_arg.minorversion, nops, 705 status = process_op(hdr_arg.minorversion, nops, rqstp,
656 rqstp, &xdr_in, argp, &xdr_out, resp); 706 &xdr_in, argp, &xdr_out, resp, &drc_status);
657 nops++; 707 nops++;
658 } 708 }
659 709
710 /* Buffer overflow in decode_ops_hdr or encode_ops_hdr. Return
711 * resource error in cb_compound status without returning op */
712 if (unlikely(status == htonl(NFS4ERR_RESOURCE_HDR))) {
713 status = htonl(NFS4ERR_RESOURCE);
714 nops--;
715 }
716
660 *hdr_res.status = status; 717 *hdr_res.status = status;
661 *hdr_res.nops = htonl(nops); 718 *hdr_res.nops = htonl(nops);
662 dprintk("%s: done, status = %u\n", __func__, ntohl(status)); 719 dprintk("%s: done, status = %u\n", __func__, ntohl(status));
@@ -688,6 +745,16 @@ static struct callback_op callback_ops[] = {
688 .encode_res = (callback_encode_res_t)encode_cb_sequence_res, 745 .encode_res = (callback_encode_res_t)encode_cb_sequence_res,
689 .res_maxsize = CB_OP_SEQUENCE_RES_MAXSZ, 746 .res_maxsize = CB_OP_SEQUENCE_RES_MAXSZ,
690 }, 747 },
748 [OP_CB_RECALL_ANY] = {
749 .process_op = (callback_process_op_t)nfs4_callback_recallany,
750 .decode_args = (callback_decode_arg_t)decode_recallany_args,
751 .res_maxsize = CB_OP_RECALLANY_RES_MAXSZ,
752 },
753 [OP_CB_RECALL_SLOT] = {
754 .process_op = (callback_process_op_t)nfs4_callback_recallslot,
755 .decode_args = (callback_decode_arg_t)decode_recallslot_args,
756 .res_maxsize = CB_OP_RECALLSLOT_RES_MAXSZ,
757 },
691#endif /* CONFIG_NFS_V4_1 */ 758#endif /* CONFIG_NFS_V4_1 */
692}; 759};
693 760
@@ -716,5 +783,13 @@ struct svc_version nfs4_callback_version1 = {
716 .vs_proc = nfs4_callback_procedures1, 783 .vs_proc = nfs4_callback_procedures1,
717 .vs_xdrsize = NFS4_CALLBACK_XDRSIZE, 784 .vs_xdrsize = NFS4_CALLBACK_XDRSIZE,
718 .vs_dispatch = NULL, 785 .vs_dispatch = NULL,
786 .vs_hidden = 1,
719}; 787};
720 788
789struct svc_version nfs4_callback_version4 = {
790 .vs_vers = 4,
791 .vs_nproc = ARRAY_SIZE(nfs4_callback_procedures1),
792 .vs_proc = nfs4_callback_procedures1,
793 .vs_xdrsize = NFS4_CALLBACK_XDRSIZE,
794 .vs_dispatch = NULL,
795};