Blame view

net/sunrpc/svc_xprt.c 33.5 KB
1d8206b97   Tom Tucker   svc: Add an svc t...
1
2
3
4
5
6
7
8
  /*
   * linux/net/sunrpc/svc_xprt.c
   *
   * Author: Tom Tucker <tom@opengridcomputing.com>
   */
  
  #include <linux/sched.h>
  #include <linux/errno.h>
1d8206b97   Tom Tucker   svc: Add an svc t...
9
  #include <linux/freezer.h>
7086721f9   Jeff Layton   SUNRPC: have svc_...
10
  #include <linux/kthread.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
11
  #include <linux/slab.h>
1d8206b97   Tom Tucker   svc: Add an svc t...
12
  #include <net/sock.h>
1d8206b97   Tom Tucker   svc: Add an svc t...
13
14
  #include <linux/sunrpc/stats.h>
  #include <linux/sunrpc/svc_xprt.h>
dcf1a3573   H Hartley Sweeten   net/sunrpc/svc_xp...
15
  #include <linux/sunrpc/svcsock.h>
99de8ea96   J. Bruce Fields   rpc: keep backcha...
16
  #include <linux/sunrpc/xprt.h>
3a9a231d9   Paul Gortmaker   net: Fix files ex...
17
  #include <linux/module.h>
1d8206b97   Tom Tucker   svc: Add an svc t...
18
19
  
  #define RPCDBG_FACILITY	RPCDBG_SVCXPRT
0f0257eaa   Tom Tucker   svc: Move the xpr...
20
21
22
23
  static struct svc_deferred_req *svc_deferred_dequeue(struct svc_xprt *xprt);
  static int svc_deferred_recv(struct svc_rqst *rqstp);
  static struct cache_deferred_req *svc_defer(struct cache_req *req);
  static void svc_age_temp_xprts(unsigned long closure);
7710ec36b   J. Bruce Fields   svcrpc: make svc_...
24
  static void svc_delete_xprt(struct svc_xprt *xprt);
0f0257eaa   Tom Tucker   svc: Move the xpr...
25
26
27
28
29
30
31
  
  /* apparently the "standard" is that clients close
   * idle connections after 5 minutes, servers after
   * 6 minutes
   *   http://www.connectathon.org/talks96/nfstcp.pdf
   */
  static int svc_conn_age_period = 6*60;
1d8206b97   Tom Tucker   svc: Add an svc t...
32
33
34
  /* List of registered transport classes */
  static DEFINE_SPINLOCK(svc_xprt_class_lock);
  static LIST_HEAD(svc_xprt_class_list);
0f0257eaa   Tom Tucker   svc: Move the xpr...
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
  /* SMP locking strategy:
   *
   *	svc_pool->sp_lock protects most of the fields of that pool.
   *	svc_serv->sv_lock protects sv_tempsocks, sv_permsocks, sv_tmpcnt.
   *	when both need to be taken (rare), svc_serv->sv_lock is first.
   *	BKL protects svc_serv->sv_nrthread.
   *	svc_sock->sk_lock protects the svc_sock->sk_deferred list
   *             and the ->sk_info_authunix cache.
   *
   *	The XPT_BUSY bit in xprt->xpt_flags prevents a transport being
   *	enqueued multiply. During normal transport processing this bit
   *	is set by svc_xprt_enqueue and cleared by svc_xprt_received.
   *	Providers should not manipulate this bit directly.
   *
   *	Some flags can be set to certain values at any time
   *	providing that certain rules are followed:
   *
   *	XPT_CONN, XPT_DATA:
   *		- Can be set or cleared at any time.
   *		- After a set, svc_xprt_enqueue must be called to enqueue
   *		  the transport for processing.
   *		- After a clear, the transport must be read/accepted.
   *		  If this succeeds, it must be set again.
   *	XPT_CLOSE:
   *		- Can set at any time. It is never cleared.
   *      XPT_DEAD:
   *		- Can only be set while XPT_BUSY is held which ensures
   *		  that no other thread will be using the transport or will
   *		  try to set XPT_DEAD.
   */
1d8206b97   Tom Tucker   svc: Add an svc t...
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
  int svc_reg_xprt_class(struct svc_xprt_class *xcl)
  {
  	struct svc_xprt_class *cl;
  	int res = -EEXIST;
  
  	dprintk("svc: Adding svc transport class '%s'
  ", xcl->xcl_name);
  
  	INIT_LIST_HEAD(&xcl->xcl_list);
  	spin_lock(&svc_xprt_class_lock);
  	/* Make sure there isn't already a class with the same name */
  	list_for_each_entry(cl, &svc_xprt_class_list, xcl_list) {
  		if (strcmp(xcl->xcl_name, cl->xcl_name) == 0)
  			goto out;
  	}
  	list_add_tail(&xcl->xcl_list, &svc_xprt_class_list);
  	res = 0;
  out:
  	spin_unlock(&svc_xprt_class_lock);
  	return res;
  }
  EXPORT_SYMBOL_GPL(svc_reg_xprt_class);
  
  void svc_unreg_xprt_class(struct svc_xprt_class *xcl)
  {
  	dprintk("svc: Removing svc transport class '%s'
  ", xcl->xcl_name);
  	spin_lock(&svc_xprt_class_lock);
  	list_del_init(&xcl->xcl_list);
  	spin_unlock(&svc_xprt_class_lock);
  }
  EXPORT_SYMBOL_GPL(svc_unreg_xprt_class);
dc9a16e49   Tom Tucker   svc: Add /proc/sy...
97
98
99
100
101
  /*
   * Format the transport list for printing
   */
  int svc_print_xprts(char *buf, int maxlen)
  {
8f3a6de31   Pavel Emelyanov   sunrpc: Turn list...
102
  	struct svc_xprt_class *xcl;
dc9a16e49   Tom Tucker   svc: Add /proc/sy...
103
104
105
106
107
  	char tmpstr[80];
  	int len = 0;
  	buf[0] = '\0';
  
  	spin_lock(&svc_xprt_class_lock);
8f3a6de31   Pavel Emelyanov   sunrpc: Turn list...
108
  	list_for_each_entry(xcl, &svc_xprt_class_list, xcl_list) {
dc9a16e49   Tom Tucker   svc: Add /proc/sy...
109
  		int slen;
dc9a16e49   Tom Tucker   svc: Add /proc/sy...
110
111
112
113
114
115
116
117
118
119
120
121
122
  
  		sprintf(tmpstr, "%s %d
  ", xcl->xcl_name, xcl->xcl_max_payload);
  		slen = strlen(tmpstr);
  		if (len + slen > maxlen)
  			break;
  		len += slen;
  		strcat(buf, tmpstr);
  	}
  	spin_unlock(&svc_xprt_class_lock);
  
  	return len;
  }
e1b3157f9   Tom Tucker   svc: Change sk_in...
123
124
125
126
127
  static void svc_xprt_free(struct kref *kref)
  {
  	struct svc_xprt *xprt =
  		container_of(kref, struct svc_xprt, xpt_ref);
  	struct module *owner = xprt->xpt_class->xcl_owner;
e3bfca01c   Pavel Emelyanov   sunrpc: Make xprt...
128
129
  	if (test_bit(XPT_CACHE_AUTH, &xprt->xpt_flags))
  		svcauth_unix_info_release(xprt);
4fb8518bd   Pavel Emelyanov   sunrpc: Tag svc_x...
130
  	put_net(xprt->xpt_net);
99de8ea96   J. Bruce Fields   rpc: keep backcha...
131
132
133
  	/* See comment on corresponding get in xs_setup_bc_tcp(): */
  	if (xprt->xpt_bc_xprt)
  		xprt_put(xprt->xpt_bc_xprt);
e1b3157f9   Tom Tucker   svc: Change sk_in...
134
135
136
137
138
139
140
141
142
  	xprt->xpt_ops->xpo_free(xprt);
  	module_put(owner);
  }
  
  void svc_xprt_put(struct svc_xprt *xprt)
  {
  	kref_put(&xprt->xpt_ref, svc_xprt_free);
  }
  EXPORT_SYMBOL_GPL(svc_xprt_put);
1d8206b97   Tom Tucker   svc: Add an svc t...
143
144
145
146
  /*
   * Called by transport drivers to initialize the transport independent
   * portion of the transport instance.
   */
bd4620ddf   Stanislav Kinsbursky   SUNRPC: create sv...
147
148
  void svc_xprt_init(struct net *net, struct svc_xprt_class *xcl,
  		   struct svc_xprt *xprt, struct svc_serv *serv)
1d8206b97   Tom Tucker   svc: Add an svc t...
149
150
151
152
  {
  	memset(xprt, 0, sizeof(*xprt));
  	xprt->xpt_class = xcl;
  	xprt->xpt_ops = xcl->xcl_ops;
e1b3157f9   Tom Tucker   svc: Change sk_in...
153
  	kref_init(&xprt->xpt_ref);
bb5cf160b   Tom Tucker   svc: Move sk_serv...
154
  	xprt->xpt_server = serv;
7a1820838   Tom Tucker   svc: Make close t...
155
156
  	INIT_LIST_HEAD(&xprt->xpt_list);
  	INIT_LIST_HEAD(&xprt->xpt_ready);
8c7b0172a   Tom Tucker   svc: Make deferra...
157
  	INIT_LIST_HEAD(&xprt->xpt_deferred);
edc7a8940   J. Bruce Fields   nfsd: provide cal...
158
  	INIT_LIST_HEAD(&xprt->xpt_users);
a50fea26b   Tom Tucker   svc: Make svc_sen...
159
  	mutex_init(&xprt->xpt_mutex);
def13d740   Tom Tucker   svc: Move the aut...
160
  	spin_lock_init(&xprt->xpt_lock);
4e5caaa5f   Tom Tucker   svc: Move create ...
161
  	set_bit(XPT_BUSY, &xprt->xpt_flags);
4cfc7e601   Rahul Iyer   nfsd41: sunrpc: A...
162
  	rpc_init_wait_queue(&xprt->xpt_bc_pending, "xpt_bc_pending");
bd4620ddf   Stanislav Kinsbursky   SUNRPC: create sv...
163
  	xprt->xpt_net = get_net(net);
1d8206b97   Tom Tucker   svc: Add an svc t...
164
165
  }
  EXPORT_SYMBOL_GPL(svc_xprt_init);
b700cbb11   Tom Tucker   svc: Add a generi...
166

5dd248f6f   Chuck Lever   SUNRPC: Use prope...
167
168
  static struct svc_xprt *__svc_xpo_create(struct svc_xprt_class *xcl,
  					 struct svc_serv *serv,
62832c039   Pavel Emelyanov   sunrpc: Pull net ...
169
  					 struct net *net,
9652ada3f   Chuck Lever   SUNRPC: Change sv...
170
171
172
  					 const int family,
  					 const unsigned short port,
  					 int flags)
b700cbb11   Tom Tucker   svc: Add a generi...
173
  {
b700cbb11   Tom Tucker   svc: Add a generi...
174
175
  	struct sockaddr_in sin = {
  		.sin_family		= AF_INET,
e6f1cebf7   Al Viro   [NET] endianness ...
176
  		.sin_addr.s_addr	= htonl(INADDR_ANY),
b700cbb11   Tom Tucker   svc: Add a generi...
177
178
  		.sin_port		= htons(port),
  	};
dfd56b8b3   Eric Dumazet   net: use IS_ENABL...
179
  #if IS_ENABLED(CONFIG_IPV6)
5dd248f6f   Chuck Lever   SUNRPC: Use prope...
180
181
182
183
184
  	struct sockaddr_in6 sin6 = {
  		.sin6_family		= AF_INET6,
  		.sin6_addr		= IN6ADDR_ANY_INIT,
  		.sin6_port		= htons(port),
  	};
dfd56b8b3   Eric Dumazet   net: use IS_ENABL...
185
  #endif
5dd248f6f   Chuck Lever   SUNRPC: Use prope...
186
187
  	struct sockaddr *sap;
  	size_t len;
9652ada3f   Chuck Lever   SUNRPC: Change sv...
188
189
  	switch (family) {
  	case PF_INET:
5dd248f6f   Chuck Lever   SUNRPC: Use prope...
190
191
192
  		sap = (struct sockaddr *)&sin;
  		len = sizeof(sin);
  		break;
dfd56b8b3   Eric Dumazet   net: use IS_ENABL...
193
  #if IS_ENABLED(CONFIG_IPV6)
9652ada3f   Chuck Lever   SUNRPC: Change sv...
194
  	case PF_INET6:
5dd248f6f   Chuck Lever   SUNRPC: Use prope...
195
196
197
  		sap = (struct sockaddr *)&sin6;
  		len = sizeof(sin6);
  		break;
dfd56b8b3   Eric Dumazet   net: use IS_ENABL...
198
  #endif
5dd248f6f   Chuck Lever   SUNRPC: Use prope...
199
200
201
  	default:
  		return ERR_PTR(-EAFNOSUPPORT);
  	}
62832c039   Pavel Emelyanov   sunrpc: Pull net ...
202
  	return xcl->xcl_ops->xpo_create(serv, net, sap, len, flags);
5dd248f6f   Chuck Lever   SUNRPC: Use prope...
203
  }
9652ada3f   Chuck Lever   SUNRPC: Change sv...
204
  int svc_create_xprt(struct svc_serv *serv, const char *xprt_name,
fc5d00b04   Pavel Emelyanov   sunrpc: Add net a...
205
206
  		    struct net *net, const int family,
  		    const unsigned short port, int flags)
5dd248f6f   Chuck Lever   SUNRPC: Use prope...
207
208
  {
  	struct svc_xprt_class *xcl;
b700cbb11   Tom Tucker   svc: Add a generi...
209
210
211
212
  	dprintk("svc: creating transport %s[%d]
  ", xprt_name, port);
  	spin_lock(&svc_xprt_class_lock);
  	list_for_each_entry(xcl, &svc_xprt_class_list, xcl_list) {
4e5caaa5f   Tom Tucker   svc: Move create ...
213
  		struct svc_xprt *newxprt;
ed2849d3e   NeilBrown   sunrpc: prevent u...
214
  		unsigned short newport;
4e5caaa5f   Tom Tucker   svc: Move create ...
215
216
217
218
219
220
221
222
  
  		if (strcmp(xprt_name, xcl->xcl_name))
  			continue;
  
  		if (!try_module_get(xcl->xcl_owner))
  			goto err;
  
  		spin_unlock(&svc_xprt_class_lock);
62832c039   Pavel Emelyanov   sunrpc: Pull net ...
223
  		newxprt = __svc_xpo_create(xcl, serv, net, family, port, flags);
4e5caaa5f   Tom Tucker   svc: Move create ...
224
225
226
  		if (IS_ERR(newxprt)) {
  			module_put(xcl->xcl_owner);
  			return PTR_ERR(newxprt);
b700cbb11   Tom Tucker   svc: Add a generi...
227
  		}
4e5caaa5f   Tom Tucker   svc: Move create ...
228
229
230
231
232
  
  		clear_bit(XPT_TEMP, &newxprt->xpt_flags);
  		spin_lock_bh(&serv->sv_lock);
  		list_add(&newxprt->xpt_list, &serv->sv_permsocks);
  		spin_unlock_bh(&serv->sv_lock);
ed2849d3e   NeilBrown   sunrpc: prevent u...
233
  		newport = svc_xprt_local_port(newxprt);
4e5caaa5f   Tom Tucker   svc: Move create ...
234
  		clear_bit(XPT_BUSY, &newxprt->xpt_flags);
ed2849d3e   NeilBrown   sunrpc: prevent u...
235
  		return newport;
b700cbb11   Tom Tucker   svc: Add a generi...
236
  	}
4e5caaa5f   Tom Tucker   svc: Move create ...
237
   err:
b700cbb11   Tom Tucker   svc: Add a generi...
238
239
240
  	spin_unlock(&svc_xprt_class_lock);
  	dprintk("svc: transport %s not found
  ", xprt_name);
687179081   Chuck Lever   SUNRPC: NFS kerne...
241
242
243
244
  
  	/* This errno is exposed to user space.  Provide a reasonable
  	 * perror msg for a bad transport. */
  	return -EPROTONOSUPPORT;
b700cbb11   Tom Tucker   svc: Add a generi...
245
246
  }
  EXPORT_SYMBOL_GPL(svc_create_xprt);
9dbc240f1   Tom Tucker   svc: Move the soc...
247
248
249
250
251
252
  
  /*
   * Copy the local and remote xprt addresses to the rqstp structure
   */
  void svc_xprt_copy_addrs(struct svc_rqst *rqstp, struct svc_xprt *xprt)
  {
9dbc240f1   Tom Tucker   svc: Move the soc...
253
254
255
256
257
258
259
  	memcpy(&rqstp->rq_addr, &xprt->xpt_remote, xprt->xpt_remotelen);
  	rqstp->rq_addrlen = xprt->xpt_remotelen;
  
  	/*
  	 * Destination address in request is needed for binding the
  	 * source address in RPC replies/callbacks later.
  	 */
849a1cf13   Mi Jinlong   SUNRPC: Replace s...
260
261
  	memcpy(&rqstp->rq_daddr, &xprt->xpt_local, xprt->xpt_locallen);
  	rqstp->rq_daddrlen = xprt->xpt_locallen;
9dbc240f1   Tom Tucker   svc: Move the soc...
262
263
  }
  EXPORT_SYMBOL_GPL(svc_xprt_copy_addrs);
0f0257eaa   Tom Tucker   svc: Move the xpr...
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
  /**
   * svc_print_addr - Format rq_addr field for printing
   * @rqstp: svc_rqst struct containing address to print
   * @buf: target buffer for formatted address
   * @len: length of target buffer
   *
   */
  char *svc_print_addr(struct svc_rqst *rqstp, char *buf, size_t len)
  {
  	return __svc_print_addr(svc_addr(rqstp), buf, len);
  }
  EXPORT_SYMBOL_GPL(svc_print_addr);
  
  /*
   * Queue up an idle server thread.  Must have pool->sp_lock held.
   * Note: this is really a stack rather than a queue, so that we only
   * use as many different threads as we need, and the rest don't pollute
   * the cache.
   */
  static void svc_thread_enqueue(struct svc_pool *pool, struct svc_rqst *rqstp)
  {
  	list_add(&rqstp->rq_list, &pool->sp_threads);
  }
  
  /*
   * Dequeue an nfsd thread.  Must have pool->sp_lock held.
   */
  static void svc_thread_dequeue(struct svc_pool *pool, struct svc_rqst *rqstp)
  {
  	list_del(&rqstp->rq_list);
  }
9c335c0b8   J. Bruce Fields   svcrpc: fix wspac...
295
296
297
298
299
300
301
302
  static bool svc_xprt_has_something_to_do(struct svc_xprt *xprt)
  {
  	if (xprt->xpt_flags & ((1<<XPT_CONN)|(1<<XPT_CLOSE)))
  		return true;
  	if (xprt->xpt_flags & ((1<<XPT_DATA)|(1<<XPT_DEFERRED)))
  		return xprt->xpt_ops->xpo_has_wspace(xprt);
  	return false;
  }
0f0257eaa   Tom Tucker   svc: Move the xpr...
303
304
305
306
307
308
309
310
311
312
313
  /*
   * Queue up a transport with data pending. If there are idle nfsd
   * processes, wake 'em up.
   *
   */
  void svc_xprt_enqueue(struct svc_xprt *xprt)
  {
  	struct svc_serv	*serv = xprt->xpt_server;
  	struct svc_pool *pool;
  	struct svc_rqst	*rqstp;
  	int cpu;
9c335c0b8   J. Bruce Fields   svcrpc: fix wspac...
314
  	if (!svc_xprt_has_something_to_do(xprt))
0f0257eaa   Tom Tucker   svc: Move the xpr...
315
  		return;
0f0257eaa   Tom Tucker   svc: Move the xpr...
316
317
318
319
320
321
  
  	cpu = get_cpu();
  	pool = svc_pool_for_cpu(xprt->xpt_server, cpu);
  	put_cpu();
  
  	spin_lock_bh(&pool->sp_lock);
78c210efd   J. Bruce Fields   Revert "knfsd: av...
322
323
324
325
326
327
  	if (!list_empty(&pool->sp_threads) &&
  	    !list_empty(&pool->sp_sockets))
  		printk(KERN_ERR
  		       "svc_xprt_enqueue: "
  		       "threads and transports both waiting??
  ");
03cf6c9f4   Greg Banks   knfsd: add file t...
328
  	pool->sp_stats.packets++;
0f0257eaa   Tom Tucker   svc: Move the xpr...
329
330
331
332
333
334
335
336
337
338
339
  	/* Mark transport as busy. It will remain in this state until
  	 * the provider calls svc_xprt_received. We update XPT_BUSY
  	 * atomically because it also guards against trying to enqueue
  	 * the transport twice.
  	 */
  	if (test_and_set_bit(XPT_BUSY, &xprt->xpt_flags)) {
  		/* Don't enqueue transport while already enqueued */
  		dprintk("svc: transport %p busy, not enqueued
  ", xprt);
  		goto out_unlock;
  	}
0f0257eaa   Tom Tucker   svc: Move the xpr...
340

78c210efd   J. Bruce Fields   Revert "knfsd: av...
341
  	if (!list_empty(&pool->sp_threads)) {
0f0257eaa   Tom Tucker   svc: Move the xpr...
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
  		rqstp = list_entry(pool->sp_threads.next,
  				   struct svc_rqst,
  				   rq_list);
  		dprintk("svc: transport %p served by daemon %p
  ",
  			xprt, rqstp);
  		svc_thread_dequeue(pool, rqstp);
  		if (rqstp->rq_xprt)
  			printk(KERN_ERR
  				"svc_xprt_enqueue: server %p, rq_xprt=%p!
  ",
  				rqstp, rqstp->rq_xprt);
  		rqstp->rq_xprt = xprt;
  		svc_xprt_get(xprt);
  		rqstp->rq_reserved = serv->sv_max_mesg;
  		atomic_add(rqstp->rq_reserved, &xprt->xpt_reserved);
03cf6c9f4   Greg Banks   knfsd: add file t...
358
  		pool->sp_stats.threads_woken++;
0f0257eaa   Tom Tucker   svc: Move the xpr...
359
360
361
362
363
  		wake_up(&rqstp->rq_wait);
  	} else {
  		dprintk("svc: transport %p put into queue
  ", xprt);
  		list_add_tail(&xprt->xpt_ready, &pool->sp_sockets);
03cf6c9f4   Greg Banks   knfsd: add file t...
364
  		pool->sp_stats.sockets_queued++;
0f0257eaa   Tom Tucker   svc: Move the xpr...
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
  	}
  
  out_unlock:
  	spin_unlock_bh(&pool->sp_lock);
  }
  EXPORT_SYMBOL_GPL(svc_xprt_enqueue);
  
  /*
   * Dequeue the first transport.  Must be called with the pool->sp_lock held.
   */
  static struct svc_xprt *svc_xprt_dequeue(struct svc_pool *pool)
  {
  	struct svc_xprt	*xprt;
  
  	if (list_empty(&pool->sp_sockets))
  		return NULL;
  
  	xprt = list_entry(pool->sp_sockets.next,
  			  struct svc_xprt, xpt_ready);
  	list_del_init(&xprt->xpt_ready);
  
  	dprintk("svc: transport %p dequeued, inuse=%d
  ",
  		xprt, atomic_read(&xprt->xpt_ref.refcount));
  
  	return xprt;
  }
  
  /*
   * svc_xprt_received conditionally queues the transport for processing
   * by another thread. The caller must hold the XPT_BUSY bit and must
   * not thereafter touch transport data.
   *
   * Note: XPT_DATA only gets cleared when a read-attempt finds no (or
   * insufficient) data.
   */
  void svc_xprt_received(struct svc_xprt *xprt)
  {
  	BUG_ON(!test_bit(XPT_BUSY, &xprt->xpt_flags));
ed2849d3e   NeilBrown   sunrpc: prevent u...
404
405
406
407
  	/* As soon as we clear busy, the xprt could be closed and
  	 * 'put', so we need a reference to call svc_xprt_enqueue with:
  	 */
  	svc_xprt_get(xprt);
0f0257eaa   Tom Tucker   svc: Move the xpr...
408
409
  	clear_bit(XPT_BUSY, &xprt->xpt_flags);
  	svc_xprt_enqueue(xprt);
ed2849d3e   NeilBrown   sunrpc: prevent u...
410
  	svc_xprt_put(xprt);
0f0257eaa   Tom Tucker   svc: Move the xpr...
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
  }
  EXPORT_SYMBOL_GPL(svc_xprt_received);
  
  /**
   * svc_reserve - change the space reserved for the reply to a request.
   * @rqstp:  The request in question
   * @space: new max space to reserve
   *
   * Each request reserves some space on the output queue of the transport
   * to make sure the reply fits.  This function reduces that reserved
   * space to be the amount of space used already, plus @space.
   *
   */
  void svc_reserve(struct svc_rqst *rqstp, int space)
  {
  	space += rqstp->rq_res.head[0].iov_len;
  
  	if (space < rqstp->rq_reserved) {
  		struct svc_xprt *xprt = rqstp->rq_xprt;
  		atomic_sub((rqstp->rq_reserved - space), &xprt->xpt_reserved);
  		rqstp->rq_reserved = space;
  
  		svc_xprt_enqueue(xprt);
  	}
  }
24c3767e4   Trond Myklebust   SUNRPC: The sunrp...
436
  EXPORT_SYMBOL_GPL(svc_reserve);
0f0257eaa   Tom Tucker   svc: Move the xpr...
437
438
439
440
441
442
  
  static void svc_xprt_release(struct svc_rqst *rqstp)
  {
  	struct svc_xprt	*xprt = rqstp->rq_xprt;
  
  	rqstp->rq_xprt->xpt_ops->xpo_release_rqst(rqstp);
2779e3ae3   Tom Tucker   svc: Move kfree o...
443
444
  	kfree(rqstp->rq_deferred);
  	rqstp->rq_deferred = NULL;
0f0257eaa   Tom Tucker   svc: Move the xpr...
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
  	svc_free_res_pages(rqstp);
  	rqstp->rq_res.page_len = 0;
  	rqstp->rq_res.page_base = 0;
  
  	/* Reset response buffer and release
  	 * the reservation.
  	 * But first, check that enough space was reserved
  	 * for the reply, otherwise we have a bug!
  	 */
  	if ((rqstp->rq_res.len) >  rqstp->rq_reserved)
  		printk(KERN_ERR "RPC request reserved %d but used %d
  ",
  		       rqstp->rq_reserved,
  		       rqstp->rq_res.len);
  
  	rqstp->rq_res.head[0].iov_len = 0;
  	svc_reserve(rqstp, 0);
  	rqstp->rq_xprt = NULL;
  
  	svc_xprt_put(xprt);
  }
  
  /*
   * External function to wake up a server waiting for data
   * This really only makes sense for services like lockd
   * which have exactly one thread anyway.
   */
  void svc_wake_up(struct svc_serv *serv)
  {
  	struct svc_rqst	*rqstp;
  	unsigned int i;
  	struct svc_pool *pool;
  
  	for (i = 0; i < serv->sv_nrpools; i++) {
  		pool = &serv->sv_pools[i];
  
  		spin_lock_bh(&pool->sp_lock);
  		if (!list_empty(&pool->sp_threads)) {
  			rqstp = list_entry(pool->sp_threads.next,
  					   struct svc_rqst,
  					   rq_list);
  			dprintk("svc: daemon %p woken up.
  ", rqstp);
  			/*
  			svc_thread_dequeue(pool, rqstp);
  			rqstp->rq_xprt = NULL;
  			 */
  			wake_up(&rqstp->rq_wait);
  		}
  		spin_unlock_bh(&pool->sp_lock);
  	}
  }
24c3767e4   Trond Myklebust   SUNRPC: The sunrp...
497
  EXPORT_SYMBOL_GPL(svc_wake_up);
0f0257eaa   Tom Tucker   svc: Move the xpr...
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
  
  int svc_port_is_privileged(struct sockaddr *sin)
  {
  	switch (sin->sa_family) {
  	case AF_INET:
  		return ntohs(((struct sockaddr_in *)sin)->sin_port)
  			< PROT_SOCK;
  	case AF_INET6:
  		return ntohs(((struct sockaddr_in6 *)sin)->sin6_port)
  			< PROT_SOCK;
  	default:
  		return 0;
  	}
  }
  
  /*
c9233eb7b   Jeff Layton   sunrpc: add sv_ma...
514
515
516
517
   * Make sure that we don't have too many active connections. If we have,
   * something must be dropped. It's not clear what will happen if we allow
   * "too many" connections, but when dealing with network-facing software,
   * we have to code defensively. Here we do that by imposing hard limits.
0f0257eaa   Tom Tucker   svc: Move the xpr...
518
519
520
521
522
523
524
525
   *
   * There's no point in trying to do random drop here for DoS
   * prevention. The NFS clients does 1 reconnect in 15 seconds. An
   * attacker can easily beat that.
   *
   * The only somewhat efficient mechanism would be if drop old
   * connections from the same IP first. But right now we don't even
   * record the client IP in svc_sock.
c9233eb7b   Jeff Layton   sunrpc: add sv_ma...
526
527
528
529
   *
   * single-threaded services that expect a lot of clients will probably
   * need to set sv_maxconn to override the default value which is based
   * on the number of threads
0f0257eaa   Tom Tucker   svc: Move the xpr...
530
531
532
   */
  static void svc_check_conn_limits(struct svc_serv *serv)
  {
c9233eb7b   Jeff Layton   sunrpc: add sv_ma...
533
534
535
536
  	unsigned int limit = serv->sv_maxconn ? serv->sv_maxconn :
  				(serv->sv_nrthreads+3) * 20;
  
  	if (serv->sv_tmpcnt > limit) {
0f0257eaa   Tom Tucker   svc: Move the xpr...
537
538
539
540
541
542
  		struct svc_xprt *xprt = NULL;
  		spin_lock_bh(&serv->sv_lock);
  		if (!list_empty(&serv->sv_tempsocks)) {
  			if (net_ratelimit()) {
  				/* Try to help the admin */
  				printk(KERN_NOTICE "%s: too many open  "
c9233eb7b   Jeff Layton   sunrpc: add sv_ma...
543
544
545
546
547
  				       "connections, consider increasing %s
  ",
  				       serv->sv_name, serv->sv_maxconn ?
  				       "the max number of connections." :
  				       "the number of threads.");
0f0257eaa   Tom Tucker   svc: Move the xpr...
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
  			}
  			/*
  			 * Always select the oldest connection. It's not fair,
  			 * but so is life
  			 */
  			xprt = list_entry(serv->sv_tempsocks.prev,
  					  struct svc_xprt,
  					  xpt_list);
  			set_bit(XPT_CLOSE, &xprt->xpt_flags);
  			svc_xprt_get(xprt);
  		}
  		spin_unlock_bh(&serv->sv_lock);
  
  		if (xprt) {
  			svc_xprt_enqueue(xprt);
  			svc_xprt_put(xprt);
  		}
  	}
  }
  
  /*
   * Receive the next request on any transport.  This code is carefully
   * organised not to touch any cachelines in the shared svc_serv
   * structure, only cachelines in the local svc_pool.
   */
  int svc_recv(struct svc_rqst *rqstp, long timeout)
  {
  	struct svc_xprt		*xprt = NULL;
  	struct svc_serv		*serv = rqstp->rq_server;
  	struct svc_pool		*pool = rqstp->rq_pool;
  	int			len, i;
  	int			pages;
  	struct xdr_buf		*arg;
  	DECLARE_WAITQUEUE(wait, current);
03cf6c9f4   Greg Banks   knfsd: add file t...
582
  	long			time_left;
0f0257eaa   Tom Tucker   svc: Move the xpr...
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
  
  	dprintk("svc: server %p waiting for data (to = %ld)
  ",
  		rqstp, timeout);
  
  	if (rqstp->rq_xprt)
  		printk(KERN_ERR
  			"svc_recv: service %p, transport not NULL!
  ",
  			 rqstp);
  	if (waitqueue_active(&rqstp->rq_wait))
  		printk(KERN_ERR
  			"svc_recv: service %p, wait queue active!
  ",
  			 rqstp);
  
  	/* now allocate needed pages.  If we get a failure, sleep briefly */
  	pages = (serv->sv_max_mesg + PAGE_SIZE) / PAGE_SIZE;
  	for (i = 0; i < pages ; i++)
  		while (rqstp->rq_pages[i] == NULL) {
  			struct page *p = alloc_page(GFP_KERNEL);
  			if (!p) {
7b54fe61f   Jeff Layton   SUNRPC: allow svc...
605
606
607
  				set_current_state(TASK_INTERRUPTIBLE);
  				if (signalled() || kthread_should_stop()) {
  					set_current_state(TASK_RUNNING);
7086721f9   Jeff Layton   SUNRPC: have svc_...
608
  					return -EINTR;
7b54fe61f   Jeff Layton   SUNRPC: allow svc...
609
610
  				}
  				schedule_timeout(msecs_to_jiffies(500));
0f0257eaa   Tom Tucker   svc: Move the xpr...
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
  			}
  			rqstp->rq_pages[i] = p;
  		}
  	rqstp->rq_pages[i++] = NULL; /* this might be seen in nfs_read_actor */
  	BUG_ON(pages >= RPCSVC_MAXPAGES);
  
  	/* Make arg->head point to first page and arg->pages point to rest */
  	arg = &rqstp->rq_arg;
  	arg->head[0].iov_base = page_address(rqstp->rq_pages[0]);
  	arg->head[0].iov_len = PAGE_SIZE;
  	arg->pages = rqstp->rq_pages + 1;
  	arg->page_base = 0;
  	/* save at least one page for response */
  	arg->page_len = (pages-2)*PAGE_SIZE;
  	arg->len = (pages-1)*PAGE_SIZE;
  	arg->tail[0].iov_len = 0;
  
  	try_to_freeze();
  	cond_resched();
7086721f9   Jeff Layton   SUNRPC: have svc_...
630
  	if (signalled() || kthread_should_stop())
0f0257eaa   Tom Tucker   svc: Move the xpr...
631
  		return -EINTR;
f16b6e8d8   NeilBrown   sunrpc/cache: all...
632
633
634
635
  	/* Normally we will wait up to 5 seconds for any required
  	 * cache information to be provided.
  	 */
  	rqstp->rq_chandle.thread_wait = 5*HZ;
0f0257eaa   Tom Tucker   svc: Move the xpr...
636
637
638
639
640
641
642
  	spin_lock_bh(&pool->sp_lock);
  	xprt = svc_xprt_dequeue(pool);
  	if (xprt) {
  		rqstp->rq_xprt = xprt;
  		svc_xprt_get(xprt);
  		rqstp->rq_reserved = serv->sv_max_mesg;
  		atomic_add(rqstp->rq_reserved, &xprt->xpt_reserved);
f16b6e8d8   NeilBrown   sunrpc/cache: all...
643
644
  
  		/* As there is a shortage of threads and this request
6610f720e   J. Bruce Fields   svcrpc: minor cac...
645
  		 * had to be queued, don't allow the thread to wait so
f16b6e8d8   NeilBrown   sunrpc/cache: all...
646
647
648
  		 * long for cache updates.
  		 */
  		rqstp->rq_chandle.thread_wait = 1*HZ;
0f0257eaa   Tom Tucker   svc: Move the xpr...
649
650
651
652
653
654
655
656
657
  	} else {
  		/* No data pending. Go to sleep */
  		svc_thread_enqueue(pool, rqstp);
  
  		/*
  		 * We have to be able to interrupt this wait
  		 * to bring down the daemons ...
  		 */
  		set_current_state(TASK_INTERRUPTIBLE);
7086721f9   Jeff Layton   SUNRPC: have svc_...
658
659
660
661
662
663
664
665
666
667
668
669
670
  
  		/*
  		 * checking kthread_should_stop() here allows us to avoid
  		 * locking and signalling when stopping kthreads that call
  		 * svc_recv. If the thread has already been woken up, then
  		 * we can exit here without sleeping. If not, then it
  		 * it'll be woken up quickly during the schedule_timeout
  		 */
  		if (kthread_should_stop()) {
  			set_current_state(TASK_RUNNING);
  			spin_unlock_bh(&pool->sp_lock);
  			return -EINTR;
  		}
0f0257eaa   Tom Tucker   svc: Move the xpr...
671
672
  		add_wait_queue(&rqstp->rq_wait, &wait);
  		spin_unlock_bh(&pool->sp_lock);
03cf6c9f4   Greg Banks   knfsd: add file t...
673
  		time_left = schedule_timeout(timeout);
0f0257eaa   Tom Tucker   svc: Move the xpr...
674
675
676
677
678
  
  		try_to_freeze();
  
  		spin_lock_bh(&pool->sp_lock);
  		remove_wait_queue(&rqstp->rq_wait, &wait);
03cf6c9f4   Greg Banks   knfsd: add file t...
679
680
  		if (!time_left)
  			pool->sp_stats.threads_timedout++;
0f0257eaa   Tom Tucker   svc: Move the xpr...
681
682
683
684
685
686
687
  
  		xprt = rqstp->rq_xprt;
  		if (!xprt) {
  			svc_thread_dequeue(pool, rqstp);
  			spin_unlock_bh(&pool->sp_lock);
  			dprintk("svc: server %p, no data yet
  ", rqstp);
7086721f9   Jeff Layton   SUNRPC: have svc_...
688
689
690
691
  			if (signalled() || kthread_should_stop())
  				return -EINTR;
  			else
  				return -EAGAIN;
0f0257eaa   Tom Tucker   svc: Move the xpr...
692
693
694
695
696
  		}
  	}
  	spin_unlock_bh(&pool->sp_lock);
  
  	len = 0;
1b644b6e6   J. Bruce Fields   Revert "sunrpc: m...
697
698
699
700
  	if (test_bit(XPT_CLOSE, &xprt->xpt_flags)) {
  		dprintk("svc_recv: found XPT_CLOSE
  ");
  		svc_delete_xprt(xprt);
ca7896cd8   J. Bruce Fields   nfsd4: centralize...
701
702
703
704
  		/* Leave XPT_BUSY set on the dead xprt: */
  		goto out;
  	}
  	if (test_bit(XPT_LISTENER, &xprt->xpt_flags)) {
0f0257eaa   Tom Tucker   svc: Move the xpr...
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
  		struct svc_xprt *newxpt;
  		newxpt = xprt->xpt_ops->xpo_accept(xprt);
  		if (newxpt) {
  			/*
  			 * We know this module_get will succeed because the
  			 * listener holds a reference too
  			 */
  			__module_get(newxpt->xpt_class->xcl_owner);
  			svc_check_conn_limits(xprt->xpt_server);
  			spin_lock_bh(&serv->sv_lock);
  			set_bit(XPT_TEMP, &newxpt->xpt_flags);
  			list_add(&newxpt->xpt_list, &serv->sv_tempsocks);
  			serv->sv_tmpcnt++;
  			if (serv->sv_temptimer.function == NULL) {
  				/* setup timer to age temp transports */
  				setup_timer(&serv->sv_temptimer,
  					    svc_age_temp_xprts,
  					    (unsigned long)serv);
  				mod_timer(&serv->sv_temptimer,
  					  jiffies + svc_conn_age_period * HZ);
  			}
  			spin_unlock_bh(&serv->sv_lock);
  			svc_xprt_received(newxpt);
  		}
9c335c0b8   J. Bruce Fields   svcrpc: fix wspac...
729
  	} else if (xprt->xpt_ops->xpo_has_wspace(xprt)) {
0f0257eaa   Tom Tucker   svc: Move the xpr...
730
731
732
733
734
  		dprintk("svc: server %p, pool %u, transport %p, inuse=%d
  ",
  			rqstp, pool->sp_id, xprt,
  			atomic_read(&xprt->xpt_ref.refcount));
  		rqstp->rq_deferred = svc_deferred_dequeue(xprt);
ca7896cd8   J. Bruce Fields   nfsd4: centralize...
735
  		if (rqstp->rq_deferred)
0f0257eaa   Tom Tucker   svc: Move the xpr...
736
  			len = svc_deferred_recv(rqstp);
ca7896cd8   J. Bruce Fields   nfsd4: centralize...
737
  		else
0f0257eaa   Tom Tucker   svc: Move the xpr...
738
739
740
741
  			len = xprt->xpt_ops->xpo_recvfrom(rqstp);
  		dprintk("svc: got len=%d
  ", len);
  	}
ca7896cd8   J. Bruce Fields   nfsd4: centralize...
742
  	svc_xprt_received(xprt);
0f0257eaa   Tom Tucker   svc: Move the xpr...
743
744
  
  	/* No data, incomplete (TCP) read, or accept() */
ca7896cd8   J. Bruce Fields   nfsd4: centralize...
745
746
  	if (len == 0 || len == -EAGAIN)
  		goto out;
0f0257eaa   Tom Tucker   svc: Move the xpr...
747
748
749
750
751
752
753
754
  	clear_bit(XPT_OLD, &xprt->xpt_flags);
  
  	rqstp->rq_secure = svc_port_is_privileged(svc_addr(rqstp));
  	rqstp->rq_chandle.defer = svc_defer;
  
  	if (serv->sv_stats)
  		serv->sv_stats->netcnt++;
  	return len;
ca7896cd8   J. Bruce Fields   nfsd4: centralize...
755
756
757
758
  out:
  	rqstp->rq_res.len = 0;
  	svc_xprt_release(rqstp);
  	return -EAGAIN;
0f0257eaa   Tom Tucker   svc: Move the xpr...
759
  }
24c3767e4   Trond Myklebust   SUNRPC: The sunrp...
760
  EXPORT_SYMBOL_GPL(svc_recv);
0f0257eaa   Tom Tucker   svc: Move the xpr...
761
762
763
764
765
766
767
768
769
770
  
  /*
   * Drop request
   */
  void svc_drop(struct svc_rqst *rqstp)
  {
  	dprintk("svc: xprt %p dropped request
  ", rqstp->rq_xprt);
  	svc_xprt_release(rqstp);
  }
24c3767e4   Trond Myklebust   SUNRPC: The sunrp...
771
  EXPORT_SYMBOL_GPL(svc_drop);
0f0257eaa   Tom Tucker   svc: Move the xpr...
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
  
  /*
   * Return reply to client.
   */
  int svc_send(struct svc_rqst *rqstp)
  {
  	struct svc_xprt	*xprt;
  	int		len;
  	struct xdr_buf	*xb;
  
  	xprt = rqstp->rq_xprt;
  	if (!xprt)
  		return -EFAULT;
  
  	/* release the receive skb before sending the reply */
  	rqstp->rq_xprt->xpt_ops->xpo_release_rqst(rqstp);
  
  	/* calculate over-all length */
  	xb = &rqstp->rq_res;
  	xb->len = xb->head[0].iov_len +
  		xb->page_len +
  		xb->tail[0].iov_len;
  
  	/* Grab mutex to serialize outgoing data. */
  	mutex_lock(&xprt->xpt_mutex);
  	if (test_bit(XPT_DEAD, &xprt->xpt_flags))
  		len = -ENOTCONN;
  	else
  		len = xprt->xpt_ops->xpo_sendto(rqstp);
  	mutex_unlock(&xprt->xpt_mutex);
4cfc7e601   Rahul Iyer   nfsd41: sunrpc: A...
802
  	rpc_wake_up(&xprt->xpt_bc_pending);
0f0257eaa   Tom Tucker   svc: Move the xpr...
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
  	svc_xprt_release(rqstp);
  
  	if (len == -ECONNREFUSED || len == -ENOTCONN || len == -EAGAIN)
  		return 0;
  	return len;
  }
  
  /*
   * Timer function to close old temporary transports, using
   * a mark-and-sweep algorithm.
   */
  static void svc_age_temp_xprts(unsigned long closure)
  {
  	struct svc_serv *serv = (struct svc_serv *)closure;
  	struct svc_xprt *xprt;
  	struct list_head *le, *next;
  	LIST_HEAD(to_be_aged);
  
  	dprintk("svc_age_temp_xprts
  ");
  
  	if (!spin_trylock_bh(&serv->sv_lock)) {
  		/* busy, try again 1 sec later */
  		dprintk("svc_age_temp_xprts: busy
  ");
  		mod_timer(&serv->sv_temptimer, jiffies + HZ);
  		return;
  	}
  
  	list_for_each_safe(le, next, &serv->sv_tempsocks) {
  		xprt = list_entry(le, struct svc_xprt, xpt_list);
  
  		/* First time through, just mark it OLD. Second time
  		 * through, close it. */
  		if (!test_and_set_bit(XPT_OLD, &xprt->xpt_flags))
  			continue;
f64f9e719   Joe Perches   net: Move && and ...
839
840
  		if (atomic_read(&xprt->xpt_ref.refcount) > 1 ||
  		    test_bit(XPT_BUSY, &xprt->xpt_flags))
0f0257eaa   Tom Tucker   svc: Move the xpr...
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
  			continue;
  		svc_xprt_get(xprt);
  		list_move(le, &to_be_aged);
  		set_bit(XPT_CLOSE, &xprt->xpt_flags);
  		set_bit(XPT_DETACHED, &xprt->xpt_flags);
  	}
  	spin_unlock_bh(&serv->sv_lock);
  
  	while (!list_empty(&to_be_aged)) {
  		le = to_be_aged.next;
  		/* fiddling the xpt_list node is safe 'cos we're XPT_DETACHED */
  		list_del_init(le);
  		xprt = list_entry(le, struct svc_xprt, xpt_list);
  
  		dprintk("queuing xprt %p for closing
  ", xprt);
  
  		/* a thread will dequeue and close it soon */
  		svc_xprt_enqueue(xprt);
  		svc_xprt_put(xprt);
  	}
  
  	mod_timer(&serv->sv_temptimer, jiffies + svc_conn_age_period * HZ);
  }
edc7a8940   J. Bruce Fields   nfsd: provide cal...
865
866
867
868
869
870
871
872
873
874
875
876
  static void call_xpt_users(struct svc_xprt *xprt)
  {
  	struct svc_xpt_user *u;
  
  	spin_lock(&xprt->xpt_lock);
  	while (!list_empty(&xprt->xpt_users)) {
  		u = list_first_entry(&xprt->xpt_users, struct svc_xpt_user, list);
  		list_del(&u->list);
  		u->callback(u);
  	}
  	spin_unlock(&xprt->xpt_lock);
  }
0f0257eaa   Tom Tucker   svc: Move the xpr...
877
878
879
  /*
   * Remove a dead transport
   */
7710ec36b   J. Bruce Fields   svcrpc: make svc_...
880
  static void svc_delete_xprt(struct svc_xprt *xprt)
0f0257eaa   Tom Tucker   svc: Move the xpr...
881
882
  {
  	struct svc_serv	*serv = xprt->xpt_server;
22945e4a1   Tom Tucker   svc: Clean up def...
883
884
885
886
  	struct svc_deferred_req *dr;
  
  	/* Only do this once */
  	if (test_and_set_bit(XPT_DEAD, &xprt->xpt_flags))
ac9303eb7   J. Bruce Fields   svcrpc: assume sv...
887
  		BUG();
0f0257eaa   Tom Tucker   svc: Move the xpr...
888
889
890
891
892
893
894
895
  
  	dprintk("svc: svc_delete_xprt(%p)
  ", xprt);
  	xprt->xpt_ops->xpo_detach(xprt);
  
  	spin_lock_bh(&serv->sv_lock);
  	if (!test_and_set_bit(XPT_DETACHED, &xprt->xpt_flags))
  		list_del_init(&xprt->xpt_list);
b4f36f88b   J. Bruce Fields   svcrpc: avoid mem...
896
  	BUG_ON(!list_empty(&xprt->xpt_ready));
22945e4a1   Tom Tucker   svc: Clean up def...
897
898
  	if (test_bit(XPT_TEMP, &xprt->xpt_flags))
  		serv->sv_tmpcnt--;
788e69e54   J. Bruce Fields   svcrpc: don't hol...
899
  	spin_unlock_bh(&serv->sv_lock);
22945e4a1   Tom Tucker   svc: Clean up def...
900

ab1b18f70   Neil Brown   sunrpc: remove un...
901
  	while ((dr = svc_deferred_dequeue(xprt)) != NULL)
22945e4a1   Tom Tucker   svc: Clean up def...
902
  		kfree(dr);
22945e4a1   Tom Tucker   svc: Clean up def...
903

edc7a8940   J. Bruce Fields   nfsd: provide cal...
904
  	call_xpt_users(xprt);
22945e4a1   Tom Tucker   svc: Clean up def...
905
  	svc_xprt_put(xprt);
0f0257eaa   Tom Tucker   svc: Move the xpr...
906
907
908
909
910
911
912
913
  }
  
  void svc_close_xprt(struct svc_xprt *xprt)
  {
  	set_bit(XPT_CLOSE, &xprt->xpt_flags);
  	if (test_and_set_bit(XPT_BUSY, &xprt->xpt_flags))
  		/* someone else will have to effect the close */
  		return;
b17633162   J. Bruce Fields   svcrpc: svc_close...
914
915
916
917
918
919
  	/*
  	 * We expect svc_close_xprt() to work even when no threads are
  	 * running (e.g., while configuring the server before starting
  	 * any threads), so if the transport isn't busy, we delete
  	 * it ourself:
  	 */
0f0257eaa   Tom Tucker   svc: Move the xpr...
920
  	svc_delete_xprt(xprt);
0f0257eaa   Tom Tucker   svc: Move the xpr...
921
  }
a217813f9   Tom Tucker   knfsd: Support ad...
922
  EXPORT_SYMBOL_GPL(svc_close_xprt);
0f0257eaa   Tom Tucker   svc: Move the xpr...
923

2fefb8a09   J. Bruce Fields   svcrpc: destroy s...
924
  static void svc_close_list(struct list_head *xprt_list)
0f0257eaa   Tom Tucker   svc: Move the xpr...
925
926
  {
  	struct svc_xprt *xprt;
0f0257eaa   Tom Tucker   svc: Move the xpr...
927

b4f36f88b   J. Bruce Fields   svcrpc: avoid mem...
928
  	list_for_each_entry(xprt, xprt_list, xpt_list) {
0f0257eaa   Tom Tucker   svc: Move the xpr...
929
  		set_bit(XPT_CLOSE, &xprt->xpt_flags);
b4f36f88b   J. Bruce Fields   svcrpc: avoid mem...
930
  		set_bit(XPT_BUSY, &xprt->xpt_flags);
0f0257eaa   Tom Tucker   svc: Move the xpr...
931
932
  	}
  }
2fefb8a09   J. Bruce Fields   svcrpc: destroy s...
933
  void svc_close_all(struct svc_serv *serv)
0f0257eaa   Tom Tucker   svc: Move the xpr...
934
  {
b4f36f88b   J. Bruce Fields   svcrpc: avoid mem...
935
  	struct svc_pool *pool;
0f0257eaa   Tom Tucker   svc: Move the xpr...
936
937
  	struct svc_xprt *xprt;
  	struct svc_xprt *tmp;
b4f36f88b   J. Bruce Fields   svcrpc: avoid mem...
938
  	int i;
2fefb8a09   J. Bruce Fields   svcrpc: destroy s...
939
940
  	svc_close_list(&serv->sv_tempsocks);
  	svc_close_list(&serv->sv_permsocks);
0f0257eaa   Tom Tucker   svc: Move the xpr...
941

b4f36f88b   J. Bruce Fields   svcrpc: avoid mem...
942
943
944
945
946
947
948
949
950
951
  	for (i = 0; i < serv->sv_nrpools; i++) {
  		pool = &serv->sv_pools[i];
  
  		spin_lock_bh(&pool->sp_lock);
  		while (!list_empty(&pool->sp_sockets)) {
  			xprt = list_first_entry(&pool->sp_sockets, struct svc_xprt, xpt_ready);
  			list_del_init(&xprt->xpt_ready);
  		}
  		spin_unlock_bh(&pool->sp_lock);
  	}
f8c0d226f   J. Bruce Fields   svcrpc: simplify ...
952
  	/*
b4f36f88b   J. Bruce Fields   svcrpc: avoid mem...
953
954
955
  	 * At this point the sp_sockets lists will stay empty, since
  	 * svc_enqueue will not add new entries without taking the
  	 * sp_lock and checking XPT_BUSY.
f8c0d226f   J. Bruce Fields   svcrpc: simplify ...
956
  	 */
b4f36f88b   J. Bruce Fields   svcrpc: avoid mem...
957
  	list_for_each_entry_safe(xprt, tmp, &serv->sv_tempsocks, xpt_list)
f8c0d226f   J. Bruce Fields   svcrpc: simplify ...
958
  		svc_delete_xprt(xprt);
b4f36f88b   J. Bruce Fields   svcrpc: avoid mem...
959
960
  	list_for_each_entry_safe(xprt, tmp, &serv->sv_permsocks, xpt_list)
  		svc_delete_xprt(xprt);
2fefb8a09   J. Bruce Fields   svcrpc: destroy s...
961
962
  	BUG_ON(!list_empty(&serv->sv_permsocks));
  	BUG_ON(!list_empty(&serv->sv_tempsocks));
0f0257eaa   Tom Tucker   svc: Move the xpr...
963
964
965
966
967
968
969
970
971
972
973
  }
  
  /*
   * Handle defer and revisit of requests
   */
  
  static void svc_revisit(struct cache_deferred_req *dreq, int too_many)
  {
  	struct svc_deferred_req *dr =
  		container_of(dreq, struct svc_deferred_req, handle);
  	struct svc_xprt *xprt = dr->xprt;
22945e4a1   Tom Tucker   svc: Clean up def...
974
975
976
977
978
979
  	spin_lock(&xprt->xpt_lock);
  	set_bit(XPT_DEFERRED, &xprt->xpt_flags);
  	if (too_many || test_bit(XPT_DEAD, &xprt->xpt_flags)) {
  		spin_unlock(&xprt->xpt_lock);
  		dprintk("revisit canceled
  ");
0f0257eaa   Tom Tucker   svc: Move the xpr...
980
981
982
983
984
985
986
  		svc_xprt_put(xprt);
  		kfree(dr);
  		return;
  	}
  	dprintk("revisit queued
  ");
  	dr->xprt = NULL;
0f0257eaa   Tom Tucker   svc: Move the xpr...
987
988
  	list_add(&dr->handle.recent, &xprt->xpt_deferred);
  	spin_unlock(&xprt->xpt_lock);
0f0257eaa   Tom Tucker   svc: Move the xpr...
989
990
991
  	svc_xprt_enqueue(xprt);
  	svc_xprt_put(xprt);
  }
260c1d129   Tom Tucker   svc: Add transpor...
992
993
994
995
996
997
998
999
1000
  /*
   * Save the request off for later processing. The request buffer looks
   * like this:
   *
   * <xprt-header><rpc-header><rpc-pagelist><rpc-tail>
   *
   * This code can only handle requests that consist of an xprt-header
   * and rpc-header.
   */
0f0257eaa   Tom Tucker   svc: Move the xpr...
1001
1002
1003
  static struct cache_deferred_req *svc_defer(struct cache_req *req)
  {
  	struct svc_rqst *rqstp = container_of(req, struct svc_rqst, rq_chandle);
0f0257eaa   Tom Tucker   svc: Move the xpr...
1004
  	struct svc_deferred_req *dr;
2f425878b   Andy Adamson   nfsd: don't use t...
1005
  	if (rqstp->rq_arg.page_len || !rqstp->rq_usedeferral)
0f0257eaa   Tom Tucker   svc: Move the xpr...
1006
1007
1008
1009
1010
  		return NULL; /* if more than a page, give up FIXME */
  	if (rqstp->rq_deferred) {
  		dr = rqstp->rq_deferred;
  		rqstp->rq_deferred = NULL;
  	} else {
260c1d129   Tom Tucker   svc: Add transpor...
1011
1012
  		size_t skip;
  		size_t size;
0f0257eaa   Tom Tucker   svc: Move the xpr...
1013
  		/* FIXME maybe discard if size too large */
260c1d129   Tom Tucker   svc: Add transpor...
1014
  		size = sizeof(struct svc_deferred_req) + rqstp->rq_arg.len;
0f0257eaa   Tom Tucker   svc: Move the xpr...
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
  		dr = kmalloc(size, GFP_KERNEL);
  		if (dr == NULL)
  			return NULL;
  
  		dr->handle.owner = rqstp->rq_server;
  		dr->prot = rqstp->rq_prot;
  		memcpy(&dr->addr, &rqstp->rq_addr, rqstp->rq_addrlen);
  		dr->addrlen = rqstp->rq_addrlen;
  		dr->daddr = rqstp->rq_daddr;
  		dr->argslen = rqstp->rq_arg.len >> 2;
260c1d129   Tom Tucker   svc: Add transpor...
1025
1026
1027
1028
1029
1030
  		dr->xprt_hlen = rqstp->rq_xprt_hlen;
  
  		/* back up head to the start of the buffer and copy */
  		skip = rqstp->rq_arg.len - rqstp->rq_arg.head[0].iov_len;
  		memcpy(dr->args, rqstp->rq_arg.head[0].iov_base - skip,
  		       dr->argslen << 2);
0f0257eaa   Tom Tucker   svc: Move the xpr...
1031
1032
1033
  	}
  	svc_xprt_get(rqstp->rq_xprt);
  	dr->xprt = rqstp->rq_xprt;
9e701c610   J. Bruce Fields   svcrpc: simpler r...
1034
  	rqstp->rq_dropme = true;
0f0257eaa   Tom Tucker   svc: Move the xpr...
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
  
  	dr->handle.revisit = svc_revisit;
  	return &dr->handle;
  }
  
  /*
   * recv data from a deferred request into an active one
   */
  static int svc_deferred_recv(struct svc_rqst *rqstp)
  {
  	struct svc_deferred_req *dr = rqstp->rq_deferred;
260c1d129   Tom Tucker   svc: Add transpor...
1046
1047
1048
1049
  	/* setup iov_base past transport header */
  	rqstp->rq_arg.head[0].iov_base = dr->args + (dr->xprt_hlen>>2);
  	/* The iov_len does not include the transport header bytes */
  	rqstp->rq_arg.head[0].iov_len = (dr->argslen<<2) - dr->xprt_hlen;
0f0257eaa   Tom Tucker   svc: Move the xpr...
1050
  	rqstp->rq_arg.page_len = 0;
260c1d129   Tom Tucker   svc: Add transpor...
1051
1052
  	/* The rq_arg.len includes the transport header bytes */
  	rqstp->rq_arg.len     = dr->argslen<<2;
0f0257eaa   Tom Tucker   svc: Move the xpr...
1053
1054
1055
  	rqstp->rq_prot        = dr->prot;
  	memcpy(&rqstp->rq_addr, &dr->addr, dr->addrlen);
  	rqstp->rq_addrlen     = dr->addrlen;
260c1d129   Tom Tucker   svc: Add transpor...
1056
1057
  	/* Save off transport header len in case we get deferred again */
  	rqstp->rq_xprt_hlen   = dr->xprt_hlen;
0f0257eaa   Tom Tucker   svc: Move the xpr...
1058
1059
  	rqstp->rq_daddr       = dr->daddr;
  	rqstp->rq_respages    = rqstp->rq_pages;
260c1d129   Tom Tucker   svc: Add transpor...
1060
  	return (dr->argslen<<2) - dr->xprt_hlen;
0f0257eaa   Tom Tucker   svc: Move the xpr...
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
  }
  
  
  static struct svc_deferred_req *svc_deferred_dequeue(struct svc_xprt *xprt)
  {
  	struct svc_deferred_req *dr = NULL;
  
  	if (!test_bit(XPT_DEFERRED, &xprt->xpt_flags))
  		return NULL;
  	spin_lock(&xprt->xpt_lock);
0f0257eaa   Tom Tucker   svc: Move the xpr...
1071
1072
1073
1074
1075
  	if (!list_empty(&xprt->xpt_deferred)) {
  		dr = list_entry(xprt->xpt_deferred.next,
  				struct svc_deferred_req,
  				handle.recent);
  		list_del_init(&dr->handle.recent);
62bac4af3   J. Bruce Fields   svcrpc: don't set...
1076
1077
  	} else
  		clear_bit(XPT_DEFERRED, &xprt->xpt_flags);
0f0257eaa   Tom Tucker   svc: Move the xpr...
1078
1079
1080
  	spin_unlock(&xprt->xpt_lock);
  	return dr;
  }
7fcb98d58   Tom Tucker   svc: Add svc API ...
1081

156e62094   Chuck Lever   SUNRPC: Clean up ...
1082
1083
1084
1085
1086
1087
1088
  /**
   * svc_find_xprt - find an RPC transport instance
   * @serv: pointer to svc_serv to search
   * @xcl_name: C string containing transport's class name
   * @af: Address family of transport's local address
   * @port: transport's IP port number
   *
7fcb98d58   Tom Tucker   svc: Add svc API ...
1089
1090
1091
1092
1093
1094
1095
1096
   * Return the transport instance pointer for the endpoint accepting
   * connections/peer traffic from the specified transport class,
   * address family and port.
   *
   * Specifying 0 for the address family or port is effectively a
   * wild-card, and will result in matching the first transport in the
   * service's list that has a matching class name.
   */
156e62094   Chuck Lever   SUNRPC: Clean up ...
1097
1098
  struct svc_xprt *svc_find_xprt(struct svc_serv *serv, const char *xcl_name,
  			       const sa_family_t af, const unsigned short port)
7fcb98d58   Tom Tucker   svc: Add svc API ...
1099
1100
1101
1102
1103
  {
  	struct svc_xprt *xprt;
  	struct svc_xprt *found = NULL;
  
  	/* Sanity check the args */
156e62094   Chuck Lever   SUNRPC: Clean up ...
1104
  	if (serv == NULL || xcl_name == NULL)
7fcb98d58   Tom Tucker   svc: Add svc API ...
1105
1106
1107
1108
1109
1110
1111
1112
  		return found;
  
  	spin_lock_bh(&serv->sv_lock);
  	list_for_each_entry(xprt, &serv->sv_permsocks, xpt_list) {
  		if (strcmp(xprt->xpt_class->xcl_name, xcl_name))
  			continue;
  		if (af != AF_UNSPEC && af != xprt->xpt_local.ss_family)
  			continue;
156e62094   Chuck Lever   SUNRPC: Clean up ...
1113
  		if (port != 0 && port != svc_xprt_local_port(xprt))
7fcb98d58   Tom Tucker   svc: Add svc API ...
1114
1115
  			continue;
  		found = xprt;
a217813f9   Tom Tucker   knfsd: Support ad...
1116
  		svc_xprt_get(xprt);
7fcb98d58   Tom Tucker   svc: Add svc API ...
1117
1118
1119
1120
1121
1122
  		break;
  	}
  	spin_unlock_bh(&serv->sv_lock);
  	return found;
  }
  EXPORT_SYMBOL_GPL(svc_find_xprt);
9571af18f   Tom Tucker   svc: Add svc_xprt...
1123

335c54bdc   Chuck Lever   NFSD: Prevent a b...
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
  static int svc_one_xprt_name(const struct svc_xprt *xprt,
  			     char *pos, int remaining)
  {
  	int len;
  
  	len = snprintf(pos, remaining, "%s %u
  ",
  			xprt->xpt_class->xcl_name,
  			svc_xprt_local_port(xprt));
  	if (len >= remaining)
  		return -ENAMETOOLONG;
  	return len;
  }
  
  /**
   * svc_xprt_names - format a buffer with a list of transport names
   * @serv: pointer to an RPC service
   * @buf: pointer to a buffer to be filled in
   * @buflen: length of buffer to be filled in
   *
   * Fills in @buf with a string containing a list of transport names,
   * each name terminated with '
  '.
   *
   * Returns positive length of the filled-in string on success; otherwise
   * a negative errno value is returned if an error occurs.
9571af18f   Tom Tucker   svc: Add svc_xprt...
1150
   */
335c54bdc   Chuck Lever   NFSD: Prevent a b...
1151
  int svc_xprt_names(struct svc_serv *serv, char *buf, const int buflen)
9571af18f   Tom Tucker   svc: Add svc_xprt...
1152
1153
  {
  	struct svc_xprt *xprt;
335c54bdc   Chuck Lever   NFSD: Prevent a b...
1154
1155
  	int len, totlen;
  	char *pos;
9571af18f   Tom Tucker   svc: Add svc_xprt...
1156
1157
1158
1159
1160
1161
  
  	/* Sanity check args */
  	if (!serv)
  		return 0;
  
  	spin_lock_bh(&serv->sv_lock);
335c54bdc   Chuck Lever   NFSD: Prevent a b...
1162
1163
1164
  
  	pos = buf;
  	totlen = 0;
9571af18f   Tom Tucker   svc: Add svc_xprt...
1165
  	list_for_each_entry(xprt, &serv->sv_permsocks, xpt_list) {
335c54bdc   Chuck Lever   NFSD: Prevent a b...
1166
1167
1168
1169
1170
1171
  		len = svc_one_xprt_name(xprt, pos, buflen - totlen);
  		if (len < 0) {
  			*buf = '\0';
  			totlen = len;
  		}
  		if (len <= 0)
9571af18f   Tom Tucker   svc: Add svc_xprt...
1172
  			break;
335c54bdc   Chuck Lever   NFSD: Prevent a b...
1173
1174
  
  		pos += len;
9571af18f   Tom Tucker   svc: Add svc_xprt...
1175
1176
  		totlen += len;
  	}
335c54bdc   Chuck Lever   NFSD: Prevent a b...
1177

9571af18f   Tom Tucker   svc: Add svc_xprt...
1178
1179
1180
1181
  	spin_unlock_bh(&serv->sv_lock);
  	return totlen;
  }
  EXPORT_SYMBOL_GPL(svc_xprt_names);
03cf6c9f4   Greg Banks   knfsd: add file t...
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
  
  
  /*----------------------------------------------------------------------------*/
  
  static void *svc_pool_stats_start(struct seq_file *m, loff_t *pos)
  {
  	unsigned int pidx = (unsigned int)*pos;
  	struct svc_serv *serv = m->private;
  
  	dprintk("svc_pool_stats_start, *pidx=%u
  ", pidx);
03cf6c9f4   Greg Banks   knfsd: add file t...
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
  	if (!pidx)
  		return SEQ_START_TOKEN;
  	return (pidx > serv->sv_nrpools ? NULL : &serv->sv_pools[pidx-1]);
  }
  
  static void *svc_pool_stats_next(struct seq_file *m, void *p, loff_t *pos)
  {
  	struct svc_pool *pool = p;
  	struct svc_serv *serv = m->private;
  
  	dprintk("svc_pool_stats_next, *pos=%llu
  ", *pos);
  
  	if (p == SEQ_START_TOKEN) {
  		pool = &serv->sv_pools[0];
  	} else {
  		unsigned int pidx = (pool - &serv->sv_pools[0]);
  		if (pidx < serv->sv_nrpools-1)
  			pool = &serv->sv_pools[pidx+1];
  		else
  			pool = NULL;
  	}
  	++*pos;
  	return pool;
  }
  
  static void svc_pool_stats_stop(struct seq_file *m, void *p)
  {
03cf6c9f4   Greg Banks   knfsd: add file t...
1221
1222
1223
1224
1225
1226
1227
  }
  
  static int svc_pool_stats_show(struct seq_file *m, void *p)
  {
  	struct svc_pool *pool = p;
  
  	if (p == SEQ_START_TOKEN) {
78c210efd   J. Bruce Fields   Revert "knfsd: av...
1228
1229
  		seq_puts(m, "# pool packets-arrived sockets-enqueued threads-woken threads-timedout
  ");
03cf6c9f4   Greg Banks   knfsd: add file t...
1230
1231
  		return 0;
  	}
78c210efd   J. Bruce Fields   Revert "knfsd: av...
1232
1233
  	seq_printf(m, "%u %lu %lu %lu %lu
  ",
03cf6c9f4   Greg Banks   knfsd: add file t...
1234
1235
1236
1237
  		pool->sp_id,
  		pool->sp_stats.packets,
  		pool->sp_stats.sockets_queued,
  		pool->sp_stats.threads_woken,
03cf6c9f4   Greg Banks   knfsd: add file t...
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
  		pool->sp_stats.threads_timedout);
  
  	return 0;
  }
  
  static const struct seq_operations svc_pool_stats_seq_ops = {
  	.start	= svc_pool_stats_start,
  	.next	= svc_pool_stats_next,
  	.stop	= svc_pool_stats_stop,
  	.show	= svc_pool_stats_show,
  };
  
  int svc_pool_stats_open(struct svc_serv *serv, struct file *file)
  {
  	int err;
  
  	err = seq_open(file, &svc_pool_stats_seq_ops);
  	if (!err)
  		((struct seq_file *) file->private_data)->private = serv;
  	return err;
  }
  EXPORT_SYMBOL(svc_pool_stats_open);
  
  /*----------------------------------------------------------------------------*/