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