Blame view

net/sunrpc/svcsock.c 43.1 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
45
46
  #include <asm/uaccess.h>
  #include <asm/ioctls.h>
  
  #include <linux/sunrpc/types.h>
ad06e4bd6   Chuck Lever   [PATCH] knfsd: SU...
47
  #include <linux/sunrpc/clnt.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
48
  #include <linux/sunrpc/xdr.h>
c0401ea00   Chuck Lever   SUNRPC: Update RP...
49
  #include <linux/sunrpc/msg_prot.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
50
51
  #include <linux/sunrpc/svcsock.h>
  #include <linux/sunrpc/stats.h>
4cfc7e601   Rahul Iyer   nfsd41: sunrpc: A...
52
  #include <linux/sunrpc/xprt.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
53

177e4f998   H Hartley Sweeten   svcsock.c: includ...
54
  #include "sunrpc.h"
360d87386   Tom Tucker   svc: Make svc_soc...
55
  #define RPCDBG_FACILITY	RPCDBG_SVCXPRT
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
56
57
58
  
  
  static struct svc_sock *svc_setup_socket(struct svc_serv *, struct socket *,
6b174337e   Chuck Lever   [PATCH] knfsd: SU...
59
  					 int *errp, int flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
60
61
62
  static void		svc_udp_data_ready(struct sock *, int);
  static int		svc_udp_recvfrom(struct svc_rqst *);
  static int		svc_udp_sendto(struct svc_rqst *);
755cceaba   Tom Tucker   svc: Add per-tran...
63
  static void		svc_sock_detach(struct svc_xprt *);
69b6ba371   Trond Myklebust   SUNRPC: Ensure th...
64
  static void		svc_tcp_sock_detach(struct svc_xprt *);
755cceaba   Tom Tucker   svc: Add per-tran...
65
  static void		svc_sock_free(struct svc_xprt *);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
66

b700cbb11   Tom Tucker   svc: Add a generi...
67
  static struct svc_xprt *svc_create_socket(struct svc_serv *, int,
62832c039   Pavel Emelyanov   sunrpc: Pull net ...
68
69
  					  struct net *, struct sockaddr *,
  					  int, int);
9e00abc3c   Trond Myklebust   SUNRPC: sunrpc sh...
70
  #if defined(CONFIG_SUNRPC_BACKCHANNEL)
1f11a034c   Andy Adamson   SUNRPC new transp...
71
72
73
74
  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...
75
  #endif /* CONFIG_SUNRPC_BACKCHANNEL */
1f11a034c   Andy Adamson   SUNRPC new transp...
76

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

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

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
207
208
  	/* send tail */
  	if (xdr->tail[0].iov_len) {
4cfc7e601   Rahul Iyer   nfsd41: sunrpc: A...
209
210
  		result = kernel_sendpage(sock, tailpage, tailoffset,
  				   xdr->tail[0].iov_len, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
211
212
213
  		if (result > 0)
  			len += result;
  	}
4cfc7e601   Rahul Iyer   nfsd41: sunrpc: A...
214
215
216
217
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
  
  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
257
  out:
ad06e4bd6   Chuck Lever   [PATCH] knfsd: SU...
258
259
  	dprintk("svc: socket %p sendto([%p %Zu... ], %d) = %d (addr %s)
  ",
57b1d3bab   Tom Tucker   svc: Removing rem...
260
  		svsk, xdr->head[0].iov_base, xdr->head[0].iov_len,
ad06e4bd6   Chuck Lever   [PATCH] knfsd: SU...
261
  		xdr->len, len, svc_print_addr(rqstp, buf, sizeof(buf)));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
262
263
264
265
266
  
  	return len;
  }
  
  /*
80212d59e   NeilBrown   [PATCH] knfsd: de...
267
268
   * Report socket names for nfsdfs
   */
e7942b9f2   Chuck Lever   SUNRPC: Switch on...
269
  static int svc_one_sock_name(struct svc_sock *svsk, char *buf, int remaining)
80212d59e   NeilBrown   [PATCH] knfsd: de...
270
  {
017cb47f4   Chuck Lever   SUNRPC: Clean up ...
271
272
273
  	const struct sock *sk = svsk->sk_sk;
  	const char *proto_name = sk->sk_protocol == IPPROTO_UDP ?
  							"udp" : "tcp";
80212d59e   NeilBrown   [PATCH] knfsd: de...
274
  	int len;
017cb47f4   Chuck Lever   SUNRPC: Clean up ...
275
  	switch (sk->sk_family) {
e7942b9f2   Chuck Lever   SUNRPC: Switch on...
276
277
278
  	case PF_INET:
  		len = snprintf(buf, remaining, "ipv4 %s %pI4 %d
  ",
017cb47f4   Chuck Lever   SUNRPC: Clean up ...
279
  				proto_name,
c720c7e83   Eric Dumazet   inet: rename some...
280
281
  				&inet_sk(sk)->inet_rcv_saddr,
  				inet_sk(sk)->inet_num);
80212d59e   NeilBrown   [PATCH] knfsd: de...
282
  		break;
58de2f865   Chuck Lever   SUNRPC: Support P...
283
284
285
  	case PF_INET6:
  		len = snprintf(buf, remaining, "ipv6 %s %pI6 %d
  ",
017cb47f4   Chuck Lever   SUNRPC: Clean up ...
286
287
  				proto_name,
  				&inet6_sk(sk)->rcv_saddr,
c720c7e83   Eric Dumazet   inet: rename some...
288
  				inet_sk(sk)->inet_num);
80212d59e   NeilBrown   [PATCH] knfsd: de...
289
290
  		break;
  	default:
e7942b9f2   Chuck Lever   SUNRPC: Switch on...
291
292
  		len = snprintf(buf, remaining, "*unknown-%d*
  ",
017cb47f4   Chuck Lever   SUNRPC: Clean up ...
293
  				sk->sk_family);
80212d59e   NeilBrown   [PATCH] knfsd: de...
294
  	}
e7942b9f2   Chuck Lever   SUNRPC: Switch on...
295
296
297
298
  
  	if (len >= remaining) {
  		*buf = '\0';
  		return -ENAMETOOLONG;
80212d59e   NeilBrown   [PATCH] knfsd: de...
299
300
301
  	}
  	return len;
  }
8435d34db   Chuck Lever   SUNRPC: pass buff...
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
  /**
   * svc_sock_names - construct a list of listener names in a string
   * @serv: pointer to RPC service
   * @buf: pointer to a buffer to fill in with socket names
   * @buflen: size of the buffer to be filled
   * @toclose: pointer to '\0'-terminated C string containing the name
   *		of a listener to be closed
   *
   * Fills in @buf with a '
  '-separated list of names of listener
   * sockets.  If @toclose is not NULL, the socket named by @toclose
   * is closed, and is not included in the output list.
   *
   * Returns positive length of the socket name string, or a negative
   * errno value on error.
   */
  int svc_sock_names(struct svc_serv *serv, char *buf, const size_t buflen,
  		   const char *toclose)
80212d59e   NeilBrown   [PATCH] knfsd: de...
320
  {
b41b66d63   NeilBrown   [PATCH] knfsd: al...
321
  	struct svc_sock *svsk, *closesk = NULL;
80212d59e   NeilBrown   [PATCH] knfsd: de...
322
323
324
325
  	int len = 0;
  
  	if (!serv)
  		return 0;
e7942b9f2   Chuck Lever   SUNRPC: Switch on...
326

aaf68cfbf   NeilBrown   [PATCH] knfsd: fi...
327
  	spin_lock_bh(&serv->sv_lock);
7a1820838   Tom Tucker   svc: Make close t...
328
  	list_for_each_entry(svsk, &serv->sv_permsocks, sk_xprt.xpt_list) {
e7942b9f2   Chuck Lever   SUNRPC: Switch on...
329
330
331
332
333
  		int onelen = svc_one_sock_name(svsk, buf + len, buflen - len);
  		if (onelen < 0) {
  			len = onelen;
  			break;
  		}
3942302ea   NeilBrown   sunrpc: svc_sock_...
334
  		if (toclose && strcmp(toclose, buf + len) == 0) {
b41b66d63   NeilBrown   [PATCH] knfsd: al...
335
  			closesk = svsk;
3942302ea   NeilBrown   sunrpc: svc_sock_...
336
337
  			svc_xprt_get(&closesk->sk_xprt);
  		} else
b41b66d63   NeilBrown   [PATCH] knfsd: al...
338
  			len += onelen;
80212d59e   NeilBrown   [PATCH] knfsd: de...
339
  	}
aaf68cfbf   NeilBrown   [PATCH] knfsd: fi...
340
  	spin_unlock_bh(&serv->sv_lock);
e7942b9f2   Chuck Lever   SUNRPC: Switch on...
341

3942302ea   NeilBrown   sunrpc: svc_sock_...
342
  	if (closesk) {
5680c4463   NeilBrown   [PATCH] knfsd: Fi...
343
344
345
  		/* Should unregister with portmap, but you cannot
  		 * unregister just one protocol...
  		 */
7a1820838   Tom Tucker   svc: Make close t...
346
  		svc_close_xprt(&closesk->sk_xprt);
3942302ea   NeilBrown   sunrpc: svc_sock_...
347
348
  		svc_xprt_put(&closesk->sk_xprt);
  	} else if (toclose)
37a034729   NeilBrown   [PATCH] knfsd: ca...
349
  		return -ENOENT;
80212d59e   NeilBrown   [PATCH] knfsd: de...
350
351
  	return len;
  }
24c3767e4   Trond Myklebust   SUNRPC: The sunrp...
352
  EXPORT_SYMBOL_GPL(svc_sock_names);
80212d59e   NeilBrown   [PATCH] knfsd: de...
353
354
  
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
355
356
   * Check input queue length
   */
0f0257eaa   Tom Tucker   svc: Move the xpr...
357
  static int svc_recv_available(struct svc_sock *svsk)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
358
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
359
360
  	struct socket	*sock = svsk->sk_sock;
  	int		avail, err;
e6242e928   Sridhar Samudrala   [SUNRPC]: Update ...
361
  	err = kernel_sock_ioctl(sock, TIOCINQ, (unsigned long) &avail);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
362
363
364
365
366
367
368
  
  	return (err >= 0)? avail : err;
  }
  
  /*
   * Generic recvfrom routine.
   */
0f0257eaa   Tom Tucker   svc: Move the xpr...
369
370
  static int svc_recvfrom(struct svc_rqst *rqstp, struct kvec *iov, int nr,
  			int buflen)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
371
  {
57b1d3bab   Tom Tucker   svc: Removing rem...
372
373
  	struct svc_sock *svsk =
  		container_of(rqstp->rq_xprt, struct svc_sock, sk_xprt);
1ba951053   Chuck Lever   [PATCH] knfsd: SU...
374
375
376
377
  	struct msghdr msg = {
  		.msg_flags	= MSG_DONTWAIT,
  	};
  	int len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
378

260c1d129   Tom Tucker   svc: Add transpor...
379
  	rqstp->rq_xprt_hlen = 0;
1ba951053   Chuck Lever   [PATCH] knfsd: SU...
380
381
  	len = kernel_recvmsg(svsk->sk_sock, &msg, iov, nr, buflen,
  				msg.msg_flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
382

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
383
384
  	dprintk("svc: socket %p recvfrom(%p, %Zu) = %d
  ",
1ba951053   Chuck Lever   [PATCH] knfsd: SU...
385
  		svsk, iov[0].iov_base, iov[0].iov_len, len);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
386
387
  	return len;
  }
31d68ef65   J. Bruce Fields   SUNRPC: Don't wai...
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
  static int svc_partial_recvfrom(struct svc_rqst *rqstp,
  				struct kvec *iov, int nr,
  				int buflen, unsigned int base)
  {
  	size_t save_iovlen;
  	void __user *save_iovbase;
  	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
414
415
416
  /*
   * Set socket snd and rcv buffer lengths
   */
0f0257eaa   Tom Tucker   svc: Move the xpr...
417
418
  static void svc_sock_setbufsize(struct socket *sock, unsigned int snd,
  				unsigned int rcv)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
  {
  #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...
436
  	sock->sk->sk_write_space(sock->sk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
437
438
439
440
441
442
  	release_sock(sock->sk);
  #endif
  }
  /*
   * INET callback when data has been received on the socket.
   */
0f0257eaa   Tom Tucker   svc: Move the xpr...
443
  static void svc_udp_data_ready(struct sock *sk, int count)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
444
  {
939bb7ef9   Neil Brown   [PATCH] Code clea...
445
  	struct svc_sock	*svsk = (struct svc_sock *)sk->sk_user_data;
eaefd1105   Eric Dumazet   net: add __rcu an...
446
  	wait_queue_head_t *wq = sk_sleep(sk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
447

939bb7ef9   Neil Brown   [PATCH] Code clea...
448
449
450
  	if (svsk) {
  		dprintk("svc: socket %p(inet %p), count=%d, busy=%d
  ",
02fc6c361   Tom Tucker   svc: Move sk_flag...
451
452
453
  			svsk, sk, count,
  			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...
454
  		svc_xprt_enqueue(&svsk->sk_xprt);
939bb7ef9   Neil Brown   [PATCH] Code clea...
455
  	}
eaefd1105   Eric Dumazet   net: add __rcu an...
456
457
  	if (wq && waitqueue_active(wq))
  		wake_up_interruptible(wq);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
458
459
460
461
462
  }
  
  /*
   * INET callback when space is newly available on the socket.
   */
0f0257eaa   Tom Tucker   svc: Move the xpr...
463
  static void svc_write_space(struct sock *sk)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
464
465
  {
  	struct svc_sock	*svsk = (struct svc_sock *)(sk->sk_user_data);
eaefd1105   Eric Dumazet   net: add __rcu an...
466
  	wait_queue_head_t *wq = sk_sleep(sk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
467
468
469
470
  
  	if (svsk) {
  		dprintk("svc: socket %p(inet %p), write_space busy=%d
  ",
02fc6c361   Tom Tucker   svc: Move sk_flag...
471
  			svsk, sk, test_bit(XPT_BUSY, &svsk->sk_xprt.xpt_flags));
f6150c3ca   Tom Tucker   svc: Make the enq...
472
  		svc_xprt_enqueue(&svsk->sk_xprt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
473
  	}
eaefd1105   Eric Dumazet   net: add __rcu an...
474
  	if (wq && waitqueue_active(wq)) {
939bb7ef9   Neil Brown   [PATCH] Code clea...
475
476
  		dprintk("RPC svc_write_space: someone sleeping on %p
  ",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
477
  		       svsk);
eaefd1105   Eric Dumazet   net: add __rcu an...
478
  		wake_up_interruptible(wq);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
479
480
  	}
  }
47fcb03fe   Trond Myklebust   SUNRPC: Fix the T...
481
482
483
484
485
486
487
488
  static void svc_tcp_write_space(struct sock *sk)
  {
  	struct socket *sock = sk->sk_socket;
  
  	if (sk_stream_wspace(sk) >= sk_stream_min_wspace(sk) && sock)
  		clear_bit(SOCK_NOSPACE, &sock->flags);
  	svc_write_space(sk);
  }
9dbc240f1   Tom Tucker   svc: Move the soc...
489
  /*
7702ce40b   Chuck Lever   SUNRPC: handle IP...
490
491
492
493
494
495
   * 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...
496
  	struct sockaddr_in *daddr = svc_daddr_in(rqstp);
7702ce40b   Chuck Lever   SUNRPC: handle IP...
497
498
  	if (cmh->cmsg_type != IP_PKTINFO)
  		return 0;
849a1cf13   Mi Jinlong   SUNRPC: Replace s...
499
500
501
  
  	daddr->sin_family = AF_INET;
  	daddr->sin_addr.s_addr = pki->ipi_spec_dst.s_addr;
7702ce40b   Chuck Lever   SUNRPC: handle IP...
502
503
504
505
506
507
508
509
510
511
  	return 1;
  }
  
  /*
   * See net/ipv6/datagram.c : datagram_recv_ctl
   */
  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...
512
  	struct sockaddr_in6 *daddr = svc_daddr_in6(rqstp);
7702ce40b   Chuck Lever   SUNRPC: handle IP...
513
514
  	if (cmh->cmsg_type != IPV6_PKTINFO)
  		return 0;
849a1cf13   Mi Jinlong   SUNRPC: Replace s...
515
516
  
  	daddr->sin6_family = AF_INET6;
4e3fd7a06   Alexey Dobriyan   net: remove ipv6_...
517
  	daddr->sin6_addr = pki->ipi6_addr;
849a1cf13   Mi Jinlong   SUNRPC: Replace s...
518
  	daddr->sin6_scope_id = pki->ipi6_ifindex;
7702ce40b   Chuck Lever   SUNRPC: handle IP...
519
520
521
522
  	return 1;
  }
  
  /*
9dbc240f1   Tom Tucker   svc: Move the soc...
523
524
525
526
527
528
   * 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...
529
530
  static int svc_udp_get_dest_address(struct svc_rqst *rqstp,
  				    struct cmsghdr *cmh)
95756482c   Chuck Lever   [PATCH] knfsd: SU...
531
  {
7702ce40b   Chuck Lever   SUNRPC: handle IP...
532
533
534
535
536
  	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...
537
  	}
7702ce40b   Chuck Lever   SUNRPC: handle IP...
538
539
  
  	return 0;
95756482c   Chuck Lever   [PATCH] knfsd: SU...
540
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
541
542
543
  /*
   * Receive a datagram from a UDP socket.
   */
0f0257eaa   Tom Tucker   svc: Move the xpr...
544
  static int svc_udp_recvfrom(struct svc_rqst *rqstp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
545
  {
57b1d3bab   Tom Tucker   svc: Removing rem...
546
547
  	struct svc_sock	*svsk =
  		container_of(rqstp->rq_xprt, struct svc_sock, sk_xprt);
bb5cf160b   Tom Tucker   svc: Move sk_serv...
548
  	struct svc_serv	*serv = svsk->sk_xprt.xpt_server;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
549
  	struct sk_buff	*skb;
bc375ea7e   David S. Miller   [SUNRPC]: Make su...
550
551
552
553
554
  	union {
  		struct cmsghdr	hdr;
  		long		all[SVC_PKTINFO_SPACE / sizeof(long)];
  	} buffer;
  	struct cmsghdr *cmh = &buffer.hdr;
7a37f5787   NeilBrown   [PATCH] knfsd: us...
555
556
557
558
559
560
  	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...
561
562
  	size_t len;
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
563

02fc6c361   Tom Tucker   svc: Move sk_flag...
564
  	if (test_and_clear_bit(XPT_CHNGBUF, &svsk->sk_xprt.xpt_flags))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
565
566
567
  	    /* 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...
568
569
570
571
  	     * 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
572
573
  	     */
  	    svc_sock_setbufsize(svsk->sk_sock,
c6b0a9f87   NeilBrown   [PATCH] knfsd: ti...
574
575
  				(serv->sv_nrthreads+3) * serv->sv_max_mesg,
  				(serv->sv_nrthreads+3) * serv->sv_max_mesg);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
576

02fc6c361   Tom Tucker   svc: Move sk_flag...
577
  	clear_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags);
05ed690ef   NeilBrown   knfsd: simplify a...
578
579
580
581
582
583
584
585
586
587
588
  	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...
589
  			set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
590
  		}
05ed690ef   NeilBrown   knfsd: simplify a...
591
  		return -EAGAIN;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
592
  	}
9dbc240f1   Tom Tucker   svc: Move the soc...
593
  	len = svc_addr_len(svc_addr(rqstp));
abc5c44d6   Chuck Lever   SUNRPC: Fix error...
594
595
  	if (len == 0)
  		return -EAFNOSUPPORT;
9dbc240f1   Tom Tucker   svc: Move the soc...
596
  	rqstp->rq_addrlen = len;
b7aa0bf70   Eric Dumazet   [NET]: convert ne...
597
598
  	if (skb->tstamp.tv64 == 0) {
  		skb->tstamp = ktime_get_real();
cca5172a7   YOSHIFUJI Hideaki   [NET] SUNRPC: Fix...
599
  		/* Don't enable netstamp, sunrpc doesn't
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
600
601
  		   need that much accuracy */
  	}
b7aa0bf70   Eric Dumazet   [NET]: convert ne...
602
  	svsk->sk_sk->sk_stamp = skb->tstamp;
02fc6c361   Tom Tucker   svc: Move sk_flag...
603
  	set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags); /* there may be more data... */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
604

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

7702ce40b   Chuck Lever   SUNRPC: handle IP...
609
  	if (!svc_udp_get_dest_address(rqstp, cmh)) {
7a37f5787   NeilBrown   [PATCH] knfsd: us...
610
  		if (net_ratelimit())
7702ce40b   Chuck Lever   SUNRPC: handle IP...
611
612
613
614
615
  			printk(KERN_WARNING
  				"svc: received unknown control message %d/%d; "
  				"dropping RPC reply datagram
  ",
  					cmh->cmsg_level, cmh->cmsg_type);
9d410c796   Eric Dumazet   net: fix sk_forwa...
616
  		skb_free_datagram_locked(svsk->sk_sk, skb);
7a37f5787   NeilBrown   [PATCH] knfsd: us...
617
618
  		return 0;
  	}
849a1cf13   Mi Jinlong   SUNRPC: Replace s...
619
  	rqstp->rq_daddrlen = svc_addr_len(svc_daddr(rqstp));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
620
621
622
623
624
625
626
  
  	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 */
9d410c796   Eric Dumazet   net: fix sk_forwa...
627
  			skb_free_datagram_locked(svsk->sk_sk, skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
628
629
630
  			return 0;
  		}
  		local_bh_enable();
9d410c796   Eric Dumazet   net: fix sk_forwa...
631
  		skb_free_datagram_locked(svsk->sk_sk, skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
632
633
  	} else {
  		/* we can use it in-place */
0f0257eaa   Tom Tucker   svc: Move the xpr...
634
635
  		rqstp->rq_arg.head[0].iov_base = skb->data +
  			sizeof(struct udphdr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
636
  		rqstp->rq_arg.head[0].iov_len = len;
fb286bb29   Herbert Xu   [NET]: Detect har...
637
  		if (skb_checksum_complete(skb)) {
9d410c796   Eric Dumazet   net: fix sk_forwa...
638
  			skb_free_datagram_locked(svsk->sk_sk, skb);
fb286bb29   Herbert Xu   [NET]: Detect har...
639
  			return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
640
  		}
5148bf4eb   Tom Tucker   svc: Add transpor...
641
  		rqstp->rq_xprt_ctxt = skb;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
642
643
644
645
646
647
  	}
  
  	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...
648
  		rqstp->rq_respages = rqstp->rq_pages+1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
649
650
  	} else {
  		rqstp->rq_arg.page_len = len - rqstp->rq_arg.head[0].iov_len;
445243594   NeilBrown   [PATCH] knfsd: Re...
651
  		rqstp->rq_respages = rqstp->rq_pages + 1 +
172589ccd   Ilpo Järvinen   [NET]: DIV_ROUND_...
652
  			DIV_ROUND_UP(rqstp->rq_arg.page_len, PAGE_SIZE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
  	}
  
  	if (serv->sv_stats)
  		serv->sv_stats->netudpcnt++;
  
  	return len;
  }
  
  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...
673
674
675
  static void svc_udp_prep_reply_hdr(struct svc_rqst *rqstp)
  {
  }
323bee32e   Tom Tucker   svc: Add a transp...
676
677
678
  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...
679
  	struct svc_serv	*serv = xprt->xpt_server;
323bee32e   Tom Tucker   svc: Add a transp...
680
681
682
683
684
685
686
  	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...
687
  	required = atomic_read(&svsk->sk_xprt.xpt_reserved) + serv->sv_max_mesg;
323bee32e   Tom Tucker   svc: Add a transp...
688
689
690
691
692
  	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...
693
694
695
696
697
  static struct svc_xprt *svc_udp_accept(struct svc_xprt *xprt)
  {
  	BUG();
  	return NULL;
  }
b700cbb11   Tom Tucker   svc: Add a generi...
698
  static struct svc_xprt *svc_udp_create(struct svc_serv *serv,
62832c039   Pavel Emelyanov   sunrpc: Pull net ...
699
  				       struct net *net,
b700cbb11   Tom Tucker   svc: Add a generi...
700
701
702
  				       struct sockaddr *sa, int salen,
  				       int flags)
  {
62832c039   Pavel Emelyanov   sunrpc: Pull net ...
703
  	return svc_create_socket(serv, IPPROTO_UDP, net, sa, salen, flags);
b700cbb11   Tom Tucker   svc: Add a generi...
704
  }
360d87386   Tom Tucker   svc: Make svc_soc...
705
  static struct svc_xprt_ops svc_udp_ops = {
b700cbb11   Tom Tucker   svc: Add a generi...
706
  	.xpo_create = svc_udp_create,
5d137990f   Tom Tucker   svc: Move sk_send...
707
708
  	.xpo_recvfrom = svc_udp_recvfrom,
  	.xpo_sendto = svc_udp_sendto,
5148bf4eb   Tom Tucker   svc: Add transpor...
709
  	.xpo_release_rqst = svc_release_skb,
755cceaba   Tom Tucker   svc: Add per-tran...
710
711
  	.xpo_detach = svc_sock_detach,
  	.xpo_free = svc_sock_free,
e831fe65b   Tom Tucker   svc: Add xpo_prep...
712
  	.xpo_prep_reply_hdr = svc_udp_prep_reply_hdr,
323bee32e   Tom Tucker   svc: Add a transp...
713
  	.xpo_has_wspace = svc_udp_has_wspace,
38a417cc9   Tom Tucker   svc: Add xpo_acce...
714
  	.xpo_accept = svc_udp_accept,
360d87386   Tom Tucker   svc: Make svc_soc...
715
716
717
718
  };
  
  static struct svc_xprt_class svc_udp_class = {
  	.xcl_name = "udp",
b700cbb11   Tom Tucker   svc: Add a generi...
719
  	.xcl_owner = THIS_MODULE,
360d87386   Tom Tucker   svc: Make svc_soc...
720
  	.xcl_ops = &svc_udp_ops,
490231558   Tom Tucker   svc: Add a max pa...
721
  	.xcl_max_payload = RPCSVC_MAXPAYLOAD_UDP,
360d87386   Tom Tucker   svc: Make svc_soc...
722
  };
bb5cf160b   Tom Tucker   svc: Move sk_serv...
723
  static void svc_udp_init(struct svc_sock *svsk, struct svc_serv *serv)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
724
  {
7702ce40b   Chuck Lever   SUNRPC: handle IP...
725
  	int err, level, optname, one = 1;
7a37f5787   NeilBrown   [PATCH] knfsd: us...
726

bd4620ddf   Stanislav Kinsbursky   SUNRPC: create sv...
727
728
  	svc_xprt_init(sock_net(svsk->sk_sock->sk), &svc_udp_class,
  		      &svsk->sk_xprt, serv);
def13d740   Tom Tucker   svc: Move the aut...
729
  	clear_bit(XPT_CACHE_AUTH, &svsk->sk_xprt.xpt_flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
730
731
  	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
732
733
  
  	/* initialise setting must have enough space to
cca5172a7   YOSHIFUJI Hideaki   [NET] SUNRPC: Fix...
734
  	 * receive and respond to one request.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
735
736
737
  	 * svc_udp_recvfrom will re-adjust if necessary
  	 */
  	svc_sock_setbufsize(svsk->sk_sock,
bb5cf160b   Tom Tucker   svc: Move sk_serv...
738
739
  			    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
740

0f0257eaa   Tom Tucker   svc: Move the xpr...
741
742
  	/* 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...
743
  	set_bit(XPT_CHNGBUF, &svsk->sk_xprt.xpt_flags);
7a37f5787   NeilBrown   [PATCH] knfsd: us...
744

7a37f5787   NeilBrown   [PATCH] knfsd: us...
745
  	/* make sure we get destination address info */
7702ce40b   Chuck Lever   SUNRPC: handle IP...
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
  	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
762
763
764
765
766
767
  }
  
  /*
   * A data_ready event on a listening socket means there's a connection
   * pending. Do not use state_change as a substitute for it.
   */
0f0257eaa   Tom Tucker   svc: Move the xpr...
768
  static void svc_tcp_listen_data_ready(struct sock *sk, int count_unused)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
769
  {
939bb7ef9   Neil Brown   [PATCH] Code clea...
770
  	struct svc_sock	*svsk = (struct svc_sock *)sk->sk_user_data;
eaefd1105   Eric Dumazet   net: add __rcu an...
771
  	wait_queue_head_t *wq;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
772
773
774
  
  	dprintk("svc: socket %p TCP (listen) state change %d
  ",
939bb7ef9   Neil Brown   [PATCH] Code clea...
775
  		sk, sk->sk_state);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
776

939bb7ef9   Neil Brown   [PATCH] Code clea...
777
778
779
780
781
782
783
784
785
786
787
788
  	/*
  	 * 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...
789
  			set_bit(XPT_CONN, &svsk->sk_xprt.xpt_flags);
f6150c3ca   Tom Tucker   svc: Make the enq...
790
  			svc_xprt_enqueue(&svsk->sk_xprt);
939bb7ef9   Neil Brown   [PATCH] Code clea...
791
792
793
  		} else
  			printk("svc: socket %p: no user data
  ", sk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
794
  	}
939bb7ef9   Neil Brown   [PATCH] Code clea...
795

eaefd1105   Eric Dumazet   net: add __rcu an...
796
797
798
  	wq = sk_sleep(sk);
  	if (wq && waitqueue_active(wq))
  		wake_up_interruptible_all(wq);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
799
800
801
802
803
  }
  
  /*
   * A state change on a connected socket means it's dying or dead.
   */
0f0257eaa   Tom Tucker   svc: Move the xpr...
804
  static void svc_tcp_state_change(struct sock *sk)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
805
  {
939bb7ef9   Neil Brown   [PATCH] Code clea...
806
  	struct svc_sock	*svsk = (struct svc_sock *)sk->sk_user_data;
eaefd1105   Eric Dumazet   net: add __rcu an...
807
  	wait_queue_head_t *wq = sk_sleep(sk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
808
809
810
  
  	dprintk("svc: socket %p TCP (connected) state change %d (svsk %p)
  ",
939bb7ef9   Neil Brown   [PATCH] Code clea...
811
  		sk, sk->sk_state, sk->sk_user_data);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
812

939bb7ef9   Neil Brown   [PATCH] Code clea...
813
  	if (!svsk)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
814
815
  		printk("svc: socket %p: no user data
  ", sk);
939bb7ef9   Neil Brown   [PATCH] Code clea...
816
  	else {
02fc6c361   Tom Tucker   svc: Move sk_flag...
817
  		set_bit(XPT_CLOSE, &svsk->sk_xprt.xpt_flags);
f6150c3ca   Tom Tucker   svc: Make the enq...
818
  		svc_xprt_enqueue(&svsk->sk_xprt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
819
  	}
eaefd1105   Eric Dumazet   net: add __rcu an...
820
821
  	if (wq && waitqueue_active(wq))
  		wake_up_interruptible_all(wq);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
822
  }
0f0257eaa   Tom Tucker   svc: Move the xpr...
823
  static void svc_tcp_data_ready(struct sock *sk, int count)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
824
  {
939bb7ef9   Neil Brown   [PATCH] Code clea...
825
  	struct svc_sock *svsk = (struct svc_sock *)sk->sk_user_data;
eaefd1105   Eric Dumazet   net: add __rcu an...
826
  	wait_queue_head_t *wq = sk_sleep(sk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
827
828
829
  
  	dprintk("svc: socket %p TCP data ready (svsk %p)
  ",
939bb7ef9   Neil Brown   [PATCH] Code clea...
830
831
  		sk, sk->sk_user_data);
  	if (svsk) {
02fc6c361   Tom Tucker   svc: Move sk_flag...
832
  		set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags);
f6150c3ca   Tom Tucker   svc: Make the enq...
833
  		svc_xprt_enqueue(&svsk->sk_xprt);
939bb7ef9   Neil Brown   [PATCH] Code clea...
834
  	}
eaefd1105   Eric Dumazet   net: add __rcu an...
835
836
  	if (wq && waitqueue_active(wq))
  		wake_up_interruptible(wq);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
837
838
839
840
841
  }
  
  /*
   * Accept a TCP connection
   */
38a417cc9   Tom Tucker   svc: Add xpo_acce...
842
  static struct svc_xprt *svc_tcp_accept(struct svc_xprt *xprt)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
843
  {
38a417cc9   Tom Tucker   svc: Add xpo_acce...
844
  	struct svc_sock *svsk = container_of(xprt, struct svc_sock, sk_xprt);
cdd88b9f3   akpm@linux-foundation.org   [PATCH] knfsd: SU...
845
846
  	struct sockaddr_storage addr;
  	struct sockaddr	*sin = (struct sockaddr *) &addr;
bb5cf160b   Tom Tucker   svc: Move sk_serv...
847
  	struct svc_serv	*serv = svsk->sk_xprt.xpt_server;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
848
849
  	struct socket	*sock = svsk->sk_sock;
  	struct socket	*newsock;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
850
851
  	struct svc_sock	*newsvsk;
  	int		err, slen;
5216a8e70   Pavel Emelyanov   Wrap buffers used...
852
  	RPC_IFDEBUG(char buf[RPC_MAX_ADDRBUFLEN]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
853
854
855
856
  
  	dprintk("svc: tcp_accept %p sock %p
  ", svsk, sock);
  	if (!sock)
38a417cc9   Tom Tucker   svc: Add xpo_acce...
857
  		return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
858

02fc6c361   Tom Tucker   svc: Move sk_flag...
859
  	clear_bit(XPT_CONN, &svsk->sk_xprt.xpt_flags);
e6242e928   Sridhar Samudrala   [SUNRPC]: Update ...
860
861
  	err = kernel_accept(sock, &newsock, O_NONBLOCK);
  	if (err < 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
862
863
864
865
  		if (err == -ENOMEM)
  			printk(KERN_WARNING "%s: no more sockets!
  ",
  			       serv->sv_name);
e6242e928   Sridhar Samudrala   [SUNRPC]: Update ...
866
  		else if (err != -EAGAIN && net_ratelimit())
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
867
868
869
  			printk(KERN_WARNING "%s: accept failed (err %d)!
  ",
  				   serv->sv_name, -err);
38a417cc9   Tom Tucker   svc: Add xpo_acce...
870
  		return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
871
  	}
02fc6c361   Tom Tucker   svc: Move sk_flag...
872
  	set_bit(XPT_CONN, &svsk->sk_xprt.xpt_flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
873

cdd88b9f3   akpm@linux-foundation.org   [PATCH] knfsd: SU...
874
  	err = kernel_getpeername(newsock, sin, &slen);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
875
876
877
878
879
880
881
882
883
  	if (err < 0) {
  		if (net_ratelimit())
  			printk(KERN_WARNING "%s: peername failed (err %d)!
  ",
  				   serv->sv_name, -err);
  		goto failed;		/* aborted connection or whatever */
  	}
  
  	/* Ideally, we would want to reject connections from unauthorized
ad06e4bd6   Chuck Lever   [PATCH] knfsd: SU...
884
885
  	 * 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
886
  	 */
cdd88b9f3   akpm@linux-foundation.org   [PATCH] knfsd: SU...
887
  	if (!svc_port_is_privileged(sin)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
888
  		dprintk(KERN_WARNING
ad06e4bd6   Chuck Lever   [PATCH] knfsd: SU...
889
890
  			"%s: connect from unprivileged port: %s
  ",
cca5172a7   YOSHIFUJI Hideaki   [NET] SUNRPC: Fix...
891
  			serv->sv_name,
cdd88b9f3   akpm@linux-foundation.org   [PATCH] knfsd: SU...
892
  			__svc_print_addr(sin, buf, sizeof(buf)));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
893
  	}
ad06e4bd6   Chuck Lever   [PATCH] knfsd: SU...
894
895
  	dprintk("%s: connect from %s
  ", serv->sv_name,
cdd88b9f3   akpm@linux-foundation.org   [PATCH] knfsd: SU...
896
  		__svc_print_addr(sin, buf, sizeof(buf)));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
897
898
899
900
901
  
  	/* make sure that a write doesn't block forever when
  	 * low on memory
  	 */
  	newsock->sk->sk_sndtimeo = HZ*30;
6b174337e   Chuck Lever   [PATCH] knfsd: SU...
902
903
  	if (!(newsvsk = svc_setup_socket(serv, newsock, &err,
  				 (SVC_SOCK_ANONYMOUS | SVC_SOCK_TEMPORARY))))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
904
  		goto failed;
9dbc240f1   Tom Tucker   svc: Move the soc...
905
  	svc_xprt_set_remote(&newsvsk->sk_xprt, sin, slen);
a97476926   Frank van Maarseveen   SUNRPC server: re...
906
907
908
909
910
911
  	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...
912
  	svc_xprt_set_local(&newsvsk->sk_xprt, sin, slen);
067d78173   Chuck Lever   [PATCH] knfsd: SU...
913

f9f3cc4fa   Tom Tucker   svc: Move connect...
914
915
916
917
918
919
920
921
922
  	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...
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
  static unsigned int svc_tcp_restore_pages(struct svc_sock *svsk, struct svc_rqst *rqstp)
  {
  	unsigned int i, len, npages;
  
  	if (svsk->sk_tcplen <= sizeof(rpc_fraghdr))
  		return 0;
  	len = svsk->sk_tcplen - sizeof(rpc_fraghdr);
  	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;
  
  	if (svsk->sk_tcplen <= sizeof(rpc_fraghdr))
  		return;
  	len = svsk->sk_tcplen - sizeof(rpc_fraghdr);
  	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;
  
  	if (svsk->sk_tcplen <= sizeof(rpc_fraghdr))
  		goto out;
  	len = svsk->sk_tcplen - sizeof(rpc_fraghdr);
  	npages = (len + PAGE_SIZE - 1) >> PAGE_SHIFT;
  	for (i = 0; i < npages; i++) {
  		BUG_ON(svsk->sk_pages[i] == NULL);
  		put_page(svsk->sk_pages[i]);
  		svsk->sk_pages[i] = NULL;
  	}
  out:
  	svsk->sk_tcplen = 0;
  }
f9f3cc4fa   Tom Tucker   svc: Move connect...
972
  /*
8f55f3c0a   Alexandros Batsakis   nfsd41: sunrpc: s...
973
974
975
976
   * Receive data.
   * If we haven't gotten the record length yet, get the next four bytes.
   * Otherwise try to gobble up as much as possible up to the complete
   * record length.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
977
   */
8f55f3c0a   Alexandros Batsakis   nfsd41: sunrpc: s...
978
  static int svc_tcp_recv_record(struct svc_sock *svsk, struct svc_rqst *rqstp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
979
  {
bb5cf160b   Tom Tucker   svc: Move sk_serv...
980
  	struct svc_serv	*serv = svsk->sk_xprt.xpt_server;
5ee78d483   Trond Myklebust   SUNRPC: svc_tcp_r...
981
  	unsigned int want;
8f55f3c0a   Alexandros Batsakis   nfsd41: sunrpc: s...
982
  	int len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
983

02fc6c361   Tom Tucker   svc: Move sk_flag...
984
  	clear_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
985

c0401ea00   Chuck Lever   SUNRPC: Update RP...
986
  	if (svsk->sk_tcplen < sizeof(rpc_fraghdr)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
987
  		struct kvec	iov;
5ee78d483   Trond Myklebust   SUNRPC: svc_tcp_r...
988
  		want = sizeof(rpc_fraghdr) - svsk->sk_tcplen;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
989
990
991
992
993
994
995
  		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...
996
997
998
  			dprintk("svc: short recvfrom while reading record "
  				"length (%d of %d)
  ", len, want);
31d68ef65   J. Bruce Fields   SUNRPC: Don't wai...
999
  			return -EAGAIN;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1000
1001
1002
  		}
  
  		svsk->sk_reclen = ntohl(svsk->sk_reclen);
c0401ea00   Chuck Lever   SUNRPC: Update RP...
1003
  		if (!(svsk->sk_reclen & RPC_LAST_STREAM_FRAGMENT)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1004
1005
1006
1007
1008
  			/* FIXME: technically, a record can be fragmented,
  			 *  and non-terminal fragments will not have the top
  			 *  bit set in the fragment length header.
  			 *  But apparently no known nfs clients send fragmented
  			 *  records. */
34e9a63b4   NeilBrown   [PATCH] knfsd: ra...
1009
  			if (net_ratelimit())
c0401ea00   Chuck Lever   SUNRPC: Update RP...
1010
1011
1012
  				printk(KERN_NOTICE "RPC: multiple fragments "
  					"per record not supported
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1013
1014
  			goto err_delete;
  		}
8f55f3c0a   Alexandros Batsakis   nfsd41: sunrpc: s...
1015

c0401ea00   Chuck Lever   SUNRPC: Update RP...
1016
  		svsk->sk_reclen &= RPC_FRAGMENT_SIZE_MASK;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1017
1018
  		dprintk("svc: TCP record, %d bytes
  ", svsk->sk_reclen);
c6b0a9f87   NeilBrown   [PATCH] knfsd: ti...
1019
  		if (svsk->sk_reclen > serv->sv_max_mesg) {
34e9a63b4   NeilBrown   [PATCH] knfsd: ra...
1020
  			if (net_ratelimit())
c0401ea00   Chuck Lever   SUNRPC: Update RP...
1021
1022
1023
1024
  				printk(KERN_NOTICE "RPC: "
  					"fragment too large: 0x%08lx
  ",
  					(unsigned long)svsk->sk_reclen);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1025
1026
1027
  			goto err_delete;
  		}
  	}
cc6c2127f   J. Bruce Fields   svcrpc: close con...
1028
1029
  	if (svsk->sk_reclen < 8)
  		goto err_delete; /* client is nuts. */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1030
  	len = svsk->sk_reclen;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1031

8f55f3c0a   Alexandros Batsakis   nfsd41: sunrpc: s...
1032
  	return len;
31d68ef65   J. Bruce Fields   SUNRPC: Don't wai...
1033
1034
1035
  error:
  	dprintk("RPC: TCP recv_record got %d
  ", len);
8f55f3c0a   Alexandros Batsakis   nfsd41: sunrpc: s...
1036
  	return len;
31d68ef65   J. Bruce Fields   SUNRPC: Don't wai...
1037
  err_delete:
8f55f3c0a   Alexandros Batsakis   nfsd41: sunrpc: s...
1038
  	set_bit(XPT_CLOSE, &svsk->sk_xprt.xpt_flags);
8f55f3c0a   Alexandros Batsakis   nfsd41: sunrpc: s...
1039
1040
  	return -EAGAIN;
  }
586c52cc6   Trond Myklebust   svcrpc: copy cb r...
1041
  static int receive_cb_reply(struct svc_sock *svsk, struct svc_rqst *rqstp)
4cfc7e601   Rahul Iyer   nfsd41: sunrpc: A...
1042
  {
586c52cc6   Trond Myklebust   svcrpc: copy cb r...
1043
  	struct rpc_xprt *bc_xprt = svsk->sk_xprt.xpt_bc_xprt;
4cfc7e601   Rahul Iyer   nfsd41: sunrpc: A...
1044
  	struct rpc_rqst *req = NULL;
586c52cc6   Trond Myklebust   svcrpc: copy cb r...
1045
1046
  	struct kvec *src, *dst;
  	__be32 *p = (__be32 *)rqstp->rq_arg.head[0].iov_base;
48e6555c7   J. Bruce Fields   svcrpc: note netw...
1047
1048
  	__be32 xid;
  	__be32 calldir;
4cfc7e601   Rahul Iyer   nfsd41: sunrpc: A...
1049

4cfc7e601   Rahul Iyer   nfsd41: sunrpc: A...
1050
1051
  	xid = *p++;
  	calldir = *p;
586c52cc6   Trond Myklebust   svcrpc: copy cb r...
1052
1053
  	if (bc_xprt)
  		req = xprt_lookup_rqst(bc_xprt, xid);
4cfc7e601   Rahul Iyer   nfsd41: sunrpc: A...
1054

586c52cc6   Trond Myklebust   svcrpc: copy cb r...
1055
1056
1057
1058
1059
1060
1061
1062
  	if (!req) {
  		printk(KERN_NOTICE
  			"%s: Got unrecognized reply: "
  			"calldir 0x%x xpt_bc_xprt %p xid %08x
  ",
  			__func__, ntohl(calldir),
  			bc_xprt, xid);
  		return -EAGAIN;
4cfc7e601   Rahul Iyer   nfsd41: sunrpc: A...
1063
  	}
586c52cc6   Trond Myklebust   svcrpc: copy cb r...
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
  
  	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)
  		return -EAGAIN; /* whatever; just giving up. */
  	memcpy(dst->iov_base, src->iov_base, src->iov_len);
  	xprt_complete_rqst(req->rq_task, svsk->sk_reclen);
  	rqstp->rq_arg.len = 0;
  	return 0;
  }
  
  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...
1093
  }
31d68ef65   J. Bruce Fields   SUNRPC: Don't wai...
1094

8f55f3c0a   Alexandros Batsakis   nfsd41: sunrpc: s...
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
  /*
   * 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...
1105
  	unsigned int want, base;
586c52cc6   Trond Myklebust   svcrpc: copy cb r...
1106
1107
  	__be32 *p;
  	__be32 calldir;
5ee78d483   Trond Myklebust   SUNRPC: svc_tcp_r...
1108
  	int pnum;
8f55f3c0a   Alexandros Batsakis   nfsd41: sunrpc: s...
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
  
  	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...
1119
1120
  	base = svc_tcp_restore_pages(svsk, rqstp);
  	want = svsk->sk_reclen - base;
3cc03b164   NeilBrown   [PATCH] knfsd: Av...
1121
  	vec = rqstp->rq_vec;
4cfc7e601   Rahul Iyer   nfsd41: sunrpc: A...
1122

586c52cc6   Trond Myklebust   svcrpc: copy cb r...
1123
1124
  	pnum = copy_pages_to_kvecs(&vec[0], &rqstp->rq_pages[0],
  						svsk->sk_reclen);
445243594   NeilBrown   [PATCH] knfsd: Re...
1125
  	rqstp->rq_respages = &rqstp->rq_pages[pnum];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1126
1127
  
  	/* Now receive data */
31d68ef65   J. Bruce Fields   SUNRPC: Don't wai...
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
  	len = svc_partial_recvfrom(rqstp, vec, pnum, want, base);
  	if (len >= 0)
  		svsk->sk_tcplen += len;
  	if (len != want) {
  		if (len < 0 && len != -EAGAIN)
  			goto err_other;
  		svc_tcp_save_pages(svsk, rqstp);
  		dprintk("svc: incomplete TCP record (%d of %d)
  ",
  			svsk->sk_tcplen, svsk->sk_reclen);
  		goto err_noclose;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1140

5ee78d483   Trond Myklebust   SUNRPC: svc_tcp_r...
1141
  	rqstp->rq_arg.len = svsk->sk_reclen;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1142
  	rqstp->rq_arg.page_base = 0;
5ee78d483   Trond Myklebust   SUNRPC: svc_tcp_r...
1143
1144
  	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
1145
  		rqstp->rq_arg.page_len = 0;
5ee78d483   Trond Myklebust   SUNRPC: svc_tcp_r...
1146
1147
  	} 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
1148

5148bf4eb   Tom Tucker   svc: Add transpor...
1149
  	rqstp->rq_xprt_ctxt   = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1150
  	rqstp->rq_prot	      = IPPROTO_TCP;
586c52cc6   Trond Myklebust   svcrpc: copy cb r...
1151
1152
  	p = (__be32 *)rqstp->rq_arg.head[0].iov_base;
  	calldir = p[1];
8985ef0b8   J. Bruce Fields   svcrpc: complete ...
1153
  	if (calldir)
586c52cc6   Trond Myklebust   svcrpc: copy cb r...
1154
  		len = receive_cb_reply(svsk, rqstp);
586c52cc6   Trond Myklebust   svcrpc: copy cb r...
1155

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1156
1157
1158
  	/* Reset TCP read info */
  	svsk->sk_reclen = 0;
  	svsk->sk_tcplen = 0;
0601f7939   Trond Myklebust   SUNRPC: requeue t...
1159
1160
1161
  	/* If we have more data, signal svc_xprt_enqueue() to try again */
  	if (svc_recv_available(svsk) > sizeof(rpc_fraghdr))
  		set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags);
8985ef0b8   J. Bruce Fields   svcrpc: complete ...
1162
1163
  	if (len < 0)
  		goto error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1164

9dbc240f1   Tom Tucker   svc: Move the soc...
1165
  	svc_xprt_copy_addrs(rqstp, &svsk->sk_xprt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1166
1167
  	if (serv->sv_stats)
  		serv->sv_stats->nettcpcnt++;
31d68ef65   J. Bruce Fields   SUNRPC: Don't wai...
1168
1169
  	dprintk("svc: TCP complete record (%d bytes)
  ", rqstp->rq_arg.len);
5ee78d483   Trond Myklebust   SUNRPC: svc_tcp_r...
1170
  	return rqstp->rq_arg.len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1171

8f55f3c0a   Alexandros Batsakis   nfsd41: sunrpc: s...
1172
  error:
31d68ef65   J. Bruce Fields   SUNRPC: Don't wai...
1173
1174
1175
1176
  	if (len != -EAGAIN)
  		goto err_other;
  	dprintk("RPC: TCP recvfrom got EAGAIN
  ");
8f55f3c0a   Alexandros Batsakis   nfsd41: sunrpc: s...
1177
  	return -EAGAIN;
31d68ef65   J. Bruce Fields   SUNRPC: Don't wai...
1178
1179
1180
1181
1182
1183
1184
  err_other:
  	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:
  	return -EAGAIN;	/* record not complete */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1185
1186
1187
1188
1189
  }
  
  /*
   * Send out data on TCP socket.
   */
0f0257eaa   Tom Tucker   svc: Move the xpr...
1190
  static int svc_tcp_sendto(struct svc_rqst *rqstp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1191
1192
1193
  {
  	struct xdr_buf	*xbufp = &rqstp->rq_res;
  	int sent;
d8ed029d6   Alexey Dobriyan   [SUNRPC]: trivial...
1194
  	__be32 reclen;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1195
1196
1197
1198
1199
1200
1201
  
  	/* 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
1202
1203
  	sent = svc_sendto(rqstp, &rqstp->rq_res);
  	if (sent != xbufp->len) {
0f0257eaa   Tom Tucker   svc: Move the xpr...
1204
1205
1206
1207
  		printk(KERN_NOTICE
  		       "rpc-srv/tcp: %s: %s %d when sending %d bytes "
  		       "- shutting down socket
  ",
57b1d3bab   Tom Tucker   svc: Removing rem...
1208
  		       rqstp->rq_xprt->xpt_server->sv_name,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1209
1210
  		       (sent<0)?"got error":"sent only",
  		       sent, xbufp->len);
57b1d3bab   Tom Tucker   svc: Removing rem...
1211
  		set_bit(XPT_CLOSE, &rqstp->rq_xprt->xpt_flags);
f6150c3ca   Tom Tucker   svc: Make the enq...
1212
  		svc_xprt_enqueue(rqstp->rq_xprt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1213
1214
1215
1216
  		sent = -EAGAIN;
  	}
  	return sent;
  }
e831fe65b   Tom Tucker   svc: Add xpo_prep...
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
  /*
   * 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);
  }
323bee32e   Tom Tucker   svc: Add a transp...
1227
1228
  static int svc_tcp_has_wspace(struct svc_xprt *xprt)
  {
57b1d3bab   Tom Tucker   svc: Removing rem...
1229
  	struct svc_sock *svsk =	container_of(xprt, struct svc_sock, sk_xprt);
47fcb03fe   Trond Myklebust   SUNRPC: Fix the T...
1230
  	struct svc_serv *serv = svsk->sk_xprt.xpt_server;
323bee32e   Tom Tucker   svc: Add a transp...
1231
  	int required;
323bee32e   Tom Tucker   svc: Add a transp...
1232

47fcb03fe   Trond Myklebust   SUNRPC: Fix the T...
1233
1234
1235
1236
1237
  	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)
  		return 1;
323bee32e   Tom Tucker   svc: Add a transp...
1238
  	set_bit(SOCK_NOSPACE, &svsk->sk_sock->flags);
47fcb03fe   Trond Myklebust   SUNRPC: Fix the T...
1239
  	return 0;
323bee32e   Tom Tucker   svc: Add a transp...
1240
  }
b700cbb11   Tom Tucker   svc: Add a generi...
1241
  static struct svc_xprt *svc_tcp_create(struct svc_serv *serv,
62832c039   Pavel Emelyanov   sunrpc: Pull net ...
1242
  				       struct net *net,
b700cbb11   Tom Tucker   svc: Add a generi...
1243
1244
1245
  				       struct sockaddr *sa, int salen,
  				       int flags)
  {
62832c039   Pavel Emelyanov   sunrpc: Pull net ...
1246
  	return svc_create_socket(serv, IPPROTO_TCP, net, sa, salen, flags);
b700cbb11   Tom Tucker   svc: Add a generi...
1247
  }
9e00abc3c   Trond Myklebust   SUNRPC: sunrpc sh...
1248
  #if defined(CONFIG_SUNRPC_BACKCHANNEL)
1f11a034c   Andy Adamson   SUNRPC new transp...
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
  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,
  };
  
  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...
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
  
  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...
1289
  #else /* CONFIG_SUNRPC_BACKCHANNEL */
16b2d1e1d   Andy Adamson   SUNRPC register a...
1290
1291
1292
1293
1294
1295
1296
  static void svc_init_bc_xprt_sock(void)
  {
  }
  
  static void svc_cleanup_bc_xprt_sock(void)
  {
  }
9e00abc3c   Trond Myklebust   SUNRPC: sunrpc sh...
1297
  #endif /* CONFIG_SUNRPC_BACKCHANNEL */
1f11a034c   Andy Adamson   SUNRPC new transp...
1298

360d87386   Tom Tucker   svc: Make svc_soc...
1299
  static struct svc_xprt_ops svc_tcp_ops = {
b700cbb11   Tom Tucker   svc: Add a generi...
1300
  	.xpo_create = svc_tcp_create,
5d137990f   Tom Tucker   svc: Move sk_send...
1301
1302
  	.xpo_recvfrom = svc_tcp_recvfrom,
  	.xpo_sendto = svc_tcp_sendto,
5148bf4eb   Tom Tucker   svc: Add transpor...
1303
  	.xpo_release_rqst = svc_release_skb,
69b6ba371   Trond Myklebust   SUNRPC: Ensure th...
1304
  	.xpo_detach = svc_tcp_sock_detach,
755cceaba   Tom Tucker   svc: Add per-tran...
1305
  	.xpo_free = svc_sock_free,
e831fe65b   Tom Tucker   svc: Add xpo_prep...
1306
  	.xpo_prep_reply_hdr = svc_tcp_prep_reply_hdr,
323bee32e   Tom Tucker   svc: Add a transp...
1307
  	.xpo_has_wspace = svc_tcp_has_wspace,
38a417cc9   Tom Tucker   svc: Add xpo_acce...
1308
  	.xpo_accept = svc_tcp_accept,
360d87386   Tom Tucker   svc: Make svc_soc...
1309
1310
1311
1312
  };
  
  static struct svc_xprt_class svc_tcp_class = {
  	.xcl_name = "tcp",
b700cbb11   Tom Tucker   svc: Add a generi...
1313
  	.xcl_owner = THIS_MODULE,
360d87386   Tom Tucker   svc: Make svc_soc...
1314
  	.xcl_ops = &svc_tcp_ops,
490231558   Tom Tucker   svc: Add a max pa...
1315
  	.xcl_max_payload = RPCSVC_MAXPAYLOAD_TCP,
360d87386   Tom Tucker   svc: Make svc_soc...
1316
1317
1318
1319
1320
1321
  };
  
  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...
1322
  	svc_init_bc_xprt_sock();
360d87386   Tom Tucker   svc: Make svc_soc...
1323
1324
1325
1326
1327
1328
  }
  
  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...
1329
  	svc_cleanup_bc_xprt_sock();
360d87386   Tom Tucker   svc: Make svc_soc...
1330
  }
bb5cf160b   Tom Tucker   svc: Move sk_serv...
1331
  static void svc_tcp_init(struct svc_sock *svsk, struct svc_serv *serv)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1332
1333
  {
  	struct sock	*sk = svsk->sk_sk;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1334

bd4620ddf   Stanislav Kinsbursky   SUNRPC: create sv...
1335
1336
  	svc_xprt_init(sock_net(svsk->sk_sock->sk), &svc_tcp_class,
  		      &svsk->sk_xprt, serv);
def13d740   Tom Tucker   svc: Move the aut...
1337
  	set_bit(XPT_CACHE_AUTH, &svsk->sk_xprt.xpt_flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1338
1339
1340
  	if (sk->sk_state == TCP_LISTEN) {
  		dprintk("setting up TCP socket for listening
  ");
02fc6c361   Tom Tucker   svc: Move sk_flag...
1341
  		set_bit(XPT_LISTENER, &svsk->sk_xprt.xpt_flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1342
  		sk->sk_data_ready = svc_tcp_listen_data_ready;
02fc6c361   Tom Tucker   svc: Move sk_flag...
1343
  		set_bit(XPT_CONN, &svsk->sk_xprt.xpt_flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1344
1345
1346
1347
1348
  	} 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...
1349
  		sk->sk_write_space = svc_tcp_write_space;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1350
1351
1352
  
  		svsk->sk_reclen = 0;
  		svsk->sk_tcplen = 0;
31d68ef65   J. Bruce Fields   SUNRPC: Don't wai...
1353
  		memset(&svsk->sk_pages[0], 0, sizeof(svsk->sk_pages));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1354

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

02fc6c361   Tom Tucker   svc: Move sk_flag...
1357
  		set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags);
cca5172a7   YOSHIFUJI Hideaki   [NET] SUNRPC: Fix...
1358
  		if (sk->sk_state != TCP_ESTABLISHED)
02fc6c361   Tom Tucker   svc: Move sk_flag...
1359
  			set_bit(XPT_CLOSE, &svsk->sk_xprt.xpt_flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1360
1361
  	}
  }
0f0257eaa   Tom Tucker   svc: Move the xpr...
1362
  void svc_sock_update_bufs(struct svc_serv *serv)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1363
1364
1365
1366
1367
  {
  	/*
  	 * The number of server threads has changed. Update
  	 * rcvbuf and sndbuf accordingly on all sockets
  	 */
8f3a6de31   Pavel Emelyanov   sunrpc: Turn list...
1368
  	struct svc_sock *svsk;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1369
1370
  
  	spin_lock_bh(&serv->sv_lock);
8f3a6de31   Pavel Emelyanov   sunrpc: Turn list...
1371
  	list_for_each_entry(svsk, &serv->sv_permsocks, sk_xprt.xpt_list)
02fc6c361   Tom Tucker   svc: Move sk_flag...
1372
  		set_bit(XPT_CHNGBUF, &svsk->sk_xprt.xpt_flags);
8f3a6de31   Pavel Emelyanov   sunrpc: Turn list...
1373
  	list_for_each_entry(svsk, &serv->sv_tempsocks, sk_xprt.xpt_list)
02fc6c361   Tom Tucker   svc: Move sk_flag...
1374
  		set_bit(XPT_CHNGBUF, &svsk->sk_xprt.xpt_flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1375
1376
  	spin_unlock_bh(&serv->sv_lock);
  }
24c3767e4   Trond Myklebust   SUNRPC: The sunrp...
1377
  EXPORT_SYMBOL_GPL(svc_sock_update_bufs);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1378
1379
  
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1380
1381
1382
   * 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...
1383
1384
1385
  static struct svc_sock *svc_setup_socket(struct svc_serv *serv,
  						struct socket *sock,
  						int *errp, int flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1386
1387
1388
  {
  	struct svc_sock	*svsk;
  	struct sock	*inet;
6b174337e   Chuck Lever   [PATCH] knfsd: SU...
1389
  	int		pmap_register = !(flags & SVC_SOCK_ANONYMOUS);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1390
1391
1392
  
  	dprintk("svc: svc_setup_socket %p
  ", sock);
0da974f4f   Panagiotis Issaris   [NET]: Conversion...
1393
  	if (!(svsk = kzalloc(sizeof(*svsk), GFP_KERNEL))) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1394
1395
1396
  		*errp = -ENOMEM;
  		return NULL;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1397
1398
1399
1400
1401
  
  	inet = sock->sk;
  
  	/* Register socket with portmapper */
  	if (*errp >= 0 && pmap_register)
baf01caf0   Chuck Lever   SUNRPC: svc_setup...
1402
  		*errp = svc_register(serv, inet->sk_family, inet->sk_protocol,
c720c7e83   Eric Dumazet   inet: rename some...
1403
  				     ntohs(inet_sk(inet)->inet_sport));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1404
1405
1406
1407
1408
  
  	if (*errp < 0) {
  		kfree(svsk);
  		return NULL;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1409
1410
1411
1412
1413
1414
  	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
1415
1416
1417
  
  	/* Initialize the socket */
  	if (sock->type == SOCK_DGRAM)
bb5cf160b   Tom Tucker   svc: Move sk_serv...
1418
  		svc_udp_init(svsk, serv);
966043986   Olga Kornievskaia   svcrpc: take adva...
1419
1420
1421
1422
1423
1424
  	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...
1425
  		svc_tcp_init(svsk, serv);
966043986   Olga Kornievskaia   svcrpc: take adva...
1426
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1427

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1428
1429
1430
  	dprintk("svc: svc_setup_socket created %p (inet %p)
  ",
  				svsk, svsk->sk_sk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1431
1432
  	return svsk;
  }
bfba9ab4c   Chuck Lever   SUNRPC: pass buff...
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
  /**
   * 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...
1447
1448
1449
1450
1451
1452
1453
  {
  	int err = 0;
  	struct socket *so = sockfd_lookup(fd, &err);
  	struct svc_sock *svsk = NULL;
  
  	if (!so)
  		return err;
205ba4230   Aime Le Rouzic   NFSD: Support AF_...
1454
  	if ((so->sk->sk_family != PF_INET) && (so->sk->sk_family != PF_INET6))
b41b66d63   NeilBrown   [PATCH] knfsd: al...
1455
1456
1457
1458
1459
1460
1461
  		err =  -EAFNOSUPPORT;
  	else if (so->sk->sk_protocol != IPPROTO_TCP &&
  	    so->sk->sk_protocol != IPPROTO_UDP)
  		err =  -EPROTONOSUPPORT;
  	else if (so->state > SS_UNCONNECTED)
  		err = -EISCONN;
  	else {
2da2c21d7   Tom Tucker   Add a reference t...
1462
1463
1464
1465
1466
  		if (!try_module_get(THIS_MODULE))
  			err = -ENOENT;
  		else
  			svsk = svc_setup_socket(serv, so, &err,
  						SVC_SOCK_DEFAULTS);
e79eff1f9   NeilBrown   [PATCH] knfsd: SU...
1467
  		if (svsk) {
9dbc240f1   Tom Tucker   svc: Move the soc...
1468
1469
1470
1471
1472
  			struct sockaddr_storage addr;
  			struct sockaddr *sin = (struct sockaddr *)&addr;
  			int salen;
  			if (kernel_getsockname(svsk->sk_sock, sin, &salen) == 0)
  				svc_xprt_set_local(&svsk->sk_xprt, sin, salen);
4e5caaa5f   Tom Tucker   svc: Move create ...
1473
1474
1475
1476
  			clear_bit(XPT_TEMP, &svsk->sk_xprt.xpt_flags);
  			spin_lock_bh(&serv->sv_lock);
  			list_add(&svsk->sk_xprt.xpt_list, &serv->sv_permsocks);
  			spin_unlock_bh(&serv->sv_lock);
a6046f71f   Tom Tucker   svc: Change svc_s...
1477
  			svc_xprt_received(&svsk->sk_xprt);
b41b66d63   NeilBrown   [PATCH] knfsd: al...
1478
  			err = 0;
2da2c21d7   Tom Tucker   Add a reference t...
1479
1480
  		} else
  			module_put(THIS_MODULE);
b41b66d63   NeilBrown   [PATCH] knfsd: al...
1481
1482
1483
1484
1485
  	}
  	if (err) {
  		sockfd_put(so);
  		return err;
  	}
e7942b9f2   Chuck Lever   SUNRPC: Switch on...
1486
  	return svc_one_sock_name(svsk, name_return, len);
b41b66d63   NeilBrown   [PATCH] knfsd: al...
1487
1488
  }
  EXPORT_SYMBOL_GPL(svc_addsock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1489
1490
1491
  /*
   * Create socket for RPC service.
   */
b700cbb11   Tom Tucker   svc: Add a generi...
1492
1493
  static struct svc_xprt *svc_create_socket(struct svc_serv *serv,
  					  int protocol,
62832c039   Pavel Emelyanov   sunrpc: Pull net ...
1494
  					  struct net *net,
b700cbb11   Tom Tucker   svc: Add a generi...
1495
1496
  					  struct sockaddr *sin, int len,
  					  int flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1497
1498
1499
1500
1501
  {
  	struct svc_sock	*svsk;
  	struct socket	*sock;
  	int		error;
  	int		type;
9dbc240f1   Tom Tucker   svc: Move the soc...
1502
1503
1504
  	struct sockaddr_storage addr;
  	struct sockaddr *newsin = (struct sockaddr *)&addr;
  	int		newlen;
c69da774b   Trond Myklebust   SUNRPC: Ensure IP...
1505
1506
  	int		family;
  	int		val;
5216a8e70   Pavel Emelyanov   Wrap buffers used...
1507
  	RPC_IFDEBUG(char buf[RPC_MAX_ADDRBUFLEN]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1508

ad06e4bd6   Chuck Lever   [PATCH] knfsd: SU...
1509
1510
1511
  	dprintk("svc: svc_create_socket(%s, %d, %s)
  ",
  			serv->sv_program->pg_name, protocol,
77f1f67a1   Chuck Lever   [PATCH] knfsd: SU...
1512
  			__svc_print_addr(sin, buf, sizeof(buf)));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1513
1514
1515
1516
1517
  
  	if (protocol != IPPROTO_UDP && protocol != IPPROTO_TCP) {
  		printk(KERN_WARNING "svc: only UDP and TCP "
  				"sockets supported
  ");
b700cbb11   Tom Tucker   svc: Add a generi...
1518
  		return ERR_PTR(-EINVAL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1519
  	}
c69da774b   Trond Myklebust   SUNRPC: Ensure IP...
1520

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1521
  	type = (protocol == IPPROTO_UDP)? SOCK_DGRAM : SOCK_STREAM;
c69da774b   Trond Myklebust   SUNRPC: Ensure IP...
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
  	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
1532

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

ed07536ed   Peter Zijlstra   [PATCH] lockdep: ...
1537
  	svc_reclassify_socket(sock);
c69da774b   Trond Myklebust   SUNRPC: Ensure IP...
1538
1539
1540
1541
1542
1543
1544
1545
1546
  	/*
  	 * 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 ...
1547
  	if (type == SOCK_STREAM)
77f1f67a1   Chuck Lever   [PATCH] knfsd: SU...
1548
1549
  		sock->sk->sk_reuse = 1;		/* allow address reuse */
  	error = kernel_bind(sock, sin, len);
181147462   Eric Sesterhenn   [SUNRPC]: Remove ...
1550
1551
  	if (error < 0)
  		goto bummer;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1552

9dbc240f1   Tom Tucker   svc: Move the soc...
1553
1554
1555
1556
  	newlen = len;
  	error = kernel_getsockname(sock, newsin, &newlen);
  	if (error < 0)
  		goto bummer;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1557
  	if (protocol == IPPROTO_TCP) {
e6242e928   Sridhar Samudrala   [SUNRPC]: Update ...
1558
  		if ((error = kernel_listen(sock, 64)) < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1559
1560
  			goto bummer;
  	}
e79eff1f9   NeilBrown   [PATCH] knfsd: SU...
1561
  	if ((svsk = svc_setup_socket(serv, sock, &error, flags)) != NULL) {
9dbc240f1   Tom Tucker   svc: Move the soc...
1562
  		svc_xprt_set_local(&svsk->sk_xprt, newsin, newlen);
b700cbb11   Tom Tucker   svc: Add a generi...
1563
  		return (struct svc_xprt *)svsk;
e79eff1f9   NeilBrown   [PATCH] knfsd: SU...
1564
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1565
1566
1567
1568
1569
  
  bummer:
  	dprintk("svc: svc_create_socket error = %d
  ", -error);
  	sock_release(sock);
b700cbb11   Tom Tucker   svc: Add a generi...
1570
  	return ERR_PTR(error);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1571
1572
1573
  }
  
  /*
755cceaba   Tom Tucker   svc: Add per-tran...
1574
1575
1576
1577
1578
1579
1580
   * 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...
1581
  	wait_queue_head_t *wq;
755cceaba   Tom Tucker   svc: Add per-tran...
1582
1583
1584
1585
1586
1587
1588
1589
  
  	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...
1590

eaefd1105   Eric Dumazet   net: add __rcu an...
1591
1592
1593
  	wq = sk_sleep(sk);
  	if (wq && waitqueue_active(wq))
  		wake_up_interruptible(wq);
69b6ba371   Trond Myklebust   SUNRPC: Ensure th...
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
  }
  
  /*
   * 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...
1607
1608
  	if (!test_bit(XPT_LISTENER, &xprt->xpt_flags)) {
  		svc_tcp_clear_pages(svsk);
69b6ba371   Trond Myklebust   SUNRPC: Ensure th...
1609
  		kernel_sock_shutdown(svsk->sk_sock, SHUT_RDWR);
31d68ef65   J. Bruce Fields   SUNRPC: Don't wai...
1610
  	}
755cceaba   Tom Tucker   svc: Add per-tran...
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
  }
  
  /*
   * 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...
1621
1622
1623
1624
1625
1626
  	if (svsk->sk_sock->file)
  		sockfd_put(svsk->sk_sock);
  	else
  		sock_release(svsk->sk_sock);
  	kfree(svsk);
  }
7652e5a09   Benny Halevy   nfs41: sunrpc: pr...
1627

9e00abc3c   Trond Myklebust   SUNRPC: sunrpc sh...
1628
  #if defined(CONFIG_SUNRPC_BACKCHANNEL)
7652e5a09   Benny Halevy   nfs41: sunrpc: pr...
1629
  /*
1f11a034c   Andy Adamson   SUNRPC new transp...
1630
   * Create a back channel svc_xprt which shares the fore channel socket.
7652e5a09   Benny Halevy   nfs41: sunrpc: pr...
1631
   */
1f11a034c   Andy Adamson   SUNRPC new transp...
1632
1633
1634
1635
1636
  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...
1637
1638
  {
  	struct svc_sock *svsk;
1f11a034c   Andy Adamson   SUNRPC new transp...
1639
1640
1641
1642
1643
1644
1645
1646
  	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...
1647

7652e5a09   Benny Halevy   nfs41: sunrpc: pr...
1648
1649
  	svsk = kzalloc(sizeof(*svsk), GFP_KERNEL);
  	if (!svsk)
1f11a034c   Andy Adamson   SUNRPC new transp...
1650
  		return ERR_PTR(-ENOMEM);
7652e5a09   Benny Halevy   nfs41: sunrpc: pr...
1651
1652
  
  	xprt = &svsk->sk_xprt;
bd4620ddf   Stanislav Kinsbursky   SUNRPC: create sv...
1653
  	svc_xprt_init(net, &svc_tcp_bc_class, xprt, serv);
1f11a034c   Andy Adamson   SUNRPC new transp...
1654

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

7652e5a09   Benny Halevy   nfs41: sunrpc: pr...
1657
1658
  	return xprt;
  }
7652e5a09   Benny Halevy   nfs41: sunrpc: pr...
1659
1660
  
  /*
1f11a034c   Andy Adamson   SUNRPC new transp...
1661
   * Free a back channel svc_sock.
7652e5a09   Benny Halevy   nfs41: sunrpc: pr...
1662
   */
1f11a034c   Andy Adamson   SUNRPC new transp...
1663
  static void svc_bc_sock_free(struct svc_xprt *xprt)
7652e5a09   Benny Halevy   nfs41: sunrpc: pr...
1664
  {
778be232a   Andy Adamson   NFS do not find c...
1665
  	if (xprt)
7652e5a09   Benny Halevy   nfs41: sunrpc: pr...
1666
1667
  		kfree(container_of(xprt, struct svc_sock, sk_xprt));
  }
9e00abc3c   Trond Myklebust   SUNRPC: sunrpc sh...
1668
  #endif /* CONFIG_SUNRPC_BACKCHANNEL */