Blame view

net/sunrpc/svcsock.c 42.5 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
  /*
   * linux/net/sunrpc/svcsock.c
   *
   * These are the RPC server socket internals.
   *
   * The server scheduling algorithm does not always distribute the load
   * evenly when servicing a single client. May need to modify the
f6150c3ca   Tom Tucker   svc: Make the enq...
8
   * svc_xprt_enqueue procedure...
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
9
10
11
12
13
14
15
16
17
18
19
20
   *
   * TCP support is largely untested and may be a little slow. The problem
   * is that we currently do two separate recvfrom's, one for the 4-byte
   * record length, and the second for the actual record. This could possibly
   * be improved by always reading a minimum size of around 100 bytes and
   * tucking any superfluous bytes away in a temporary store. Still, that
   * leaves write requests out in the rain. An alternative may be to peek at
   * the first skb in the queue, and if it matches the next TCP sequence
   * number, to extract the record marker. Yuck.
   *
   * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
   */
172589ccd   Ilpo Järvinen   [NET]: DIV_ROUND_...
21
  #include <linux/kernel.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
22
  #include <linux/sched.h>
3a9a231d9   Paul Gortmaker   net: Fix files ex...
23
  #include <linux/module.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
24
25
26
27
28
29
  #include <linux/errno.h>
  #include <linux/fcntl.h>
  #include <linux/net.h>
  #include <linux/in.h>
  #include <linux/inet.h>
  #include <linux/udp.h>
91483c4b7   Andrew Morton   [SUNRPC]: svcsock...
30
  #include <linux/tcp.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
31
32
33
34
  #include <linux/unistd.h>
  #include <linux/slab.h>
  #include <linux/netdevice.h>
  #include <linux/skbuff.h>
b41b66d63   NeilBrown   [PATCH] knfsd: al...
35
  #include <linux/file.h>
7dfb71030   Nigel Cunningham   [PATCH] Add inclu...
36
  #include <linux/freezer.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
37
38
39
  #include <net/sock.h>
  #include <net/checksum.h>
  #include <net/ip.h>
b92503b25   Chuck Lever   [PATCH] knfsd: SU...
40
  #include <net/ipv6.h>
b7872fe86   Chuck Lever   SUNRPC: RPC serve...
41
  #include <net/tcp.h>
c752f0739   Arnaldo Carvalho de Melo   [TCP]: Move the t...
42
  #include <net/tcp_states.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
43
44
  #include <asm/uaccess.h>
  #include <asm/ioctls.h>
22911fc58   Eric Dumazet   net: skb_free_dat...
45
  #include <trace/events/skb.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
46
47
  
  #include <linux/sunrpc/types.h>
ad06e4bd6   Chuck Lever   [PATCH] knfsd: SU...
48
  #include <linux/sunrpc/clnt.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
49
  #include <linux/sunrpc/xdr.h>
c0401ea00   Chuck Lever   SUNRPC: Update RP...
50
  #include <linux/sunrpc/msg_prot.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
51
52
  #include <linux/sunrpc/svcsock.h>
  #include <linux/sunrpc/stats.h>
4cfc7e601   Rahul Iyer   nfsd41: sunrpc: A...
53
  #include <linux/sunrpc/xprt.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
54

177e4f998   H Hartley Sweeten   svcsock.c: includ...
55
  #include "sunrpc.h"
360d87386   Tom Tucker   svc: Make svc_soc...
56
  #define RPCDBG_FACILITY	RPCDBG_SVCXPRT
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
57
58
59
  
  
  static struct svc_sock *svc_setup_socket(struct svc_serv *, struct socket *,
72c353760   J. Bruce Fields   svcrpc: standardi...
60
  					 int flags);
676d23690   David S. Miller   net: Fix use afte...
61
  static void		svc_udp_data_ready(struct sock *);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
62
63
  static int		svc_udp_recvfrom(struct svc_rqst *);
  static int		svc_udp_sendto(struct svc_rqst *);
755cceaba   Tom Tucker   svc: Add per-tran...
64
  static void		svc_sock_detach(struct svc_xprt *);
69b6ba371   Trond Myklebust   SUNRPC: Ensure th...
65
  static void		svc_tcp_sock_detach(struct svc_xprt *);
755cceaba   Tom Tucker   svc: Add per-tran...
66
  static void		svc_sock_free(struct svc_xprt *);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
67

b700cbb11   Tom Tucker   svc: Add a generi...
68
  static struct svc_xprt *svc_create_socket(struct svc_serv *, int,
62832c039   Pavel Emelyanov   sunrpc: Pull net ...
69
70
  					  struct net *, struct sockaddr *,
  					  int, int);
9e00abc3c   Trond Myklebust   SUNRPC: sunrpc sh...
71
  #if defined(CONFIG_SUNRPC_BACKCHANNEL)
1f11a034c   Andy Adamson   SUNRPC new transp...
72
73
74
75
  static struct svc_xprt *svc_bc_create_socket(struct svc_serv *, int,
  					     struct net *, struct sockaddr *,
  					     int, int);
  static void svc_bc_sock_free(struct svc_xprt *xprt);
9e00abc3c   Trond Myklebust   SUNRPC: sunrpc sh...
76
  #endif /* CONFIG_SUNRPC_BACKCHANNEL */
1f11a034c   Andy Adamson   SUNRPC new transp...
77

ed07536ed   Peter Zijlstra   [PATCH] lockdep: ...
78
79
80
  #ifdef CONFIG_DEBUG_LOCK_ALLOC
  static struct lock_class_key svc_key[2];
  static struct lock_class_key svc_slock_key[2];
0f0257eaa   Tom Tucker   svc: Move the xpr...
81
  static void svc_reclassify_socket(struct socket *sock)
ed07536ed   Peter Zijlstra   [PATCH] lockdep: ...
82
83
  {
  	struct sock *sk = sock->sk;
1b7a18190   Weston Andros Adamson   SUNRPC: remove BU...
84
85
86
87
  
  	WARN_ON_ONCE(sock_owned_by_user(sk));
  	if (sock_owned_by_user(sk))
  		return;
ed07536ed   Peter Zijlstra   [PATCH] lockdep: ...
88
89
90
  	switch (sk->sk_family) {
  	case AF_INET:
  		sock_lock_init_class_and_name(sk, "slock-AF_INET-NFSD",
def13d740   Tom Tucker   svc: Move the aut...
91
92
93
  					      &svc_slock_key[0],
  					      "sk_xprt.xpt_lock-AF_INET-NFSD",
  					      &svc_key[0]);
ed07536ed   Peter Zijlstra   [PATCH] lockdep: ...
94
95
96
97
  		break;
  
  	case AF_INET6:
  		sock_lock_init_class_and_name(sk, "slock-AF_INET6-NFSD",
def13d740   Tom Tucker   svc: Move the aut...
98
99
100
  					      &svc_slock_key[1],
  					      "sk_xprt.xpt_lock-AF_INET6-NFSD",
  					      &svc_key[1]);
ed07536ed   Peter Zijlstra   [PATCH] lockdep: ...
101
102
103
104
105
106
107
  		break;
  
  	default:
  		BUG();
  	}
  }
  #else
0f0257eaa   Tom Tucker   svc: Move the xpr...
108
  static void svc_reclassify_socket(struct socket *sock)
ed07536ed   Peter Zijlstra   [PATCH] lockdep: ...
109
110
111
  {
  }
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
112
113
114
  /*
   * Release an skbuff after use
   */
5148bf4eb   Tom Tucker   svc: Add transpor...
115
  static void svc_release_skb(struct svc_rqst *rqstp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
116
  {
5148bf4eb   Tom Tucker   svc: Add transpor...
117
  	struct sk_buff *skb = rqstp->rq_xprt_ctxt;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
118
119
  
  	if (skb) {
57b1d3bab   Tom Tucker   svc: Removing rem...
120
121
  		struct svc_sock *svsk =
  			container_of(rqstp->rq_xprt, struct svc_sock, sk_xprt);
5148bf4eb   Tom Tucker   svc: Add transpor...
122
  		rqstp->rq_xprt_ctxt = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
123
124
125
  
  		dprintk("svc: service %p, releasing skb %p
  ", rqstp, skb);
9d410c796   Eric Dumazet   net: fix sk_forwa...
126
  		skb_free_datagram_locked(svsk->sk_sk, skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
127
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
128
  }
b92503b25   Chuck Lever   [PATCH] knfsd: SU...
129
130
  union svc_pktinfo_u {
  	struct in_pktinfo pkti;
b92503b25   Chuck Lever   [PATCH] knfsd: SU...
131
  	struct in6_pktinfo pkti6;
b92503b25   Chuck Lever   [PATCH] knfsd: SU...
132
  };
bc375ea7e   David S. Miller   [SUNRPC]: Make su...
133
134
  #define SVC_PKTINFO_SPACE \
  	CMSG_SPACE(sizeof(union svc_pktinfo_u))
b92503b25   Chuck Lever   [PATCH] knfsd: SU...
135
136
137
  
  static void svc_set_cmsg_data(struct svc_rqst *rqstp, struct cmsghdr *cmh)
  {
57b1d3bab   Tom Tucker   svc: Removing rem...
138
139
140
  	struct svc_sock *svsk =
  		container_of(rqstp->rq_xprt, struct svc_sock, sk_xprt);
  	switch (svsk->sk_sk->sk_family) {
b92503b25   Chuck Lever   [PATCH] knfsd: SU...
141
142
143
144
145
146
  	case AF_INET: {
  			struct in_pktinfo *pki = CMSG_DATA(cmh);
  
  			cmh->cmsg_level = SOL_IP;
  			cmh->cmsg_type = IP_PKTINFO;
  			pki->ipi_ifindex = 0;
849a1cf13   Mi Jinlong   SUNRPC: Replace s...
147
148
  			pki->ipi_spec_dst.s_addr =
  				 svc_daddr_in(rqstp)->sin_addr.s_addr;
b92503b25   Chuck Lever   [PATCH] knfsd: SU...
149
150
151
  			cmh->cmsg_len = CMSG_LEN(sizeof(*pki));
  		}
  		break;
5a05ed73e   NeilBrown   [PATCH] knfsd: re...
152

b92503b25   Chuck Lever   [PATCH] knfsd: SU...
153
154
  	case AF_INET6: {
  			struct in6_pktinfo *pki = CMSG_DATA(cmh);
849a1cf13   Mi Jinlong   SUNRPC: Replace s...
155
  			struct sockaddr_in6 *daddr = svc_daddr_in6(rqstp);
b92503b25   Chuck Lever   [PATCH] knfsd: SU...
156
157
158
  
  			cmh->cmsg_level = SOL_IPV6;
  			cmh->cmsg_type = IPV6_PKTINFO;
849a1cf13   Mi Jinlong   SUNRPC: Replace s...
159
  			pki->ipi6_ifindex = daddr->sin6_scope_id;
4e3fd7a06   Alexey Dobriyan   net: remove ipv6_...
160
  			pki->ipi6_addr = daddr->sin6_addr;
b92503b25   Chuck Lever   [PATCH] knfsd: SU...
161
162
163
  			cmh->cmsg_len = CMSG_LEN(sizeof(*pki));
  		}
  		break;
b92503b25   Chuck Lever   [PATCH] knfsd: SU...
164
  	}
b92503b25   Chuck Lever   [PATCH] knfsd: SU...
165
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
166
  /*
4cfc7e601   Rahul Iyer   nfsd41: sunrpc: A...
167
   * send routine intended to be shared by the fore- and back-channel
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
168
   */
4cfc7e601   Rahul Iyer   nfsd41: sunrpc: A...
169
170
171
  int svc_send_common(struct socket *sock, struct xdr_buf *xdr,
  		    struct page *headpage, unsigned long headoffset,
  		    struct page *tailpage, unsigned long tailoffset)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
172
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
173
174
175
176
177
178
  	int		result;
  	int		size;
  	struct page	**ppage = xdr->pages;
  	size_t		base = xdr->page_base;
  	unsigned int	pglen = xdr->page_len;
  	unsigned int	flags = MSG_MORE;
4cfc7e601   Rahul Iyer   nfsd41: sunrpc: A...
179
180
  	int		slen;
  	int		len = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
181
182
  
  	slen = xdr->len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
183
184
185
  	/* send head */
  	if (slen == xdr->head[0].iov_len)
  		flags = 0;
4cfc7e601   Rahul Iyer   nfsd41: sunrpc: A...
186
  	len = kernel_sendpage(sock, headpage, headoffset,
445243594   NeilBrown   [PATCH] knfsd: Re...
187
  				  xdr->head[0].iov_len, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
188
189
190
191
192
193
194
195
196
197
198
  	if (len != xdr->head[0].iov_len)
  		goto out;
  	slen -= xdr->head[0].iov_len;
  	if (slen == 0)
  		goto out;
  
  	/* send page data */
  	size = PAGE_SIZE - base < pglen ? PAGE_SIZE - base : pglen;
  	while (pglen > 0) {
  		if (slen == size)
  			flags = 0;
e6242e928   Sridhar Samudrala   [SUNRPC]: Update ...
199
  		result = kernel_sendpage(sock, *ppage, base, size, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
200
201
202
203
204
205
206
207
208
209
  		if (result > 0)
  			len += result;
  		if (result != size)
  			goto out;
  		slen -= size;
  		pglen -= size;
  		size = PAGE_SIZE < pglen ? PAGE_SIZE : pglen;
  		base = 0;
  		ppage++;
  	}
4cfc7e601   Rahul Iyer   nfsd41: sunrpc: A...
210

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
211
212
  	/* send tail */
  	if (xdr->tail[0].iov_len) {
4cfc7e601   Rahul Iyer   nfsd41: sunrpc: A...
213
214
  		result = kernel_sendpage(sock, tailpage, tailoffset,
  				   xdr->tail[0].iov_len, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
215
216
217
  		if (result > 0)
  			len += result;
  	}
4cfc7e601   Rahul Iyer   nfsd41: sunrpc: A...
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
  
  out:
  	return len;
  }
  
  
  /*
   * Generic sendto routine
   */
  static int svc_sendto(struct svc_rqst *rqstp, struct xdr_buf *xdr)
  {
  	struct svc_sock	*svsk =
  		container_of(rqstp->rq_xprt, struct svc_sock, sk_xprt);
  	struct socket	*sock = svsk->sk_sock;
  	union {
  		struct cmsghdr	hdr;
  		long		all[SVC_PKTINFO_SPACE / sizeof(long)];
  	} buffer;
  	struct cmsghdr *cmh = &buffer.hdr;
  	int		len = 0;
  	unsigned long tailoff;
  	unsigned long headoff;
  	RPC_IFDEBUG(char buf[RPC_MAX_ADDRBUFLEN]);
  
  	if (rqstp->rq_prot == IPPROTO_UDP) {
  		struct msghdr msg = {
  			.msg_name	= &rqstp->rq_addr,
  			.msg_namelen	= rqstp->rq_addrlen,
  			.msg_control	= cmh,
  			.msg_controllen	= sizeof(buffer),
  			.msg_flags	= MSG_MORE,
  		};
  
  		svc_set_cmsg_data(rqstp, cmh);
  
  		if (sock_sendmsg(sock, &msg, 0) < 0)
  			goto out;
  	}
  
  	tailoff = ((unsigned long)xdr->tail[0].iov_base) & (PAGE_SIZE-1);
  	headoff = 0;
  	len = svc_send_common(sock, xdr, rqstp->rq_respages[0], headoff,
  			       rqstp->rq_respages[0], tailoff);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
261
  out:
ad06e4bd6   Chuck Lever   [PATCH] knfsd: SU...
262
263
  	dprintk("svc: socket %p sendto([%p %Zu... ], %d) = %d (addr %s)
  ",
57b1d3bab   Tom Tucker   svc: Removing rem...
264
  		svsk, xdr->head[0].iov_base, xdr->head[0].iov_len,
ad06e4bd6   Chuck Lever   [PATCH] knfsd: SU...
265
  		xdr->len, len, svc_print_addr(rqstp, buf, sizeof(buf)));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
266
267
268
269
270
  
  	return len;
  }
  
  /*
80212d59e   NeilBrown   [PATCH] knfsd: de...
271
272
   * Report socket names for nfsdfs
   */
e7942b9f2   Chuck Lever   SUNRPC: Switch on...
273
  static int svc_one_sock_name(struct svc_sock *svsk, char *buf, int remaining)
80212d59e   NeilBrown   [PATCH] knfsd: de...
274
  {
017cb47f4   Chuck Lever   SUNRPC: Clean up ...
275
276
277
  	const struct sock *sk = svsk->sk_sk;
  	const char *proto_name = sk->sk_protocol == IPPROTO_UDP ?
  							"udp" : "tcp";
80212d59e   NeilBrown   [PATCH] knfsd: de...
278
  	int len;
017cb47f4   Chuck Lever   SUNRPC: Clean up ...
279
  	switch (sk->sk_family) {
e7942b9f2   Chuck Lever   SUNRPC: Switch on...
280
281
282
  	case PF_INET:
  		len = snprintf(buf, remaining, "ipv4 %s %pI4 %d
  ",
017cb47f4   Chuck Lever   SUNRPC: Clean up ...
283
  				proto_name,
c720c7e83   Eric Dumazet   inet: rename some...
284
285
  				&inet_sk(sk)->inet_rcv_saddr,
  				inet_sk(sk)->inet_num);
80212d59e   NeilBrown   [PATCH] knfsd: de...
286
  		break;
c2bb06db5   Eric Dumazet   net: fix build er...
287
  #if IS_ENABLED(CONFIG_IPV6)
58de2f865   Chuck Lever   SUNRPC: Support P...
288
289
290
  	case PF_INET6:
  		len = snprintf(buf, remaining, "ipv6 %s %pI6 %d
  ",
017cb47f4   Chuck Lever   SUNRPC: Clean up ...
291
  				proto_name,
efe4208f4   Eric Dumazet   ipv6: make lookup...
292
  				&sk->sk_v6_rcv_saddr,
c720c7e83   Eric Dumazet   inet: rename some...
293
  				inet_sk(sk)->inet_num);
80212d59e   NeilBrown   [PATCH] knfsd: de...
294
  		break;
c2bb06db5   Eric Dumazet   net: fix build er...
295
  #endif
80212d59e   NeilBrown   [PATCH] knfsd: de...
296
  	default:
e7942b9f2   Chuck Lever   SUNRPC: Switch on...
297
298
  		len = snprintf(buf, remaining, "*unknown-%d*
  ",
017cb47f4   Chuck Lever   SUNRPC: Clean up ...
299
  				sk->sk_family);
80212d59e   NeilBrown   [PATCH] knfsd: de...
300
  	}
e7942b9f2   Chuck Lever   SUNRPC: Switch on...
301
302
303
304
  
  	if (len >= remaining) {
  		*buf = '\0';
  		return -ENAMETOOLONG;
80212d59e   NeilBrown   [PATCH] knfsd: de...
305
306
307
  	}
  	return len;
  }
80212d59e   NeilBrown   [PATCH] knfsd: de...
308
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
309
310
   * Generic recvfrom routine.
   */
0f0257eaa   Tom Tucker   svc: Move the xpr...
311
312
  static int svc_recvfrom(struct svc_rqst *rqstp, struct kvec *iov, int nr,
  			int buflen)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
313
  {
57b1d3bab   Tom Tucker   svc: Removing rem...
314
315
  	struct svc_sock *svsk =
  		container_of(rqstp->rq_xprt, struct svc_sock, sk_xprt);
1ba951053   Chuck Lever   [PATCH] knfsd: SU...
316
317
318
319
  	struct msghdr msg = {
  		.msg_flags	= MSG_DONTWAIT,
  	};
  	int len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
320

260c1d129   Tom Tucker   svc: Add transpor...
321
  	rqstp->rq_xprt_hlen = 0;
f8d1ff47b   Trond Myklebust   SUNRPC: Optimise ...
322
  	clear_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags);
1ba951053   Chuck Lever   [PATCH] knfsd: SU...
323
324
  	len = kernel_recvmsg(svsk->sk_sock, &msg, iov, nr, buflen,
  				msg.msg_flags);
f8d1ff47b   Trond Myklebust   SUNRPC: Optimise ...
325
326
327
328
329
  	/* If we read a full record, then assume there may be more
  	 * data to read (stream based sockets only!)
  	 */
  	if (len == buflen)
  		set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
330

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
331
332
  	dprintk("svc: socket %p recvfrom(%p, %Zu) = %d
  ",
1ba951053   Chuck Lever   [PATCH] knfsd: SU...
333
  		svsk, iov[0].iov_base, iov[0].iov_len, len);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
334
335
  	return len;
  }
31d68ef65   J. Bruce Fields   SUNRPC: Don't wai...
336
337
338
339
340
  static int svc_partial_recvfrom(struct svc_rqst *rqstp,
  				struct kvec *iov, int nr,
  				int buflen, unsigned int base)
  {
  	size_t save_iovlen;
09acfea5d   Trond Myklebust   SUNRPC: Fix a few...
341
  	void *save_iovbase;
31d68ef65   J. Bruce Fields   SUNRPC: Don't wai...
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
  	unsigned int i;
  	int ret;
  
  	if (base == 0)
  		return svc_recvfrom(rqstp, iov, nr, buflen);
  
  	for (i = 0; i < nr; i++) {
  		if (iov[i].iov_len > base)
  			break;
  		base -= iov[i].iov_len;
  	}
  	save_iovlen = iov[i].iov_len;
  	save_iovbase = iov[i].iov_base;
  	iov[i].iov_len -= base;
  	iov[i].iov_base += base;
  	ret = svc_recvfrom(rqstp, &iov[i], nr - i, buflen);
  	iov[i].iov_len = save_iovlen;
  	iov[i].iov_base = save_iovbase;
  	return ret;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
362
363
364
  /*
   * Set socket snd and rcv buffer lengths
   */
0f0257eaa   Tom Tucker   svc: Move the xpr...
365
366
  static void svc_sock_setbufsize(struct socket *sock, unsigned int snd,
  				unsigned int rcv)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
  {
  #if 0
  	mm_segment_t	oldfs;
  	oldfs = get_fs(); set_fs(KERNEL_DS);
  	sock_setsockopt(sock, SOL_SOCKET, SO_SNDBUF,
  			(char*)&snd, sizeof(snd));
  	sock_setsockopt(sock, SOL_SOCKET, SO_RCVBUF,
  			(char*)&rcv, sizeof(rcv));
  #else
  	/* sock_setsockopt limits use to sysctl_?mem_max,
  	 * which isn't acceptable.  Until that is made conditional
  	 * on not having CAP_SYS_RESOURCE or similar, we go direct...
  	 * DaveM said I could!
  	 */
  	lock_sock(sock->sk);
  	sock->sk->sk_sndbuf = snd * 2;
  	sock->sk->sk_rcvbuf = rcv * 2;
47fcb03fe   Trond Myklebust   SUNRPC: Fix the T...
384
  	sock->sk->sk_write_space(sock->sk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
385
386
387
  	release_sock(sock->sk);
  #endif
  }
16e4d93f6   Chuck Lever   NFSD: Ignore clie...
388
389
390
391
392
  
  static int svc_sock_secure_port(struct svc_rqst *rqstp)
  {
  	return svc_port_is_privileged(svc_addr(rqstp));
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
393
394
395
  /*
   * INET callback when data has been received on the socket.
   */
676d23690   David S. Miller   net: Fix use afte...
396
  static void svc_udp_data_ready(struct sock *sk)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
397
  {
939bb7ef9   Neil Brown   [PATCH] Code clea...
398
  	struct svc_sock	*svsk = (struct svc_sock *)sk->sk_user_data;
eaefd1105   Eric Dumazet   net: add __rcu an...
399
  	wait_queue_head_t *wq = sk_sleep(sk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
400

939bb7ef9   Neil Brown   [PATCH] Code clea...
401
  	if (svsk) {
676d23690   David S. Miller   net: Fix use afte...
402
403
404
  		dprintk("svc: socket %p(inet %p), busy=%d
  ",
  			svsk, sk,
02fc6c361   Tom Tucker   svc: Move sk_flag...
405
406
  			test_bit(XPT_BUSY, &svsk->sk_xprt.xpt_flags));
  		set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags);
f6150c3ca   Tom Tucker   svc: Make the enq...
407
  		svc_xprt_enqueue(&svsk->sk_xprt);
939bb7ef9   Neil Brown   [PATCH] Code clea...
408
  	}
eaefd1105   Eric Dumazet   net: add __rcu an...
409
410
  	if (wq && waitqueue_active(wq))
  		wake_up_interruptible(wq);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
411
412
413
414
415
  }
  
  /*
   * INET callback when space is newly available on the socket.
   */
0f0257eaa   Tom Tucker   svc: Move the xpr...
416
  static void svc_write_space(struct sock *sk)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
417
418
  {
  	struct svc_sock	*svsk = (struct svc_sock *)(sk->sk_user_data);
eaefd1105   Eric Dumazet   net: add __rcu an...
419
  	wait_queue_head_t *wq = sk_sleep(sk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
420
421
422
423
  
  	if (svsk) {
  		dprintk("svc: socket %p(inet %p), write_space busy=%d
  ",
02fc6c361   Tom Tucker   svc: Move sk_flag...
424
  			svsk, sk, test_bit(XPT_BUSY, &svsk->sk_xprt.xpt_flags));
f6150c3ca   Tom Tucker   svc: Make the enq...
425
  		svc_xprt_enqueue(&svsk->sk_xprt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
426
  	}
eaefd1105   Eric Dumazet   net: add __rcu an...
427
  	if (wq && waitqueue_active(wq)) {
939bb7ef9   Neil Brown   [PATCH] Code clea...
428
429
  		dprintk("RPC svc_write_space: someone sleeping on %p
  ",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
430
  		       svsk);
eaefd1105   Eric Dumazet   net: add __rcu an...
431
  		wake_up_interruptible(wq);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
432
433
  	}
  }
c7fb3f063   Trond Myklebust   SUNRPC: svc_tcp_w...
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
  static int svc_tcp_has_wspace(struct svc_xprt *xprt)
  {
  	struct svc_sock *svsk =	container_of(xprt, struct svc_sock, sk_xprt);
  	struct svc_serv *serv = svsk->sk_xprt.xpt_server;
  	int required;
  
  	if (test_bit(XPT_LISTENER, &xprt->xpt_flags))
  		return 1;
  	required = atomic_read(&xprt->xpt_reserved) + serv->sv_max_mesg;
  	if (sk_stream_wspace(svsk->sk_sk) >= required ||
  	    (sk_stream_min_wspace(svsk->sk_sk) == 0 &&
  	     atomic_read(&xprt->xpt_reserved) == 0))
  		return 1;
  	set_bit(SOCK_NOSPACE, &svsk->sk_sock->flags);
  	return 0;
  }
47fcb03fe   Trond Myklebust   SUNRPC: Fix the T...
450
451
  static void svc_tcp_write_space(struct sock *sk)
  {
c7fb3f063   Trond Myklebust   SUNRPC: svc_tcp_w...
452
  	struct svc_sock *svsk = (struct svc_sock *)(sk->sk_user_data);
47fcb03fe   Trond Myklebust   SUNRPC: Fix the T...
453
  	struct socket *sock = sk->sk_socket;
c7fb3f063   Trond Myklebust   SUNRPC: svc_tcp_w...
454
455
456
  	if (!sk_stream_is_writeable(sk) || !sock)
  		return;
  	if (!svsk || svc_tcp_has_wspace(&svsk->sk_xprt))
47fcb03fe   Trond Myklebust   SUNRPC: Fix the T...
457
458
459
  		clear_bit(SOCK_NOSPACE, &sock->flags);
  	svc_write_space(sk);
  }
518776800   Trond Myklebust   SUNRPC: Allow svc...
460
461
462
463
464
465
466
  static void svc_tcp_adjust_wspace(struct svc_xprt *xprt)
  {
  	struct svc_sock *svsk = container_of(xprt, struct svc_sock, sk_xprt);
  
  	if (svc_tcp_has_wspace(xprt))
  		clear_bit(SOCK_NOSPACE, &svsk->sk_sock->flags);
  }
9dbc240f1   Tom Tucker   svc: Move the soc...
467
  /*
7702ce40b   Chuck Lever   SUNRPC: handle IP...
468
469
470
471
472
473
   * See net/ipv6/ip_sockglue.c : ip_cmsg_recv_pktinfo
   */
  static int svc_udp_get_dest_address4(struct svc_rqst *rqstp,
  				     struct cmsghdr *cmh)
  {
  	struct in_pktinfo *pki = CMSG_DATA(cmh);
849a1cf13   Mi Jinlong   SUNRPC: Replace s...
474
  	struct sockaddr_in *daddr = svc_daddr_in(rqstp);
7702ce40b   Chuck Lever   SUNRPC: handle IP...
475
476
  	if (cmh->cmsg_type != IP_PKTINFO)
  		return 0;
849a1cf13   Mi Jinlong   SUNRPC: Replace s...
477
478
479
  
  	daddr->sin_family = AF_INET;
  	daddr->sin_addr.s_addr = pki->ipi_spec_dst.s_addr;
7702ce40b   Chuck Lever   SUNRPC: handle IP...
480
481
482
483
  	return 1;
  }
  
  /*
73df66f8b   Tom Parkin   ipv6: rename data...
484
   * See net/ipv6/datagram.c : ip6_datagram_recv_ctl
7702ce40b   Chuck Lever   SUNRPC: handle IP...
485
486
487
488
489
   */
  static int svc_udp_get_dest_address6(struct svc_rqst *rqstp,
  				     struct cmsghdr *cmh)
  {
  	struct in6_pktinfo *pki = CMSG_DATA(cmh);
849a1cf13   Mi Jinlong   SUNRPC: Replace s...
490
  	struct sockaddr_in6 *daddr = svc_daddr_in6(rqstp);
7702ce40b   Chuck Lever   SUNRPC: handle IP...
491
492
  	if (cmh->cmsg_type != IPV6_PKTINFO)
  		return 0;
849a1cf13   Mi Jinlong   SUNRPC: Replace s...
493
494
  
  	daddr->sin6_family = AF_INET6;
4e3fd7a06   Alexey Dobriyan   net: remove ipv6_...
495
  	daddr->sin6_addr = pki->ipi6_addr;
849a1cf13   Mi Jinlong   SUNRPC: Replace s...
496
  	daddr->sin6_scope_id = pki->ipi6_ifindex;
7702ce40b   Chuck Lever   SUNRPC: handle IP...
497
498
499
500
  	return 1;
  }
  
  /*
9dbc240f1   Tom Tucker   svc: Move the soc...
501
502
503
504
505
506
   * Copy the UDP datagram's destination address to the rqstp structure.
   * The 'destination' address in this case is the address to which the
   * peer sent the datagram, i.e. our local address. For multihomed
   * hosts, this can change from msg to msg. Note that only the IP
   * address changes, the port number should remain the same.
   */
7702ce40b   Chuck Lever   SUNRPC: handle IP...
507
508
  static int svc_udp_get_dest_address(struct svc_rqst *rqstp,
  				    struct cmsghdr *cmh)
95756482c   Chuck Lever   [PATCH] knfsd: SU...
509
  {
7702ce40b   Chuck Lever   SUNRPC: handle IP...
510
511
512
513
514
  	switch (cmh->cmsg_level) {
  	case SOL_IP:
  		return svc_udp_get_dest_address4(rqstp, cmh);
  	case SOL_IPV6:
  		return svc_udp_get_dest_address6(rqstp, cmh);
95756482c   Chuck Lever   [PATCH] knfsd: SU...
515
  	}
7702ce40b   Chuck Lever   SUNRPC: handle IP...
516
517
  
  	return 0;
95756482c   Chuck Lever   [PATCH] knfsd: SU...
518
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
519
520
521
  /*
   * Receive a datagram from a UDP socket.
   */
0f0257eaa   Tom Tucker   svc: Move the xpr...
522
  static int svc_udp_recvfrom(struct svc_rqst *rqstp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
523
  {
57b1d3bab   Tom Tucker   svc: Removing rem...
524
525
  	struct svc_sock	*svsk =
  		container_of(rqstp->rq_xprt, struct svc_sock, sk_xprt);
bb5cf160b   Tom Tucker   svc: Move sk_serv...
526
  	struct svc_serv	*serv = svsk->sk_xprt.xpt_server;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
527
  	struct sk_buff	*skb;
bc375ea7e   David S. Miller   [SUNRPC]: Make su...
528
529
530
531
532
  	union {
  		struct cmsghdr	hdr;
  		long		all[SVC_PKTINFO_SPACE / sizeof(long)];
  	} buffer;
  	struct cmsghdr *cmh = &buffer.hdr;
7a37f5787   NeilBrown   [PATCH] knfsd: us...
533
534
535
536
537
538
  	struct msghdr msg = {
  		.msg_name = svc_addr(rqstp),
  		.msg_control = cmh,
  		.msg_controllen = sizeof(buffer),
  		.msg_flags = MSG_DONTWAIT,
  	};
abc5c44d6   Chuck Lever   SUNRPC: Fix error...
539
540
  	size_t len;
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
541

02fc6c361   Tom Tucker   svc: Move sk_flag...
542
  	if (test_and_clear_bit(XPT_CHNGBUF, &svsk->sk_xprt.xpt_flags))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
543
544
545
  	    /* udp sockets need large rcvbuf as all pending
  	     * requests are still in that buffer.  sndbuf must
  	     * also be large enough that there is enough space
3262c816a   Greg Banks   [PATCH] knfsd: sp...
546
547
548
549
  	     * for one reply per thread.  We count all threads
  	     * rather than threads in a particular pool, which
  	     * provides an upper bound on the number of threads
  	     * which will access the socket.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
550
551
  	     */
  	    svc_sock_setbufsize(svsk->sk_sock,
c6b0a9f87   NeilBrown   [PATCH] knfsd: ti...
552
553
  				(serv->sv_nrthreads+3) * serv->sv_max_mesg,
  				(serv->sv_nrthreads+3) * serv->sv_max_mesg);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
554

02fc6c361   Tom Tucker   svc: Move sk_flag...
555
  	clear_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags);
05ed690ef   NeilBrown   knfsd: simplify a...
556
557
558
559
560
561
562
563
564
565
566
  	skb = NULL;
  	err = kernel_recvmsg(svsk->sk_sock, &msg, NULL,
  			     0, 0, MSG_PEEK | MSG_DONTWAIT);
  	if (err >= 0)
  		skb = skb_recv_datagram(svsk->sk_sk, 0, 1, &err);
  
  	if (skb == NULL) {
  		if (err != -EAGAIN) {
  			/* possibly an icmp error */
  			dprintk("svc: recvfrom returned error %d
  ", -err);
02fc6c361   Tom Tucker   svc: Move sk_flag...
567
  			set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
568
  		}
9f9d2ebe6   J. Bruce Fields   svcrpc: make xpo_...
569
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
570
  	}
9dbc240f1   Tom Tucker   svc: Move the soc...
571
  	len = svc_addr_len(svc_addr(rqstp));
9dbc240f1   Tom Tucker   svc: Move the soc...
572
  	rqstp->rq_addrlen = len;
b7aa0bf70   Eric Dumazet   [NET]: convert ne...
573
574
  	if (skb->tstamp.tv64 == 0) {
  		skb->tstamp = ktime_get_real();
cca5172a7   YOSHIFUJI Hideaki   [NET] SUNRPC: Fix...
575
  		/* Don't enable netstamp, sunrpc doesn't
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
576
577
  		   need that much accuracy */
  	}
b7aa0bf70   Eric Dumazet   [NET]: convert ne...
578
  	svsk->sk_sk->sk_stamp = skb->tstamp;
02fc6c361   Tom Tucker   svc: Move sk_flag...
579
  	set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags); /* there may be more data... */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
580

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
581
582
  	len  = skb->len - sizeof(struct udphdr);
  	rqstp->rq_arg.len = len;
95756482c   Chuck Lever   [PATCH] knfsd: SU...
583
  	rqstp->rq_prot = IPPROTO_UDP;
27459f094   Chuck Lever   [PATCH] knfsd: SU...
584

7702ce40b   Chuck Lever   SUNRPC: handle IP...
585
  	if (!svc_udp_get_dest_address(rqstp, cmh)) {
e87cc4728   Joe Perches   net: Convert net_...
586
587
588
  		net_warn_ratelimited("svc: received unknown control message %d/%d; dropping RPC reply datagram
  ",
  				     cmh->cmsg_level, cmh->cmsg_type);
f23abfdb9   J. Bruce Fields   svcrpc: minor udp...
589
  		goto out_free;
7a37f5787   NeilBrown   [PATCH] knfsd: us...
590
  	}
849a1cf13   Mi Jinlong   SUNRPC: Replace s...
591
  	rqstp->rq_daddrlen = svc_addr_len(svc_daddr(rqstp));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
592
593
594
595
596
597
598
  
  	if (skb_is_nonlinear(skb)) {
  		/* we have to copy */
  		local_bh_disable();
  		if (csum_partial_copy_to_xdr(&rqstp->rq_arg, skb)) {
  			local_bh_enable();
  			/* checksum error */
22911fc58   Eric Dumazet   net: skb_free_dat...
599
  			goto out_free;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
600
601
  		}
  		local_bh_enable();
9d410c796   Eric Dumazet   net: fix sk_forwa...
602
  		skb_free_datagram_locked(svsk->sk_sk, skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
603
604
  	} else {
  		/* we can use it in-place */
0f0257eaa   Tom Tucker   svc: Move the xpr...
605
606
  		rqstp->rq_arg.head[0].iov_base = skb->data +
  			sizeof(struct udphdr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
607
  		rqstp->rq_arg.head[0].iov_len = len;
22911fc58   Eric Dumazet   net: skb_free_dat...
608
609
  		if (skb_checksum_complete(skb))
  			goto out_free;
5148bf4eb   Tom Tucker   svc: Add transpor...
610
  		rqstp->rq_xprt_ctxt = skb;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
611
612
613
614
615
616
  	}
  
  	rqstp->rq_arg.page_base = 0;
  	if (len <= rqstp->rq_arg.head[0].iov_len) {
  		rqstp->rq_arg.head[0].iov_len = len;
  		rqstp->rq_arg.page_len = 0;
445243594   NeilBrown   [PATCH] knfsd: Re...
617
  		rqstp->rq_respages = rqstp->rq_pages+1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
618
619
  	} else {
  		rqstp->rq_arg.page_len = len - rqstp->rq_arg.head[0].iov_len;
445243594   NeilBrown   [PATCH] knfsd: Re...
620
  		rqstp->rq_respages = rqstp->rq_pages + 1 +
172589ccd   Ilpo Järvinen   [NET]: DIV_ROUND_...
621
  			DIV_ROUND_UP(rqstp->rq_arg.page_len, PAGE_SIZE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
622
  	}
afc59400d   J. Bruce Fields   nfsd4: cleanup: r...
623
  	rqstp->rq_next_page = rqstp->rq_respages+1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
624
625
626
627
628
  
  	if (serv->sv_stats)
  		serv->sv_stats->netudpcnt++;
  
  	return len;
f23abfdb9   J. Bruce Fields   svcrpc: minor udp...
629
630
631
632
  out_free:
  	trace_kfree_skb(skb, svc_udp_recvfrom);
  	skb_free_datagram_locked(svsk->sk_sk, skb);
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
633
634
635
636
637
638
639
640
641
642
643
644
645
646
  }
  
  static int
  svc_udp_sendto(struct svc_rqst *rqstp)
  {
  	int		error;
  
  	error = svc_sendto(rqstp, &rqstp->rq_res);
  	if (error == -ECONNREFUSED)
  		/* ICMP error on earlier request. */
  		error = svc_sendto(rqstp, &rqstp->rq_res);
  
  	return error;
  }
e831fe65b   Tom Tucker   svc: Add xpo_prep...
647
648
649
  static void svc_udp_prep_reply_hdr(struct svc_rqst *rqstp)
  {
  }
323bee32e   Tom Tucker   svc: Add a transp...
650
651
652
  static int svc_udp_has_wspace(struct svc_xprt *xprt)
  {
  	struct svc_sock *svsk = container_of(xprt, struct svc_sock, sk_xprt);
bb5cf160b   Tom Tucker   svc: Move sk_serv...
653
  	struct svc_serv	*serv = xprt->xpt_server;
323bee32e   Tom Tucker   svc: Add a transp...
654
655
656
657
658
659
660
  	unsigned long required;
  
  	/*
  	 * Set the SOCK_NOSPACE flag before checking the available
  	 * sock space.
  	 */
  	set_bit(SOCK_NOSPACE, &svsk->sk_sock->flags);
7a90e8cc2   Tom Tucker   svc: Move sk_rese...
661
  	required = atomic_read(&svsk->sk_xprt.xpt_reserved) + serv->sv_max_mesg;
323bee32e   Tom Tucker   svc: Add a transp...
662
663
664
665
666
  	if (required*2 > sock_wspace(svsk->sk_sk))
  		return 0;
  	clear_bit(SOCK_NOSPACE, &svsk->sk_sock->flags);
  	return 1;
  }
38a417cc9   Tom Tucker   svc: Add xpo_acce...
667
668
669
670
671
  static struct svc_xprt *svc_udp_accept(struct svc_xprt *xprt)
  {
  	BUG();
  	return NULL;
  }
b700cbb11   Tom Tucker   svc: Add a generi...
672
  static struct svc_xprt *svc_udp_create(struct svc_serv *serv,
62832c039   Pavel Emelyanov   sunrpc: Pull net ...
673
  				       struct net *net,
b700cbb11   Tom Tucker   svc: Add a generi...
674
675
676
  				       struct sockaddr *sa, int salen,
  				       int flags)
  {
62832c039   Pavel Emelyanov   sunrpc: Pull net ...
677
  	return svc_create_socket(serv, IPPROTO_UDP, net, sa, salen, flags);
b700cbb11   Tom Tucker   svc: Add a generi...
678
  }
360d87386   Tom Tucker   svc: Make svc_soc...
679
  static struct svc_xprt_ops svc_udp_ops = {
b700cbb11   Tom Tucker   svc: Add a generi...
680
  	.xpo_create = svc_udp_create,
5d137990f   Tom Tucker   svc: Move sk_send...
681
682
  	.xpo_recvfrom = svc_udp_recvfrom,
  	.xpo_sendto = svc_udp_sendto,
5148bf4eb   Tom Tucker   svc: Add transpor...
683
  	.xpo_release_rqst = svc_release_skb,
755cceaba   Tom Tucker   svc: Add per-tran...
684
685
  	.xpo_detach = svc_sock_detach,
  	.xpo_free = svc_sock_free,
e831fe65b   Tom Tucker   svc: Add xpo_prep...
686
  	.xpo_prep_reply_hdr = svc_udp_prep_reply_hdr,
323bee32e   Tom Tucker   svc: Add a transp...
687
  	.xpo_has_wspace = svc_udp_has_wspace,
38a417cc9   Tom Tucker   svc: Add xpo_acce...
688
  	.xpo_accept = svc_udp_accept,
16e4d93f6   Chuck Lever   NFSD: Ignore clie...
689
  	.xpo_secure_port = svc_sock_secure_port,
360d87386   Tom Tucker   svc: Make svc_soc...
690
691
692
693
  };
  
  static struct svc_xprt_class svc_udp_class = {
  	.xcl_name = "udp",
b700cbb11   Tom Tucker   svc: Add a generi...
694
  	.xcl_owner = THIS_MODULE,
360d87386   Tom Tucker   svc: Make svc_soc...
695
  	.xcl_ops = &svc_udp_ops,
490231558   Tom Tucker   svc: Add a max pa...
696
  	.xcl_max_payload = RPCSVC_MAXPAYLOAD_UDP,
3c45ddf82   Chuck Lever   svcrdma: Select N...
697
  	.xcl_ident = XPRT_TRANSPORT_UDP,
360d87386   Tom Tucker   svc: Make svc_soc...
698
  };
bb5cf160b   Tom Tucker   svc: Move sk_serv...
699
  static void svc_udp_init(struct svc_sock *svsk, struct svc_serv *serv)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
700
  {
7702ce40b   Chuck Lever   SUNRPC: handle IP...
701
  	int err, level, optname, one = 1;
7a37f5787   NeilBrown   [PATCH] knfsd: us...
702

bd4620ddf   Stanislav Kinsbursky   SUNRPC: create sv...
703
704
  	svc_xprt_init(sock_net(svsk->sk_sock->sk), &svc_udp_class,
  		      &svsk->sk_xprt, serv);
def13d740   Tom Tucker   svc: Move the aut...
705
  	clear_bit(XPT_CACHE_AUTH, &svsk->sk_xprt.xpt_flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
706
707
  	svsk->sk_sk->sk_data_ready = svc_udp_data_ready;
  	svsk->sk_sk->sk_write_space = svc_write_space;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
708
709
  
  	/* initialise setting must have enough space to
cca5172a7   YOSHIFUJI Hideaki   [NET] SUNRPC: Fix...
710
  	 * receive and respond to one request.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
711
712
713
  	 * svc_udp_recvfrom will re-adjust if necessary
  	 */
  	svc_sock_setbufsize(svsk->sk_sock,
bb5cf160b   Tom Tucker   svc: Move sk_serv...
714
715
  			    3 * svsk->sk_xprt.xpt_server->sv_max_mesg,
  			    3 * svsk->sk_xprt.xpt_server->sv_max_mesg);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
716

0f0257eaa   Tom Tucker   svc: Move the xpr...
717
718
  	/* data might have come in before data_ready set up */
  	set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags);
02fc6c361   Tom Tucker   svc: Move sk_flag...
719
  	set_bit(XPT_CHNGBUF, &svsk->sk_xprt.xpt_flags);
7a37f5787   NeilBrown   [PATCH] knfsd: us...
720

7a37f5787   NeilBrown   [PATCH] knfsd: us...
721
  	/* make sure we get destination address info */
7702ce40b   Chuck Lever   SUNRPC: handle IP...
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
  	switch (svsk->sk_sk->sk_family) {
  	case AF_INET:
  		level = SOL_IP;
  		optname = IP_PKTINFO;
  		break;
  	case AF_INET6:
  		level = SOL_IPV6;
  		optname = IPV6_RECVPKTINFO;
  		break;
  	default:
  		BUG();
  	}
  	err = kernel_setsockopt(svsk->sk_sock, level, optname,
  					(char *)&one, sizeof(one));
  	dprintk("svc: kernel_setsockopt returned %d
  ", err);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
738
739
740
741
742
743
  }
  
  /*
   * A data_ready event on a listening socket means there's a connection
   * pending. Do not use state_change as a substitute for it.
   */
676d23690   David S. Miller   net: Fix use afte...
744
  static void svc_tcp_listen_data_ready(struct sock *sk)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
745
  {
939bb7ef9   Neil Brown   [PATCH] Code clea...
746
  	struct svc_sock	*svsk = (struct svc_sock *)sk->sk_user_data;
eaefd1105   Eric Dumazet   net: add __rcu an...
747
  	wait_queue_head_t *wq;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
748
749
750
  
  	dprintk("svc: socket %p TCP (listen) state change %d
  ",
939bb7ef9   Neil Brown   [PATCH] Code clea...
751
  		sk, sk->sk_state);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
752

939bb7ef9   Neil Brown   [PATCH] Code clea...
753
754
755
756
757
758
759
760
761
762
763
764
  	/*
  	 * This callback may called twice when a new connection
  	 * is established as a child socket inherits everything
  	 * from a parent LISTEN socket.
  	 * 1) data_ready method of the parent socket will be called
  	 *    when one of child sockets become ESTABLISHED.
  	 * 2) data_ready method of the child socket may be called
  	 *    when it receives data before the socket is accepted.
  	 * In case of 2, we should ignore it silently.
  	 */
  	if (sk->sk_state == TCP_LISTEN) {
  		if (svsk) {
02fc6c361   Tom Tucker   svc: Move sk_flag...
765
  			set_bit(XPT_CONN, &svsk->sk_xprt.xpt_flags);
f6150c3ca   Tom Tucker   svc: Make the enq...
766
  			svc_xprt_enqueue(&svsk->sk_xprt);
939bb7ef9   Neil Brown   [PATCH] Code clea...
767
768
769
  		} else
  			printk("svc: socket %p: no user data
  ", sk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
770
  	}
939bb7ef9   Neil Brown   [PATCH] Code clea...
771

eaefd1105   Eric Dumazet   net: add __rcu an...
772
773
774
  	wq = sk_sleep(sk);
  	if (wq && waitqueue_active(wq))
  		wake_up_interruptible_all(wq);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
775
776
777
778
779
  }
  
  /*
   * A state change on a connected socket means it's dying or dead.
   */
0f0257eaa   Tom Tucker   svc: Move the xpr...
780
  static void svc_tcp_state_change(struct sock *sk)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
781
  {
939bb7ef9   Neil Brown   [PATCH] Code clea...
782
  	struct svc_sock	*svsk = (struct svc_sock *)sk->sk_user_data;
eaefd1105   Eric Dumazet   net: add __rcu an...
783
  	wait_queue_head_t *wq = sk_sleep(sk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
784
785
786
  
  	dprintk("svc: socket %p TCP (connected) state change %d (svsk %p)
  ",
939bb7ef9   Neil Brown   [PATCH] Code clea...
787
  		sk, sk->sk_state, sk->sk_user_data);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
788

939bb7ef9   Neil Brown   [PATCH] Code clea...
789
  	if (!svsk)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
790
791
  		printk("svc: socket %p: no user data
  ", sk);
939bb7ef9   Neil Brown   [PATCH] Code clea...
792
  	else {
02fc6c361   Tom Tucker   svc: Move sk_flag...
793
  		set_bit(XPT_CLOSE, &svsk->sk_xprt.xpt_flags);
f6150c3ca   Tom Tucker   svc: Make the enq...
794
  		svc_xprt_enqueue(&svsk->sk_xprt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
795
  	}
eaefd1105   Eric Dumazet   net: add __rcu an...
796
797
  	if (wq && waitqueue_active(wq))
  		wake_up_interruptible_all(wq);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
798
  }
676d23690   David S. Miller   net: Fix use afte...
799
  static void svc_tcp_data_ready(struct sock *sk)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
800
  {
939bb7ef9   Neil Brown   [PATCH] Code clea...
801
  	struct svc_sock *svsk = (struct svc_sock *)sk->sk_user_data;
eaefd1105   Eric Dumazet   net: add __rcu an...
802
  	wait_queue_head_t *wq = sk_sleep(sk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
803
804
805
  
  	dprintk("svc: socket %p TCP data ready (svsk %p)
  ",
939bb7ef9   Neil Brown   [PATCH] Code clea...
806
807
  		sk, sk->sk_user_data);
  	if (svsk) {
02fc6c361   Tom Tucker   svc: Move sk_flag...
808
  		set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags);
f6150c3ca   Tom Tucker   svc: Make the enq...
809
  		svc_xprt_enqueue(&svsk->sk_xprt);
939bb7ef9   Neil Brown   [PATCH] Code clea...
810
  	}
eaefd1105   Eric Dumazet   net: add __rcu an...
811
812
  	if (wq && waitqueue_active(wq))
  		wake_up_interruptible(wq);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
813
814
815
816
817
  }
  
  /*
   * Accept a TCP connection
   */
38a417cc9   Tom Tucker   svc: Add xpo_acce...
818
  static struct svc_xprt *svc_tcp_accept(struct svc_xprt *xprt)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
819
  {
38a417cc9   Tom Tucker   svc: Add xpo_acce...
820
  	struct svc_sock *svsk = container_of(xprt, struct svc_sock, sk_xprt);
cdd88b9f3   akpm@linux-foundation.org   [PATCH] knfsd: SU...
821
822
  	struct sockaddr_storage addr;
  	struct sockaddr	*sin = (struct sockaddr *) &addr;
bb5cf160b   Tom Tucker   svc: Move sk_serv...
823
  	struct svc_serv	*serv = svsk->sk_xprt.xpt_server;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
824
825
  	struct socket	*sock = svsk->sk_sock;
  	struct socket	*newsock;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
826
827
  	struct svc_sock	*newsvsk;
  	int		err, slen;
5216a8e70   Pavel Emelyanov   Wrap buffers used...
828
  	RPC_IFDEBUG(char buf[RPC_MAX_ADDRBUFLEN]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
829
830
831
832
  
  	dprintk("svc: tcp_accept %p sock %p
  ", svsk, sock);
  	if (!sock)
38a417cc9   Tom Tucker   svc: Add xpo_acce...
833
  		return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
834

02fc6c361   Tom Tucker   svc: Move sk_flag...
835
  	clear_bit(XPT_CONN, &svsk->sk_xprt.xpt_flags);
e6242e928   Sridhar Samudrala   [SUNRPC]: Update ...
836
837
  	err = kernel_accept(sock, &newsock, O_NONBLOCK);
  	if (err < 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
838
839
840
841
  		if (err == -ENOMEM)
  			printk(KERN_WARNING "%s: no more sockets!
  ",
  			       serv->sv_name);
e87cc4728   Joe Perches   net: Convert net_...
842
843
844
845
  		else if (err != -EAGAIN)
  			net_warn_ratelimited("%s: accept failed (err %d)!
  ",
  					     serv->sv_name, -err);
38a417cc9   Tom Tucker   svc: Add xpo_acce...
846
  		return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
847
  	}
02fc6c361   Tom Tucker   svc: Move sk_flag...
848
  	set_bit(XPT_CONN, &svsk->sk_xprt.xpt_flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
849

cdd88b9f3   akpm@linux-foundation.org   [PATCH] knfsd: SU...
850
  	err = kernel_getpeername(newsock, sin, &slen);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
851
  	if (err < 0) {
e87cc4728   Joe Perches   net: Convert net_...
852
853
854
  		net_warn_ratelimited("%s: peername failed (err %d)!
  ",
  				     serv->sv_name, -err);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
855
856
857
858
  		goto failed;		/* aborted connection or whatever */
  	}
  
  	/* Ideally, we would want to reject connections from unauthorized
ad06e4bd6   Chuck Lever   [PATCH] knfsd: SU...
859
860
  	 * hosts here, but when we get encryption, the IP of the host won't
  	 * tell us anything.  For now just warn about unpriv connections.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
861
  	 */
cdd88b9f3   akpm@linux-foundation.org   [PATCH] knfsd: SU...
862
  	if (!svc_port_is_privileged(sin)) {
a48fd0f9f   Kinglong Mee   SUNRPC/NFSD: Remo...
863
864
  		dprintk("%s: connect from unprivileged port: %s
  ",
cca5172a7   YOSHIFUJI Hideaki   [NET] SUNRPC: Fix...
865
  			serv->sv_name,
cdd88b9f3   akpm@linux-foundation.org   [PATCH] knfsd: SU...
866
  			__svc_print_addr(sin, buf, sizeof(buf)));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
867
  	}
ad06e4bd6   Chuck Lever   [PATCH] knfsd: SU...
868
869
  	dprintk("%s: connect from %s
  ", serv->sv_name,
cdd88b9f3   akpm@linux-foundation.org   [PATCH] knfsd: SU...
870
  		__svc_print_addr(sin, buf, sizeof(buf)));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
871
872
873
874
875
  
  	/* make sure that a write doesn't block forever when
  	 * low on memory
  	 */
  	newsock->sk->sk_sndtimeo = HZ*30;
72c353760   J. Bruce Fields   svcrpc: standardi...
876
877
878
  	newsvsk = svc_setup_socket(serv, newsock,
  				 (SVC_SOCK_ANONYMOUS | SVC_SOCK_TEMPORARY));
  	if (IS_ERR(newsvsk))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
879
  		goto failed;
9dbc240f1   Tom Tucker   svc: Move the soc...
880
  	svc_xprt_set_remote(&newsvsk->sk_xprt, sin, slen);
a97476926   Frank van Maarseveen   SUNRPC server: re...
881
882
883
884
885
886
  	err = kernel_getsockname(newsock, sin, &slen);
  	if (unlikely(err < 0)) {
  		dprintk("svc_tcp_accept: kernel_getsockname error %d
  ", -err);
  		slen = offsetof(struct sockaddr, sa_data);
  	}
9dbc240f1   Tom Tucker   svc: Move the soc...
887
  	svc_xprt_set_local(&newsvsk->sk_xprt, sin, slen);
067d78173   Chuck Lever   [PATCH] knfsd: SU...
888

ef11ce248   NeilBrown   SUNRPC: track whe...
889
890
891
892
  	if (sock_is_loopback(newsock->sk))
  		set_bit(XPT_LOCAL, &newsvsk->sk_xprt.xpt_flags);
  	else
  		clear_bit(XPT_LOCAL, &newsvsk->sk_xprt.xpt_flags);
f9f3cc4fa   Tom Tucker   svc: Move connect...
893
894
895
896
897
898
899
900
901
  	if (serv->sv_stats)
  		serv->sv_stats->nettcpconn++;
  
  	return &newsvsk->sk_xprt;
  
  failed:
  	sock_release(newsock);
  	return NULL;
  }
31d68ef65   J. Bruce Fields   SUNRPC: Don't wai...
902
903
904
  static unsigned int svc_tcp_restore_pages(struct svc_sock *svsk, struct svc_rqst *rqstp)
  {
  	unsigned int i, len, npages;
8af345f58   J. Bruce Fields   svcrpc: track rpc...
905
  	if (svsk->sk_datalen == 0)
31d68ef65   J. Bruce Fields   SUNRPC: Don't wai...
906
  		return 0;
8af345f58   J. Bruce Fields   svcrpc: track rpc...
907
  	len = svsk->sk_datalen;
31d68ef65   J. Bruce Fields   SUNRPC: Don't wai...
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
  	npages = (len + PAGE_SIZE - 1) >> PAGE_SHIFT;
  	for (i = 0; i < npages; i++) {
  		if (rqstp->rq_pages[i] != NULL)
  			put_page(rqstp->rq_pages[i]);
  		BUG_ON(svsk->sk_pages[i] == NULL);
  		rqstp->rq_pages[i] = svsk->sk_pages[i];
  		svsk->sk_pages[i] = NULL;
  	}
  	rqstp->rq_arg.head[0].iov_base = page_address(rqstp->rq_pages[0]);
  	return len;
  }
  
  static void svc_tcp_save_pages(struct svc_sock *svsk, struct svc_rqst *rqstp)
  {
  	unsigned int i, len, npages;
8af345f58   J. Bruce Fields   svcrpc: track rpc...
923
  	if (svsk->sk_datalen == 0)
31d68ef65   J. Bruce Fields   SUNRPC: Don't wai...
924
  		return;
8af345f58   J. Bruce Fields   svcrpc: track rpc...
925
  	len = svsk->sk_datalen;
31d68ef65   J. Bruce Fields   SUNRPC: Don't wai...
926
927
928
929
930
931
932
933
934
935
  	npages = (len + PAGE_SIZE - 1) >> PAGE_SHIFT;
  	for (i = 0; i < npages; i++) {
  		svsk->sk_pages[i] = rqstp->rq_pages[i];
  		rqstp->rq_pages[i] = NULL;
  	}
  }
  
  static void svc_tcp_clear_pages(struct svc_sock *svsk)
  {
  	unsigned int i, len, npages;
8af345f58   J. Bruce Fields   svcrpc: track rpc...
936
  	if (svsk->sk_datalen == 0)
31d68ef65   J. Bruce Fields   SUNRPC: Don't wai...
937
  		goto out;
8af345f58   J. Bruce Fields   svcrpc: track rpc...
938
  	len = svsk->sk_datalen;
31d68ef65   J. Bruce Fields   SUNRPC: Don't wai...
939
940
  	npages = (len + PAGE_SIZE - 1) >> PAGE_SHIFT;
  	for (i = 0; i < npages; i++) {
cf3aa02cb   J. Bruce Fields   svcrpc: fix handl...
941
942
943
944
  		if (svsk->sk_pages[i] == NULL) {
  			WARN_ON_ONCE(1);
  			continue;
  		}
31d68ef65   J. Bruce Fields   SUNRPC: Don't wai...
945
946
947
948
949
  		put_page(svsk->sk_pages[i]);
  		svsk->sk_pages[i] = NULL;
  	}
  out:
  	svsk->sk_tcplen = 0;
8af345f58   J. Bruce Fields   svcrpc: track rpc...
950
  	svsk->sk_datalen = 0;
31d68ef65   J. Bruce Fields   SUNRPC: Don't wai...
951
  }
f9f3cc4fa   Tom Tucker   svc: Move connect...
952
  /*
ad46ccf09   J. Bruce Fields   svcrpc: delay min...
953
   * Receive fragment record header.
8f55f3c0a   Alexandros Batsakis   nfsd41: sunrpc: s...
954
   * If we haven't gotten the record length yet, get the next four bytes.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
955
   */
8f55f3c0a   Alexandros Batsakis   nfsd41: sunrpc: s...
956
  static int svc_tcp_recv_record(struct svc_sock *svsk, struct svc_rqst *rqstp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
957
  {
bb5cf160b   Tom Tucker   svc: Move sk_serv...
958
  	struct svc_serv	*serv = svsk->sk_xprt.xpt_server;
5ee78d483   Trond Myklebust   SUNRPC: svc_tcp_r...
959
  	unsigned int want;
8f55f3c0a   Alexandros Batsakis   nfsd41: sunrpc: s...
960
  	int len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
961

c0401ea00   Chuck Lever   SUNRPC: Update RP...
962
  	if (svsk->sk_tcplen < sizeof(rpc_fraghdr)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
963
  		struct kvec	iov;
5ee78d483   Trond Myklebust   SUNRPC: svc_tcp_r...
964
  		want = sizeof(rpc_fraghdr) - svsk->sk_tcplen;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
965
966
967
968
969
970
971
  		iov.iov_base = ((char *) &svsk->sk_reclen) + svsk->sk_tcplen;
  		iov.iov_len  = want;
  		if ((len = svc_recvfrom(rqstp, &iov, 1, want)) < 0)
  			goto error;
  		svsk->sk_tcplen += len;
  
  		if (len < want) {
c0401ea00   Chuck Lever   SUNRPC: Update RP...
972
973
974
  			dprintk("svc: short recvfrom while reading record "
  				"length (%d of %d)
  ", len, want);
31d68ef65   J. Bruce Fields   SUNRPC: Don't wai...
975
  			return -EAGAIN;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
976
  		}
cc248d4b1   J. Bruce Fields   svcrpc: don't byt...
977
978
  		dprintk("svc: TCP record, %d bytes
  ", svc_sock_reclen(svsk));
836fbadb9   J. Bruce Fields   svcrpc: support m...
979
980
  		if (svc_sock_reclen(svsk) + svsk->sk_datalen >
  							serv->sv_max_mesg) {
3a28e3311   J. Bruce Fields   svcrpc: fix some ...
981
982
983
  			net_notice_ratelimited("RPC: fragment too large: %d
  ",
  					svc_sock_reclen(svsk));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
984
985
986
  			goto err_delete;
  		}
  	}
cc248d4b1   J. Bruce Fields   svcrpc: don't byt...
987
  	return svc_sock_reclen(svsk);
31d68ef65   J. Bruce Fields   SUNRPC: Don't wai...
988
989
990
  error:
  	dprintk("RPC: TCP recv_record got %d
  ", len);
8f55f3c0a   Alexandros Batsakis   nfsd41: sunrpc: s...
991
  	return len;
31d68ef65   J. Bruce Fields   SUNRPC: Don't wai...
992
  err_delete:
8f55f3c0a   Alexandros Batsakis   nfsd41: sunrpc: s...
993
  	set_bit(XPT_CLOSE, &svsk->sk_xprt.xpt_flags);
8f55f3c0a   Alexandros Batsakis   nfsd41: sunrpc: s...
994
995
  	return -EAGAIN;
  }
586c52cc6   Trond Myklebust   svcrpc: copy cb r...
996
  static int receive_cb_reply(struct svc_sock *svsk, struct svc_rqst *rqstp)
4cfc7e601   Rahul Iyer   nfsd41: sunrpc: A...
997
  {
586c52cc6   Trond Myklebust   svcrpc: copy cb r...
998
  	struct rpc_xprt *bc_xprt = svsk->sk_xprt.xpt_bc_xprt;
4cfc7e601   Rahul Iyer   nfsd41: sunrpc: A...
999
  	struct rpc_rqst *req = NULL;
586c52cc6   Trond Myklebust   svcrpc: copy cb r...
1000
1001
  	struct kvec *src, *dst;
  	__be32 *p = (__be32 *)rqstp->rq_arg.head[0].iov_base;
48e6555c7   J. Bruce Fields   svcrpc: note netw...
1002
1003
  	__be32 xid;
  	__be32 calldir;
4cfc7e601   Rahul Iyer   nfsd41: sunrpc: A...
1004

4cfc7e601   Rahul Iyer   nfsd41: sunrpc: A...
1005
1006
  	xid = *p++;
  	calldir = *p;
093a1468b   Trond Myklebust   SUNRPC: Fix locki...
1007
  	if (!bc_xprt)
586c52cc6   Trond Myklebust   svcrpc: copy cb r...
1008
  		return -EAGAIN;
093a1468b   Trond Myklebust   SUNRPC: Fix locki...
1009
1010
1011
1012
  	spin_lock_bh(&bc_xprt->transport_lock);
  	req = xprt_lookup_rqst(bc_xprt, xid);
  	if (!req)
  		goto unlock_notfound;
586c52cc6   Trond Myklebust   svcrpc: copy cb r...
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
  
  	memcpy(&req->rq_private_buf, &req->rq_rcv_buf, sizeof(struct xdr_buf));
  	/*
  	 * XXX!: cheating for now!  Only copying HEAD.
  	 * But we know this is good enough for now (in fact, for any
  	 * callback reply in the forseeable future).
  	 */
  	dst = &req->rq_private_buf.head[0];
  	src = &rqstp->rq_arg.head[0];
  	if (dst->iov_len < src->iov_len)
093a1468b   Trond Myklebust   SUNRPC: Fix locki...
1023
  		goto unlock_eagain; /* whatever; just giving up. */
586c52cc6   Trond Myklebust   svcrpc: copy cb r...
1024
  	memcpy(dst->iov_base, src->iov_base, src->iov_len);
cc248d4b1   J. Bruce Fields   svcrpc: don't byt...
1025
  	xprt_complete_rqst(req->rq_task, rqstp->rq_arg.len);
586c52cc6   Trond Myklebust   svcrpc: copy cb r...
1026
  	rqstp->rq_arg.len = 0;
093a1468b   Trond Myklebust   SUNRPC: Fix locki...
1027
  	spin_unlock_bh(&bc_xprt->transport_lock);
586c52cc6   Trond Myklebust   svcrpc: copy cb r...
1028
  	return 0;
093a1468b   Trond Myklebust   SUNRPC: Fix locki...
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
  unlock_notfound:
  	printk(KERN_NOTICE
  		"%s: Got unrecognized reply: "
  		"calldir 0x%x xpt_bc_xprt %p xid %08x
  ",
  		__func__, ntohl(calldir),
  		bc_xprt, ntohl(xid));
  unlock_eagain:
  	spin_unlock_bh(&bc_xprt->transport_lock);
  	return -EAGAIN;
586c52cc6   Trond Myklebust   svcrpc: copy cb r...
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
  }
  
  static int copy_pages_to_kvecs(struct kvec *vec, struct page **pages, int len)
  {
  	int i = 0;
  	int t = 0;
  
  	while (t < len) {
  		vec[i].iov_base = page_address(pages[i]);
  		vec[i].iov_len = PAGE_SIZE;
  		i++;
  		t += PAGE_SIZE;
  	}
  	return i;
4cfc7e601   Rahul Iyer   nfsd41: sunrpc: A...
1053
  }
836fbadb9   J. Bruce Fields   svcrpc: support m...
1054
1055
1056
  static void svc_tcp_fragment_received(struct svc_sock *svsk)
  {
  	/* If we have more data, signal svc_xprt_enqueue() to try again */
836fbadb9   J. Bruce Fields   svcrpc: support m...
1057
1058
1059
1060
1061
1062
1063
  	dprintk("svc: TCP %s record (%d bytes)
  ",
  		svc_sock_final_rec(svsk) ? "final" : "nonfinal",
  		svc_sock_reclen(svsk));
  	svsk->sk_tcplen = 0;
  	svsk->sk_reclen = 0;
  }
31d68ef65   J. Bruce Fields   SUNRPC: Don't wai...
1064

8f55f3c0a   Alexandros Batsakis   nfsd41: sunrpc: s...
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
  /*
   * Receive data from a TCP socket.
   */
  static int svc_tcp_recvfrom(struct svc_rqst *rqstp)
  {
  	struct svc_sock	*svsk =
  		container_of(rqstp->rq_xprt, struct svc_sock, sk_xprt);
  	struct svc_serv	*serv = svsk->sk_xprt.xpt_server;
  	int		len;
  	struct kvec *vec;
31d68ef65   J. Bruce Fields   SUNRPC: Don't wai...
1075
  	unsigned int want, base;
586c52cc6   Trond Myklebust   svcrpc: copy cb r...
1076
1077
  	__be32 *p;
  	__be32 calldir;
5ee78d483   Trond Myklebust   SUNRPC: svc_tcp_r...
1078
  	int pnum;
8f55f3c0a   Alexandros Batsakis   nfsd41: sunrpc: s...
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
  
  	dprintk("svc: tcp_recv %p data %d conn %d close %d
  ",
  		svsk, test_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags),
  		test_bit(XPT_CONN, &svsk->sk_xprt.xpt_flags),
  		test_bit(XPT_CLOSE, &svsk->sk_xprt.xpt_flags));
  
  	len = svc_tcp_recv_record(svsk, rqstp);
  	if (len < 0)
  		goto error;
31d68ef65   J. Bruce Fields   SUNRPC: Don't wai...
1089
  	base = svc_tcp_restore_pages(svsk, rqstp);
836fbadb9   J. Bruce Fields   svcrpc: support m...
1090
  	want = svc_sock_reclen(svsk) - (svsk->sk_tcplen - sizeof(rpc_fraghdr));
31d68ef65   J. Bruce Fields   SUNRPC: Don't wai...
1091

3cc03b164   NeilBrown   [PATCH] knfsd: Av...
1092
  	vec = rqstp->rq_vec;
4cfc7e601   Rahul Iyer   nfsd41: sunrpc: A...
1093

586c52cc6   Trond Myklebust   svcrpc: copy cb r...
1094
  	pnum = copy_pages_to_kvecs(&vec[0], &rqstp->rq_pages[0],
836fbadb9   J. Bruce Fields   svcrpc: support m...
1095
  						svsk->sk_datalen + want);
586c52cc6   Trond Myklebust   svcrpc: copy cb r...
1096

445243594   NeilBrown   [PATCH] knfsd: Re...
1097
  	rqstp->rq_respages = &rqstp->rq_pages[pnum];
afc59400d   J. Bruce Fields   nfsd4: cleanup: r...
1098
  	rqstp->rq_next_page = rqstp->rq_respages + 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1099
1100
  
  	/* Now receive data */
31d68ef65   J. Bruce Fields   SUNRPC: Don't wai...
1101
  	len = svc_partial_recvfrom(rqstp, vec, pnum, want, base);
8af345f58   J. Bruce Fields   svcrpc: track rpc...
1102
  	if (len >= 0) {
31d68ef65   J. Bruce Fields   SUNRPC: Don't wai...
1103
  		svsk->sk_tcplen += len;
8af345f58   J. Bruce Fields   svcrpc: track rpc...
1104
1105
  		svsk->sk_datalen += len;
  	}
836fbadb9   J. Bruce Fields   svcrpc: support m...
1106
  	if (len != want || !svc_sock_final_rec(svsk)) {
be1e44441   J. Bruce Fields   svcrpc: fix BUG()...
1107
  		svc_tcp_save_pages(svsk, rqstp);
31d68ef65   J. Bruce Fields   SUNRPC: Don't wai...
1108
  		if (len < 0 && len != -EAGAIN)
ad46ccf09   J. Bruce Fields   svcrpc: delay min...
1109
  			goto err_delete;
836fbadb9   J. Bruce Fields   svcrpc: support m...
1110
1111
1112
  		if (len == want)
  			svc_tcp_fragment_received(svsk);
  		else
3a28e3311   J. Bruce Fields   svcrpc: fix some ...
1113
1114
1115
  			dprintk("svc: incomplete TCP record (%d of %d)
  ",
  				(int)(svsk->sk_tcplen - sizeof(rpc_fraghdr)),
836fbadb9   J. Bruce Fields   svcrpc: support m...
1116
  				svc_sock_reclen(svsk));
31d68ef65   J. Bruce Fields   SUNRPC: Don't wai...
1117
1118
  		goto err_noclose;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1119

1f691b07c   J. Bruce Fields   svcrpc: don't err...
1120
  	if (svsk->sk_datalen < 8) {
cf3aa02cb   J. Bruce Fields   svcrpc: fix handl...
1121
  		svsk->sk_datalen = 0;
ad46ccf09   J. Bruce Fields   svcrpc: delay min...
1122
  		goto err_delete; /* client is nuts. */
cf3aa02cb   J. Bruce Fields   svcrpc: fix handl...
1123
  	}
ad46ccf09   J. Bruce Fields   svcrpc: delay min...
1124

836fbadb9   J. Bruce Fields   svcrpc: support m...
1125
  	rqstp->rq_arg.len = svsk->sk_datalen;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1126
  	rqstp->rq_arg.page_base = 0;
5ee78d483   Trond Myklebust   SUNRPC: svc_tcp_r...
1127
1128
  	if (rqstp->rq_arg.len <= rqstp->rq_arg.head[0].iov_len) {
  		rqstp->rq_arg.head[0].iov_len = rqstp->rq_arg.len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1129
  		rqstp->rq_arg.page_len = 0;
5ee78d483   Trond Myklebust   SUNRPC: svc_tcp_r...
1130
1131
  	} else
  		rqstp->rq_arg.page_len = rqstp->rq_arg.len - rqstp->rq_arg.head[0].iov_len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1132

5148bf4eb   Tom Tucker   svc: Add transpor...
1133
  	rqstp->rq_xprt_ctxt   = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1134
  	rqstp->rq_prot	      = IPPROTO_TCP;
7501cc2bc   Jeff Layton   sunrpc: move rq_l...
1135
1136
1137
1138
  	if (test_bit(XPT_LOCAL, &svsk->sk_xprt.xpt_flags))
  		set_bit(RQ_LOCAL, &rqstp->rq_flags);
  	else
  		clear_bit(RQ_LOCAL, &rqstp->rq_flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1139

586c52cc6   Trond Myklebust   svcrpc: copy cb r...
1140
1141
  	p = (__be32 *)rqstp->rq_arg.head[0].iov_base;
  	calldir = p[1];
8985ef0b8   J. Bruce Fields   svcrpc: complete ...
1142
  	if (calldir)
586c52cc6   Trond Myklebust   svcrpc: copy cb r...
1143
  		len = receive_cb_reply(svsk, rqstp);
586c52cc6   Trond Myklebust   svcrpc: copy cb r...
1144

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1145
  	/* Reset TCP read info */
8af345f58   J. Bruce Fields   svcrpc: track rpc...
1146
  	svsk->sk_datalen = 0;
836fbadb9   J. Bruce Fields   svcrpc: support m...
1147
  	svc_tcp_fragment_received(svsk);
0601f7939   Trond Myklebust   SUNRPC: requeue t...
1148

8985ef0b8   J. Bruce Fields   svcrpc: complete ...
1149
1150
  	if (len < 0)
  		goto error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1151

9dbc240f1   Tom Tucker   svc: Move the soc...
1152
  	svc_xprt_copy_addrs(rqstp, &svsk->sk_xprt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1153
1154
  	if (serv->sv_stats)
  		serv->sv_stats->nettcpcnt++;
5ee78d483   Trond Myklebust   SUNRPC: svc_tcp_r...
1155
  	return rqstp->rq_arg.len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1156

8f55f3c0a   Alexandros Batsakis   nfsd41: sunrpc: s...
1157
  error:
31d68ef65   J. Bruce Fields   SUNRPC: Don't wai...
1158
  	if (len != -EAGAIN)
ad46ccf09   J. Bruce Fields   svcrpc: delay min...
1159
  		goto err_delete;
31d68ef65   J. Bruce Fields   SUNRPC: Don't wai...
1160
1161
  	dprintk("RPC: TCP recvfrom got EAGAIN
  ");
9f9d2ebe6   J. Bruce Fields   svcrpc: make xpo_...
1162
  	return 0;
ad46ccf09   J. Bruce Fields   svcrpc: delay min...
1163
  err_delete:
31d68ef65   J. Bruce Fields   SUNRPC: Don't wai...
1164
1165
1166
1167
1168
  	printk(KERN_NOTICE "%s: recvfrom returned errno %d
  ",
  	       svsk->sk_xprt.xpt_server->sv_name, -len);
  	set_bit(XPT_CLOSE, &svsk->sk_xprt.xpt_flags);
  err_noclose:
9f9d2ebe6   J. Bruce Fields   svcrpc: make xpo_...
1169
  	return 0;	/* record not complete */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1170
1171
1172
1173
1174
  }
  
  /*
   * Send out data on TCP socket.
   */
0f0257eaa   Tom Tucker   svc: Move the xpr...
1175
  static int svc_tcp_sendto(struct svc_rqst *rqstp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1176
1177
1178
  {
  	struct xdr_buf	*xbufp = &rqstp->rq_res;
  	int sent;
d8ed029d6   Alexey Dobriyan   [SUNRPC]: trivial...
1179
  	__be32 reclen;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1180
1181
1182
1183
1184
1185
1186
  
  	/* Set up the first element of the reply kvec.
  	 * Any other kvecs that may be in use have been taken
  	 * care of by the server implementation itself.
  	 */
  	reclen = htonl(0x80000000|((xbufp->len ) - 4));
  	memcpy(xbufp->head[0].iov_base, &reclen, 4);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1187
1188
  	sent = svc_sendto(rqstp, &rqstp->rq_res);
  	if (sent != xbufp->len) {
0f0257eaa   Tom Tucker   svc: Move the xpr...
1189
1190
1191
1192
  		printk(KERN_NOTICE
  		       "rpc-srv/tcp: %s: %s %d when sending %d bytes "
  		       "- shutting down socket
  ",
57b1d3bab   Tom Tucker   svc: Removing rem...
1193
  		       rqstp->rq_xprt->xpt_server->sv_name,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1194
1195
  		       (sent<0)?"got error":"sent only",
  		       sent, xbufp->len);
57b1d3bab   Tom Tucker   svc: Removing rem...
1196
  		set_bit(XPT_CLOSE, &rqstp->rq_xprt->xpt_flags);
f6150c3ca   Tom Tucker   svc: Make the enq...
1197
  		svc_xprt_enqueue(rqstp->rq_xprt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1198
1199
1200
1201
  		sent = -EAGAIN;
  	}
  	return sent;
  }
e831fe65b   Tom Tucker   svc: Add xpo_prep...
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
  /*
   * Setup response header. TCP has a 4B record length field.
   */
  static void svc_tcp_prep_reply_hdr(struct svc_rqst *rqstp)
  {
  	struct kvec *resv = &rqstp->rq_res.head[0];
  
  	/* tcp needs a space for the record length... */
  	svc_putnl(resv, 0);
  }
b700cbb11   Tom Tucker   svc: Add a generi...
1212
  static struct svc_xprt *svc_tcp_create(struct svc_serv *serv,
62832c039   Pavel Emelyanov   sunrpc: Pull net ...
1213
  				       struct net *net,
b700cbb11   Tom Tucker   svc: Add a generi...
1214
1215
1216
  				       struct sockaddr *sa, int salen,
  				       int flags)
  {
62832c039   Pavel Emelyanov   sunrpc: Pull net ...
1217
  	return svc_create_socket(serv, IPPROTO_TCP, net, sa, salen, flags);
b700cbb11   Tom Tucker   svc: Add a generi...
1218
  }
9e00abc3c   Trond Myklebust   SUNRPC: sunrpc sh...
1219
  #if defined(CONFIG_SUNRPC_BACKCHANNEL)
1f11a034c   Andy Adamson   SUNRPC new transp...
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
  static struct svc_xprt *svc_bc_create_socket(struct svc_serv *, int,
  					     struct net *, struct sockaddr *,
  					     int, int);
  static void svc_bc_sock_free(struct svc_xprt *xprt);
  
  static struct svc_xprt *svc_bc_tcp_create(struct svc_serv *serv,
  				       struct net *net,
  				       struct sockaddr *sa, int salen,
  				       int flags)
  {
  	return svc_bc_create_socket(serv, IPPROTO_TCP, net, sa, salen, flags);
  }
  
  static void svc_bc_tcp_sock_detach(struct svc_xprt *xprt)
  {
  }
  
  static struct svc_xprt_ops svc_tcp_bc_ops = {
  	.xpo_create = svc_bc_tcp_create,
  	.xpo_detach = svc_bc_tcp_sock_detach,
  	.xpo_free = svc_bc_sock_free,
  	.xpo_prep_reply_hdr = svc_tcp_prep_reply_hdr,
16e4d93f6   Chuck Lever   NFSD: Ignore clie...
1242
  	.xpo_secure_port = svc_sock_secure_port,
1f11a034c   Andy Adamson   SUNRPC new transp...
1243
1244
1245
1246
1247
1248
1249
1250
  };
  
  static struct svc_xprt_class svc_tcp_bc_class = {
  	.xcl_name = "tcp-bc",
  	.xcl_owner = THIS_MODULE,
  	.xcl_ops = &svc_tcp_bc_ops,
  	.xcl_max_payload = RPCSVC_MAXPAYLOAD_TCP,
  };
16b2d1e1d   Andy Adamson   SUNRPC register a...
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
  
  static void svc_init_bc_xprt_sock(void)
  {
  	svc_reg_xprt_class(&svc_tcp_bc_class);
  }
  
  static void svc_cleanup_bc_xprt_sock(void)
  {
  	svc_unreg_xprt_class(&svc_tcp_bc_class);
  }
9e00abc3c   Trond Myklebust   SUNRPC: sunrpc sh...
1261
  #else /* CONFIG_SUNRPC_BACKCHANNEL */
16b2d1e1d   Andy Adamson   SUNRPC register a...
1262
1263
1264
1265
1266
1267
1268
  static void svc_init_bc_xprt_sock(void)
  {
  }
  
  static void svc_cleanup_bc_xprt_sock(void)
  {
  }
9e00abc3c   Trond Myklebust   SUNRPC: sunrpc sh...
1269
  #endif /* CONFIG_SUNRPC_BACKCHANNEL */
1f11a034c   Andy Adamson   SUNRPC new transp...
1270

360d87386   Tom Tucker   svc: Make svc_soc...
1271
  static struct svc_xprt_ops svc_tcp_ops = {
b700cbb11   Tom Tucker   svc: Add a generi...
1272
  	.xpo_create = svc_tcp_create,
5d137990f   Tom Tucker   svc: Move sk_send...
1273
1274
  	.xpo_recvfrom = svc_tcp_recvfrom,
  	.xpo_sendto = svc_tcp_sendto,
5148bf4eb   Tom Tucker   svc: Add transpor...
1275
  	.xpo_release_rqst = svc_release_skb,
69b6ba371   Trond Myklebust   SUNRPC: Ensure th...
1276
  	.xpo_detach = svc_tcp_sock_detach,
755cceaba   Tom Tucker   svc: Add per-tran...
1277
  	.xpo_free = svc_sock_free,
e831fe65b   Tom Tucker   svc: Add xpo_prep...
1278
  	.xpo_prep_reply_hdr = svc_tcp_prep_reply_hdr,
323bee32e   Tom Tucker   svc: Add a transp...
1279
  	.xpo_has_wspace = svc_tcp_has_wspace,
38a417cc9   Tom Tucker   svc: Add xpo_acce...
1280
  	.xpo_accept = svc_tcp_accept,
16e4d93f6   Chuck Lever   NFSD: Ignore clie...
1281
  	.xpo_secure_port = svc_sock_secure_port,
518776800   Trond Myklebust   SUNRPC: Allow svc...
1282
  	.xpo_adjust_wspace = svc_tcp_adjust_wspace,
360d87386   Tom Tucker   svc: Make svc_soc...
1283
1284
1285
1286
  };
  
  static struct svc_xprt_class svc_tcp_class = {
  	.xcl_name = "tcp",
b700cbb11   Tom Tucker   svc: Add a generi...
1287
  	.xcl_owner = THIS_MODULE,
360d87386   Tom Tucker   svc: Make svc_soc...
1288
  	.xcl_ops = &svc_tcp_ops,
490231558   Tom Tucker   svc: Add a max pa...
1289
  	.xcl_max_payload = RPCSVC_MAXPAYLOAD_TCP,
3c45ddf82   Chuck Lever   svcrdma: Select N...
1290
  	.xcl_ident = XPRT_TRANSPORT_TCP,
360d87386   Tom Tucker   svc: Make svc_soc...
1291
1292
1293
1294
1295
1296
  };
  
  void svc_init_xprt_sock(void)
  {
  	svc_reg_xprt_class(&svc_tcp_class);
  	svc_reg_xprt_class(&svc_udp_class);
16b2d1e1d   Andy Adamson   SUNRPC register a...
1297
  	svc_init_bc_xprt_sock();
360d87386   Tom Tucker   svc: Make svc_soc...
1298
1299
1300
1301
1302
1303
  }
  
  void svc_cleanup_xprt_sock(void)
  {
  	svc_unreg_xprt_class(&svc_tcp_class);
  	svc_unreg_xprt_class(&svc_udp_class);
16b2d1e1d   Andy Adamson   SUNRPC register a...
1304
  	svc_cleanup_bc_xprt_sock();
360d87386   Tom Tucker   svc: Make svc_soc...
1305
  }
bb5cf160b   Tom Tucker   svc: Move sk_serv...
1306
  static void svc_tcp_init(struct svc_sock *svsk, struct svc_serv *serv)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1307
1308
  {
  	struct sock	*sk = svsk->sk_sk;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1309

bd4620ddf   Stanislav Kinsbursky   SUNRPC: create sv...
1310
1311
  	svc_xprt_init(sock_net(svsk->sk_sock->sk), &svc_tcp_class,
  		      &svsk->sk_xprt, serv);
def13d740   Tom Tucker   svc: Move the aut...
1312
  	set_bit(XPT_CACHE_AUTH, &svsk->sk_xprt.xpt_flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1313
1314
1315
  	if (sk->sk_state == TCP_LISTEN) {
  		dprintk("setting up TCP socket for listening
  ");
02fc6c361   Tom Tucker   svc: Move sk_flag...
1316
  		set_bit(XPT_LISTENER, &svsk->sk_xprt.xpt_flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1317
  		sk->sk_data_ready = svc_tcp_listen_data_ready;
02fc6c361   Tom Tucker   svc: Move sk_flag...
1318
  		set_bit(XPT_CONN, &svsk->sk_xprt.xpt_flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1319
1320
1321
1322
1323
  	} else {
  		dprintk("setting up TCP socket for reading
  ");
  		sk->sk_state_change = svc_tcp_state_change;
  		sk->sk_data_ready = svc_tcp_data_ready;
47fcb03fe   Trond Myklebust   SUNRPC: Fix the T...
1324
  		sk->sk_write_space = svc_tcp_write_space;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1325
1326
1327
  
  		svsk->sk_reclen = 0;
  		svsk->sk_tcplen = 0;
8af345f58   J. Bruce Fields   svcrpc: track rpc...
1328
  		svsk->sk_datalen = 0;
31d68ef65   J. Bruce Fields   SUNRPC: Don't wai...
1329
  		memset(&svsk->sk_pages[0], 0, sizeof(svsk->sk_pages));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1330

b7872fe86   Chuck Lever   SUNRPC: RPC serve...
1331
  		tcp_sk(sk)->nonagle |= TCP_NAGLE_OFF;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1332

02fc6c361   Tom Tucker   svc: Move sk_flag...
1333
  		set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags);
cca5172a7   YOSHIFUJI Hideaki   [NET] SUNRPC: Fix...
1334
  		if (sk->sk_state != TCP_ESTABLISHED)
02fc6c361   Tom Tucker   svc: Move sk_flag...
1335
  			set_bit(XPT_CLOSE, &svsk->sk_xprt.xpt_flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1336
1337
  	}
  }
0f0257eaa   Tom Tucker   svc: Move the xpr...
1338
  void svc_sock_update_bufs(struct svc_serv *serv)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1339
1340
1341
1342
1343
  {
  	/*
  	 * The number of server threads has changed. Update
  	 * rcvbuf and sndbuf accordingly on all sockets
  	 */
8f3a6de31   Pavel Emelyanov   sunrpc: Turn list...
1344
  	struct svc_sock *svsk;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1345
1346
  
  	spin_lock_bh(&serv->sv_lock);
8f3a6de31   Pavel Emelyanov   sunrpc: Turn list...
1347
  	list_for_each_entry(svsk, &serv->sv_permsocks, sk_xprt.xpt_list)
02fc6c361   Tom Tucker   svc: Move sk_flag...
1348
  		set_bit(XPT_CHNGBUF, &svsk->sk_xprt.xpt_flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1349
1350
  	spin_unlock_bh(&serv->sv_lock);
  }
24c3767e4   Trond Myklebust   SUNRPC: The sunrp...
1351
  EXPORT_SYMBOL_GPL(svc_sock_update_bufs);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1352
1353
  
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1354
1355
1356
   * Initialize socket for RPC use and create svc_sock struct
   * XXX: May want to setsockopt SO_SNDBUF and SO_RCVBUF.
   */
6b174337e   Chuck Lever   [PATCH] knfsd: SU...
1357
1358
  static struct svc_sock *svc_setup_socket(struct svc_serv *serv,
  						struct socket *sock,
72c353760   J. Bruce Fields   svcrpc: standardi...
1359
  						int flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1360
1361
1362
  {
  	struct svc_sock	*svsk;
  	struct sock	*inet;
6b174337e   Chuck Lever   [PATCH] knfsd: SU...
1363
  	int		pmap_register = !(flags & SVC_SOCK_ANONYMOUS);
72c353760   J. Bruce Fields   svcrpc: standardi...
1364
  	int		err = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1365
1366
1367
  
  	dprintk("svc: svc_setup_socket %p
  ", sock);
72c353760   J. Bruce Fields   svcrpc: standardi...
1368
1369
1370
  	svsk = kzalloc(sizeof(*svsk), GFP_KERNEL);
  	if (!svsk)
  		return ERR_PTR(-ENOMEM);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1371
1372
1373
1374
  
  	inet = sock->sk;
  
  	/* Register socket with portmapper */
72c353760   J. Bruce Fields   svcrpc: standardi...
1375
1376
  	if (pmap_register)
  		err = svc_register(serv, sock_net(sock->sk), inet->sk_family,
5247fab5c   Stanislav Kinsbursky   SUNRPC: pass netw...
1377
  				     inet->sk_protocol,
c720c7e83   Eric Dumazet   inet: rename some...
1378
  				     ntohs(inet_sk(inet)->inet_sport));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1379

72c353760   J. Bruce Fields   svcrpc: standardi...
1380
  	if (err < 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1381
  		kfree(svsk);
72c353760   J. Bruce Fields   svcrpc: standardi...
1382
  		return ERR_PTR(err);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1383
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1384
1385
1386
1387
1388
1389
  	inet->sk_user_data = svsk;
  	svsk->sk_sock = sock;
  	svsk->sk_sk = inet;
  	svsk->sk_ostate = inet->sk_state_change;
  	svsk->sk_odata = inet->sk_data_ready;
  	svsk->sk_owspace = inet->sk_write_space;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1390
1391
1392
  
  	/* Initialize the socket */
  	if (sock->type == SOCK_DGRAM)
bb5cf160b   Tom Tucker   svc: Move sk_serv...
1393
  		svc_udp_init(svsk, serv);
966043986   Olga Kornievskaia   svcrpc: take adva...
1394
1395
1396
1397
1398
1399
  	else {
  		/* initialise setting must have enough space to
  		 * receive and respond to one request.
  		 */
  		svc_sock_setbufsize(svsk->sk_sock, 4 * serv->sv_max_mesg,
  					4 * serv->sv_max_mesg);
bb5cf160b   Tom Tucker   svc: Move sk_serv...
1400
  		svc_tcp_init(svsk, serv);
966043986   Olga Kornievskaia   svcrpc: take adva...
1401
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1402

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1403
1404
1405
  	dprintk("svc: svc_setup_socket created %p (inet %p)
  ",
  				svsk, svsk->sk_sk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1406
1407
  	return svsk;
  }
306463942   Stanislav Kinsbursky   nfsd: check passe...
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
  bool svc_alien_sock(struct net *net, int fd)
  {
  	int err;
  	struct socket *sock = sockfd_lookup(fd, &err);
  	bool ret = false;
  
  	if (!sock)
  		goto out;
  	if (sock_net(sock->sk) != net)
  		ret = true;
  	sockfd_put(sock);
  out:
  	return ret;
  }
  EXPORT_SYMBOL_GPL(svc_alien_sock);
bfba9ab4c   Chuck Lever   SUNRPC: pass buff...
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
  /**
   * svc_addsock - add a listener socket to an RPC service
   * @serv: pointer to RPC service to which to add a new listener
   * @fd: file descriptor of the new listener
   * @name_return: pointer to buffer to fill in with name of listener
   * @len: size of the buffer
   *
   * Fills in socket name and returns positive length of name if successful.
   * Name is terminated with '
  '.  On error, returns a negative errno
   * value.
   */
  int svc_addsock(struct svc_serv *serv, const int fd, char *name_return,
  		const size_t len)
b41b66d63   NeilBrown   [PATCH] knfsd: al...
1437
1438
1439
1440
  {
  	int err = 0;
  	struct socket *so = sockfd_lookup(fd, &err);
  	struct svc_sock *svsk = NULL;
a8e10078a   J. Bruce Fields   svcrpc: clean up ...
1441
1442
1443
  	struct sockaddr_storage addr;
  	struct sockaddr *sin = (struct sockaddr *)&addr;
  	int salen;
b41b66d63   NeilBrown   [PATCH] knfsd: al...
1444
1445
1446
  
  	if (!so)
  		return err;
a8e10078a   J. Bruce Fields   svcrpc: clean up ...
1447
  	err = -EAFNOSUPPORT;
205ba4230   Aime Le Rouzic   NFSD: Support AF_...
1448
  	if ((so->sk->sk_family != PF_INET) && (so->sk->sk_family != PF_INET6))
a8e10078a   J. Bruce Fields   svcrpc: clean up ...
1449
1450
1451
  		goto out;
  	err =  -EPROTONOSUPPORT;
  	if (so->sk->sk_protocol != IPPROTO_TCP &&
b41b66d63   NeilBrown   [PATCH] knfsd: al...
1452
  	    so->sk->sk_protocol != IPPROTO_UDP)
a8e10078a   J. Bruce Fields   svcrpc: clean up ...
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
  		goto out;
  	err = -EISCONN;
  	if (so->state > SS_UNCONNECTED)
  		goto out;
  	err = -ENOENT;
  	if (!try_module_get(THIS_MODULE))
  		goto out;
  	svsk = svc_setup_socket(serv, so, SVC_SOCK_DEFAULTS);
  	if (IS_ERR(svsk)) {
  		module_put(THIS_MODULE);
  		err = PTR_ERR(svsk);
  		goto out;
b41b66d63   NeilBrown   [PATCH] knfsd: al...
1465
  	}
a8e10078a   J. Bruce Fields   svcrpc: clean up ...
1466
1467
  	if (kernel_getsockname(svsk->sk_sock, sin, &salen) == 0)
  		svc_xprt_set_local(&svsk->sk_xprt, sin, salen);
39b553013   J. Bruce Fields   svcrpc: share som...
1468
  	svc_add_new_perm_xprt(serv, &svsk->sk_xprt);
e7942b9f2   Chuck Lever   SUNRPC: Switch on...
1469
  	return svc_one_sock_name(svsk, name_return, len);
a8e10078a   J. Bruce Fields   svcrpc: clean up ...
1470
1471
1472
  out:
  	sockfd_put(so);
  	return err;
b41b66d63   NeilBrown   [PATCH] knfsd: al...
1473
1474
  }
  EXPORT_SYMBOL_GPL(svc_addsock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1475
1476
1477
  /*
   * Create socket for RPC service.
   */
b700cbb11   Tom Tucker   svc: Add a generi...
1478
1479
  static struct svc_xprt *svc_create_socket(struct svc_serv *serv,
  					  int protocol,
62832c039   Pavel Emelyanov   sunrpc: Pull net ...
1480
  					  struct net *net,
b700cbb11   Tom Tucker   svc: Add a generi...
1481
1482
  					  struct sockaddr *sin, int len,
  					  int flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1483
1484
1485
1486
1487
  {
  	struct svc_sock	*svsk;
  	struct socket	*sock;
  	int		error;
  	int		type;
9dbc240f1   Tom Tucker   svc: Move the soc...
1488
1489
1490
  	struct sockaddr_storage addr;
  	struct sockaddr *newsin = (struct sockaddr *)&addr;
  	int		newlen;
c69da774b   Trond Myklebust   SUNRPC: Ensure IP...
1491
1492
  	int		family;
  	int		val;
5216a8e70   Pavel Emelyanov   Wrap buffers used...
1493
  	RPC_IFDEBUG(char buf[RPC_MAX_ADDRBUFLEN]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1494

ad06e4bd6   Chuck Lever   [PATCH] knfsd: SU...
1495
1496
1497
  	dprintk("svc: svc_create_socket(%s, %d, %s)
  ",
  			serv->sv_program->pg_name, protocol,
77f1f67a1   Chuck Lever   [PATCH] knfsd: SU...
1498
  			__svc_print_addr(sin, buf, sizeof(buf)));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1499
1500
1501
1502
1503
  
  	if (protocol != IPPROTO_UDP && protocol != IPPROTO_TCP) {
  		printk(KERN_WARNING "svc: only UDP and TCP "
  				"sockets supported
  ");
b700cbb11   Tom Tucker   svc: Add a generi...
1504
  		return ERR_PTR(-EINVAL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1505
  	}
c69da774b   Trond Myklebust   SUNRPC: Ensure IP...
1506

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1507
  	type = (protocol == IPPROTO_UDP)? SOCK_DGRAM : SOCK_STREAM;
c69da774b   Trond Myklebust   SUNRPC: Ensure IP...
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
  	switch (sin->sa_family) {
  	case AF_INET6:
  		family = PF_INET6;
  		break;
  	case AF_INET:
  		family = PF_INET;
  		break;
  	default:
  		return ERR_PTR(-EINVAL);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1518

14ec63c33   Pavel Emelyanov   sunrpc: Create so...
1519
  	error = __sock_create(net, family, type, protocol, &sock, 1);
77f1f67a1   Chuck Lever   [PATCH] knfsd: SU...
1520
  	if (error < 0)
b700cbb11   Tom Tucker   svc: Add a generi...
1521
  		return ERR_PTR(error);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1522

ed07536ed   Peter Zijlstra   [PATCH] lockdep: ...
1523
  	svc_reclassify_socket(sock);
c69da774b   Trond Myklebust   SUNRPC: Ensure IP...
1524
1525
1526
1527
1528
1529
1530
1531
1532
  	/*
  	 * If this is an PF_INET6 listener, we want to avoid
  	 * getting requests from IPv4 remotes.  Those should
  	 * be shunted to a PF_INET listener via rpcbind.
  	 */
  	val = 1;
  	if (family == PF_INET6)
  		kernel_setsockopt(sock, SOL_IPV6, IPV6_V6ONLY,
  					(char *)&val, sizeof(val));
181147462   Eric Sesterhenn   [SUNRPC]: Remove ...
1533
  	if (type == SOCK_STREAM)
4a17fd522   Pavel Emelyanov   sock: Introduce n...
1534
  		sock->sk->sk_reuse = SK_CAN_REUSE; /* allow address reuse */
77f1f67a1   Chuck Lever   [PATCH] knfsd: SU...
1535
  	error = kernel_bind(sock, sin, len);
181147462   Eric Sesterhenn   [SUNRPC]: Remove ...
1536
1537
  	if (error < 0)
  		goto bummer;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1538

9dbc240f1   Tom Tucker   svc: Move the soc...
1539
1540
1541
1542
  	newlen = len;
  	error = kernel_getsockname(sock, newsin, &newlen);
  	if (error < 0)
  		goto bummer;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1543
  	if (protocol == IPPROTO_TCP) {
e6242e928   Sridhar Samudrala   [SUNRPC]: Update ...
1544
  		if ((error = kernel_listen(sock, 64)) < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1545
1546
  			goto bummer;
  	}
72c353760   J. Bruce Fields   svcrpc: standardi...
1547
  	svsk = svc_setup_socket(serv, sock, flags);
a8e10078a   J. Bruce Fields   svcrpc: clean up ...
1548
1549
1550
  	if (IS_ERR(svsk)) {
  		error = PTR_ERR(svsk);
  		goto bummer;
e79eff1f9   NeilBrown   [PATCH] knfsd: SU...
1551
  	}
a8e10078a   J. Bruce Fields   svcrpc: clean up ...
1552
1553
  	svc_xprt_set_local(&svsk->sk_xprt, newsin, newlen);
  	return (struct svc_xprt *)svsk;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1554
1555
1556
1557
  bummer:
  	dprintk("svc: svc_create_socket error = %d
  ", -error);
  	sock_release(sock);
b700cbb11   Tom Tucker   svc: Add a generi...
1558
  	return ERR_PTR(error);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1559
1560
1561
  }
  
  /*
755cceaba   Tom Tucker   svc: Add per-tran...
1562
1563
1564
1565
1566
1567
1568
   * Detach the svc_sock from the socket so that no
   * more callbacks occur.
   */
  static void svc_sock_detach(struct svc_xprt *xprt)
  {
  	struct svc_sock *svsk = container_of(xprt, struct svc_sock, sk_xprt);
  	struct sock *sk = svsk->sk_sk;
eaefd1105   Eric Dumazet   net: add __rcu an...
1569
  	wait_queue_head_t *wq;
755cceaba   Tom Tucker   svc: Add per-tran...
1570
1571
1572
1573
1574
1575
1576
1577
  
  	dprintk("svc: svc_sock_detach(%p)
  ", svsk);
  
  	/* put back the old socket callbacks */
  	sk->sk_state_change = svsk->sk_ostate;
  	sk->sk_data_ready = svsk->sk_odata;
  	sk->sk_write_space = svsk->sk_owspace;
69b6ba371   Trond Myklebust   SUNRPC: Ensure th...
1578

eaefd1105   Eric Dumazet   net: add __rcu an...
1579
1580
1581
  	wq = sk_sleep(sk);
  	if (wq && waitqueue_active(wq))
  		wake_up_interruptible(wq);
69b6ba371   Trond Myklebust   SUNRPC: Ensure th...
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
  }
  
  /*
   * Disconnect the socket, and reset the callbacks
   */
  static void svc_tcp_sock_detach(struct svc_xprt *xprt)
  {
  	struct svc_sock *svsk = container_of(xprt, struct svc_sock, sk_xprt);
  
  	dprintk("svc: svc_tcp_sock_detach(%p)
  ", svsk);
  
  	svc_sock_detach(xprt);
31d68ef65   J. Bruce Fields   SUNRPC: Don't wai...
1595
1596
  	if (!test_bit(XPT_LISTENER, &xprt->xpt_flags)) {
  		svc_tcp_clear_pages(svsk);
69b6ba371   Trond Myklebust   SUNRPC: Ensure th...
1597
  		kernel_sock_shutdown(svsk->sk_sock, SHUT_RDWR);
31d68ef65   J. Bruce Fields   SUNRPC: Don't wai...
1598
  	}
755cceaba   Tom Tucker   svc: Add per-tran...
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
  }
  
  /*
   * Free the svc_sock's socket resources and the svc_sock itself.
   */
  static void svc_sock_free(struct svc_xprt *xprt)
  {
  	struct svc_sock *svsk = container_of(xprt, struct svc_sock, sk_xprt);
  	dprintk("svc: svc_sock_free(%p)
  ", svsk);
755cceaba   Tom Tucker   svc: Add per-tran...
1609
1610
1611
1612
1613
1614
  	if (svsk->sk_sock->file)
  		sockfd_put(svsk->sk_sock);
  	else
  		sock_release(svsk->sk_sock);
  	kfree(svsk);
  }
7652e5a09   Benny Halevy   nfs41: sunrpc: pr...
1615

9e00abc3c   Trond Myklebust   SUNRPC: sunrpc sh...
1616
  #if defined(CONFIG_SUNRPC_BACKCHANNEL)
7652e5a09   Benny Halevy   nfs41: sunrpc: pr...
1617
  /*
1f11a034c   Andy Adamson   SUNRPC new transp...
1618
   * Create a back channel svc_xprt which shares the fore channel socket.
7652e5a09   Benny Halevy   nfs41: sunrpc: pr...
1619
   */
1f11a034c   Andy Adamson   SUNRPC new transp...
1620
1621
1622
1623
1624
  static struct svc_xprt *svc_bc_create_socket(struct svc_serv *serv,
  					     int protocol,
  					     struct net *net,
  					     struct sockaddr *sin, int len,
  					     int flags)
7652e5a09   Benny Halevy   nfs41: sunrpc: pr...
1625
1626
  {
  	struct svc_sock *svsk;
1f11a034c   Andy Adamson   SUNRPC new transp...
1627
1628
1629
1630
1631
1632
1633
1634
  	struct svc_xprt *xprt;
  
  	if (protocol != IPPROTO_TCP) {
  		printk(KERN_WARNING "svc: only TCP sockets"
  			" supported on shared back channel
  ");
  		return ERR_PTR(-EINVAL);
  	}
7652e5a09   Benny Halevy   nfs41: sunrpc: pr...
1635

7652e5a09   Benny Halevy   nfs41: sunrpc: pr...
1636
1637
  	svsk = kzalloc(sizeof(*svsk), GFP_KERNEL);
  	if (!svsk)
1f11a034c   Andy Adamson   SUNRPC new transp...
1638
  		return ERR_PTR(-ENOMEM);
7652e5a09   Benny Halevy   nfs41: sunrpc: pr...
1639
1640
  
  	xprt = &svsk->sk_xprt;
bd4620ddf   Stanislav Kinsbursky   SUNRPC: create sv...
1641
  	svc_xprt_init(net, &svc_tcp_bc_class, xprt, serv);
1f11a034c   Andy Adamson   SUNRPC new transp...
1642

4a19de0f4   Andy Adamson   NFS rename client...
1643
  	serv->sv_bc_xprt = xprt;
1f11a034c   Andy Adamson   SUNRPC new transp...
1644

7652e5a09   Benny Halevy   nfs41: sunrpc: pr...
1645
1646
  	return xprt;
  }
7652e5a09   Benny Halevy   nfs41: sunrpc: pr...
1647
1648
  
  /*
1f11a034c   Andy Adamson   SUNRPC new transp...
1649
   * Free a back channel svc_sock.
7652e5a09   Benny Halevy   nfs41: sunrpc: pr...
1650
   */
1f11a034c   Andy Adamson   SUNRPC new transp...
1651
  static void svc_bc_sock_free(struct svc_xprt *xprt)
7652e5a09   Benny Halevy   nfs41: sunrpc: pr...
1652
  {
778be232a   Andy Adamson   NFS do not find c...
1653
  	if (xprt)
7652e5a09   Benny Halevy   nfs41: sunrpc: pr...
1654
1655
  		kfree(container_of(xprt, struct svc_sock, sk_xprt));
  }
9e00abc3c   Trond Myklebust   SUNRPC: sunrpc sh...
1656
  #endif /* CONFIG_SUNRPC_BACKCHANNEL */