diff options
author | Rahul Iyer <iyer@netapp.com> | 2009-09-10 10:32:28 -0400 |
---|---|---|
committer | J. Bruce Fields <bfields@citi.umich.edu> | 2009-09-11 15:04:16 -0400 |
commit | 4cfc7e6019caa3e97d2a81c48c8d575d7b38d751 (patch) | |
tree | 8dced61360d385b115da94f9a4fd5f8d635c296d /net | |
parent | 6951867b9967066eda090f46ad91ce69e0ead611 (diff) |
nfsd41: sunrpc: Added rpc server-side backchannel handling
When the call direction is a reply, copy the xid and call direction into the
req->rq_private_buf.head[0].iov_base otherwise rpc_verify_header returns
rpc_garbage.
Signed-off-by: Rahul Iyer <iyer@netapp.com>
Signed-off-by: Mike Sager <sager@netapp.com>
Signed-off-by: Marc Eshel <eshel@almaden.ibm.com>
Signed-off-by: Benny Halevy <bhalevy@panasas.com>
Signed-off-by: Ricardo Labiaga <Ricardo.Labiaga@netapp.com>
Signed-off-by: Andy Adamson <andros@netapp.com>
Signed-off-by: Benny Halevy <bhalevy@panasas.com>
[get rid of CONFIG_NFSD_V4_1]
[sunrpc: refactoring of svc_tcp_recvfrom]
[nfsd41: sunrpc: create common send routine for the fore and the back channels]
[nfsd41: sunrpc: Use free_page() to free server backchannel pages]
[nfsd41: sunrpc: Document server backchannel locking]
[nfsd41: sunrpc: remove bc_connect_worker()]
[nfsd41: sunrpc: Define xprt_server_backchannel()[
[nfsd41: sunrpc: remove bc_close and bc_init_auto_disconnect dummy functions]
[nfsd41: sunrpc: eliminate unneeded switch statement in xs_setup_tcp()]
[nfsd41: sunrpc: Don't auto close the server backchannel connection]
[nfsd41: sunrpc: Remove unused functions]
Signed-off-by: Alexandros Batsakis <batsakis@netapp.com>
Signed-off-by: Ricardo Labiaga <Ricardo.Labiaga@netapp.com>
Signed-off-by: Benny Halevy <bhalevy@panasas.com>
[nfsd41: change bc_sock to bc_xprt]
[nfsd41: sunrpc: move struct rpc_buffer def into a common header file]
[nfsd41: sunrpc: use rpc_sleep in bc_send_request so not to block on mutex]
[removed cosmetic changes]
Signed-off-by: Benny Halevy <bhalevy@panasas.com>
[sunrpc: add new xprt class for nfsv4.1 backchannel]
[sunrpc: v2.1 change handling of auto_close and init_auto_disconnect operations for the nfsv4.1 backchannel]
Signed-off-by: Alexandros Batsakis <batsakis@netapp.com>
[reverted more cosmetic leftovers]
[got rid of xprt_server_backchannel]
[separated "nfsd41: sunrpc: add new xprt class for nfsv4.1 backchannel"]
Signed-off-by: Benny Halevy <bhalevy@panasas.com>
Cc: Trond Myklebust <trond.myklebust@netapp.com>
[sunrpc: change idle timeout value for the backchannel]
Signed-off-by: Alexandros Batsakis <batsakis@netapp.com>
Signed-off-by: Benny Halevy <bhalevy@panasas.com>
Acked-by: Trond Myklebust <trond.myklebust@netapp.com>
Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
Diffstat (limited to 'net')
-rw-r--r-- | net/sunrpc/sunrpc.h | 4 | ||||
-rw-r--r-- | net/sunrpc/svc_xprt.c | 2 | ||||
-rw-r--r-- | net/sunrpc/svcsock.c | 172 | ||||
-rw-r--r-- | net/sunrpc/xprt.c | 15 | ||||
-rw-r--r-- | net/sunrpc/xprtsock.c | 146 |
5 files changed, 300 insertions, 39 deletions
diff --git a/net/sunrpc/sunrpc.h b/net/sunrpc/sunrpc.h index 13171e63f51b..90c292e2738b 100644 --- a/net/sunrpc/sunrpc.h +++ b/net/sunrpc/sunrpc.h | |||
@@ -43,5 +43,9 @@ static inline int rpc_reply_expected(struct rpc_task *task) | |||
43 | (task->tk_msg.rpc_proc->p_decode != NULL); | 43 | (task->tk_msg.rpc_proc->p_decode != NULL); |
44 | } | 44 | } |
45 | 45 | ||
46 | int svc_send_common(struct socket *sock, struct xdr_buf *xdr, | ||
47 | struct page *headpage, unsigned long headoffset, | ||
48 | struct page *tailpage, unsigned long tailoffset); | ||
49 | |||
46 | #endif /* _NET_SUNRPC_SUNRPC_H */ | 50 | #endif /* _NET_SUNRPC_SUNRPC_H */ |
47 | 51 | ||
diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c index 912dea558ccc..df124f78ee48 100644 --- a/net/sunrpc/svc_xprt.c +++ b/net/sunrpc/svc_xprt.c | |||
@@ -160,6 +160,7 @@ void svc_xprt_init(struct svc_xprt_class *xcl, struct svc_xprt *xprt, | |||
160 | mutex_init(&xprt->xpt_mutex); | 160 | mutex_init(&xprt->xpt_mutex); |
161 | spin_lock_init(&xprt->xpt_lock); | 161 | spin_lock_init(&xprt->xpt_lock); |
162 | set_bit(XPT_BUSY, &xprt->xpt_flags); | 162 | set_bit(XPT_BUSY, &xprt->xpt_flags); |
163 | rpc_init_wait_queue(&xprt->xpt_bc_pending, "xpt_bc_pending"); | ||
163 | } | 164 | } |
164 | EXPORT_SYMBOL_GPL(svc_xprt_init); | 165 | EXPORT_SYMBOL_GPL(svc_xprt_init); |
165 | 166 | ||
@@ -810,6 +811,7 @@ int svc_send(struct svc_rqst *rqstp) | |||
810 | else | 811 | else |
811 | len = xprt->xpt_ops->xpo_sendto(rqstp); | 812 | len = xprt->xpt_ops->xpo_sendto(rqstp); |
812 | mutex_unlock(&xprt->xpt_mutex); | 813 | mutex_unlock(&xprt->xpt_mutex); |
814 | rpc_wake_up(&xprt->xpt_bc_pending); | ||
813 | svc_xprt_release(rqstp); | 815 | svc_xprt_release(rqstp); |
814 | 816 | ||
815 | if (len == -ECONNREFUSED || len == -ENOTCONN || len == -EAGAIN) | 817 | if (len == -ECONNREFUSED || len == -ENOTCONN || len == -EAGAIN) |
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index 76a380d37de4..ccc5e83cae5d 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c | |||
@@ -49,6 +49,7 @@ | |||
49 | #include <linux/sunrpc/msg_prot.h> | 49 | #include <linux/sunrpc/msg_prot.h> |
50 | #include <linux/sunrpc/svcsock.h> | 50 | #include <linux/sunrpc/svcsock.h> |
51 | #include <linux/sunrpc/stats.h> | 51 | #include <linux/sunrpc/stats.h> |
52 | #include <linux/sunrpc/xprt.h> | ||
52 | 53 | ||
53 | #define RPCDBG_FACILITY RPCDBG_SVCXPRT | 54 | #define RPCDBG_FACILITY RPCDBG_SVCXPRT |
54 | 55 | ||
@@ -153,49 +154,27 @@ static void svc_set_cmsg_data(struct svc_rqst *rqstp, struct cmsghdr *cmh) | |||
153 | } | 154 | } |
154 | 155 | ||
155 | /* | 156 | /* |
156 | * Generic sendto routine | 157 | * send routine intended to be shared by the fore- and back-channel |
157 | */ | 158 | */ |
158 | static int svc_sendto(struct svc_rqst *rqstp, struct xdr_buf *xdr) | 159 | int svc_send_common(struct socket *sock, struct xdr_buf *xdr, |
160 | struct page *headpage, unsigned long headoffset, | ||
161 | struct page *tailpage, unsigned long tailoffset) | ||
159 | { | 162 | { |
160 | struct svc_sock *svsk = | ||
161 | container_of(rqstp->rq_xprt, struct svc_sock, sk_xprt); | ||
162 | struct socket *sock = svsk->sk_sock; | ||
163 | int slen; | ||
164 | union { | ||
165 | struct cmsghdr hdr; | ||
166 | long all[SVC_PKTINFO_SPACE / sizeof(long)]; | ||
167 | } buffer; | ||
168 | struct cmsghdr *cmh = &buffer.hdr; | ||
169 | int len = 0; | ||
170 | int result; | 163 | int result; |
171 | int size; | 164 | int size; |
172 | struct page **ppage = xdr->pages; | 165 | struct page **ppage = xdr->pages; |
173 | size_t base = xdr->page_base; | 166 | size_t base = xdr->page_base; |
174 | unsigned int pglen = xdr->page_len; | 167 | unsigned int pglen = xdr->page_len; |
175 | unsigned int flags = MSG_MORE; | 168 | unsigned int flags = MSG_MORE; |
176 | RPC_IFDEBUG(char buf[RPC_MAX_ADDRBUFLEN]); | 169 | int slen; |
170 | int len = 0; | ||
177 | 171 | ||
178 | slen = xdr->len; | 172 | slen = xdr->len; |
179 | 173 | ||
180 | if (rqstp->rq_prot == IPPROTO_UDP) { | ||
181 | struct msghdr msg = { | ||
182 | .msg_name = &rqstp->rq_addr, | ||
183 | .msg_namelen = rqstp->rq_addrlen, | ||
184 | .msg_control = cmh, | ||
185 | .msg_controllen = sizeof(buffer), | ||
186 | .msg_flags = MSG_MORE, | ||
187 | }; | ||
188 | |||
189 | svc_set_cmsg_data(rqstp, cmh); | ||
190 | |||
191 | if (sock_sendmsg(sock, &msg, 0) < 0) | ||
192 | goto out; | ||
193 | } | ||
194 | |||
195 | /* send head */ | 174 | /* send head */ |
196 | if (slen == xdr->head[0].iov_len) | 175 | if (slen == xdr->head[0].iov_len) |
197 | flags = 0; | 176 | flags = 0; |
198 | len = kernel_sendpage(sock, rqstp->rq_respages[0], 0, | 177 | len = kernel_sendpage(sock, headpage, headoffset, |
199 | xdr->head[0].iov_len, flags); | 178 | xdr->head[0].iov_len, flags); |
200 | if (len != xdr->head[0].iov_len) | 179 | if (len != xdr->head[0].iov_len) |
201 | goto out; | 180 | goto out; |
@@ -219,16 +198,58 @@ static int svc_sendto(struct svc_rqst *rqstp, struct xdr_buf *xdr) | |||
219 | base = 0; | 198 | base = 0; |
220 | ppage++; | 199 | ppage++; |
221 | } | 200 | } |
201 | |||
222 | /* send tail */ | 202 | /* send tail */ |
223 | if (xdr->tail[0].iov_len) { | 203 | if (xdr->tail[0].iov_len) { |
224 | result = kernel_sendpage(sock, rqstp->rq_respages[0], | 204 | result = kernel_sendpage(sock, tailpage, tailoffset, |
225 | ((unsigned long)xdr->tail[0].iov_base) | 205 | xdr->tail[0].iov_len, 0); |
226 | & (PAGE_SIZE-1), | ||
227 | xdr->tail[0].iov_len, 0); | ||
228 | |||
229 | if (result > 0) | 206 | if (result > 0) |
230 | len += result; | 207 | len += result; |
231 | } | 208 | } |
209 | |||
210 | out: | ||
211 | return len; | ||
212 | } | ||
213 | |||
214 | |||
215 | /* | ||
216 | * Generic sendto routine | ||
217 | */ | ||
218 | static int svc_sendto(struct svc_rqst *rqstp, struct xdr_buf *xdr) | ||
219 | { | ||
220 | struct svc_sock *svsk = | ||
221 | container_of(rqstp->rq_xprt, struct svc_sock, sk_xprt); | ||
222 | struct socket *sock = svsk->sk_sock; | ||
223 | union { | ||
224 | struct cmsghdr hdr; | ||
225 | long all[SVC_PKTINFO_SPACE / sizeof(long)]; | ||
226 | } buffer; | ||
227 | struct cmsghdr *cmh = &buffer.hdr; | ||
228 | int len = 0; | ||
229 | unsigned long tailoff; | ||
230 | unsigned long headoff; | ||
231 | RPC_IFDEBUG(char buf[RPC_MAX_ADDRBUFLEN]); | ||
232 | |||
233 | if (rqstp->rq_prot == IPPROTO_UDP) { | ||
234 | struct msghdr msg = { | ||
235 | .msg_name = &rqstp->rq_addr, | ||
236 | .msg_namelen = rqstp->rq_addrlen, | ||
237 | .msg_control = cmh, | ||
238 | .msg_controllen = sizeof(buffer), | ||
239 | .msg_flags = MSG_MORE, | ||
240 | }; | ||
241 | |||
242 | svc_set_cmsg_data(rqstp, cmh); | ||
243 | |||
244 | if (sock_sendmsg(sock, &msg, 0) < 0) | ||
245 | goto out; | ||
246 | } | ||
247 | |||
248 | tailoff = ((unsigned long)xdr->tail[0].iov_base) & (PAGE_SIZE-1); | ||
249 | headoff = 0; | ||
250 | len = svc_send_common(sock, xdr, rqstp->rq_respages[0], headoff, | ||
251 | rqstp->rq_respages[0], tailoff); | ||
252 | |||
232 | out: | 253 | out: |
233 | dprintk("svc: socket %p sendto([%p %Zu... ], %d) = %d (addr %s)\n", | 254 | dprintk("svc: socket %p sendto([%p %Zu... ], %d) = %d (addr %s)\n", |
234 | svsk, xdr->head[0].iov_base, xdr->head[0].iov_len, | 255 | svsk, xdr->head[0].iov_base, xdr->head[0].iov_len, |
@@ -951,6 +972,57 @@ static int svc_tcp_recv_record(struct svc_sock *svsk, struct svc_rqst *rqstp) | |||
951 | return -EAGAIN; | 972 | return -EAGAIN; |
952 | } | 973 | } |
953 | 974 | ||
975 | static int svc_process_calldir(struct svc_sock *svsk, struct svc_rqst *rqstp, | ||
976 | struct rpc_rqst **reqpp, struct kvec *vec) | ||
977 | { | ||
978 | struct rpc_rqst *req = NULL; | ||
979 | u32 *p; | ||
980 | u32 xid; | ||
981 | u32 calldir; | ||
982 | int len; | ||
983 | |||
984 | len = svc_recvfrom(rqstp, vec, 1, 8); | ||
985 | if (len < 0) | ||
986 | goto error; | ||
987 | |||
988 | p = (u32 *)rqstp->rq_arg.head[0].iov_base; | ||
989 | xid = *p++; | ||
990 | calldir = *p; | ||
991 | |||
992 | if (calldir == 0) { | ||
993 | /* REQUEST is the most common case */ | ||
994 | vec[0] = rqstp->rq_arg.head[0]; | ||
995 | } else { | ||
996 | /* REPLY */ | ||
997 | if (svsk->sk_bc_xprt) | ||
998 | req = xprt_lookup_rqst(svsk->sk_bc_xprt, xid); | ||
999 | |||
1000 | if (!req) { | ||
1001 | printk(KERN_NOTICE | ||
1002 | "%s: Got unrecognized reply: " | ||
1003 | "calldir 0x%x sk_bc_xprt %p xid %08x\n", | ||
1004 | __func__, ntohl(calldir), | ||
1005 | svsk->sk_bc_xprt, xid); | ||
1006 | vec[0] = rqstp->rq_arg.head[0]; | ||
1007 | goto out; | ||
1008 | } | ||
1009 | |||
1010 | memcpy(&req->rq_private_buf, &req->rq_rcv_buf, | ||
1011 | sizeof(struct xdr_buf)); | ||
1012 | /* copy the xid and call direction */ | ||
1013 | memcpy(req->rq_private_buf.head[0].iov_base, | ||
1014 | rqstp->rq_arg.head[0].iov_base, 8); | ||
1015 | vec[0] = req->rq_private_buf.head[0]; | ||
1016 | } | ||
1017 | out: | ||
1018 | vec[0].iov_base += 8; | ||
1019 | vec[0].iov_len -= 8; | ||
1020 | len = svsk->sk_reclen - 8; | ||
1021 | error: | ||
1022 | *reqpp = req; | ||
1023 | return len; | ||
1024 | } | ||
1025 | |||
954 | /* | 1026 | /* |
955 | * Receive data from a TCP socket. | 1027 | * Receive data from a TCP socket. |
956 | */ | 1028 | */ |
@@ -962,6 +1034,7 @@ static int svc_tcp_recvfrom(struct svc_rqst *rqstp) | |||
962 | int len; | 1034 | int len; |
963 | struct kvec *vec; | 1035 | struct kvec *vec; |
964 | int pnum, vlen; | 1036 | int pnum, vlen; |
1037 | struct rpc_rqst *req = NULL; | ||
965 | 1038 | ||
966 | dprintk("svc: tcp_recv %p data %d conn %d close %d\n", | 1039 | dprintk("svc: tcp_recv %p data %d conn %d close %d\n", |
967 | svsk, test_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags), | 1040 | svsk, test_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags), |
@@ -975,9 +1048,27 @@ static int svc_tcp_recvfrom(struct svc_rqst *rqstp) | |||
975 | vec = rqstp->rq_vec; | 1048 | vec = rqstp->rq_vec; |
976 | vec[0] = rqstp->rq_arg.head[0]; | 1049 | vec[0] = rqstp->rq_arg.head[0]; |
977 | vlen = PAGE_SIZE; | 1050 | vlen = PAGE_SIZE; |
1051 | |||
1052 | /* | ||
1053 | * We have enough data for the whole tcp record. Let's try and read the | ||
1054 | * first 8 bytes to get the xid and the call direction. We can use this | ||
1055 | * to figure out if this is a call or a reply to a callback. If | ||
1056 | * sk_reclen is < 8 (xid and calldir), then this is a malformed packet. | ||
1057 | * In that case, don't bother with the calldir and just read the data. | ||
1058 | * It will be rejected in svc_process. | ||
1059 | */ | ||
1060 | if (len >= 8) { | ||
1061 | len = svc_process_calldir(svsk, rqstp, &req, vec); | ||
1062 | if (len < 0) | ||
1063 | goto err_again; | ||
1064 | vlen -= 8; | ||
1065 | } | ||
1066 | |||
978 | pnum = 1; | 1067 | pnum = 1; |
979 | while (vlen < len) { | 1068 | while (vlen < len) { |
980 | vec[pnum].iov_base = page_address(rqstp->rq_pages[pnum]); | 1069 | vec[pnum].iov_base = (req) ? |
1070 | page_address(req->rq_private_buf.pages[pnum - 1]) : | ||
1071 | page_address(rqstp->rq_pages[pnum]); | ||
981 | vec[pnum].iov_len = PAGE_SIZE; | 1072 | vec[pnum].iov_len = PAGE_SIZE; |
982 | pnum++; | 1073 | pnum++; |
983 | vlen += PAGE_SIZE; | 1074 | vlen += PAGE_SIZE; |
@@ -989,6 +1080,16 @@ static int svc_tcp_recvfrom(struct svc_rqst *rqstp) | |||
989 | if (len < 0) | 1080 | if (len < 0) |
990 | goto err_again; | 1081 | goto err_again; |
991 | 1082 | ||
1083 | /* | ||
1084 | * Account for the 8 bytes we read earlier | ||
1085 | */ | ||
1086 | len += 8; | ||
1087 | |||
1088 | if (req) { | ||
1089 | xprt_complete_rqst(req->rq_task, len); | ||
1090 | len = 0; | ||
1091 | goto out; | ||
1092 | } | ||
992 | dprintk("svc: TCP complete record (%d bytes)\n", len); | 1093 | dprintk("svc: TCP complete record (%d bytes)\n", len); |
993 | rqstp->rq_arg.len = len; | 1094 | rqstp->rq_arg.len = len; |
994 | rqstp->rq_arg.page_base = 0; | 1095 | rqstp->rq_arg.page_base = 0; |
@@ -1002,6 +1103,7 @@ static int svc_tcp_recvfrom(struct svc_rqst *rqstp) | |||
1002 | rqstp->rq_xprt_ctxt = NULL; | 1103 | rqstp->rq_xprt_ctxt = NULL; |
1003 | rqstp->rq_prot = IPPROTO_TCP; | 1104 | rqstp->rq_prot = IPPROTO_TCP; |
1004 | 1105 | ||
1106 | out: | ||
1005 | /* Reset TCP read info */ | 1107 | /* Reset TCP read info */ |
1006 | svsk->sk_reclen = 0; | 1108 | svsk->sk_reclen = 0; |
1007 | svsk->sk_tcplen = 0; | 1109 | svsk->sk_tcplen = 0; |
diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index f412a852bc73..fd46d42afa89 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c | |||
@@ -832,6 +832,11 @@ static void xprt_timer(struct rpc_task *task) | |||
832 | spin_unlock_bh(&xprt->transport_lock); | 832 | spin_unlock_bh(&xprt->transport_lock); |
833 | } | 833 | } |
834 | 834 | ||
835 | static inline int xprt_has_timer(struct rpc_xprt *xprt) | ||
836 | { | ||
837 | return xprt->idle_timeout != 0; | ||
838 | } | ||
839 | |||
835 | /** | 840 | /** |
836 | * xprt_prepare_transmit - reserve the transport before sending a request | 841 | * xprt_prepare_transmit - reserve the transport before sending a request |
837 | * @task: RPC task about to send a request | 842 | * @task: RPC task about to send a request |
@@ -1013,7 +1018,7 @@ void xprt_release(struct rpc_task *task) | |||
1013 | if (!list_empty(&req->rq_list)) | 1018 | if (!list_empty(&req->rq_list)) |
1014 | list_del(&req->rq_list); | 1019 | list_del(&req->rq_list); |
1015 | xprt->last_used = jiffies; | 1020 | xprt->last_used = jiffies; |
1016 | if (list_empty(&xprt->recv)) | 1021 | if (list_empty(&xprt->recv) && xprt_has_timer(xprt)) |
1017 | mod_timer(&xprt->timer, | 1022 | mod_timer(&xprt->timer, |
1018 | xprt->last_used + xprt->idle_timeout); | 1023 | xprt->last_used + xprt->idle_timeout); |
1019 | spin_unlock_bh(&xprt->transport_lock); | 1024 | spin_unlock_bh(&xprt->transport_lock); |
@@ -1082,8 +1087,11 @@ found: | |||
1082 | #endif /* CONFIG_NFS_V4_1 */ | 1087 | #endif /* CONFIG_NFS_V4_1 */ |
1083 | 1088 | ||
1084 | INIT_WORK(&xprt->task_cleanup, xprt_autoclose); | 1089 | INIT_WORK(&xprt->task_cleanup, xprt_autoclose); |
1085 | setup_timer(&xprt->timer, xprt_init_autodisconnect, | 1090 | if (xprt_has_timer(xprt)) |
1086 | (unsigned long)xprt); | 1091 | setup_timer(&xprt->timer, xprt_init_autodisconnect, |
1092 | (unsigned long)xprt); | ||
1093 | else | ||
1094 | init_timer(&xprt->timer); | ||
1087 | xprt->last_used = jiffies; | 1095 | xprt->last_used = jiffies; |
1088 | xprt->cwnd = RPC_INITCWND; | 1096 | xprt->cwnd = RPC_INITCWND; |
1089 | xprt->bind_index = 0; | 1097 | xprt->bind_index = 0; |
@@ -1102,7 +1110,6 @@ found: | |||
1102 | 1110 | ||
1103 | dprintk("RPC: created transport %p with %u slots\n", xprt, | 1111 | dprintk("RPC: created transport %p with %u slots\n", xprt, |
1104 | xprt->max_reqs); | 1112 | xprt->max_reqs); |
1105 | |||
1106 | return xprt; | 1113 | return xprt; |
1107 | } | 1114 | } |
1108 | 1115 | ||
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 62438f3a914d..d9a2b815714e 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c | |||
@@ -32,6 +32,7 @@ | |||
32 | #include <linux/tcp.h> | 32 | #include <linux/tcp.h> |
33 | #include <linux/sunrpc/clnt.h> | 33 | #include <linux/sunrpc/clnt.h> |
34 | #include <linux/sunrpc/sched.h> | 34 | #include <linux/sunrpc/sched.h> |
35 | #include <linux/sunrpc/svcsock.h> | ||
35 | #include <linux/sunrpc/xprtsock.h> | 36 | #include <linux/sunrpc/xprtsock.h> |
36 | #include <linux/file.h> | 37 | #include <linux/file.h> |
37 | #ifdef CONFIG_NFS_V4_1 | 38 | #ifdef CONFIG_NFS_V4_1 |
@@ -43,6 +44,7 @@ | |||
43 | #include <net/udp.h> | 44 | #include <net/udp.h> |
44 | #include <net/tcp.h> | 45 | #include <net/tcp.h> |
45 | 46 | ||
47 | #include "sunrpc.h" | ||
46 | /* | 48 | /* |
47 | * xprtsock tunables | 49 | * xprtsock tunables |
48 | */ | 50 | */ |
@@ -2098,6 +2100,134 @@ static void xs_tcp_print_stats(struct rpc_xprt *xprt, struct seq_file *seq) | |||
2098 | xprt->stat.bklog_u); | 2100 | xprt->stat.bklog_u); |
2099 | } | 2101 | } |
2100 | 2102 | ||
2103 | /* | ||
2104 | * Allocate a bunch of pages for a scratch buffer for the rpc code. The reason | ||
2105 | * we allocate pages instead doing a kmalloc like rpc_malloc is because we want | ||
2106 | * to use the server side send routines. | ||
2107 | */ | ||
2108 | void *bc_malloc(struct rpc_task *task, size_t size) | ||
2109 | { | ||
2110 | struct page *page; | ||
2111 | struct rpc_buffer *buf; | ||
2112 | |||
2113 | BUG_ON(size > PAGE_SIZE - sizeof(struct rpc_buffer)); | ||
2114 | page = alloc_page(GFP_KERNEL); | ||
2115 | |||
2116 | if (!page) | ||
2117 | return NULL; | ||
2118 | |||
2119 | buf = page_address(page); | ||
2120 | buf->len = PAGE_SIZE; | ||
2121 | |||
2122 | return buf->data; | ||
2123 | } | ||
2124 | |||
2125 | /* | ||
2126 | * Free the space allocated in the bc_alloc routine | ||
2127 | */ | ||
2128 | void bc_free(void *buffer) | ||
2129 | { | ||
2130 | struct rpc_buffer *buf; | ||
2131 | |||
2132 | if (!buffer) | ||
2133 | return; | ||
2134 | |||
2135 | buf = container_of(buffer, struct rpc_buffer, data); | ||
2136 | free_page((unsigned long)buf); | ||
2137 | } | ||
2138 | |||
2139 | /* | ||
2140 | * Use the svc_sock to send the callback. Must be called with svsk->sk_mutex | ||
2141 | * held. Borrows heavily from svc_tcp_sendto and xs_tcp_send_request. | ||
2142 | */ | ||
2143 | static int bc_sendto(struct rpc_rqst *req) | ||
2144 | { | ||
2145 | int len; | ||
2146 | struct xdr_buf *xbufp = &req->rq_snd_buf; | ||
2147 | struct rpc_xprt *xprt = req->rq_xprt; | ||
2148 | struct sock_xprt *transport = | ||
2149 | container_of(xprt, struct sock_xprt, xprt); | ||
2150 | struct socket *sock = transport->sock; | ||
2151 | unsigned long headoff; | ||
2152 | unsigned long tailoff; | ||
2153 | |||
2154 | /* | ||
2155 | * Set up the rpc header and record marker stuff | ||
2156 | */ | ||
2157 | xs_encode_tcp_record_marker(xbufp); | ||
2158 | |||
2159 | tailoff = (unsigned long)xbufp->tail[0].iov_base & ~PAGE_MASK; | ||
2160 | headoff = (unsigned long)xbufp->head[0].iov_base & ~PAGE_MASK; | ||
2161 | len = svc_send_common(sock, xbufp, | ||
2162 | virt_to_page(xbufp->head[0].iov_base), headoff, | ||
2163 | xbufp->tail[0].iov_base, tailoff); | ||
2164 | |||
2165 | if (len != xbufp->len) { | ||
2166 | printk(KERN_NOTICE "Error sending entire callback!\n"); | ||
2167 | len = -EAGAIN; | ||
2168 | } | ||
2169 | |||
2170 | return len; | ||
2171 | } | ||
2172 | |||
2173 | /* | ||
2174 | * The send routine. Borrows from svc_send | ||
2175 | */ | ||
2176 | static int bc_send_request(struct rpc_task *task) | ||
2177 | { | ||
2178 | struct rpc_rqst *req = task->tk_rqstp; | ||
2179 | struct svc_xprt *xprt; | ||
2180 | struct svc_sock *svsk; | ||
2181 | u32 len; | ||
2182 | |||
2183 | dprintk("sending request with xid: %08x\n", ntohl(req->rq_xid)); | ||
2184 | /* | ||
2185 | * Get the server socket associated with this callback xprt | ||
2186 | */ | ||
2187 | xprt = req->rq_xprt->bc_xprt; | ||
2188 | svsk = container_of(xprt, struct svc_sock, sk_xprt); | ||
2189 | |||
2190 | /* | ||
2191 | * Grab the mutex to serialize data as the connection is shared | ||
2192 | * with the fore channel | ||
2193 | */ | ||
2194 | if (!mutex_trylock(&xprt->xpt_mutex)) { | ||
2195 | rpc_sleep_on(&xprt->xpt_bc_pending, task, NULL); | ||
2196 | if (!mutex_trylock(&xprt->xpt_mutex)) | ||
2197 | return -EAGAIN; | ||
2198 | rpc_wake_up_queued_task(&xprt->xpt_bc_pending, task); | ||
2199 | } | ||
2200 | if (test_bit(XPT_DEAD, &xprt->xpt_flags)) | ||
2201 | len = -ENOTCONN; | ||
2202 | else | ||
2203 | len = bc_sendto(req); | ||
2204 | mutex_unlock(&xprt->xpt_mutex); | ||
2205 | |||
2206 | if (len > 0) | ||
2207 | len = 0; | ||
2208 | |||
2209 | return len; | ||
2210 | } | ||
2211 | |||
2212 | /* | ||
2213 | * The close routine. Since this is client initiated, we do nothing | ||
2214 | */ | ||
2215 | |||
2216 | static void bc_close(struct rpc_xprt *xprt) | ||
2217 | { | ||
2218 | return; | ||
2219 | } | ||
2220 | |||
2221 | /* | ||
2222 | * The xprt destroy routine. Again, because this connection is client | ||
2223 | * initiated, we do nothing | ||
2224 | */ | ||
2225 | |||
2226 | static void bc_destroy(struct rpc_xprt *xprt) | ||
2227 | { | ||
2228 | return; | ||
2229 | } | ||
2230 | |||
2101 | static struct rpc_xprt_ops xs_udp_ops = { | 2231 | static struct rpc_xprt_ops xs_udp_ops = { |
2102 | .set_buffer_size = xs_udp_set_buffer_size, | 2232 | .set_buffer_size = xs_udp_set_buffer_size, |
2103 | .reserve_xprt = xprt_reserve_xprt_cong, | 2233 | .reserve_xprt = xprt_reserve_xprt_cong, |
@@ -2134,6 +2264,22 @@ static struct rpc_xprt_ops xs_tcp_ops = { | |||
2134 | .print_stats = xs_tcp_print_stats, | 2264 | .print_stats = xs_tcp_print_stats, |
2135 | }; | 2265 | }; |
2136 | 2266 | ||
2267 | /* | ||
2268 | * The rpc_xprt_ops for the server backchannel | ||
2269 | */ | ||
2270 | |||
2271 | static struct rpc_xprt_ops bc_tcp_ops = { | ||
2272 | .reserve_xprt = xprt_reserve_xprt, | ||
2273 | .release_xprt = xprt_release_xprt, | ||
2274 | .buf_alloc = bc_malloc, | ||
2275 | .buf_free = bc_free, | ||
2276 | .send_request = bc_send_request, | ||
2277 | .set_retrans_timeout = xprt_set_retrans_timeout_def, | ||
2278 | .close = bc_close, | ||
2279 | .destroy = bc_destroy, | ||
2280 | .print_stats = xs_tcp_print_stats, | ||
2281 | }; | ||
2282 | |||
2137 | static struct rpc_xprt *xs_setup_xprt(struct xprt_create *args, | 2283 | static struct rpc_xprt *xs_setup_xprt(struct xprt_create *args, |
2138 | unsigned int slot_table_size) | 2284 | unsigned int slot_table_size) |
2139 | { | 2285 | { |