aboutsummaryrefslogtreecommitdiffstats
path: root/net/sunrpc/svcsock.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/sunrpc/svcsock.c')
-rw-r--r--net/sunrpc/svcsock.c122
1 files changed, 56 insertions, 66 deletions
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c
index 62ff7c5c09c2..40b502b11442 100644
--- a/net/sunrpc/svcsock.c
+++ b/net/sunrpc/svcsock.c
@@ -981,57 +981,58 @@ static int svc_tcp_recv_record(struct svc_sock *svsk, struct svc_rqst *rqstp)
981 return -EAGAIN; 981 return -EAGAIN;
982} 982}
983 983
984static int svc_process_calldir(struct svc_sock *svsk, struct svc_rqst *rqstp, 984static int receive_cb_reply(struct svc_sock *svsk, struct svc_rqst *rqstp)
985 struct rpc_rqst **reqpp, struct kvec *vec)
986{ 985{
986 struct rpc_xprt *bc_xprt = svsk->sk_xprt.xpt_bc_xprt;
987 struct rpc_rqst *req = NULL; 987 struct rpc_rqst *req = NULL;
988 __be32 *p; 988 struct kvec *src, *dst;
989 __be32 *p = (__be32 *)rqstp->rq_arg.head[0].iov_base;
989 __be32 xid; 990 __be32 xid;
990 __be32 calldir; 991 __be32 calldir;
991 int len;
992
993 len = svc_recvfrom(rqstp, vec, 1, 8);
994 if (len < 0)
995 goto error;
996 992
997 p = (u32 *)rqstp->rq_arg.head[0].iov_base;
998 xid = *p++; 993 xid = *p++;
999 calldir = *p; 994 calldir = *p;
1000 995
1001 if (calldir == 0) { 996 if (bc_xprt)
1002 /* REQUEST is the most common case */ 997 req = xprt_lookup_rqst(bc_xprt, xid);
1003 vec[0] = rqstp->rq_arg.head[0];
1004 } else {
1005 /* REPLY */
1006 struct rpc_xprt *bc_xprt = svsk->sk_xprt.xpt_bc_xprt;
1007
1008 if (bc_xprt)
1009 req = xprt_lookup_rqst(bc_xprt, xid);
1010
1011 if (!req) {
1012 printk(KERN_NOTICE
1013 "%s: Got unrecognized reply: "
1014 "calldir 0x%x xpt_bc_xprt %p xid %08x\n",
1015 __func__, ntohl(calldir),
1016 bc_xprt, xid);
1017 vec[0] = rqstp->rq_arg.head[0];
1018 goto out;
1019 }
1020 998
1021 memcpy(&req->rq_private_buf, &req->rq_rcv_buf, 999 if (!req) {
1022 sizeof(struct xdr_buf)); 1000 printk(KERN_NOTICE
1023 /* copy the xid and call direction */ 1001 "%s: Got unrecognized reply: "
1024 memcpy(req->rq_private_buf.head[0].iov_base, 1002 "calldir 0x%x xpt_bc_xprt %p xid %08x\n",
1025 rqstp->rq_arg.head[0].iov_base, 8); 1003 __func__, ntohl(calldir),
1026 vec[0] = req->rq_private_buf.head[0]; 1004 bc_xprt, xid);
1005 return -EAGAIN;
1027 } 1006 }
1028 out: 1007
1029 vec[0].iov_base += 8; 1008 memcpy(&req->rq_private_buf, &req->rq_rcv_buf, sizeof(struct xdr_buf));
1030 vec[0].iov_len -= 8; 1009 /*
1031 len = svsk->sk_reclen - 8; 1010 * XXX!: cheating for now! Only copying HEAD.
1032 error: 1011 * But we know this is good enough for now (in fact, for any
1033 *reqpp = req; 1012 * callback reply in the forseeable future).
1034 return len; 1013 */
1014 dst = &req->rq_private_buf.head[0];
1015 src = &rqstp->rq_arg.head[0];
1016 if (dst->iov_len < src->iov_len)
1017 return -EAGAIN; /* whatever; just giving up. */
1018 memcpy(dst->iov_base, src->iov_base, src->iov_len);
1019 xprt_complete_rqst(req->rq_task, svsk->sk_reclen);
1020 rqstp->rq_arg.len = 0;
1021 return 0;
1022}
1023
1024static int copy_pages_to_kvecs(struct kvec *vec, struct page **pages, int len)
1025{
1026 int i = 0;
1027 int t = 0;
1028
1029 while (t < len) {
1030 vec[i].iov_base = page_address(pages[i]);
1031 vec[i].iov_len = PAGE_SIZE;
1032 i++;
1033 t += PAGE_SIZE;
1034 }
1035 return i;
1035} 1036}
1036 1037
1037/* 1038/*
@@ -1044,8 +1045,8 @@ static int svc_tcp_recvfrom(struct svc_rqst *rqstp)
1044 struct svc_serv *serv = svsk->sk_xprt.xpt_server; 1045 struct svc_serv *serv = svsk->sk_xprt.xpt_server;
1045 int len; 1046 int len;
1046 struct kvec *vec; 1047 struct kvec *vec;
1047 struct rpc_rqst *req = NULL; 1048 __be32 *p;
1048 unsigned int vlen; 1049 __be32 calldir;
1049 int pnum; 1050 int pnum;
1050 1051
1051 dprintk("svc: tcp_recv %p data %d conn %d close %d\n", 1052 dprintk("svc: tcp_recv %p data %d conn %d close %d\n",
@@ -1058,35 +1059,17 @@ static int svc_tcp_recvfrom(struct svc_rqst *rqstp)
1058 goto error; 1059 goto error;
1059 1060
1060 vec = rqstp->rq_vec; 1061 vec = rqstp->rq_vec;
1061 vec[0] = rqstp->rq_arg.head[0];
1062 vlen = PAGE_SIZE;
1063 1062
1064 len = svc_process_calldir(svsk, rqstp, &req, vec); 1063 pnum = copy_pages_to_kvecs(&vec[0], &rqstp->rq_pages[0],
1065 if (len < 0) 1064 svsk->sk_reclen);
1066 goto err_again; 1065
1067 vlen -= 8;
1068
1069 pnum = 1;
1070 while (vlen < svsk->sk_reclen - 8) {
1071 vec[pnum].iov_base = (req) ?
1072 page_address(req->rq_private_buf.pages[pnum - 1]) :
1073 page_address(rqstp->rq_pages[pnum]);
1074 vec[pnum].iov_len = PAGE_SIZE;
1075 pnum++;
1076 vlen += PAGE_SIZE;
1077 }
1078 rqstp->rq_respages = &rqstp->rq_pages[pnum]; 1066 rqstp->rq_respages = &rqstp->rq_pages[pnum];
1079 1067
1080 /* Now receive data */ 1068 /* Now receive data */
1081 len = svc_recvfrom(rqstp, vec, pnum, svsk->sk_reclen - 8); 1069 len = svc_recvfrom(rqstp, vec, pnum, svsk->sk_reclen);
1082 if (len < 0) 1070 if (len < 0)
1083 goto err_again; 1071 goto err_again;
1084 1072
1085 if (req) {
1086 xprt_complete_rqst(req->rq_task, svsk->sk_reclen);
1087 rqstp->rq_arg.len = 0;
1088 goto out;
1089 }
1090 dprintk("svc: TCP complete record (%d bytes)\n", svsk->sk_reclen); 1073 dprintk("svc: TCP complete record (%d bytes)\n", svsk->sk_reclen);
1091 rqstp->rq_arg.len = svsk->sk_reclen; 1074 rqstp->rq_arg.len = svsk->sk_reclen;
1092 rqstp->rq_arg.page_base = 0; 1075 rqstp->rq_arg.page_base = 0;
@@ -1099,7 +1082,14 @@ static int svc_tcp_recvfrom(struct svc_rqst *rqstp)
1099 rqstp->rq_xprt_ctxt = NULL; 1082 rqstp->rq_xprt_ctxt = NULL;
1100 rqstp->rq_prot = IPPROTO_TCP; 1083 rqstp->rq_prot = IPPROTO_TCP;
1101 1084
1102out: 1085 p = (__be32 *)rqstp->rq_arg.head[0].iov_base;
1086 calldir = p[1];
1087 if (calldir) {
1088 len = receive_cb_reply(svsk, rqstp);
1089 if (len < 0)
1090 goto err_again;
1091 }
1092
1103 /* Reset TCP read info */ 1093 /* Reset TCP read info */
1104 svsk->sk_reclen = 0; 1094 svsk->sk_reclen = 0;
1105 svsk->sk_tcplen = 0; 1095 svsk->sk_tcplen = 0;