diff options
Diffstat (limited to 'net/sunrpc/svcsock.c')
-rw-r--r-- | net/sunrpc/svcsock.c | 122 |
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 | ||
984 | static int svc_process_calldir(struct svc_sock *svsk, struct svc_rqst *rqstp, | 984 | static 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 | |||
1024 | static 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 | ||
1102 | out: | 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; |