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.c105
1 files changed, 73 insertions, 32 deletions
diff --git a/fs/nfs/callback_xdr.c b/fs/nfs/callback_xdr.c
index 8e1a2511c8be..db30c0b398b5 100644
--- a/fs/nfs/callback_xdr.c
+++ b/fs/nfs/callback_xdr.c
@@ -24,10 +24,14 @@
24#define CB_OP_SEQUENCE_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ + \ 24#define CB_OP_SEQUENCE_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ + \
25 4 + 1 + 3) 25 4 + 1 + 3)
26#define CB_OP_RECALLANY_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ) 26#define CB_OP_RECALLANY_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ)
27#define CB_OP_RECALLSLOT_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ)
27#endif /* CONFIG_NFS_V4_1 */ 28#endif /* CONFIG_NFS_V4_1 */
28 29
29#define NFSDBG_FACILITY NFSDBG_CALLBACK 30#define NFSDBG_FACILITY NFSDBG_CALLBACK
30 31
32/* Internal error code */
33#define NFS4ERR_RESOURCE_HDR 11050
34
31typedef __be32 (*callback_process_op_t)(void *, void *); 35typedef __be32 (*callback_process_op_t)(void *, void *);
32typedef __be32 (*callback_decode_arg_t)(struct svc_rqst *, struct xdr_stream *, void *); 36typedef __be32 (*callback_decode_arg_t)(struct svc_rqst *, struct xdr_stream *, void *);
33typedef __be32 (*callback_encode_res_t)(struct svc_rqst *, struct xdr_stream *, void *); 37typedef __be32 (*callback_encode_res_t)(struct svc_rqst *, struct xdr_stream *, void *);
@@ -173,7 +177,7 @@ static __be32 decode_op_hdr(struct xdr_stream *xdr, unsigned int *op)
173 __be32 *p; 177 __be32 *p;
174 p = read_buf(xdr, 4); 178 p = read_buf(xdr, 4);
175 if (unlikely(p == NULL)) 179 if (unlikely(p == NULL))
176 return htonl(NFS4ERR_RESOURCE); 180 return htonl(NFS4ERR_RESOURCE_HDR);
177 *op = ntohl(*p); 181 *op = ntohl(*p);
178 return 0; 182 return 0;
179} 183}
@@ -215,10 +219,10 @@ out:
215 219
216#if defined(CONFIG_NFS_V4_1) 220#if defined(CONFIG_NFS_V4_1)
217 221
218static unsigned decode_sessionid(struct xdr_stream *xdr, 222static __be32 decode_sessionid(struct xdr_stream *xdr,
219 struct nfs4_sessionid *sid) 223 struct nfs4_sessionid *sid)
220{ 224{
221 uint32_t *p; 225 __be32 *p;
222 int len = NFS4_MAX_SESSIONID_LEN; 226 int len = NFS4_MAX_SESSIONID_LEN;
223 227
224 p = read_buf(xdr, len); 228 p = read_buf(xdr, len);
@@ -229,12 +233,12 @@ static unsigned decode_sessionid(struct xdr_stream *xdr,
229 return 0; 233 return 0;
230} 234}
231 235
232static unsigned decode_rc_list(struct xdr_stream *xdr, 236static __be32 decode_rc_list(struct xdr_stream *xdr,
233 struct referring_call_list *rc_list) 237 struct referring_call_list *rc_list)
234{ 238{
235 uint32_t *p; 239 __be32 *p;
236 int i; 240 int i;
237 unsigned status; 241 __be32 status;
238 242
239 status = decode_sessionid(xdr, &rc_list->rcl_sessionid); 243 status = decode_sessionid(xdr, &rc_list->rcl_sessionid);
240 if (status) 244 if (status)
@@ -267,13 +271,13 @@ out:
267 return status; 271 return status;
268} 272}
269 273
270static unsigned decode_cb_sequence_args(struct svc_rqst *rqstp, 274static __be32 decode_cb_sequence_args(struct svc_rqst *rqstp,
271 struct xdr_stream *xdr, 275 struct xdr_stream *xdr,
272 struct cb_sequenceargs *args) 276 struct cb_sequenceargs *args)
273{ 277{
274 uint32_t *p; 278 __be32 *p;
275 int i; 279 int i;
276 unsigned status; 280 __be32 status;
277 281
278 status = decode_sessionid(xdr, &args->csa_sessionid); 282 status = decode_sessionid(xdr, &args->csa_sessionid);
279 if (status) 283 if (status)
@@ -327,11 +331,11 @@ out_free:
327 goto out; 331 goto out;
328} 332}
329 333
330static unsigned decode_recallany_args(struct svc_rqst *rqstp, 334static __be32 decode_recallany_args(struct svc_rqst *rqstp,
331 struct xdr_stream *xdr, 335 struct xdr_stream *xdr,
332 struct cb_recallanyargs *args) 336 struct cb_recallanyargs *args)
333{ 337{
334 uint32_t *p; 338 __be32 *p;
335 339
336 args->craa_addr = svc_addr(rqstp); 340 args->craa_addr = svc_addr(rqstp);
337 p = read_buf(xdr, 4); 341 p = read_buf(xdr, 4);
@@ -346,6 +350,20 @@ static unsigned decode_recallany_args(struct svc_rqst *rqstp,
346 return 0; 350 return 0;
347} 351}
348 352
353static __be32 decode_recallslot_args(struct svc_rqst *rqstp,
354 struct xdr_stream *xdr,
355 struct cb_recallslotargs *args)
356{
357 __be32 *p;
358
359 args->crsa_addr = svc_addr(rqstp);
360 p = read_buf(xdr, 4);
361 if (unlikely(p == NULL))
362 return htonl(NFS4ERR_BADXDR);
363 args->crsa_target_max_slots = ntohl(*p++);
364 return 0;
365}
366
349#endif /* CONFIG_NFS_V4_1 */ 367#endif /* CONFIG_NFS_V4_1 */
350 368
351static __be32 encode_string(struct xdr_stream *xdr, unsigned int len, const char *str) 369static __be32 encode_string(struct xdr_stream *xdr, unsigned int len, const char *str)
@@ -465,7 +483,7 @@ static __be32 encode_op_hdr(struct xdr_stream *xdr, uint32_t op, __be32 res)
465 483
466 p = xdr_reserve_space(xdr, 8); 484 p = xdr_reserve_space(xdr, 8);
467 if (unlikely(p == NULL)) 485 if (unlikely(p == NULL))
468 return htonl(NFS4ERR_RESOURCE); 486 return htonl(NFS4ERR_RESOURCE_HDR);
469 *p++ = htonl(op); 487 *p++ = htonl(op);
470 *p = res; 488 *p = res;
471 return 0; 489 return 0;
@@ -499,10 +517,10 @@ out:
499 517
500#if defined(CONFIG_NFS_V4_1) 518#if defined(CONFIG_NFS_V4_1)
501 519
502static unsigned encode_sessionid(struct xdr_stream *xdr, 520static __be32 encode_sessionid(struct xdr_stream *xdr,
503 const struct nfs4_sessionid *sid) 521 const struct nfs4_sessionid *sid)
504{ 522{
505 uint32_t *p; 523 __be32 *p;
506 int len = NFS4_MAX_SESSIONID_LEN; 524 int len = NFS4_MAX_SESSIONID_LEN;
507 525
508 p = xdr_reserve_space(xdr, len); 526 p = xdr_reserve_space(xdr, len);
@@ -513,11 +531,11 @@ static unsigned encode_sessionid(struct xdr_stream *xdr,
513 return 0; 531 return 0;
514} 532}
515 533
516static unsigned encode_cb_sequence_res(struct svc_rqst *rqstp, 534static __be32 encode_cb_sequence_res(struct svc_rqst *rqstp,
517 struct xdr_stream *xdr, 535 struct xdr_stream *xdr,
518 const struct cb_sequenceres *res) 536 const struct cb_sequenceres *res)
519{ 537{
520 uint32_t *p; 538 __be32 *p;
521 unsigned status = res->csr_status; 539 unsigned status = res->csr_status;
522 540
523 if (unlikely(status != 0)) 541 if (unlikely(status != 0))
@@ -554,6 +572,7 @@ preprocess_nfs41_op(int nop, unsigned int op_nr, struct callback_op **op)
554 case OP_CB_RECALL: 572 case OP_CB_RECALL:
555 case OP_CB_SEQUENCE: 573 case OP_CB_SEQUENCE:
556 case OP_CB_RECALL_ANY: 574 case OP_CB_RECALL_ANY:
575 case OP_CB_RECALL_SLOT:
557 *op = &callback_ops[op_nr]; 576 *op = &callback_ops[op_nr];
558 break; 577 break;
559 578
@@ -562,7 +581,6 @@ preprocess_nfs41_op(int nop, unsigned int op_nr, struct callback_op **op)
562 case OP_CB_NOTIFY: 581 case OP_CB_NOTIFY:
563 case OP_CB_PUSH_DELEG: 582 case OP_CB_PUSH_DELEG:
564 case OP_CB_RECALLABLE_OBJ_AVAIL: 583 case OP_CB_RECALLABLE_OBJ_AVAIL:
565 case OP_CB_RECALL_SLOT:
566 case OP_CB_WANTS_CANCELLED: 584 case OP_CB_WANTS_CANCELLED:
567 case OP_CB_NOTIFY_LOCK: 585 case OP_CB_NOTIFY_LOCK:
568 return htonl(NFS4ERR_NOTSUPP); 586 return htonl(NFS4ERR_NOTSUPP);
@@ -602,20 +620,18 @@ preprocess_nfs4_op(unsigned int op_nr, struct callback_op **op)
602static __be32 process_op(uint32_t minorversion, int nop, 620static __be32 process_op(uint32_t minorversion, int nop,
603 struct svc_rqst *rqstp, 621 struct svc_rqst *rqstp,
604 struct xdr_stream *xdr_in, void *argp, 622 struct xdr_stream *xdr_in, void *argp,
605 struct xdr_stream *xdr_out, void *resp) 623 struct xdr_stream *xdr_out, void *resp, int* drc_status)
606{ 624{
607 struct callback_op *op = &callback_ops[0]; 625 struct callback_op *op = &callback_ops[0];
608 unsigned int op_nr = OP_CB_ILLEGAL; 626 unsigned int op_nr;
609 __be32 status; 627 __be32 status;
610 long maxlen; 628 long maxlen;
611 __be32 res; 629 __be32 res;
612 630
613 dprintk("%s: start\n", __func__); 631 dprintk("%s: start\n", __func__);
614 status = decode_op_hdr(xdr_in, &op_nr); 632 status = decode_op_hdr(xdr_in, &op_nr);
615 if (unlikely(status)) { 633 if (unlikely(status))
616 status = htonl(NFS4ERR_OP_ILLEGAL); 634 return status;
617 goto out;
618 }
619 635
620 dprintk("%s: minorversion=%d nop=%d op_nr=%u\n", 636 dprintk("%s: minorversion=%d nop=%d op_nr=%u\n",
621 __func__, minorversion, nop, op_nr); 637 __func__, minorversion, nop, op_nr);
@@ -624,19 +640,32 @@ static __be32 process_op(uint32_t minorversion, int nop,
624 preprocess_nfs4_op(op_nr, &op); 640 preprocess_nfs4_op(op_nr, &op);
625 if (status == htonl(NFS4ERR_OP_ILLEGAL)) 641 if (status == htonl(NFS4ERR_OP_ILLEGAL))
626 op_nr = OP_CB_ILLEGAL; 642 op_nr = OP_CB_ILLEGAL;
627out: 643 if (status)
644 goto encode_hdr;
645
646 if (*drc_status) {
647 status = *drc_status;
648 goto encode_hdr;
649 }
650
628 maxlen = xdr_out->end - xdr_out->p; 651 maxlen = xdr_out->end - xdr_out->p;
629 if (maxlen > 0 && maxlen < PAGE_SIZE) { 652 if (maxlen > 0 && maxlen < PAGE_SIZE) {
630 if (likely(status == 0 && op->decode_args != NULL)) 653 status = op->decode_args(rqstp, xdr_in, argp);
631 status = op->decode_args(rqstp, xdr_in, argp); 654 if (likely(status == 0))
632 if (likely(status == 0 && op->process_op != NULL))
633 status = op->process_op(argp, resp); 655 status = op->process_op(argp, resp);
634 } else 656 } else
635 status = htonl(NFS4ERR_RESOURCE); 657 status = htonl(NFS4ERR_RESOURCE);
636 658
659 /* Only set by OP_CB_SEQUENCE processing */
660 if (status == htonl(NFS4ERR_RETRY_UNCACHED_REP)) {
661 *drc_status = status;
662 status = 0;
663 }
664
665encode_hdr:
637 res = encode_op_hdr(xdr_out, op_nr, status); 666 res = encode_op_hdr(xdr_out, op_nr, status);
638 if (status == 0) 667 if (unlikely(res))
639 status = res; 668 return res;
640 if (op->encode_res != NULL && status == 0) 669 if (op->encode_res != NULL && status == 0)
641 status = op->encode_res(rqstp, xdr_out, resp); 670 status = op->encode_res(rqstp, xdr_out, resp);
642 dprintk("%s: done, status = %d\n", __func__, ntohl(status)); 671 dprintk("%s: done, status = %d\n", __func__, ntohl(status));
@@ -652,7 +681,7 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *r
652 struct cb_compound_hdr_res hdr_res = { NULL }; 681 struct cb_compound_hdr_res hdr_res = { NULL };
653 struct xdr_stream xdr_in, xdr_out; 682 struct xdr_stream xdr_in, xdr_out;
654 __be32 *p; 683 __be32 *p;
655 __be32 status; 684 __be32 status, drc_status = 0;
656 unsigned int nops = 0; 685 unsigned int nops = 0;
657 686
658 dprintk("%s: start\n", __func__); 687 dprintk("%s: start\n", __func__);
@@ -672,11 +701,18 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *r
672 return rpc_system_err; 701 return rpc_system_err;
673 702
674 while (status == 0 && nops != hdr_arg.nops) { 703 while (status == 0 && nops != hdr_arg.nops) {
675 status = process_op(hdr_arg.minorversion, nops, 704 status = process_op(hdr_arg.minorversion, nops, rqstp,
676 rqstp, &xdr_in, argp, &xdr_out, resp); 705 &xdr_in, argp, &xdr_out, resp, &drc_status);
677 nops++; 706 nops++;
678 } 707 }
679 708
709 /* Buffer overflow in decode_ops_hdr or encode_ops_hdr. Return
710 * resource error in cb_compound status without returning op */
711 if (unlikely(status == htonl(NFS4ERR_RESOURCE_HDR))) {
712 status = htonl(NFS4ERR_RESOURCE);
713 nops--;
714 }
715
680 *hdr_res.status = status; 716 *hdr_res.status = status;
681 *hdr_res.nops = htonl(nops); 717 *hdr_res.nops = htonl(nops);
682 dprintk("%s: done, status = %u\n", __func__, ntohl(status)); 718 dprintk("%s: done, status = %u\n", __func__, ntohl(status));
@@ -713,6 +749,11 @@ static struct callback_op callback_ops[] = {
713 .decode_args = (callback_decode_arg_t)decode_recallany_args, 749 .decode_args = (callback_decode_arg_t)decode_recallany_args,
714 .res_maxsize = CB_OP_RECALLANY_RES_MAXSZ, 750 .res_maxsize = CB_OP_RECALLANY_RES_MAXSZ,
715 }, 751 },
752 [OP_CB_RECALL_SLOT] = {
753 .process_op = (callback_process_op_t)nfs4_callback_recallslot,
754 .decode_args = (callback_decode_arg_t)decode_recallslot_args,
755 .res_maxsize = CB_OP_RECALLSLOT_RES_MAXSZ,
756 },
716#endif /* CONFIG_NFS_V4_1 */ 757#endif /* CONFIG_NFS_V4_1 */
717}; 758};
718 759