Blame view

net/sunrpc/svc_xprt.c 35 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
  }
6741019c8   J. Bruce Fields   svcrpc: make svc_...
204
205
206
207
208
209
210
211
212
213
  /*
   * 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.
   */
  static void svc_xprt_received(struct svc_xprt *xprt)
  {
ff1fdb9b8   Weston Andros Adamson   SUNRPC: remove BU...
214
215
216
  	WARN_ON_ONCE(!test_bit(XPT_BUSY, &xprt->xpt_flags));
  	if (!test_bit(XPT_BUSY, &xprt->xpt_flags))
  		return;
6741019c8   J. Bruce Fields   svcrpc: make svc_...
217
218
219
220
221
222
223
224
  	/* 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);
  	clear_bit(XPT_BUSY, &xprt->xpt_flags);
  	svc_xprt_enqueue(xprt);
  	svc_xprt_put(xprt);
  }
39b553013   J. Bruce Fields   svcrpc: share som...
225
226
227
228
229
230
231
232
  void svc_add_new_perm_xprt(struct svc_serv *serv, struct svc_xprt *new)
  {
  	clear_bit(XPT_TEMP, &new->xpt_flags);
  	spin_lock_bh(&serv->sv_lock);
  	list_add(&new->xpt_list, &serv->sv_permsocks);
  	spin_unlock_bh(&serv->sv_lock);
  	svc_xprt_received(new);
  }
9652ada3f   Chuck Lever   SUNRPC: Change sv...
233
  int svc_create_xprt(struct svc_serv *serv, const char *xprt_name,
fc5d00b04   Pavel Emelyanov   sunrpc: Add net a...
234
235
  		    struct net *net, const int family,
  		    const unsigned short port, int flags)
5dd248f6f   Chuck Lever   SUNRPC: Use prope...
236
237
  {
  	struct svc_xprt_class *xcl;
b700cbb11   Tom Tucker   svc: Add a generi...
238
239
240
241
  	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 ...
242
  		struct svc_xprt *newxprt;
ed2849d3e   NeilBrown   sunrpc: prevent u...
243
  		unsigned short newport;
4e5caaa5f   Tom Tucker   svc: Move create ...
244
245
246
247
248
249
250
251
  
  		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 ...
252
  		newxprt = __svc_xpo_create(xcl, serv, net, family, port, flags);
4e5caaa5f   Tom Tucker   svc: Move create ...
253
254
255
  		if (IS_ERR(newxprt)) {
  			module_put(xcl->xcl_owner);
  			return PTR_ERR(newxprt);
b700cbb11   Tom Tucker   svc: Add a generi...
256
  		}
39b553013   J. Bruce Fields   svcrpc: share som...
257
  		svc_add_new_perm_xprt(serv, newxprt);
ed2849d3e   NeilBrown   sunrpc: prevent u...
258
  		newport = svc_xprt_local_port(newxprt);
ed2849d3e   NeilBrown   sunrpc: prevent u...
259
  		return newport;
b700cbb11   Tom Tucker   svc: Add a generi...
260
  	}
4e5caaa5f   Tom Tucker   svc: Move create ...
261
   err:
b700cbb11   Tom Tucker   svc: Add a generi...
262
263
264
  	spin_unlock(&svc_xprt_class_lock);
  	dprintk("svc: transport %s not found
  ", xprt_name);
687179081   Chuck Lever   SUNRPC: NFS kerne...
265
266
267
268
  
  	/* 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...
269
270
  }
  EXPORT_SYMBOL_GPL(svc_create_xprt);
9dbc240f1   Tom Tucker   svc: Move the soc...
271
272
273
274
275
276
  
  /*
   * 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...
277
278
279
280
281
282
283
  	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...
284
285
  	memcpy(&rqstp->rq_daddr, &xprt->xpt_local, xprt->xpt_locallen);
  	rqstp->rq_daddrlen = xprt->xpt_locallen;
9dbc240f1   Tom Tucker   svc: Move the soc...
286
287
  }
  EXPORT_SYMBOL_GPL(svc_xprt_copy_addrs);
0f0257eaa   Tom Tucker   svc: Move the xpr...
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
  /**
   * 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...
319
320
321
322
323
324
325
326
  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...
327
328
329
330
331
332
333
  /*
   * Queue up a transport with data pending. If there are idle nfsd
   * processes, wake 'em up.
   *
   */
  void svc_xprt_enqueue(struct svc_xprt *xprt)
  {
0f0257eaa   Tom Tucker   svc: Move the xpr...
334
335
336
  	struct svc_pool *pool;
  	struct svc_rqst	*rqstp;
  	int cpu;
9c335c0b8   J. Bruce Fields   svcrpc: fix wspac...
337
  	if (!svc_xprt_has_something_to_do(xprt))
0f0257eaa   Tom Tucker   svc: Move the xpr...
338
  		return;
0f0257eaa   Tom Tucker   svc: Move the xpr...
339
340
341
342
343
344
  
  	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...
345
346
347
348
349
350
  	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...
351
  	pool->sp_stats.packets++;
0f0257eaa   Tom Tucker   svc: Move the xpr...
352
353
354
355
356
357
358
359
360
361
362
  	/* 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...
363

78c210efd   J. Bruce Fields   Revert "knfsd: av...
364
  	if (!list_empty(&pool->sp_threads)) {
0f0257eaa   Tom Tucker   svc: Move the xpr...
365
366
367
368
369
370
371
372
373
374
375
376
377
378
  		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);
03cf6c9f4   Greg Banks   knfsd: add file t...
379
  		pool->sp_stats.threads_woken++;
0f0257eaa   Tom Tucker   svc: Move the xpr...
380
381
382
383
384
  		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...
385
  		pool->sp_stats.sockets_queued++;
0f0257eaa   Tom Tucker   svc: Move the xpr...
386
387
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
  	}
  
  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;
  }
0f0257eaa   Tom Tucker   svc: Move the xpr...
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
  /**
   * 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...
435
  EXPORT_SYMBOL_GPL(svc_reserve);
0f0257eaa   Tom Tucker   svc: Move the xpr...
436
437
438
439
440
441
  
  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...
442
443
  	kfree(rqstp->rq_deferred);
  	rqstp->rq_deferred = NULL;
0f0257eaa   Tom Tucker   svc: Move the xpr...
444
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
  	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);
35525b797   Andriy Skulysh   sunrpc: Fix lockd...
492
493
  		} else
  			pool->sp_task_pending = 1;
0f0257eaa   Tom Tucker   svc: Move the xpr...
494
495
496
  		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
  		struct svc_xprt *xprt = NULL;
  		spin_lock_bh(&serv->sv_lock);
  		if (!list_empty(&serv->sv_tempsocks)) {
e87cc4728   Joe Perches   net: Convert net_...
540
541
542
543
544
545
  			/* Try to help the admin */
  			net_notice_ratelimited("%s: too many open connections, consider increasing the %s
  ",
  					       serv->sv_name, serv->sv_maxconn ?
  					       "max number of connections" :
  					       "number of threads");
0f0257eaa   Tom Tucker   svc: Move the xpr...
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
  			/*
  			 * 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);
  		}
  	}
  }
6797fa5a0   J. Bruce Fields   svcrpc: break up ...
564
  int svc_alloc_arg(struct svc_rqst *rqstp)
0f0257eaa   Tom Tucker   svc: Move the xpr...
565
  {
6797fa5a0   J. Bruce Fields   svcrpc: break up ...
566
567
568
569
  	struct svc_serv *serv = rqstp->rq_server;
  	struct xdr_buf *arg;
  	int pages;
  	int i;
0f0257eaa   Tom Tucker   svc: Move the xpr...
570
571
572
  
  	/* now allocate needed pages.  If we get a failure, sleep briefly */
  	pages = (serv->sv_max_mesg + PAGE_SIZE) / PAGE_SIZE;
b25cd058f   Weston Andros Adamson   SUNRPC: remove BU...
573
574
575
576
  	WARN_ON_ONCE(pages >= RPCSVC_MAXPAGES);
  	if (pages >= RPCSVC_MAXPAGES)
  		/* use as many pages as possible */
  		pages = RPCSVC_MAXPAGES - 1;
0f0257eaa   Tom Tucker   svc: Move the xpr...
577
578
579
580
  	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...
581
582
583
  				set_current_state(TASK_INTERRUPTIBLE);
  				if (signalled() || kthread_should_stop()) {
  					set_current_state(TASK_RUNNING);
7086721f9   Jeff Layton   SUNRPC: have svc_...
584
  					return -EINTR;
7b54fe61f   Jeff Layton   SUNRPC: allow svc...
585
586
  				}
  				schedule_timeout(msecs_to_jiffies(500));
0f0257eaa   Tom Tucker   svc: Move the xpr...
587
588
589
590
  			}
  			rqstp->rq_pages[i] = p;
  		}
  	rqstp->rq_pages[i++] = NULL; /* this might be seen in nfs_read_actor */
0f0257eaa   Tom Tucker   svc: Move the xpr...
591
592
593
594
595
596
597
598
599
600
601
  
  	/* 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;
6797fa5a0   J. Bruce Fields   svcrpc: break up ...
602
603
  	return 0;
  }
0f0257eaa   Tom Tucker   svc: Move the xpr...
604

6797fa5a0   J. Bruce Fields   svcrpc: break up ...
605
606
607
608
609
610
  struct svc_xprt *svc_get_next_xprt(struct svc_rqst *rqstp, long timeout)
  {
  	struct svc_xprt *xprt;
  	struct svc_pool		*pool = rqstp->rq_pool;
  	DECLARE_WAITQUEUE(wait, current);
  	long			time_left;
0f0257eaa   Tom Tucker   svc: Move the xpr...
611

f16b6e8d8   NeilBrown   sunrpc/cache: all...
612
613
614
615
  	/* 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...
616
617
618
619
620
  	spin_lock_bh(&pool->sp_lock);
  	xprt = svc_xprt_dequeue(pool);
  	if (xprt) {
  		rqstp->rq_xprt = xprt;
  		svc_xprt_get(xprt);
f16b6e8d8   NeilBrown   sunrpc/cache: all...
621
622
  
  		/* As there is a shortage of threads and this request
6610f720e   J. Bruce Fields   svcrpc: minor cac...
623
  		 * had to be queued, don't allow the thread to wait so
f16b6e8d8   NeilBrown   sunrpc/cache: all...
624
625
626
  		 * long for cache updates.
  		 */
  		rqstp->rq_chandle.thread_wait = 1*HZ;
35525b797   Andriy Skulysh   sunrpc: Fix lockd...
627
  		pool->sp_task_pending = 0;
0f0257eaa   Tom Tucker   svc: Move the xpr...
628
  	} else {
35525b797   Andriy Skulysh   sunrpc: Fix lockd...
629
630
631
632
633
  		if (pool->sp_task_pending) {
  			pool->sp_task_pending = 0;
  			spin_unlock_bh(&pool->sp_lock);
  			return ERR_PTR(-EAGAIN);
  		}
0f0257eaa   Tom Tucker   svc: Move the xpr...
634
635
636
637
638
639
640
641
  		/* 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_...
642
643
644
645
646
647
648
649
650
651
652
  
  		/*
  		 * 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);
6797fa5a0   J. Bruce Fields   svcrpc: break up ...
653
  			return ERR_PTR(-EINTR);
7086721f9   Jeff Layton   SUNRPC: have svc_...
654
  		}
0f0257eaa   Tom Tucker   svc: Move the xpr...
655
656
  		add_wait_queue(&rqstp->rq_wait, &wait);
  		spin_unlock_bh(&pool->sp_lock);
03cf6c9f4   Greg Banks   knfsd: add file t...
657
  		time_left = schedule_timeout(timeout);
0f0257eaa   Tom Tucker   svc: Move the xpr...
658
659
660
661
662
  
  		try_to_freeze();
  
  		spin_lock_bh(&pool->sp_lock);
  		remove_wait_queue(&rqstp->rq_wait, &wait);
03cf6c9f4   Greg Banks   knfsd: add file t...
663
664
  		if (!time_left)
  			pool->sp_stats.threads_timedout++;
0f0257eaa   Tom Tucker   svc: Move the xpr...
665
666
667
668
669
670
671
  
  		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_...
672
  			if (signalled() || kthread_should_stop())
6797fa5a0   J. Bruce Fields   svcrpc: break up ...
673
  				return ERR_PTR(-EINTR);
7086721f9   Jeff Layton   SUNRPC: have svc_...
674
  			else
6797fa5a0   J. Bruce Fields   svcrpc: break up ...
675
  				return ERR_PTR(-EAGAIN);
0f0257eaa   Tom Tucker   svc: Move the xpr...
676
677
678
  		}
  	}
  	spin_unlock_bh(&pool->sp_lock);
6797fa5a0   J. Bruce Fields   svcrpc: break up ...
679
680
  	return xprt;
  }
65b2e6656   J. Bruce Fields   svcrpc: split up ...
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
  void svc_add_new_temp_xprt(struct svc_serv *serv, struct svc_xprt *newxpt)
  {
  	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);
  }
6797fa5a0   J. Bruce Fields   svcrpc: break up ...
697
698
699
700
  static int svc_handle_xprt(struct svc_rqst *rqstp, struct svc_xprt *xprt)
  {
  	struct svc_serv *serv = rqstp->rq_server;
  	int len = 0;
0f0257eaa   Tom Tucker   svc: Move the xpr...
701

1b644b6e6   J. Bruce Fields   Revert "sunrpc: m...
702
703
704
705
  	if (test_bit(XPT_CLOSE, &xprt->xpt_flags)) {
  		dprintk("svc_recv: found XPT_CLOSE
  ");
  		svc_delete_xprt(xprt);
ca7896cd8   J. Bruce Fields   nfsd4: centralize...
706
  		/* Leave XPT_BUSY set on the dead xprt: */
6797fa5a0   J. Bruce Fields   svcrpc: break up ...
707
  		return 0;
ca7896cd8   J. Bruce Fields   nfsd4: centralize...
708
709
  	}
  	if (test_bit(XPT_LISTENER, &xprt->xpt_flags)) {
0f0257eaa   Tom Tucker   svc: Move the xpr...
710
  		struct svc_xprt *newxpt;
65b2e6656   J. Bruce Fields   svcrpc: split up ...
711
712
713
714
715
716
  		/*
  		 * We know this module_get will succeed because the
  		 * listener holds a reference too
  		 */
  		__module_get(xprt->xpt_class->xcl_owner);
  		svc_check_conn_limits(xprt->xpt_server);
0f0257eaa   Tom Tucker   svc: Move the xpr...
717
  		newxpt = xprt->xpt_ops->xpo_accept(xprt);
65b2e6656   J. Bruce Fields   svcrpc: split up ...
718
719
  		if (newxpt)
  			svc_add_new_temp_xprt(serv, newxpt);
9c335c0b8   J. Bruce Fields   svcrpc: fix wspac...
720
  	} else if (xprt->xpt_ops->xpo_has_wspace(xprt)) {
6797fa5a0   J. Bruce Fields   svcrpc: break up ...
721
  		/* XPT_DATA|XPT_DEFERRED case: */
0f0257eaa   Tom Tucker   svc: Move the xpr...
722
723
  		dprintk("svc: server %p, pool %u, transport %p, inuse=%d
  ",
6797fa5a0   J. Bruce Fields   svcrpc: break up ...
724
  			rqstp, rqstp->rq_pool->sp_id, xprt,
0f0257eaa   Tom Tucker   svc: Move the xpr...
725
726
  			atomic_read(&xprt->xpt_ref.refcount));
  		rqstp->rq_deferred = svc_deferred_dequeue(xprt);
ca7896cd8   J. Bruce Fields   nfsd4: centralize...
727
  		if (rqstp->rq_deferred)
0f0257eaa   Tom Tucker   svc: Move the xpr...
728
  			len = svc_deferred_recv(rqstp);
ca7896cd8   J. Bruce Fields   nfsd4: centralize...
729
  		else
0f0257eaa   Tom Tucker   svc: Move the xpr...
730
731
732
  			len = xprt->xpt_ops->xpo_recvfrom(rqstp);
  		dprintk("svc: got len=%d
  ", len);
d10f27a75   J. Bruce Fields   svcrpc: fix svc_x...
733
734
  		rqstp->rq_reserved = serv->sv_max_mesg;
  		atomic_add(rqstp->rq_reserved, &xprt->xpt_reserved);
0f0257eaa   Tom Tucker   svc: Move the xpr...
735
  	}
6797fa5a0   J. Bruce Fields   svcrpc: break up ...
736
  	/* clear XPT_BUSY: */
ca7896cd8   J. Bruce Fields   nfsd4: centralize...
737
  	svc_xprt_received(xprt);
6797fa5a0   J. Bruce Fields   svcrpc: break up ...
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
  	return len;
  }
  
  /*
   * 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;
  	int			len, err;
  
  	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);
  
  	err = svc_alloc_arg(rqstp);
  	if (err)
  		return err;
  
  	try_to_freeze();
  	cond_resched();
  	if (signalled() || kthread_should_stop())
  		return -EINTR;
  
  	xprt = svc_get_next_xprt(rqstp, timeout);
  	if (IS_ERR(xprt))
  		return PTR_ERR(xprt);
  
  	len = svc_handle_xprt(rqstp, xprt);
0f0257eaa   Tom Tucker   svc: Move the xpr...
781
782
  
  	/* No data, incomplete (TCP) read, or accept() */
9f9d2ebe6   J. Bruce Fields   svcrpc: make xpo_...
783
  	if (len <= 0)
ca7896cd8   J. Bruce Fields   nfsd4: centralize...
784
  		goto out;
0f0257eaa   Tom Tucker   svc: Move the xpr...
785
786
787
788
789
790
791
792
  	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...
793
794
795
796
  out:
  	rqstp->rq_res.len = 0;
  	svc_xprt_release(rqstp);
  	return -EAGAIN;
0f0257eaa   Tom Tucker   svc: Move the xpr...
797
  }
24c3767e4   Trond Myklebust   SUNRPC: The sunrp...
798
  EXPORT_SYMBOL_GPL(svc_recv);
0f0257eaa   Tom Tucker   svc: Move the xpr...
799
800
801
802
803
804
805
806
807
808
  
  /*
   * 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...
809
  EXPORT_SYMBOL_GPL(svc_drop);
0f0257eaa   Tom Tucker   svc: Move the xpr...
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
  
  /*
   * 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);
f06f00a24   J. Bruce Fields   svcrpc: sends on ...
835
836
  	if (test_bit(XPT_DEAD, &xprt->xpt_flags)
  			|| test_bit(XPT_CLOSE, &xprt->xpt_flags))
0f0257eaa   Tom Tucker   svc: Move the xpr...
837
838
839
840
  		len = -ENOTCONN;
  	else
  		len = xprt->xpt_ops->xpo_sendto(rqstp);
  	mutex_unlock(&xprt->xpt_mutex);
4cfc7e601   Rahul Iyer   nfsd41: sunrpc: A...
841
  	rpc_wake_up(&xprt->xpt_bc_pending);
0f0257eaa   Tom Tucker   svc: Move the xpr...
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
  	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;
0f0257eaa   Tom Tucker   svc: Move the xpr...
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
  
  	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 ...
877
878
  		if (atomic_read(&xprt->xpt_ref.refcount) > 1 ||
  		    test_bit(XPT_BUSY, &xprt->xpt_flags))
0f0257eaa   Tom Tucker   svc: Move the xpr...
879
  			continue;
e75bafbff   J. Bruce Fields   svcrpc: make svc_...
880
  		list_del_init(le);
0f0257eaa   Tom Tucker   svc: Move the xpr...
881
882
  		set_bit(XPT_CLOSE, &xprt->xpt_flags);
  		set_bit(XPT_DETACHED, &xprt->xpt_flags);
0f0257eaa   Tom Tucker   svc: Move the xpr...
883
884
885
886
887
  		dprintk("queuing xprt %p for closing
  ", xprt);
  
  		/* a thread will dequeue and close it soon */
  		svc_xprt_enqueue(xprt);
0f0257eaa   Tom Tucker   svc: Move the xpr...
888
  	}
e75bafbff   J. Bruce Fields   svcrpc: make svc_...
889
  	spin_unlock_bh(&serv->sv_lock);
0f0257eaa   Tom Tucker   svc: Move the xpr...
890
891
892
  
  	mod_timer(&serv->sv_temptimer, jiffies + svc_conn_age_period * HZ);
  }
edc7a8940   J. Bruce Fields   nfsd: provide cal...
893
894
895
896
897
898
899
900
901
902
903
904
  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...
905
906
907
  /*
   * Remove a dead transport
   */
7710ec36b   J. Bruce Fields   svcrpc: make svc_...
908
  static void svc_delete_xprt(struct svc_xprt *xprt)
0f0257eaa   Tom Tucker   svc: Move the xpr...
909
910
  {
  	struct svc_serv	*serv = xprt->xpt_server;
22945e4a1   Tom Tucker   svc: Clean up def...
911
912
913
914
  	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...
915
  		BUG();
0f0257eaa   Tom Tucker   svc: Move the xpr...
916
917
918
919
920
921
922
923
  
  	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);
010472980   Weston Andros Adamson   SUNRPC: remove BU...
924
  	WARN_ON_ONCE(!list_empty(&xprt->xpt_ready));
22945e4a1   Tom Tucker   svc: Clean up def...
925
926
  	if (test_bit(XPT_TEMP, &xprt->xpt_flags))
  		serv->sv_tmpcnt--;
788e69e54   J. Bruce Fields   svcrpc: don't hol...
927
  	spin_unlock_bh(&serv->sv_lock);
22945e4a1   Tom Tucker   svc: Clean up def...
928

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

edc7a8940   J. Bruce Fields   nfsd: provide cal...
932
  	call_xpt_users(xprt);
22945e4a1   Tom Tucker   svc: Clean up def...
933
  	svc_xprt_put(xprt);
0f0257eaa   Tom Tucker   svc: Move the xpr...
934
935
936
937
938
939
940
941
  }
  
  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...
942
943
944
945
946
947
  	/*
  	 * 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...
948
  	svc_delete_xprt(xprt);
0f0257eaa   Tom Tucker   svc: Move the xpr...
949
  }
a217813f9   Tom Tucker   knfsd: Support ad...
950
  EXPORT_SYMBOL_GPL(svc_close_xprt);
0f0257eaa   Tom Tucker   svc: Move the xpr...
951

cc630d9f4   J. Bruce Fields   svcrpc: fix rpc s...
952
  static int svc_close_list(struct svc_serv *serv, struct list_head *xprt_list, struct net *net)
0f0257eaa   Tom Tucker   svc: Move the xpr...
953
954
  {
  	struct svc_xprt *xprt;
cc630d9f4   J. Bruce Fields   svcrpc: fix rpc s...
955
  	int ret = 0;
0f0257eaa   Tom Tucker   svc: Move the xpr...
956

719f8bcc8   J. Bruce Fields   svcrpc: fix xpt_l...
957
  	spin_lock(&serv->sv_lock);
b4f36f88b   J. Bruce Fields   svcrpc: avoid mem...
958
  	list_for_each_entry(xprt, xprt_list, xpt_list) {
7b147f1ff   Stanislav Kinsbursky   SUNRPC: service d...
959
960
  		if (xprt->xpt_net != net)
  			continue;
cc630d9f4   J. Bruce Fields   svcrpc: fix rpc s...
961
  		ret++;
0f0257eaa   Tom Tucker   svc: Move the xpr...
962
  		set_bit(XPT_CLOSE, &xprt->xpt_flags);
cc630d9f4   J. Bruce Fields   svcrpc: fix rpc s...
963
  		svc_xprt_enqueue(xprt);
0f0257eaa   Tom Tucker   svc: Move the xpr...
964
  	}
719f8bcc8   J. Bruce Fields   svcrpc: fix xpt_l...
965
  	spin_unlock(&serv->sv_lock);
cc630d9f4   J. Bruce Fields   svcrpc: fix rpc s...
966
  	return ret;
0f0257eaa   Tom Tucker   svc: Move the xpr...
967
  }
cc630d9f4   J. Bruce Fields   svcrpc: fix rpc s...
968
  static struct svc_xprt *svc_dequeue_net(struct svc_serv *serv, struct net *net)
0f0257eaa   Tom Tucker   svc: Move the xpr...
969
  {
b4f36f88b   J. Bruce Fields   svcrpc: avoid mem...
970
  	struct svc_pool *pool;
0f0257eaa   Tom Tucker   svc: Move the xpr...
971
972
  	struct svc_xprt *xprt;
  	struct svc_xprt *tmp;
b4f36f88b   J. Bruce Fields   svcrpc: avoid mem...
973
  	int i;
b4f36f88b   J. Bruce Fields   svcrpc: avoid mem...
974
975
976
977
  	for (i = 0; i < serv->sv_nrpools; i++) {
  		pool = &serv->sv_pools[i];
  
  		spin_lock_bh(&pool->sp_lock);
6f5133652   Stanislav Kinsbursky   SUNRPC: clear svc...
978
  		list_for_each_entry_safe(xprt, tmp, &pool->sp_sockets, xpt_ready) {
7b147f1ff   Stanislav Kinsbursky   SUNRPC: service d...
979
980
  			if (xprt->xpt_net != net)
  				continue;
b4f36f88b   J. Bruce Fields   svcrpc: avoid mem...
981
  			list_del_init(&xprt->xpt_ready);
cc630d9f4   J. Bruce Fields   svcrpc: fix rpc s...
982
983
  			spin_unlock_bh(&pool->sp_lock);
  			return xprt;
b4f36f88b   J. Bruce Fields   svcrpc: avoid mem...
984
985
986
  		}
  		spin_unlock_bh(&pool->sp_lock);
  	}
cc630d9f4   J. Bruce Fields   svcrpc: fix rpc s...
987
  	return NULL;
6f5133652   Stanislav Kinsbursky   SUNRPC: clear svc...
988
  }
cc630d9f4   J. Bruce Fields   svcrpc: fix rpc s...
989
  static void svc_clean_up_xprts(struct svc_serv *serv, struct net *net)
6f5133652   Stanislav Kinsbursky   SUNRPC: clear svc...
990
991
  {
  	struct svc_xprt *xprt;
719f8bcc8   J. Bruce Fields   svcrpc: fix xpt_l...
992

cc630d9f4   J. Bruce Fields   svcrpc: fix rpc s...
993
994
  	while ((xprt = svc_dequeue_net(serv, net))) {
  		set_bit(XPT_CLOSE, &xprt->xpt_flags);
719f8bcc8   J. Bruce Fields   svcrpc: fix xpt_l...
995
  		svc_delete_xprt(xprt);
cc630d9f4   J. Bruce Fields   svcrpc: fix rpc s...
996
  	}
3a22bf506   Stanislav Kinsbursky   SUNRPC: clear svc...
997
  }
cc630d9f4   J. Bruce Fields   svcrpc: fix rpc s...
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
  /*
   * Server threads may still be running (especially in the case where the
   * service is still running in other network namespaces).
   *
   * So we shut down sockets the same way we would on a running server, by
   * setting XPT_CLOSE, enqueuing, and letting a thread pick it up to do
   * the close.  In the case there are no such other threads,
   * threads running, svc_clean_up_xprts() does a simple version of a
   * server's main event loop, and in the case where there are other
   * threads, we may need to wait a little while and then check again to
   * see if they're done.
   */
7b147f1ff   Stanislav Kinsbursky   SUNRPC: service d...
1010
  void svc_close_net(struct svc_serv *serv, struct net *net)
3a22bf506   Stanislav Kinsbursky   SUNRPC: clear svc...
1011
  {
cc630d9f4   J. Bruce Fields   svcrpc: fix rpc s...
1012
  	int delay = 0;
6f5133652   Stanislav Kinsbursky   SUNRPC: clear svc...
1013

cc630d9f4   J. Bruce Fields   svcrpc: fix rpc s...
1014
1015
1016
1017
1018
1019
  	while (svc_close_list(serv, &serv->sv_permsocks, net) +
  	       svc_close_list(serv, &serv->sv_tempsocks, net)) {
  
  		svc_clean_up_xprts(serv, net);
  		msleep(delay++);
  	}
0f0257eaa   Tom Tucker   svc: Move the xpr...
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
  }
  
  /*
   * 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...
1031
1032
1033
1034
1035
1036
  	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...
1037
1038
1039
1040
1041
1042
1043
  		svc_xprt_put(xprt);
  		kfree(dr);
  		return;
  	}
  	dprintk("revisit queued
  ");
  	dr->xprt = NULL;
0f0257eaa   Tom Tucker   svc: Move the xpr...
1044
1045
  	list_add(&dr->handle.recent, &xprt->xpt_deferred);
  	spin_unlock(&xprt->xpt_lock);
0f0257eaa   Tom Tucker   svc: Move the xpr...
1046
1047
1048
  	svc_xprt_enqueue(xprt);
  	svc_xprt_put(xprt);
  }
260c1d129   Tom Tucker   svc: Add transpor...
1049
1050
1051
1052
1053
1054
1055
1056
1057
  /*
   * 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...
1058
1059
1060
  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...
1061
  	struct svc_deferred_req *dr;
2f425878b   Andy Adamson   nfsd: don't use t...
1062
  	if (rqstp->rq_arg.page_len || !rqstp->rq_usedeferral)
0f0257eaa   Tom Tucker   svc: Move the xpr...
1063
1064
1065
1066
1067
  		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...
1068
1069
  		size_t skip;
  		size_t size;
0f0257eaa   Tom Tucker   svc: Move the xpr...
1070
  		/* FIXME maybe discard if size too large */
260c1d129   Tom Tucker   svc: Add transpor...
1071
  		size = sizeof(struct svc_deferred_req) + rqstp->rq_arg.len;
0f0257eaa   Tom Tucker   svc: Move the xpr...
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
  		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...
1082
1083
1084
1085
1086
1087
  		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...
1088
1089
1090
  	}
  	svc_xprt_get(rqstp->rq_xprt);
  	dr->xprt = rqstp->rq_xprt;
9e701c610   J. Bruce Fields   svcrpc: simpler r...
1091
  	rqstp->rq_dropme = true;
0f0257eaa   Tom Tucker   svc: Move the xpr...
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
  
  	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...
1103
1104
1105
1106
  	/* 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...
1107
  	rqstp->rq_arg.page_len = 0;
260c1d129   Tom Tucker   svc: Add transpor...
1108
1109
  	/* The rq_arg.len includes the transport header bytes */
  	rqstp->rq_arg.len     = dr->argslen<<2;
0f0257eaa   Tom Tucker   svc: Move the xpr...
1110
1111
1112
  	rqstp->rq_prot        = dr->prot;
  	memcpy(&rqstp->rq_addr, &dr->addr, dr->addrlen);
  	rqstp->rq_addrlen     = dr->addrlen;
260c1d129   Tom Tucker   svc: Add transpor...
1113
1114
  	/* 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...
1115
1116
  	rqstp->rq_daddr       = dr->daddr;
  	rqstp->rq_respages    = rqstp->rq_pages;
260c1d129   Tom Tucker   svc: Add transpor...
1117
  	return (dr->argslen<<2) - dr->xprt_hlen;
0f0257eaa   Tom Tucker   svc: Move the xpr...
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
  }
  
  
  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...
1128
1129
1130
1131
1132
  	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...
1133
1134
  	} else
  		clear_bit(XPT_DEFERRED, &xprt->xpt_flags);
0f0257eaa   Tom Tucker   svc: Move the xpr...
1135
1136
1137
  	spin_unlock(&xprt->xpt_lock);
  	return dr;
  }
7fcb98d58   Tom Tucker   svc: Add svc API ...
1138

156e62094   Chuck Lever   SUNRPC: Clean up ...
1139
1140
1141
1142
  /**
   * svc_find_xprt - find an RPC transport instance
   * @serv: pointer to svc_serv to search
   * @xcl_name: C string containing transport's class name
4cb54ca20   Stanislav Kinsbursky   SUNRPC: search fo...
1143
   * @net: owner net pointer
156e62094   Chuck Lever   SUNRPC: Clean up ...
1144
1145
1146
   * @af: Address family of transport's local address
   * @port: transport's IP port number
   *
7fcb98d58   Tom Tucker   svc: Add svc API ...
1147
1148
1149
1150
1151
1152
1153
1154
   * 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 ...
1155
  struct svc_xprt *svc_find_xprt(struct svc_serv *serv, const char *xcl_name,
4cb54ca20   Stanislav Kinsbursky   SUNRPC: search fo...
1156
1157
  			       struct net *net, const sa_family_t af,
  			       const unsigned short port)
7fcb98d58   Tom Tucker   svc: Add svc API ...
1158
1159
1160
1161
1162
  {
  	struct svc_xprt *xprt;
  	struct svc_xprt *found = NULL;
  
  	/* Sanity check the args */
156e62094   Chuck Lever   SUNRPC: Clean up ...
1163
  	if (serv == NULL || xcl_name == NULL)
7fcb98d58   Tom Tucker   svc: Add svc API ...
1164
1165
1166
1167
  		return found;
  
  	spin_lock_bh(&serv->sv_lock);
  	list_for_each_entry(xprt, &serv->sv_permsocks, xpt_list) {
4cb54ca20   Stanislav Kinsbursky   SUNRPC: search fo...
1168
1169
  		if (xprt->xpt_net != net)
  			continue;
7fcb98d58   Tom Tucker   svc: Add svc API ...
1170
1171
1172
1173
  		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 ...
1174
  		if (port != 0 && port != svc_xprt_local_port(xprt))
7fcb98d58   Tom Tucker   svc: Add svc API ...
1175
1176
  			continue;
  		found = xprt;
a217813f9   Tom Tucker   knfsd: Support ad...
1177
  		svc_xprt_get(xprt);
7fcb98d58   Tom Tucker   svc: Add svc API ...
1178
1179
1180
1181
1182
1183
  		break;
  	}
  	spin_unlock_bh(&serv->sv_lock);
  	return found;
  }
  EXPORT_SYMBOL_GPL(svc_find_xprt);
9571af18f   Tom Tucker   svc: Add svc_xprt...
1184

335c54bdc   Chuck Lever   NFSD: Prevent a b...
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
  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...
1211
   */
335c54bdc   Chuck Lever   NFSD: Prevent a b...
1212
  int svc_xprt_names(struct svc_serv *serv, char *buf, const int buflen)
9571af18f   Tom Tucker   svc: Add svc_xprt...
1213
1214
  {
  	struct svc_xprt *xprt;
335c54bdc   Chuck Lever   NFSD: Prevent a b...
1215
1216
  	int len, totlen;
  	char *pos;
9571af18f   Tom Tucker   svc: Add svc_xprt...
1217
1218
1219
1220
1221
1222
  
  	/* Sanity check args */
  	if (!serv)
  		return 0;
  
  	spin_lock_bh(&serv->sv_lock);
335c54bdc   Chuck Lever   NFSD: Prevent a b...
1223
1224
1225
  
  	pos = buf;
  	totlen = 0;
9571af18f   Tom Tucker   svc: Add svc_xprt...
1226
  	list_for_each_entry(xprt, &serv->sv_permsocks, xpt_list) {
335c54bdc   Chuck Lever   NFSD: Prevent a b...
1227
1228
1229
1230
1231
1232
  		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...
1233
  			break;
335c54bdc   Chuck Lever   NFSD: Prevent a b...
1234
1235
  
  		pos += len;
9571af18f   Tom Tucker   svc: Add svc_xprt...
1236
1237
  		totlen += len;
  	}
335c54bdc   Chuck Lever   NFSD: Prevent a b...
1238

9571af18f   Tom Tucker   svc: Add svc_xprt...
1239
1240
1241
1242
  	spin_unlock_bh(&serv->sv_lock);
  	return totlen;
  }
  EXPORT_SYMBOL_GPL(svc_xprt_names);
03cf6c9f4   Greg Banks   knfsd: add file t...
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
  
  
  /*----------------------------------------------------------------------------*/
  
  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...
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
  	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...
1282
1283
1284
1285
1286
1287
1288
  }
  
  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...
1289
1290
  		seq_puts(m, "# pool packets-arrived sockets-enqueued threads-woken threads-timedout
  ");
03cf6c9f4   Greg Banks   knfsd: add file t...
1291
1292
  		return 0;
  	}
78c210efd   J. Bruce Fields   Revert "knfsd: av...
1293
1294
  	seq_printf(m, "%u %lu %lu %lu %lu
  ",
03cf6c9f4   Greg Banks   knfsd: add file t...
1295
1296
1297
1298
  		pool->sp_id,
  		pool->sp_stats.packets,
  		pool->sp_stats.sockets_queued,
  		pool->sp_stats.threads_woken,
03cf6c9f4   Greg Banks   knfsd: add file t...
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
  		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);
  
  /*----------------------------------------------------------------------------*/