Blame view

net/sunrpc/svcsock.c 43 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
156
  			pki->ipi6_ifindex = daddr->sin6_scope_id;
  			ipv6_addr_copy(&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
517
518
  
  	daddr->sin6_family = AF_INET6;
  	ipv6_addr_copy(&daddr->sin6_addr, &pki->ipi6_addr);
  	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

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

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

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

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

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

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

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

cdd88b9f3   akpm@linux-foundation.org   [PATCH] knfsd: SU...
873
  	err = kernel_getpeername(newsock, sin, &slen);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
874
875
876
877
878
879
880
881
882
  	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...
883
884
  	 * 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
885
  	 */
cdd88b9f3   akpm@linux-foundation.org   [PATCH] knfsd: SU...
886
  	if (!svc_port_is_privileged(sin)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
887
  		dprintk(KERN_WARNING
ad06e4bd6   Chuck Lever   [PATCH] knfsd: SU...
888
889
  			"%s: connect from unprivileged port: %s
  ",
cca5172a7   YOSHIFUJI Hideaki   [NET] SUNRPC: Fix...
890
  			serv->sv_name,
cdd88b9f3   akpm@linux-foundation.org   [PATCH] knfsd: SU...
891
  			__svc_print_addr(sin, buf, sizeof(buf)));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
892
  	}
ad06e4bd6   Chuck Lever   [PATCH] knfsd: SU...
893
894
  	dprintk("%s: connect from %s
  ", serv->sv_name,
cdd88b9f3   akpm@linux-foundation.org   [PATCH] knfsd: SU...
895
  		__svc_print_addr(sin, buf, sizeof(buf)));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
896
897
898
899
900
  
  	/* 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...
901
902
  	if (!(newsvsk = svc_setup_socket(serv, newsock, &err,
  				 (SVC_SOCK_ANONYMOUS | SVC_SOCK_TEMPORARY))))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
903
  		goto failed;
9dbc240f1   Tom Tucker   svc: Move the soc...
904
  	svc_xprt_set_remote(&newsvsk->sk_xprt, sin, slen);
a97476926   Frank van Maarseveen   SUNRPC server: re...
905
906
907
908
909
910
  	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...
911
  	svc_xprt_set_local(&newsvsk->sk_xprt, sin, slen);
067d78173   Chuck Lever   [PATCH] knfsd: SU...
912

f9f3cc4fa   Tom Tucker   svc: Move connect...
913
914
915
916
917
918
919
920
921
  	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...
922
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
  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...
971
  /*
8f55f3c0a   Alexandros Batsakis   nfsd41: sunrpc: s...
972
973
974
975
   * 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
976
   */
8f55f3c0a   Alexandros Batsakis   nfsd41: sunrpc: s...
977
  static int svc_tcp_recv_record(struct svc_sock *svsk, struct svc_rqst *rqstp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
978
  {
bb5cf160b   Tom Tucker   svc: Move sk_serv...
979
  	struct svc_serv	*serv = svsk->sk_xprt.xpt_server;
5ee78d483   Trond Myklebust   SUNRPC: svc_tcp_r...
980
  	unsigned int want;
8f55f3c0a   Alexandros Batsakis   nfsd41: sunrpc: s...
981
  	int len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
982

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

c0401ea00   Chuck Lever   SUNRPC: Update RP...
985
  	if (svsk->sk_tcplen < sizeof(rpc_fraghdr)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
986
  		struct kvec	iov;
5ee78d483   Trond Myklebust   SUNRPC: svc_tcp_r...
987
  		want = sizeof(rpc_fraghdr) - svsk->sk_tcplen;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
988
989
990
991
992
993
994
  		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...
995
996
997
  			dprintk("svc: short recvfrom while reading record "
  				"length (%d of %d)
  ", len, want);
31d68ef65   J. Bruce Fields   SUNRPC: Don't wai...
998
  			return -EAGAIN;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
999
1000
1001
  		}
  
  		svsk->sk_reclen = ntohl(svsk->sk_reclen);
c0401ea00   Chuck Lever   SUNRPC: Update RP...
1002
  		if (!(svsk->sk_reclen & RPC_LAST_STREAM_FRAGMENT)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1003
1004
1005
1006
1007
  			/* 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...
1008
  			if (net_ratelimit())
c0401ea00   Chuck Lever   SUNRPC: Update RP...
1009
1010
1011
  				printk(KERN_NOTICE "RPC: multiple fragments "
  					"per record not supported
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1012
1013
  			goto err_delete;
  		}
8f55f3c0a   Alexandros Batsakis   nfsd41: sunrpc: s...
1014

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

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

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

586c52cc6   Trond Myklebust   svcrpc: copy cb r...
1054
1055
1056
1057
1058
1059
1060
1061
  	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...
1062
  	}
586c52cc6   Trond Myklebust   svcrpc: copy cb r...
1063
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
  
  	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...
1092
  }
31d68ef65   J. Bruce Fields   SUNRPC: Don't wai...
1093

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

586c52cc6   Trond Myklebust   svcrpc: copy cb r...
1122
1123
  	pnum = copy_pages_to_kvecs(&vec[0], &rqstp->rq_pages[0],
  						svsk->sk_reclen);
445243594   NeilBrown   [PATCH] knfsd: Re...
1124
  	rqstp->rq_respages = &rqstp->rq_pages[pnum];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1125
1126
  
  	/* Now receive data */
31d68ef65   J. Bruce Fields   SUNRPC: Don't wai...
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
  	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
1139

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

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

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1155
1156
1157
  	/* Reset TCP read info */
  	svsk->sk_reclen = 0;
  	svsk->sk_tcplen = 0;
0601f7939   Trond Myklebust   SUNRPC: requeue t...
1158
1159
1160
  	/* 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 ...
1161
1162
  	if (len < 0)
  		goto error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1163

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

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

47fcb03fe   Trond Myklebust   SUNRPC: Fix the T...
1232
1233
1234
1235
1236
  	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...
1237
  	set_bit(SOCK_NOSPACE, &svsk->sk_sock->flags);
47fcb03fe   Trond Myklebust   SUNRPC: Fix the T...
1238
  	return 0;
323bee32e   Tom Tucker   svc: Add a transp...
1239
  }
b700cbb11   Tom Tucker   svc: Add a generi...
1240
  static struct svc_xprt *svc_tcp_create(struct svc_serv *serv,
62832c039   Pavel Emelyanov   sunrpc: Pull net ...
1241
  				       struct net *net,
b700cbb11   Tom Tucker   svc: Add a generi...
1242
1243
1244
  				       struct sockaddr *sa, int salen,
  				       int flags)
  {
62832c039   Pavel Emelyanov   sunrpc: Pull net ...
1245
  	return svc_create_socket(serv, IPPROTO_TCP, net, sa, salen, flags);
b700cbb11   Tom Tucker   svc: Add a generi...
1246
  }
9e00abc3c   Trond Myklebust   SUNRPC: sunrpc sh...
1247
  #if defined(CONFIG_SUNRPC_BACKCHANNEL)
1f11a034c   Andy Adamson   SUNRPC new transp...
1248
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
  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...
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
  
  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...
1288
  #else /* CONFIG_SUNRPC_BACKCHANNEL */
16b2d1e1d   Andy Adamson   SUNRPC register a...
1289
1290
1291
1292
1293
1294
1295
  static void svc_init_bc_xprt_sock(void)
  {
  }
  
  static void svc_cleanup_bc_xprt_sock(void)
  {
  }
9e00abc3c   Trond Myklebust   SUNRPC: sunrpc sh...
1296
  #endif /* CONFIG_SUNRPC_BACKCHANNEL */
1f11a034c   Andy Adamson   SUNRPC new transp...
1297

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

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

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

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

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

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

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

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

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

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

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

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

7652e5a09   Benny Halevy   nfs41: sunrpc: pr...
1646
1647
  	svsk = kzalloc(sizeof(*svsk), GFP_KERNEL);
  	if (!svsk)
1f11a034c   Andy Adamson   SUNRPC new transp...
1648
  		return ERR_PTR(-ENOMEM);
7652e5a09   Benny Halevy   nfs41: sunrpc: pr...
1649
1650
  
  	xprt = &svsk->sk_xprt;
1f11a034c   Andy Adamson   SUNRPC new transp...
1651
  	svc_xprt_init(&svc_tcp_bc_class, xprt, serv);
4a19de0f4   Andy Adamson   NFS rename client...
1652
  	serv->sv_bc_xprt = xprt;
1f11a034c   Andy Adamson   SUNRPC new transp...
1653

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