xprt.c 31.1 KB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed
1
2
3
4
5
6
7
8
9
10
11
12
/*
 *  linux/net/sunrpc/xprt.c
 *
 *  This is a generic RPC call interface supporting congestion avoidance,
 *  and asynchronous calls.
 *
 *  The interface works like this:
 *
 *  -	When a process places a call, it allocates a request slot if
 *	one is available. Otherwise, it sleeps on the backlog queue
 *	(xprt_reserve).
 *  -	Next, the caller puts together the RPC message, stuffs it into
13
14
 *	the request struct, and calls xprt_transmit().
 *  -	xprt_transmit sends the message and installs the caller on the
15
16
17
 *	transport's wait list. At the same time, if a reply is expected,
 *	it installs a timer that is run after the packet's timeout has
 *	expired.
Linus Torvalds's avatar
Linus Torvalds committed
18
 *  -	When a packet arrives, the data_ready handler walks the list of
19
 *	pending requests for that transport. If a matching XID is found, the
Linus Torvalds's avatar
Linus Torvalds committed
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
 *	caller is woken up, and the timer removed.
 *  -	When no reply arrives within the timeout interval, the timer is
 *	fired by the kernel and runs xprt_timer(). It either adjusts the
 *	timeout values (minor timeout) or wakes up the caller with a status
 *	of -ETIMEDOUT.
 *  -	When the caller receives a notification from RPC that a reply arrived,
 *	it should release the RPC slot, and process the reply.
 *	If the call timed out, it may choose to retry the operation by
 *	adjusting the initial timeout value, and simply calling rpc_call
 *	again.
 *
 *  Support for async RPC is done through a set of RPC-specific scheduling
 *  primitives that `transparently' work for processes as well as async
 *  tasks that rely on callbacks.
 *
 *  Copyright (C) 1995-1997, Olaf Kirch <okir@monad.swb.de>
36
37
 *
 *  Transport switch API copyright (C) 2005, Chuck Lever <cel@netapp.com>
Linus Torvalds's avatar
Linus Torvalds committed
38
39
 */

40
41
#include <linux/module.h>

Linus Torvalds's avatar
Linus Torvalds committed
42
#include <linux/types.h>
43
#include <linux/interrupt.h>
Linus Torvalds's avatar
Linus Torvalds committed
44
#include <linux/workqueue.h>
45
#include <linux/net.h>
46
#include <linux/ktime.h>
Linus Torvalds's avatar
Linus Torvalds committed
47

48
#include <linux/sunrpc/clnt.h>
49
#include <linux/sunrpc/metrics.h>
50
#include <linux/sunrpc/bc_xprt.h>
Linus Torvalds's avatar
Linus Torvalds committed
51

52
53
#include "sunrpc.h"

Linus Torvalds's avatar
Linus Torvalds committed
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
/*
 * Local variables
 */

#ifdef RPC_DEBUG
# define RPCDBG_FACILITY	RPCDBG_XPRT
#endif

/*
 * Local functions
 */
static void	xprt_request_init(struct rpc_task *, struct rpc_xprt *);
static void	xprt_connect_status(struct rpc_task *task);
static int      __xprt_get_cong(struct rpc_xprt *, struct rpc_task *);

69
static DEFINE_SPINLOCK(xprt_list_lock);
70
71
static LIST_HEAD(xprt_list);

72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
/*
 * The transport code maintains an estimate on the maximum number of out-
 * standing RPC requests, using a smoothed version of the congestion
 * avoidance implemented in 44BSD. This is basically the Van Jacobson
 * congestion algorithm: If a retransmit occurs, the congestion window is
 * halved; otherwise, it is incremented by 1/cwnd when
 *
 *	-	a reply is received and
 *	-	a full number of requests are outstanding and
 *	-	the congestion window hasn't been updated recently.
 */
#define RPC_CWNDSHIFT		(8U)
#define RPC_CWNDSCALE		(1U << RPC_CWNDSHIFT)
#define RPC_INITCWND		RPC_CWNDSCALE
#define RPC_MAXCWND(xprt)	((xprt)->max_reqs << RPC_CWNDSHIFT)

#define RPCXPRT_CONGESTED(xprt) ((xprt)->cong >= (xprt)->cwnd)
Linus Torvalds's avatar
Linus Torvalds committed
89

90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
/**
 * xprt_register_transport - register a transport implementation
 * @transport: transport to register
 *
 * If a transport implementation is loaded as a kernel module, it can
 * call this interface to make itself known to the RPC client.
 *
 * Returns:
 * 0:		transport successfully registered
 * -EEXIST:	transport already registered
 * -EINVAL:	transport module being unloaded
 */
int xprt_register_transport(struct xprt_class *transport)
{
	struct xprt_class *t;
	int result;

	result = -EEXIST;
	spin_lock(&xprt_list_lock);
	list_for_each_entry(t, &xprt_list, list) {
		/* don't register the same transport class twice */
111
		if (t->ident == transport->ident)
112
113
114
			goto out;
	}

115
116
117
118
	list_add_tail(&transport->list, &xprt_list);
	printk(KERN_INFO "RPC: Registered %s transport module.\n",
	       transport->name);
	result = 0;
119
120
121
122
123
124
125
126
127

out:
	spin_unlock(&xprt_list_lock);
	return result;
}
EXPORT_SYMBOL_GPL(xprt_register_transport);

/**
 * xprt_unregister_transport - unregister a transport implementation
128
 * @transport: transport to unregister
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
 *
 * Returns:
 * 0:		transport successfully unregistered
 * -ENOENT:	transport never registered
 */
int xprt_unregister_transport(struct xprt_class *transport)
{
	struct xprt_class *t;
	int result;

	result = 0;
	spin_lock(&xprt_list_lock);
	list_for_each_entry(t, &xprt_list, list) {
		if (t == transport) {
			printk(KERN_INFO
				"RPC: Unregistered %s transport module.\n",
				transport->name);
			list_del_init(&transport->list);
			goto out;
		}
	}
	result = -ENOENT;

out:
	spin_unlock(&xprt_list_lock);
	return result;
}
EXPORT_SYMBOL_GPL(xprt_unregister_transport);

158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
/**
 * xprt_load_transport - load a transport implementation
 * @transport_name: transport to load
 *
 * Returns:
 * 0:		transport successfully loaded
 * -ENOENT:	transport module not available
 */
int xprt_load_transport(const char *transport_name)
{
	struct xprt_class *t;
	int result;

	result = 0;
	spin_lock(&xprt_list_lock);
	list_for_each_entry(t, &xprt_list, list) {
		if (strcmp(t->name, transport_name) == 0) {
			spin_unlock(&xprt_list_lock);
			goto out;
		}
	}
	spin_unlock(&xprt_list_lock);
180
	result = request_module("xprt%s", transport_name);
181
182
183
184
185
out:
	return result;
}
EXPORT_SYMBOL_GPL(xprt_load_transport);

186
187
188
189
190
191
192
193
194
195
196
/**
 * xprt_reserve_xprt - serialize write access to transports
 * @task: task that is requesting access to the transport
 *
 * This prevents mixing the payload of separate requests, and prevents
 * transport connects from colliding with writes.  No congestion control
 * is provided.
 */
int xprt_reserve_xprt(struct rpc_task *task)
{
	struct rpc_rqst *req = task->tk_rqstp;
197
	struct rpc_xprt	*xprt = req->rq_xprt;
198
199
200
201
202
203
204
205
206
207
208
209
210
211

	if (test_and_set_bit(XPRT_LOCKED, &xprt->state)) {
		if (task == xprt->snd_task)
			return 1;
		goto out_sleep;
	}
	xprt->snd_task = task;
	if (req) {
		req->rq_bytes_sent = 0;
		req->rq_ntrans++;
	}
	return 1;

out_sleep:
212
	dprintk("RPC: %5u failed to lock transport %p\n",
213
214
215
216
			task->tk_pid, xprt);
	task->tk_timeout = 0;
	task->tk_status = -EAGAIN;
	if (req && req->rq_ntrans)
217
		rpc_sleep_on(&xprt->resend, task, NULL);
218
	else
219
		rpc_sleep_on(&xprt->sending, task, NULL);
220
221
	return 0;
}
222
EXPORT_SYMBOL_GPL(xprt_reserve_xprt);
223

224
225
226
227
228
229
230
231
static void xprt_clear_locked(struct rpc_xprt *xprt)
{
	xprt->snd_task = NULL;
	if (!test_bit(XPRT_CLOSE_WAIT, &xprt->state) || xprt->shutdown) {
		smp_mb__before_clear_bit();
		clear_bit(XPRT_LOCKED, &xprt->state);
		smp_mb__after_clear_bit();
	} else
232
		queue_work(rpciod_workqueue, &xprt->task_cleanup);
233
234
}

Linus Torvalds's avatar
Linus Torvalds committed
235
/*
236
237
238
239
240
241
 * xprt_reserve_xprt_cong - serialize write access to transports
 * @task: task that is requesting access to the transport
 *
 * Same as xprt_reserve_xprt, but Van Jacobson congestion control is
 * integrated into the decision of whether a request is allowed to be
 * woken up and given access to the transport.
Linus Torvalds's avatar
Linus Torvalds committed
242
 */
243
int xprt_reserve_xprt_cong(struct rpc_task *task)
Linus Torvalds's avatar
Linus Torvalds committed
244
{
245
	struct rpc_xprt	*xprt = task->tk_xprt;
Linus Torvalds's avatar
Linus Torvalds committed
246
247
	struct rpc_rqst *req = task->tk_rqstp;

248
	if (test_and_set_bit(XPRT_LOCKED, &xprt->state)) {
Linus Torvalds's avatar
Linus Torvalds committed
249
250
251
252
		if (task == xprt->snd_task)
			return 1;
		goto out_sleep;
	}
253
	if (__xprt_get_cong(xprt, task)) {
Linus Torvalds's avatar
Linus Torvalds committed
254
255
256
257
258
259
260
		xprt->snd_task = task;
		if (req) {
			req->rq_bytes_sent = 0;
			req->rq_ntrans++;
		}
		return 1;
	}
261
	xprt_clear_locked(xprt);
Linus Torvalds's avatar
Linus Torvalds committed
262
out_sleep:
263
	dprintk("RPC: %5u failed to lock transport %p\n", task->tk_pid, xprt);
Linus Torvalds's avatar
Linus Torvalds committed
264
265
266
	task->tk_timeout = 0;
	task->tk_status = -EAGAIN;
	if (req && req->rq_ntrans)
267
		rpc_sleep_on(&xprt->resend, task, NULL);
Linus Torvalds's avatar
Linus Torvalds committed
268
	else
269
		rpc_sleep_on(&xprt->sending, task, NULL);
Linus Torvalds's avatar
Linus Torvalds committed
270
271
	return 0;
}
272
EXPORT_SYMBOL_GPL(xprt_reserve_xprt_cong);
Linus Torvalds's avatar
Linus Torvalds committed
273

274
static inline int xprt_lock_write(struct rpc_xprt *xprt, struct rpc_task *task)
Linus Torvalds's avatar
Linus Torvalds committed
275
276
277
{
	int retval;

Chuck Lever's avatar
Chuck Lever committed
278
	spin_lock_bh(&xprt->transport_lock);
279
	retval = xprt->ops->reserve_xprt(task);
Chuck Lever's avatar
Chuck Lever committed
280
	spin_unlock_bh(&xprt->transport_lock);
Linus Torvalds's avatar
Linus Torvalds committed
281
282
283
	return retval;
}

284
static void __xprt_lock_write_next(struct rpc_xprt *xprt)
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
{
	struct rpc_task *task;
	struct rpc_rqst *req;

	if (test_and_set_bit(XPRT_LOCKED, &xprt->state))
		return;

	task = rpc_wake_up_next(&xprt->resend);
	if (!task) {
		task = rpc_wake_up_next(&xprt->sending);
		if (!task)
			goto out_unlock;
	}

	req = task->tk_rqstp;
	xprt->snd_task = task;
	if (req) {
		req->rq_bytes_sent = 0;
		req->rq_ntrans++;
	}
	return;

out_unlock:
308
	xprt_clear_locked(xprt);
309
310
311
}

static void __xprt_lock_write_next_cong(struct rpc_xprt *xprt)
Linus Torvalds's avatar
Linus Torvalds committed
312
313
314
{
	struct rpc_task *task;

315
	if (test_and_set_bit(XPRT_LOCKED, &xprt->state))
Linus Torvalds's avatar
Linus Torvalds committed
316
		return;
317
	if (RPCXPRT_CONGESTED(xprt))
Linus Torvalds's avatar
Linus Torvalds committed
318
319
320
321
322
323
324
		goto out_unlock;
	task = rpc_wake_up_next(&xprt->resend);
	if (!task) {
		task = rpc_wake_up_next(&xprt->sending);
		if (!task)
			goto out_unlock;
	}
325
	if (__xprt_get_cong(xprt, task)) {
Linus Torvalds's avatar
Linus Torvalds committed
326
327
328
329
330
331
332
333
334
		struct rpc_rqst *req = task->tk_rqstp;
		xprt->snd_task = task;
		if (req) {
			req->rq_bytes_sent = 0;
			req->rq_ntrans++;
		}
		return;
	}
out_unlock:
335
	xprt_clear_locked(xprt);
Linus Torvalds's avatar
Linus Torvalds committed
336
337
}

338
339
340
341
342
343
/**
 * xprt_release_xprt - allow other requests to use a transport
 * @xprt: transport with other tasks potentially waiting
 * @task: task that is releasing access to the transport
 *
 * Note that "task" can be NULL.  No congestion control is provided.
Linus Torvalds's avatar
Linus Torvalds committed
344
 */
345
void xprt_release_xprt(struct rpc_xprt *xprt, struct rpc_task *task)
Linus Torvalds's avatar
Linus Torvalds committed
346
347
{
	if (xprt->snd_task == task) {
348
		xprt_clear_locked(xprt);
Linus Torvalds's avatar
Linus Torvalds committed
349
350
351
		__xprt_lock_write_next(xprt);
	}
}
352
EXPORT_SYMBOL_GPL(xprt_release_xprt);
Linus Torvalds's avatar
Linus Torvalds committed
353

354
355
356
357
358
359
360
361
362
363
364
/**
 * xprt_release_xprt_cong - allow other requests to use a transport
 * @xprt: transport with other tasks potentially waiting
 * @task: task that is releasing access to the transport
 *
 * Note that "task" can be NULL.  Another task is awoken to use the
 * transport if the transport's congestion window allows it.
 */
void xprt_release_xprt_cong(struct rpc_xprt *xprt, struct rpc_task *task)
{
	if (xprt->snd_task == task) {
365
		xprt_clear_locked(xprt);
366
367
368
		__xprt_lock_write_next_cong(xprt);
	}
}
369
EXPORT_SYMBOL_GPL(xprt_release_xprt_cong);
370
371

static inline void xprt_release_write(struct rpc_xprt *xprt, struct rpc_task *task)
Linus Torvalds's avatar
Linus Torvalds committed
372
{
Chuck Lever's avatar
Chuck Lever committed
373
	spin_lock_bh(&xprt->transport_lock);
374
	xprt->ops->release_xprt(xprt, task);
Chuck Lever's avatar
Chuck Lever committed
375
	spin_unlock_bh(&xprt->transport_lock);
Linus Torvalds's avatar
Linus Torvalds committed
376
377
378
379
380
381
382
383
384
385
386
387
388
}

/*
 * Van Jacobson congestion avoidance. Check if the congestion window
 * overflowed. Put the task to sleep if this is the case.
 */
static int
__xprt_get_cong(struct rpc_xprt *xprt, struct rpc_task *task)
{
	struct rpc_rqst *req = task->tk_rqstp;

	if (req->rq_cong)
		return 1;
389
	dprintk("RPC: %5u xprt_cwnd_limited cong = %lu cwnd = %lu\n",
Linus Torvalds's avatar
Linus Torvalds committed
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
			task->tk_pid, xprt->cong, xprt->cwnd);
	if (RPCXPRT_CONGESTED(xprt))
		return 0;
	req->rq_cong = 1;
	xprt->cong += RPC_CWNDSCALE;
	return 1;
}

/*
 * Adjust the congestion window, and wake up the next task
 * that has been sleeping due to congestion
 */
static void
__xprt_put_cong(struct rpc_xprt *xprt, struct rpc_rqst *req)
{
	if (!req->rq_cong)
		return;
	req->rq_cong = 0;
	xprt->cong -= RPC_CWNDSCALE;
409
	__xprt_lock_write_next_cong(xprt);
Linus Torvalds's avatar
Linus Torvalds committed
410
411
}

412
413
414
415
416
417
418
419
420
421
/**
 * xprt_release_rqst_cong - housekeeping when request is complete
 * @task: RPC request that recently completed
 *
 * Useful for transports that require congestion control.
 */
void xprt_release_rqst_cong(struct rpc_task *task)
{
	__xprt_put_cong(task->tk_xprt, task->tk_rqstp);
}
422
EXPORT_SYMBOL_GPL(xprt_release_rqst_cong);
423

424
425
426
427
428
/**
 * xprt_adjust_cwnd - adjust transport congestion window
 * @task: recently completed RPC request used to adjust window
 * @result: result code of completed RPC request
 *
Linus Torvalds's avatar
Linus Torvalds committed
429
430
 * We use a time-smoothed congestion estimator to avoid heavy oscillation.
 */
431
void xprt_adjust_cwnd(struct rpc_task *task, int result)
Linus Torvalds's avatar
Linus Torvalds committed
432
{
433
434
435
	struct rpc_rqst *req = task->tk_rqstp;
	struct rpc_xprt *xprt = task->tk_xprt;
	unsigned long cwnd = xprt->cwnd;
Linus Torvalds's avatar
Linus Torvalds committed
436
437
438
439
440
441
442

	if (result >= 0 && cwnd <= xprt->cong) {
		/* The (cwnd >> 1) term makes sure
		 * the result gets rounded properly. */
		cwnd += (RPC_CWNDSCALE * RPC_CWNDSCALE + (cwnd >> 1)) / cwnd;
		if (cwnd > RPC_MAXCWND(xprt))
			cwnd = RPC_MAXCWND(xprt);
443
		__xprt_lock_write_next_cong(xprt);
Linus Torvalds's avatar
Linus Torvalds committed
444
445
446
447
448
	} else if (result == -ETIMEDOUT) {
		cwnd >>= 1;
		if (cwnd < RPC_CWNDSCALE)
			cwnd = RPC_CWNDSCALE;
	}
449
	dprintk("RPC:       cong %ld, cwnd was %ld, now %ld\n",
Linus Torvalds's avatar
Linus Torvalds committed
450
451
			xprt->cong, xprt->cwnd, cwnd);
	xprt->cwnd = cwnd;
452
	__xprt_put_cong(xprt, req);
Linus Torvalds's avatar
Linus Torvalds committed
453
}
454
EXPORT_SYMBOL_GPL(xprt_adjust_cwnd);
Linus Torvalds's avatar
Linus Torvalds committed
455

456
457
458
459
460
461
462
463
464
465
466
467
468
/**
 * xprt_wake_pending_tasks - wake all tasks on a transport's pending queue
 * @xprt: transport with waiting tasks
 * @status: result code to plant in each task before waking it
 *
 */
void xprt_wake_pending_tasks(struct rpc_xprt *xprt, int status)
{
	if (status < 0)
		rpc_wake_up_status(&xprt->pending, status);
	else
		rpc_wake_up(&xprt->pending);
}
469
EXPORT_SYMBOL_GPL(xprt_wake_pending_tasks);
470

471
472
473
/**
 * xprt_wait_for_buffer_space - wait for transport output buffer to clear
 * @task: task to be put to sleep
Randy Dunlap's avatar
Randy Dunlap committed
474
 * @action: function pointer to be executed after wait
475
 */
476
void xprt_wait_for_buffer_space(struct rpc_task *task, rpc_action action)
477
478
479
480
481
{
	struct rpc_rqst *req = task->tk_rqstp;
	struct rpc_xprt *xprt = req->rq_xprt;

	task->tk_timeout = req->rq_timeout;
482
	rpc_sleep_on(&xprt->pending, task, action);
483
}
484
EXPORT_SYMBOL_GPL(xprt_wait_for_buffer_space);
485
486
487
488
489
490
491
492
493
494
495
496
497
498

/**
 * xprt_write_space - wake the task waiting for transport output buffer space
 * @xprt: transport with waiting tasks
 *
 * Can be called in a soft IRQ context, so xprt_write_space never sleeps.
 */
void xprt_write_space(struct rpc_xprt *xprt)
{
	if (unlikely(xprt->shutdown))
		return;

	spin_lock_bh(&xprt->transport_lock);
	if (xprt->snd_task) {
499
500
		dprintk("RPC:       write space: waking waiting task on "
				"xprt %p\n", xprt);
501
		rpc_wake_up_queued_task(&xprt->pending, xprt->snd_task);
502
503
504
	}
	spin_unlock_bh(&xprt->transport_lock);
}
505
EXPORT_SYMBOL_GPL(xprt_write_space);
506

507
508
509
510
511
512
513
514
515
516
517
518
/**
 * xprt_set_retrans_timeout_def - set a request's retransmit timeout
 * @task: task whose timeout is to be set
 *
 * Set a request's retransmit timeout based on the transport's
 * default timeout parameters.  Used by transports that don't adjust
 * the retransmit timeout based on round-trip time estimation.
 */
void xprt_set_retrans_timeout_def(struct rpc_task *task)
{
	task->tk_timeout = task->tk_rqstp->rq_timeout;
}
519
EXPORT_SYMBOL_GPL(xprt_set_retrans_timeout_def);
520
521
522
523

/*
 * xprt_set_retrans_timeout_rtt - set a request's retransmit timeout
 * @task: task whose timeout is to be set
524
 *
525
526
527
528
529
 * Set a request's retransmit timeout using the RTT estimator.
 */
void xprt_set_retrans_timeout_rtt(struct rpc_task *task)
{
	int timer = task->tk_msg.rpc_proc->p_timer;
530
531
	struct rpc_clnt *clnt = task->tk_client;
	struct rpc_rtt *rtt = clnt->cl_rtt;
532
	struct rpc_rqst *req = task->tk_rqstp;
533
	unsigned long max_timeout = clnt->cl_timeout->to_maxval;
534
535
536
537
538
539

	task->tk_timeout = rpc_calc_rto(rtt, timer);
	task->tk_timeout <<= rpc_ntimeo(rtt, timer) + req->rq_retries;
	if (task->tk_timeout > max_timeout || task->tk_timeout == 0)
		task->tk_timeout = max_timeout;
}
540
EXPORT_SYMBOL_GPL(xprt_set_retrans_timeout_rtt);
541

Linus Torvalds's avatar
Linus Torvalds committed
542
543
static void xprt_reset_majortimeo(struct rpc_rqst *req)
{
544
	const struct rpc_timeout *to = req->rq_task->tk_client->cl_timeout;
Linus Torvalds's avatar
Linus Torvalds committed
545
546
547
548
549
550
551
552
553
554
555

	req->rq_majortimeo = req->rq_timeout;
	if (to->to_exponential)
		req->rq_majortimeo <<= to->to_retries;
	else
		req->rq_majortimeo += to->to_increment * to->to_retries;
	if (req->rq_majortimeo > to->to_maxval || req->rq_majortimeo == 0)
		req->rq_majortimeo = to->to_maxval;
	req->rq_majortimeo += jiffies;
}

556
557
558
559
/**
 * xprt_adjust_timeout - adjust timeout values for next retransmit
 * @req: RPC request containing parameters to use for the adjustment
 *
Linus Torvalds's avatar
Linus Torvalds committed
560
561
562
563
 */
int xprt_adjust_timeout(struct rpc_rqst *req)
{
	struct rpc_xprt *xprt = req->rq_xprt;
564
	const struct rpc_timeout *to = req->rq_task->tk_client->cl_timeout;
Linus Torvalds's avatar
Linus Torvalds committed
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
	int status = 0;

	if (time_before(jiffies, req->rq_majortimeo)) {
		if (to->to_exponential)
			req->rq_timeout <<= 1;
		else
			req->rq_timeout += to->to_increment;
		if (to->to_maxval && req->rq_timeout >= to->to_maxval)
			req->rq_timeout = to->to_maxval;
		req->rq_retries++;
	} else {
		req->rq_timeout = to->to_initval;
		req->rq_retries = 0;
		xprt_reset_majortimeo(req);
		/* Reset the RTT counters == "slow start" */
Chuck Lever's avatar
Chuck Lever committed
580
		spin_lock_bh(&xprt->transport_lock);
Linus Torvalds's avatar
Linus Torvalds committed
581
		rpc_init_rtt(req->rq_task->tk_client->cl_rtt, to->to_initval);
Chuck Lever's avatar
Chuck Lever committed
582
		spin_unlock_bh(&xprt->transport_lock);
Linus Torvalds's avatar
Linus Torvalds committed
583
584
585
586
587
588
589
590
591
592
		status = -ETIMEDOUT;
	}

	if (req->rq_timeout == 0) {
		printk(KERN_WARNING "xprt_adjust_timeout: rq_timeout = 0!\n");
		req->rq_timeout = 5 * HZ;
	}
	return status;
}

593
static void xprt_autoclose(struct work_struct *work)
Linus Torvalds's avatar
Linus Torvalds committed
594
{
595
596
	struct rpc_xprt *xprt =
		container_of(work, struct rpc_xprt, task_cleanup);
Linus Torvalds's avatar
Linus Torvalds committed
597

598
	xprt->ops->close(xprt);
599
	clear_bit(XPRT_CLOSE_WAIT, &xprt->state);
Linus Torvalds's avatar
Linus Torvalds committed
600
601
602
	xprt_release_write(xprt, NULL);
}

603
/**
604
 * xprt_disconnect_done - mark a transport as disconnected
605
606
 * @xprt: transport to flag for disconnect
 *
Linus Torvalds's avatar
Linus Torvalds committed
607
 */
608
void xprt_disconnect_done(struct rpc_xprt *xprt)
Linus Torvalds's avatar
Linus Torvalds committed
609
{
610
	dprintk("RPC:       disconnected transport %p\n", xprt);
Chuck Lever's avatar
Chuck Lever committed
611
	spin_lock_bh(&xprt->transport_lock);
Linus Torvalds's avatar
Linus Torvalds committed
612
	xprt_clear_connected(xprt);
613
	xprt_wake_pending_tasks(xprt, -EAGAIN);
Chuck Lever's avatar
Chuck Lever committed
614
	spin_unlock_bh(&xprt->transport_lock);
Linus Torvalds's avatar
Linus Torvalds committed
615
}
616
EXPORT_SYMBOL_GPL(xprt_disconnect_done);
Linus Torvalds's avatar
Linus Torvalds committed
617

618
619
620
621
622
623
624
625
626
627
628
629
630
/**
 * xprt_force_disconnect - force a transport to disconnect
 * @xprt: transport to disconnect
 *
 */
void xprt_force_disconnect(struct rpc_xprt *xprt)
{
	/* Don't race with the test_bit() in xprt_clear_locked() */
	spin_lock_bh(&xprt->transport_lock);
	set_bit(XPRT_CLOSE_WAIT, &xprt->state);
	/* Try to schedule an autoclose RPC call */
	if (test_and_set_bit(XPRT_LOCKED, &xprt->state) == 0)
		queue_work(rpciod_workqueue, &xprt->task_cleanup);
631
	xprt_wake_pending_tasks(xprt, -EAGAIN);
632
633
634
	spin_unlock_bh(&xprt->transport_lock);
}

635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
/**
 * xprt_conditional_disconnect - force a transport to disconnect
 * @xprt: transport to disconnect
 * @cookie: 'connection cookie'
 *
 * This attempts to break the connection if and only if 'cookie' matches
 * the current transport 'connection cookie'. It ensures that we don't
 * try to break the connection more than once when we need to retransmit
 * a batch of RPC requests.
 *
 */
void xprt_conditional_disconnect(struct rpc_xprt *xprt, unsigned int cookie)
{
	/* Don't race with the test_bit() in xprt_clear_locked() */
	spin_lock_bh(&xprt->transport_lock);
	if (cookie != xprt->connect_cookie)
		goto out;
	if (test_bit(XPRT_CLOSING, &xprt->state) || !xprt_connected(xprt))
		goto out;
	set_bit(XPRT_CLOSE_WAIT, &xprt->state);
	/* Try to schedule an autoclose RPC call */
	if (test_and_set_bit(XPRT_LOCKED, &xprt->state) == 0)
		queue_work(rpciod_workqueue, &xprt->task_cleanup);
658
	xprt_wake_pending_tasks(xprt, -EAGAIN);
659
660
661
662
out:
	spin_unlock_bh(&xprt->transport_lock);
}

Linus Torvalds's avatar
Linus Torvalds committed
663
664
665
666
667
static void
xprt_init_autodisconnect(unsigned long data)
{
	struct rpc_xprt *xprt = (struct rpc_xprt *)data;

Chuck Lever's avatar
Chuck Lever committed
668
	spin_lock(&xprt->transport_lock);
Linus Torvalds's avatar
Linus Torvalds committed
669
670
	if (!list_empty(&xprt->recv) || xprt->shutdown)
		goto out_abort;
671
	if (test_and_set_bit(XPRT_LOCKED, &xprt->state))
Linus Torvalds's avatar
Linus Torvalds committed
672
		goto out_abort;
Chuck Lever's avatar
Chuck Lever committed
673
	spin_unlock(&xprt->transport_lock);
674
675
	set_bit(XPRT_CONNECTION_CLOSE, &xprt->state);
	queue_work(rpciod_workqueue, &xprt->task_cleanup);
Linus Torvalds's avatar
Linus Torvalds committed
676
677
	return;
out_abort:
Chuck Lever's avatar
Chuck Lever committed
678
	spin_unlock(&xprt->transport_lock);
Linus Torvalds's avatar
Linus Torvalds committed
679
680
}

681
682
683
/**
 * xprt_connect - schedule a transport connect operation
 * @task: RPC task that is requesting the connect
Linus Torvalds's avatar
Linus Torvalds committed
684
685
686
687
688
689
 *
 */
void xprt_connect(struct rpc_task *task)
{
	struct rpc_xprt	*xprt = task->tk_xprt;

690
	dprintk("RPC: %5u xprt_connect xprt %p %s connected\n", task->tk_pid,
Linus Torvalds's avatar
Linus Torvalds committed
691
692
			xprt, (xprt_connected(xprt) ? "is" : "is not"));

693
	if (!xprt_bound(xprt)) {
694
		task->tk_status = -EAGAIN;
Linus Torvalds's avatar
Linus Torvalds committed
695
696
697
698
		return;
	}
	if (!xprt_lock_write(xprt, task))
		return;
699
700
701
702

	if (test_and_clear_bit(XPRT_CLOSE_WAIT, &xprt->state))
		xprt->ops->close(xprt);

Linus Torvalds's avatar
Linus Torvalds committed
703
	if (xprt_connected(xprt))
704
705
706
707
		xprt_release_write(xprt, task);
	else {
		if (task->tk_rqstp)
			task->tk_rqstp->rq_bytes_sent = 0;
Linus Torvalds's avatar
Linus Torvalds committed
708

709
		task->tk_timeout = task->tk_rqstp->rq_timeout;
710
		rpc_sleep_on(&xprt->pending, task, xprt_connect_status);
711
712
713
714
715

		if (test_bit(XPRT_CLOSING, &xprt->state))
			return;
		if (xprt_test_and_set_connecting(xprt))
			return;
716
		xprt->stat.connect_start = jiffies;
717
		xprt->ops->connect(task);
Linus Torvalds's avatar
Linus Torvalds committed
718
719
720
	}
}

721
static void xprt_connect_status(struct rpc_task *task)
Linus Torvalds's avatar
Linus Torvalds committed
722
723
724
{
	struct rpc_xprt	*xprt = task->tk_xprt;

725
	if (task->tk_status == 0) {
726
727
		xprt->stat.connect_count++;
		xprt->stat.connect_time += (long)jiffies - xprt->stat.connect_start;
728
		dprintk("RPC: %5u xprt_connect_status: connection established\n",
Linus Torvalds's avatar
Linus Torvalds committed
729
730
731
732
733
				task->tk_pid);
		return;
	}

	switch (task->tk_status) {
734
735
	case -EAGAIN:
		dprintk("RPC: %5u xprt_connect_status: retrying\n", task->tk_pid);
736
		break;
Linus Torvalds's avatar
Linus Torvalds committed
737
	case -ETIMEDOUT:
738
739
		dprintk("RPC: %5u xprt_connect_status: connect attempt timed "
				"out\n", task->tk_pid);
Linus Torvalds's avatar
Linus Torvalds committed
740
741
		break;
	default:
742
743
744
		dprintk("RPC: %5u xprt_connect_status: error %d connecting to "
				"server %s\n", task->tk_pid, -task->tk_status,
				task->tk_client->cl_server);
745
746
		xprt_release_write(xprt, task);
		task->tk_status = -EIO;
Linus Torvalds's avatar
Linus Torvalds committed
747
748
749
	}
}

750
751
752
753
754
/**
 * xprt_lookup_rqst - find an RPC request corresponding to an XID
 * @xprt: transport on which the original request was transmitted
 * @xid: RPC XID of incoming reply
 *
Linus Torvalds's avatar
Linus Torvalds committed
755
 */
756
struct rpc_rqst *xprt_lookup_rqst(struct rpc_xprt *xprt, __be32 xid)
Linus Torvalds's avatar
Linus Torvalds committed
757
{
758
	struct rpc_rqst *entry;
Linus Torvalds's avatar
Linus Torvalds committed
759

760
	list_for_each_entry(entry, &xprt->recv, rq_list)
761
762
		if (entry->rq_xid == xid)
			return entry;
763
764
765

	dprintk("RPC:       xprt_lookup_rqst did not find xid %08x\n",
			ntohl(xid));
766
767
	xprt->stat.bad_xids++;
	return NULL;
Linus Torvalds's avatar
Linus Torvalds committed
768
}
769
EXPORT_SYMBOL_GPL(xprt_lookup_rqst);
Linus Torvalds's avatar
Linus Torvalds committed
770

771
static void xprt_update_rtt(struct rpc_task *task)
772
773
774
775
{
	struct rpc_rqst *req = task->tk_rqstp;
	struct rpc_rtt *rtt = task->tk_client->cl_rtt;
	unsigned timer = task->tk_msg.rpc_proc->p_timer;
776
	long m = usecs_to_jiffies(ktime_to_us(req->rq_rtt));
777
778
779

	if (timer) {
		if (req->rq_ntrans == 1)
780
			rpc_update_rtt(rtt, timer, m);
781
782
783
784
		rpc_set_timeo(rtt, timer, req->rq_ntrans - 1);
	}
}

785
786
/**
 * xprt_complete_rqst - called when reply processing is complete
787
 * @task: RPC request that recently completed
788
789
 * @copied: actual number of bytes received from the transport
 *
790
 * Caller holds transport lock.
Linus Torvalds's avatar
Linus Torvalds committed
791
 */
792
void xprt_complete_rqst(struct rpc_task *task, int copied)
Linus Torvalds's avatar
Linus Torvalds committed
793
{
794
	struct rpc_rqst *req = task->tk_rqstp;
795
	struct rpc_xprt *xprt = req->rq_xprt;
Linus Torvalds's avatar
Linus Torvalds committed
796

797
798
	dprintk("RPC: %5u xid %08x complete (%d bytes received)\n",
			task->tk_pid, ntohl(req->rq_xid), copied);
Linus Torvalds's avatar
Linus Torvalds committed
799

800
	xprt->stat.recvs++;
801
	req->rq_rtt = ktime_sub(ktime_get(), req->rq_xtime);
802
803
	if (xprt->ops->timer != NULL)
		xprt_update_rtt(task);
804

Linus Torvalds's avatar
Linus Torvalds committed
805
	list_del_init(&req->rq_list);
806
	req->rq_private_buf.len = copied;
807
808
	/* Ensure all writes are done before we update */
	/* req->rq_reply_bytes_recvd */
809
	smp_wmb();
810
	req->rq_reply_bytes_recvd = copied;
811
	rpc_wake_up_queued_task(&xprt->pending, task);
Linus Torvalds's avatar
Linus Torvalds committed
812
}
813
EXPORT_SYMBOL_GPL(xprt_complete_rqst);
Linus Torvalds's avatar
Linus Torvalds committed
814

815
static void xprt_timer(struct rpc_task *task)
Linus Torvalds's avatar
Linus Torvalds committed
816
{
817
	struct rpc_rqst *req = task->tk_rqstp;
Linus Torvalds's avatar
Linus Torvalds committed
818
819
	struct rpc_xprt *xprt = req->rq_xprt;

820
821
	if (task->tk_status != -ETIMEDOUT)
		return;
822
	dprintk("RPC: %5u xprt_timer\n", task->tk_pid);
Linus Torvalds's avatar
Linus Torvalds committed
823

824
	spin_lock_bh(&xprt->transport_lock);
825
	if (!req->rq_reply_bytes_recvd) {
826
827
		if (xprt->ops->timer)
			xprt->ops->timer(task);
828
829
830
	} else
		task->tk_status = 0;
	spin_unlock_bh(&xprt->transport_lock);
Linus Torvalds's avatar
Linus Torvalds committed
831
832
}

833
834
835
836
837
static inline int xprt_has_timer(struct rpc_xprt *xprt)
{
	return xprt->idle_timeout != 0;
}

838
839
840
841
/**
 * xprt_prepare_transmit - reserve the transport before sending a request
 * @task: RPC task about to send a request
 *
Linus Torvalds's avatar
Linus Torvalds committed
842
 */
843
int xprt_prepare_transmit(struct rpc_task *task)
Linus Torvalds's avatar
Linus Torvalds committed
844
845
846
847
848
{
	struct rpc_rqst	*req = task->tk_rqstp;
	struct rpc_xprt	*xprt = req->rq_xprt;
	int err = 0;

849
	dprintk("RPC: %5u xprt_prepare_transmit\n", task->tk_pid);
Linus Torvalds's avatar
Linus Torvalds committed
850

Chuck Lever's avatar
Chuck Lever committed
851
	spin_lock_bh(&xprt->transport_lock);
852
853
	if (req->rq_reply_bytes_recvd && !req->rq_bytes_sent) {
		err = req->rq_reply_bytes_recvd;
Linus Torvalds's avatar
Linus Torvalds committed
854
855
		goto out_unlock;
	}
856
	if (!xprt->ops->reserve_xprt(task))
Linus Torvalds's avatar
Linus Torvalds committed
857
858
		err = -EAGAIN;
out_unlock:
Chuck Lever's avatar
Chuck Lever committed
859
	spin_unlock_bh(&xprt->transport_lock);
Linus Torvalds's avatar
Linus Torvalds committed
860
861
862
	return err;
}

863
void xprt_end_transmit(struct rpc_task *task)
864
{
865
	xprt_release_write(task->tk_rqstp->rq_xprt, task);
866
867
}

868
869
870
871
872
873
874
/**
 * xprt_transmit - send an RPC request on a transport
 * @task: controlling RPC task
 *
 * We have to copy the iovec because sendmsg fiddles with its contents.
 */
void xprt_transmit(struct rpc_task *task)
Linus Torvalds's avatar
Linus Torvalds committed
875
876
877
{
	struct rpc_rqst	*req = task->tk_rqstp;
	struct rpc_xprt	*xprt = req->rq_xprt;
878
	int status;
Linus Torvalds's avatar
Linus Torvalds committed
879

880
	dprintk("RPC: %5u xprt_transmit(%u)\n", task->tk_pid, req->rq_slen);
Linus Torvalds's avatar
Linus Torvalds committed
881

882
	if (!req->rq_reply_bytes_recvd) {
883
884
885
886
		if (list_empty(&req->rq_list) && rpc_reply_expected(task)) {
			/*
			 * Add to the list only if we're expecting a reply
			 */
Chuck Lever's avatar
Chuck Lever committed
887
			spin_lock_bh(&xprt->transport_lock);
Linus Torvalds's avatar
Linus Torvalds committed
888
889
890
891
892
			/* Update the softirq receive buffer */
			memcpy(&req->rq_private_buf, &req->rq_rcv_buf,
					sizeof(req->rq_private_buf));
			/* Add request to the receive list */
			list_add_tail(&req->rq_list, &xprt->recv);
Chuck Lever's avatar
Chuck Lever committed
893
			spin_unlock_bh(&xprt->transport_lock);
Linus Torvalds's avatar
Linus Torvalds committed
894
			xprt_reset_majortimeo(req);
895
896
			/* Turn off autodisconnect */
			del_singleshot_timer_sync(&xprt->timer);
Linus Torvalds's avatar
Linus Torvalds committed
897
898
899
900
		}
	} else if (!req->rq_bytes_sent)
		return;

901
	req->rq_connect_cookie = xprt->connect_cookie;
902
	req->rq_xtime = ktime_get();
903
	status = xprt->ops->send_request(task);
904
905
906
907
	if (status != 0) {
		task->tk_status = status;
		return;
	}
908

909
910
	dprintk("RPC: %5u xmit complete\n", task->tk_pid);
	spin_lock_bh(&xprt->transport_lock);
911

912
	xprt->ops->set_retrans_timeout(task);
913

914
915
916
	xprt->stat.sends++;
	xprt->stat.req_u += xprt->stat.sends - xprt->stat.recvs;
	xprt->stat.bklog_u += xprt->backlog.qlen;
Linus Torvalds's avatar
Linus Torvalds committed
917

918
919
920
	/* Don't race with disconnect */
	if (!xprt_connected(xprt))
		task->tk_status = -ENOTCONN;
921
	else if (!req->rq_reply_bytes_recvd && rpc_reply_expected(task)) {
922
923
924
925
		/*
		 * Sleep on the pending queue since
		 * we're expecting a reply.
		 */
926
		rpc_sleep_on(&xprt->pending, task, xprt_timer);
927
	}
928
	spin_unlock_bh(&xprt->transport_lock);
Linus Torvalds's avatar
Linus Torvalds committed
929
930
}

931
static void xprt_alloc_slot(struct rpc_task *task)
Linus Torvalds's avatar
Linus Torvalds committed
932
933
934
935
936
937
938
939
940
941
942
943
944
{
	struct rpc_xprt	*xprt = task->tk_xprt;

	task->tk_status = 0;
	if (task->tk_rqstp)
		return;
	if (!list_empty(&xprt->free)) {
		struct rpc_rqst	*req = list_entry(xprt->free.next, struct rpc_rqst, rq_list);
		list_del_init(&req->rq_list);
		task->tk_rqstp = req;
		xprt_request_init(task, xprt);
		return;
	}
945
	dprintk("RPC:       waiting for request slot\n");
Linus Torvalds's avatar
Linus Torvalds committed
946
947
	task->tk_status = -EAGAIN;
	task->tk_timeout = 0;
948
	rpc_sleep_on(&xprt->backlog, task, NULL);
Linus Torvalds's avatar
Linus Torvalds committed
949
950
}

951
952
953
954
955
956
957
958
959
960
static void xprt_free_slot(struct rpc_xprt *xprt, struct rpc_rqst *req)
{
	memset(req, 0, sizeof(*req));	/* mark unused */

	spin_lock(&xprt->reserve_lock);
	list_add(&req->rq_list, &xprt->free);
	rpc_wake_up_next(&xprt->backlog);
	spin_unlock(&xprt->reserve_lock);
}

961
struct rpc_xprt *xprt_alloc(struct net *net, int size, int max_req)
962
963
964
965
966
967
{
	struct rpc_xprt *xprt;

	xprt = kzalloc(size, GFP_KERNEL);
	if (xprt == NULL)
		goto out;
968
	kref_init(&xprt->kref);
969
970
971
972
973
974

	xprt->max_reqs = max_req;
	xprt->slot = kcalloc(max_req, sizeof(struct rpc_rqst), GFP_KERNEL);
	if (xprt->slot == NULL)
		goto out_free;

975
	xprt->xprt_net = get_net(net);
976
977
978
979
980
981
982
983
984
	return xprt;

out_free:
	kfree(xprt);
out:
	return NULL;
}
EXPORT_SYMBOL_GPL(xprt_alloc);

985
986
void xprt_free(struct rpc_xprt *xprt)
{
987
	put_net(xprt->xprt_net);
988
989
990
991
992
	kfree(xprt->slot);
	kfree(xprt);
}
EXPORT_SYMBOL_GPL(xprt_free);

993
994
995
996
997
998
999
1000
/**
 * xprt_reserve - allocate an RPC request slot
 * @task: RPC task requesting a slot allocation
 *
 * If no more slots are available, place the task on the transport's
 * backlog queue.
 */
void xprt_reserve(struct rpc_task *task)
Linus Torvalds's avatar
Linus Torvalds committed
1001
1002
1003
1004
{
	struct rpc_xprt	*xprt = task->tk_xprt;

	task->tk_status = -EIO;
1005
	spin_lock(&xprt->reserve_lock);
1006
	xprt_alloc_slot(task);
1007
	spin_unlock(&xprt->reserve_lock);
Linus Torvalds's avatar
Linus Torvalds committed
1008
1009
}

1010
static inline __be32 xprt_alloc_xid(struct rpc_xprt *xprt)
Linus Torvalds's avatar
Linus Torvalds committed
1011
{
1012
	return (__force __be32)xprt->xid++;
Linus Torvalds's avatar
Linus Torvalds committed
1013
1014
1015
1016
}

static inline void xprt_init_xid(struct rpc_xprt *xprt)
{
1017
	xprt->xid = net_random();
Linus Torvalds's avatar
Linus Torvalds committed
1018
1019
}

1020
static void xprt_request_init(struct rpc_task *task, struct rpc_xprt *xprt)
Linus Torvalds's avatar
Linus Torvalds committed
1021
1022
1023
{
	struct rpc_rqst	*req = task->tk_rqstp;

1024
	req->rq_timeout = task->tk_client->cl_timeout->to_initval;
Linus Torvalds's avatar
Linus Torvalds committed
1025
1026
	req->rq_task	= task;
	req->rq_xprt    = xprt;
1027
	req->rq_buffer  = NULL;
Linus Torvalds's avatar
Linus Torvalds committed
1028
	req->rq_xid     = xprt_alloc_xid(xprt);
1029
	req->rq_release_snd_buf = NULL;
1030
	xprt_reset_majortimeo(req);
1031
	dprintk("RPC: %5u reserved req %p xid %08x\n", task->tk_pid,
Linus Torvalds's avatar
Linus Torvalds committed
1032
1033
1034
			req, ntohl(req->rq_xid));
}

1035
1036
1037
1038
/**
 * xprt_release - release an RPC request slot
 * @task: task which is finished with the slot
 *
Linus Torvalds's avatar
Linus Torvalds committed
1039
 */
1040
void xprt_release(struct rpc_task *task)
Linus Torvalds's avatar
Linus Torvalds committed
1041
{
1042
	struct rpc_xprt	*xprt;
Linus Torvalds's avatar
Linus Torvalds committed
1043
1044
1045
1046
	struct rpc_rqst	*req;

	if (!(req = task->tk_rqstp))
		return;
1047
1048

	xprt = req->rq_xprt;
1049
	rpc_count_iostats(task);
Chuck Lever's avatar
Chuck Lever committed
1050
	spin_lock_bh(&xprt->transport_lock);
1051
	xprt->ops->release_xprt(xprt, task);
1052
1053
	if (xprt->ops->release_request)
		xprt->ops->release_request(task);
Linus Torvalds's avatar
Linus Torvalds committed
1054
1055
1056
	if (!list_empty(&req->rq_list))
		list_del(&req->rq_list);
	xprt->last_used = jiffies;
1057
	if (list_empty(&xprt->recv) && xprt_has_timer(xprt))
1058
		mod_timer(&xprt->timer,
1059
				xprt->last_used + xprt->idle_timeout);
Chuck Lever's avatar
Chuck Lever committed
1060
	spin_unlock_bh(&xprt->transport_lock);
1061
	if (req->rq_buffer)
1062
		xprt->ops->buf_free(req->rq_buffer);
1063
1064
	if (req->rq_cred != NULL)
		put_rpccred(req->rq_cred);
Linus Torvalds's avatar
Linus Torvalds committed
1065
	task->tk_rqstp = NULL;
1066
1067
	if (req->rq_release_snd_buf)
		req->rq_release_snd_buf(req);
1068

1069
	dprintk("RPC: %5u release request %p\n", task->tk_pid, req);
1070
1071
1072
	if (likely(!bc_prealloc(req)))
		xprt_free_slot(xprt, req);
	else
1073
		xprt_free_bc_request(req);
Linus Torvalds's avatar
Linus Torvalds committed
1074
1075
}

1076
1077
/**
 * xprt_create_transport - create an RPC transport
1078
 * @args: rpc transport creation arguments
1079
1080
 *
 */
1081
struct rpc_xprt *xprt_create_transport(struct xprt_create *args)
1082
1083
1084
{
	struct rpc_xprt	*xprt;
	struct rpc_rqst	*req;
1085
	struct xprt_class *t;
1086

1087
1088
	spin_lock(&xprt_list_lock);
	list_for_each_entry(t, &xprt_list, list) {
1089
		if (t->ident == args->ident) {
1090
1091
1092
			spin_unlock(&xprt_list_lock);
			goto found;
		}
1093
	}
1094
	spin_unlock(&xprt_list_lock);
1095
	printk(KERN_ERR "RPC: transport (%d) not supported\n", args->ident);
1096
1097
1098
1099
	return ERR_PTR(-EIO);

found:
	xprt = t->setup(args);
1100
	if (IS_ERR(xprt)) {
1101
		dprintk("RPC:       xprt_create_transport: failed, %ld\n",
1102
1103
				-PTR_ERR(xprt));
		return xprt;
1104
	}
1105
1106
1107
	if (test_and_set_bit(XPRT_INITIALIZED, &xprt->state))
		/* ->setup returned a pre-initialized xprt: */
		return xprt;
1108
1109
1110
1111
1112
1113

	spin_lock_init(&xprt->transport_lock);
	spin_lock_init(&xprt->reserve_lock);

	INIT_LIST_HEAD(&xprt->free);
	INIT_LIST_HEAD(&xprt->recv);
1114
1115
1116
1117
1118
#if defined(CONFIG_NFS_V4_1)
	spin_lock_init(&xprt->bc_pa_lock);
	INIT_LIST_HEAD(&xprt->bc_pa_list);
#endif /* CONFIG_NFS_V4_1 */

1119
	INIT_WORK(&xprt->task_cleanup, xprt_autoclose);
1120
1121
1122
1123
1124
	if (xprt_has_timer(xprt))
		setup_timer(&xprt->timer, xprt_init_autodisconnect,
			    (unsigned long)xprt);
	else
		init_timer(&xprt->timer);
1125
1126
	xprt->last_used = jiffies;
	xprt->cwnd = RPC_INITCWND;
1127
	xprt->bind_index = 0;
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140

	rpc_init_wait_queue(&xprt->binding, "xprt_binding");
	rpc_init_wait_queue(&xprt->pending, "xprt_pending");
	rpc_init_wait_queue(&xprt->sending, "xprt_sending");
	rpc_init_wait_queue(&xprt->resend, "xprt_resend");
	rpc_init_priority_wait_queue(&xprt->backlog, "xprt_backlog");

	/* initialize free list */
	for (req = &xprt->slot[xprt->max_reqs-1]; req >= &xprt->slot[0]; req--)
		list_add(&req->rq_list, &xprt->free);

	xprt_init_xid(xprt);

1141
	dprintk("RPC:       created transport %p with %u slots\n", xprt,
1142
1143
1144
1145
			xprt->max_reqs);
	return xprt;
}

1146
1147
/**
 * xprt_destroy - destroy an RPC transport, killing off all requests.
1148
 * @kref: kref for the transport to destroy
1149
 *
Linus Torvalds's avatar
Linus Torvalds committed
1150
 */
1151
static void xprt_destroy(struct kref *kref)
Linus Torvalds's avatar
Linus Torvalds committed
1152
{
1153
1154
	struct