aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRahul Iyer <iyer@netapp.com>2009-09-10 10:32:28 -0400
committerJ. Bruce Fields <bfields@citi.umich.edu>2009-09-11 15:04:16 -0400
commit4cfc7e6019caa3e97d2a81c48c8d575d7b38d751 (patch)
tree8dced61360d385b115da94f9a4fd5f8d635c296d
parent6951867b9967066eda090f46ad91ce69e0ead611 (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>
-rw-r--r--include/linux/sunrpc/svc_xprt.h1
-rw-r--r--include/linux/sunrpc/svcsock.h1
-rw-r--r--include/linux/sunrpc/xprt.h1
-rw-r--r--net/sunrpc/sunrpc.h4
-rw-r--r--net/sunrpc/svc_xprt.c2
-rw-r--r--net/sunrpc/svcsock.c172
-rw-r--r--net/sunrpc/xprt.c15
-rw-r--r--net/sunrpc/xprtsock.c146
8 files changed, 303 insertions, 39 deletions
diff --git a/include/linux/sunrpc/svc_xprt.h b/include/linux/sunrpc/svc_xprt.h
index 2223ae0b5ed5..5f4e18b3ce73 100644
--- a/include/linux/sunrpc/svc_xprt.h
+++ b/include/linux/sunrpc/svc_xprt.h
@@ -65,6 +65,7 @@ struct svc_xprt {
65 size_t xpt_locallen; /* length of address */ 65 size_t xpt_locallen; /* length of address */
66 struct sockaddr_storage xpt_remote; /* remote peer's address */ 66 struct sockaddr_storage xpt_remote; /* remote peer's address */
67 size_t xpt_remotelen; /* length of address */ 67 size_t xpt_remotelen; /* length of address */
68 struct rpc_wait_queue xpt_bc_pending; /* backchannel wait queue */
68}; 69};
69 70
70int svc_reg_xprt_class(struct svc_xprt_class *); 71int svc_reg_xprt_class(struct svc_xprt_class *);
diff --git a/include/linux/sunrpc/svcsock.h b/include/linux/sunrpc/svcsock.h
index 04dba23c59f2..1b353a76c304 100644
--- a/include/linux/sunrpc/svcsock.h
+++ b/include/linux/sunrpc/svcsock.h
@@ -28,6 +28,7 @@ struct svc_sock {
28 /* private TCP part */ 28 /* private TCP part */
29 u32 sk_reclen; /* length of record */ 29 u32 sk_reclen; /* length of record */
30 u32 sk_tcplen; /* current read length */ 30 u32 sk_tcplen; /* current read length */
31 struct rpc_xprt *sk_bc_xprt; /* NFSv4.1 backchannel xprt */
31}; 32};
32 33
33/* 34/*
diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h
index c090df442572..228d694dbb90 100644
--- a/include/linux/sunrpc/xprt.h
+++ b/include/linux/sunrpc/xprt.h
@@ -179,6 +179,7 @@ struct rpc_xprt {
179 spinlock_t reserve_lock; /* lock slot table */ 179 spinlock_t reserve_lock; /* lock slot table */
180 u32 xid; /* Next XID value to use */ 180 u32 xid; /* Next XID value to use */
181 struct rpc_task * snd_task; /* Task blocked in send */ 181 struct rpc_task * snd_task; /* Task blocked in send */
182 struct svc_xprt *bc_xprt; /* NFSv4.1 backchannel */
182#if defined(CONFIG_NFS_V4_1) 183#if defined(CONFIG_NFS_V4_1)
183 struct svc_serv *bc_serv; /* The RPC service which will */ 184 struct svc_serv *bc_serv; /* The RPC service which will */
184 /* process the callback */ 185 /* process the callback */
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
46int 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}
164EXPORT_SYMBOL_GPL(svc_xprt_init); 165EXPORT_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 */
158static int svc_sendto(struct svc_rqst *rqstp, struct xdr_buf *xdr) 159int 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
210out:
211 return len;
212}
213
214
215/*
216 * Generic sendto routine
217 */
218static 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
232out: 253out:
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
975static 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
1106out:
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
835static 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 */
2108void *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 */
2128void 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 */
2143static 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 */
2176static 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
2216static 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
2226static void bc_destroy(struct rpc_xprt *xprt)
2227{
2228 return;
2229}
2230
2101static struct rpc_xprt_ops xs_udp_ops = { 2231static 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
2271static 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
2137static struct rpc_xprt *xs_setup_xprt(struct xprt_create *args, 2283static struct rpc_xprt *xs_setup_xprt(struct xprt_create *args,
2138 unsigned int slot_table_size) 2284 unsigned int slot_table_size)
2139{ 2285{