blob: e8d11bd6158e66e83df9df62db6d12dc4184f89e [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * linux/net/sunrpc/xprt.c
3 *
4 * This is a generic RPC call interface supporting congestion avoidance,
5 * and asynchronous calls.
6 *
7 * The interface works like this:
8 *
9 * - When a process places a call, it allocates a request slot if
10 * one is available. Otherwise, it sleeps on the backlog queue
11 * (xprt_reserve).
12 * - Next, the caller puts together the RPC message, stuffs it into
Chuck Lever55aa4f52005-08-11 16:25:47 -040013 * the request struct, and calls xprt_transmit().
14 * - xprt_transmit sends the message and installs the caller on the
15 * transport's wait list. At the same time, it installs a timer that
Linus Torvalds1da177e2005-04-16 15:20:36 -070016 * is run after the packet's timeout has expired.
17 * - When a packet arrives, the data_ready handler walks the list of
Chuck Lever55aa4f52005-08-11 16:25:47 -040018 * pending requests for that transport. If a matching XID is found, the
Linus Torvalds1da177e2005-04-16 15:20:36 -070019 * caller is woken up, and the timer removed.
20 * - When no reply arrives within the timeout interval, the timer is
21 * fired by the kernel and runs xprt_timer(). It either adjusts the
22 * timeout values (minor timeout) or wakes up the caller with a status
23 * of -ETIMEDOUT.
24 * - When the caller receives a notification from RPC that a reply arrived,
25 * it should release the RPC slot, and process the reply.
26 * If the call timed out, it may choose to retry the operation by
27 * adjusting the initial timeout value, and simply calling rpc_call
28 * again.
29 *
30 * Support for async RPC is done through a set of RPC-specific scheduling
31 * primitives that `transparently' work for processes as well as async
32 * tasks that rely on callbacks.
33 *
34 * Copyright (C) 1995-1997, Olaf Kirch <okir@monad.swb.de>
Chuck Lever55aa4f52005-08-11 16:25:47 -040035 *
36 * Transport switch API copyright (C) 2005, Chuck Lever <cel@netapp.com>
Linus Torvalds1da177e2005-04-16 15:20:36 -070037 */
38
Chuck Levera246b012005-08-11 16:25:23 -040039#include <linux/module.h>
40
Linus Torvalds1da177e2005-04-16 15:20:36 -070041#include <linux/types.h>
Chuck Levera246b012005-08-11 16:25:23 -040042#include <linux/interrupt.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070043#include <linux/workqueue.h>
44#include <linux/random.h>
45
Chuck Levera246b012005-08-11 16:25:23 -040046#include <linux/sunrpc/clnt.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070047
48/*
49 * Local variables
50 */
51
52#ifdef RPC_DEBUG
53# undef RPC_DEBUG_DATA
54# define RPCDBG_FACILITY RPCDBG_XPRT
55#endif
56
Linus Torvalds1da177e2005-04-16 15:20:36 -070057/*
58 * Local functions
59 */
60static void xprt_request_init(struct rpc_task *, struct rpc_xprt *);
61static inline void do_xprt_reserve(struct rpc_task *);
Linus Torvalds1da177e2005-04-16 15:20:36 -070062static void xprt_connect_status(struct rpc_task *task);
Linus Torvalds1da177e2005-04-16 15:20:36 -070063static int __xprt_get_cong(struct rpc_xprt *, struct rpc_task *);
64
65static int xprt_clear_backlog(struct rpc_xprt *xprt);
66
Chuck Lever12a80462005-08-25 16:25:51 -070067/**
68 * xprt_reserve_xprt - serialize write access to transports
69 * @task: task that is requesting access to the transport
70 *
71 * This prevents mixing the payload of separate requests, and prevents
72 * transport connects from colliding with writes. No congestion control
73 * is provided.
Linus Torvalds1da177e2005-04-16 15:20:36 -070074 */
Chuck Lever12a80462005-08-25 16:25:51 -070075int xprt_reserve_xprt(struct rpc_task *task)
Linus Torvalds1da177e2005-04-16 15:20:36 -070076{
Chuck Lever12a80462005-08-25 16:25:51 -070077 struct rpc_xprt *xprt = task->tk_xprt;
78 struct rpc_rqst *req = task->tk_rqstp;
79
80 if (test_and_set_bit(XPRT_LOCKED, &xprt->state)) {
81 if (task == xprt->snd_task)
82 return 1;
83 if (task == NULL)
84 return 0;
85 goto out_sleep;
86 }
87 xprt->snd_task = task;
88 if (req) {
89 req->rq_bytes_sent = 0;
90 req->rq_ntrans++;
91 }
92 return 1;
93
94out_sleep:
95 dprintk("RPC: %4d failed to lock transport %p\n",
96 task->tk_pid, xprt);
97 task->tk_timeout = 0;
98 task->tk_status = -EAGAIN;
99 if (req && req->rq_ntrans)
100 rpc_sleep_on(&xprt->resend, task, NULL, NULL);
101 else
102 rpc_sleep_on(&xprt->sending, task, NULL, NULL);
103 return 0;
104}
105
106/*
107 * xprt_reserve_xprt_cong - serialize write access to transports
108 * @task: task that is requesting access to the transport
109 *
110 * Same as xprt_reserve_xprt, but Van Jacobson congestion control is
111 * integrated into the decision of whether a request is allowed to be
112 * woken up and given access to the transport.
113 */
114int xprt_reserve_xprt_cong(struct rpc_task *task)
115{
116 struct rpc_xprt *xprt = task->tk_xprt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117 struct rpc_rqst *req = task->tk_rqstp;
118
Chuck Lever2226feb2005-08-11 16:25:38 -0400119 if (test_and_set_bit(XPRT_LOCKED, &xprt->state)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700120 if (task == xprt->snd_task)
121 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122 goto out_sleep;
123 }
Chuck Lever12a80462005-08-25 16:25:51 -0700124 if (__xprt_get_cong(xprt, task)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125 xprt->snd_task = task;
126 if (req) {
127 req->rq_bytes_sent = 0;
128 req->rq_ntrans++;
129 }
130 return 1;
131 }
132 smp_mb__before_clear_bit();
Chuck Lever2226feb2005-08-11 16:25:38 -0400133 clear_bit(XPRT_LOCKED, &xprt->state);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134 smp_mb__after_clear_bit();
135out_sleep:
Chuck Lever55aa4f52005-08-11 16:25:47 -0400136 dprintk("RPC: %4d failed to lock transport %p\n", task->tk_pid, xprt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137 task->tk_timeout = 0;
138 task->tk_status = -EAGAIN;
139 if (req && req->rq_ntrans)
140 rpc_sleep_on(&xprt->resend, task, NULL, NULL);
141 else
142 rpc_sleep_on(&xprt->sending, task, NULL, NULL);
143 return 0;
144}
145
Chuck Lever12a80462005-08-25 16:25:51 -0700146static inline int xprt_lock_write(struct rpc_xprt *xprt, struct rpc_task *task)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147{
148 int retval;
149
Chuck Lever4a0f8c02005-08-11 16:25:32 -0400150 spin_lock_bh(&xprt->transport_lock);
Chuck Lever12a80462005-08-25 16:25:51 -0700151 retval = xprt->ops->reserve_xprt(task);
Chuck Lever4a0f8c02005-08-11 16:25:32 -0400152 spin_unlock_bh(&xprt->transport_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153 return retval;
154}
155
Chuck Lever12a80462005-08-25 16:25:51 -0700156static void __xprt_lock_write_next(struct rpc_xprt *xprt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157{
158 struct rpc_task *task;
Chuck Lever49e9a892005-08-25 16:25:51 -0700159 struct rpc_rqst *req;
160
161 if (test_and_set_bit(XPRT_LOCKED, &xprt->state))
162 return;
163
164 task = rpc_wake_up_next(&xprt->resend);
165 if (!task) {
166 task = rpc_wake_up_next(&xprt->sending);
167 if (!task)
168 goto out_unlock;
169 }
170
171 req = task->tk_rqstp;
172 xprt->snd_task = task;
173 if (req) {
174 req->rq_bytes_sent = 0;
175 req->rq_ntrans++;
176 }
177 return;
178
179out_unlock:
180 smp_mb__before_clear_bit();
181 clear_bit(XPRT_LOCKED, &xprt->state);
182 smp_mb__after_clear_bit();
183}
184
185static void __xprt_lock_write_next_cong(struct rpc_xprt *xprt)
186{
187 struct rpc_task *task;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188
Chuck Lever2226feb2005-08-11 16:25:38 -0400189 if (test_and_set_bit(XPRT_LOCKED, &xprt->state))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190 return;
Chuck Lever49e9a892005-08-25 16:25:51 -0700191 if (RPCXPRT_CONGESTED(xprt))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192 goto out_unlock;
193 task = rpc_wake_up_next(&xprt->resend);
194 if (!task) {
195 task = rpc_wake_up_next(&xprt->sending);
196 if (!task)
197 goto out_unlock;
198 }
Chuck Lever49e9a892005-08-25 16:25:51 -0700199 if (__xprt_get_cong(xprt, task)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200 struct rpc_rqst *req = task->tk_rqstp;
201 xprt->snd_task = task;
202 if (req) {
203 req->rq_bytes_sent = 0;
204 req->rq_ntrans++;
205 }
206 return;
207 }
208out_unlock:
209 smp_mb__before_clear_bit();
Chuck Lever2226feb2005-08-11 16:25:38 -0400210 clear_bit(XPRT_LOCKED, &xprt->state);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211 smp_mb__after_clear_bit();
212}
213
Chuck Lever49e9a892005-08-25 16:25:51 -0700214/**
215 * xprt_release_xprt - allow other requests to use a transport
216 * @xprt: transport with other tasks potentially waiting
217 * @task: task that is releasing access to the transport
218 *
219 * Note that "task" can be NULL. No congestion control is provided.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220 */
Chuck Lever49e9a892005-08-25 16:25:51 -0700221void xprt_release_xprt(struct rpc_xprt *xprt, struct rpc_task *task)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222{
223 if (xprt->snd_task == task) {
224 xprt->snd_task = NULL;
225 smp_mb__before_clear_bit();
Chuck Lever2226feb2005-08-11 16:25:38 -0400226 clear_bit(XPRT_LOCKED, &xprt->state);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227 smp_mb__after_clear_bit();
228 __xprt_lock_write_next(xprt);
229 }
230}
231
Chuck Lever49e9a892005-08-25 16:25:51 -0700232/**
233 * xprt_release_xprt_cong - allow other requests to use a transport
234 * @xprt: transport with other tasks potentially waiting
235 * @task: task that is releasing access to the transport
236 *
237 * Note that "task" can be NULL. Another task is awoken to use the
238 * transport if the transport's congestion window allows it.
239 */
240void xprt_release_xprt_cong(struct rpc_xprt *xprt, struct rpc_task *task)
241{
242 if (xprt->snd_task == task) {
243 xprt->snd_task = NULL;
244 smp_mb__before_clear_bit();
245 clear_bit(XPRT_LOCKED, &xprt->state);
246 smp_mb__after_clear_bit();
247 __xprt_lock_write_next_cong(xprt);
248 }
249}
250
251static inline void xprt_release_write(struct rpc_xprt *xprt, struct rpc_task *task)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252{
Chuck Lever4a0f8c02005-08-11 16:25:32 -0400253 spin_lock_bh(&xprt->transport_lock);
Chuck Lever49e9a892005-08-25 16:25:51 -0700254 xprt->ops->release_xprt(xprt, task);
Chuck Lever4a0f8c02005-08-11 16:25:32 -0400255 spin_unlock_bh(&xprt->transport_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256}
257
258/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259 * Van Jacobson congestion avoidance. Check if the congestion window
260 * overflowed. Put the task to sleep if this is the case.
261 */
262static int
263__xprt_get_cong(struct rpc_xprt *xprt, struct rpc_task *task)
264{
265 struct rpc_rqst *req = task->tk_rqstp;
266
267 if (req->rq_cong)
268 return 1;
269 dprintk("RPC: %4d xprt_cwnd_limited cong = %ld cwnd = %ld\n",
270 task->tk_pid, xprt->cong, xprt->cwnd);
271 if (RPCXPRT_CONGESTED(xprt))
272 return 0;
273 req->rq_cong = 1;
274 xprt->cong += RPC_CWNDSCALE;
275 return 1;
276}
277
278/*
279 * Adjust the congestion window, and wake up the next task
280 * that has been sleeping due to congestion
281 */
282static void
283__xprt_put_cong(struct rpc_xprt *xprt, struct rpc_rqst *req)
284{
285 if (!req->rq_cong)
286 return;
287 req->rq_cong = 0;
288 xprt->cong -= RPC_CWNDSCALE;
Chuck Lever49e9a892005-08-25 16:25:51 -0700289 __xprt_lock_write_next_cong(xprt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290}
291
Chuck Lever46c0ee82005-08-25 16:25:52 -0700292/**
Chuck Levera58dd392005-08-25 16:25:53 -0700293 * xprt_release_rqst_cong - housekeeping when request is complete
294 * @task: RPC request that recently completed
295 *
296 * Useful for transports that require congestion control.
297 */
298void xprt_release_rqst_cong(struct rpc_task *task)
299{
300 __xprt_put_cong(task->tk_xprt, task->tk_rqstp);
301}
302
303/**
Chuck Lever46c0ee82005-08-25 16:25:52 -0700304 * xprt_adjust_cwnd - adjust transport congestion window
305 * @task: recently completed RPC request used to adjust window
306 * @result: result code of completed RPC request
307 *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308 * We use a time-smoothed congestion estimator to avoid heavy oscillation.
309 */
Chuck Lever46c0ee82005-08-25 16:25:52 -0700310void xprt_adjust_cwnd(struct rpc_task *task, int result)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311{
Chuck Lever46c0ee82005-08-25 16:25:52 -0700312 struct rpc_rqst *req = task->tk_rqstp;
313 struct rpc_xprt *xprt = task->tk_xprt;
314 unsigned long cwnd = xprt->cwnd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316 if (result >= 0 && cwnd <= xprt->cong) {
317 /* The (cwnd >> 1) term makes sure
318 * the result gets rounded properly. */
319 cwnd += (RPC_CWNDSCALE * RPC_CWNDSCALE + (cwnd >> 1)) / cwnd;
320 if (cwnd > RPC_MAXCWND(xprt))
321 cwnd = RPC_MAXCWND(xprt);
Chuck Lever49e9a892005-08-25 16:25:51 -0700322 __xprt_lock_write_next_cong(xprt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323 } else if (result == -ETIMEDOUT) {
324 cwnd >>= 1;
325 if (cwnd < RPC_CWNDSCALE)
326 cwnd = RPC_CWNDSCALE;
327 }
328 dprintk("RPC: cong %ld, cwnd was %ld, now %ld\n",
329 xprt->cong, xprt->cwnd, cwnd);
330 xprt->cwnd = cwnd;
Chuck Lever46c0ee82005-08-25 16:25:52 -0700331 __xprt_put_cong(xprt, req);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332}
333
Chuck Lever44fbac22005-08-11 16:25:44 -0400334/**
335 * xprt_wake_pending_tasks - wake all tasks on a transport's pending queue
336 * @xprt: transport with waiting tasks
337 * @status: result code to plant in each task before waking it
338 *
339 */
340void xprt_wake_pending_tasks(struct rpc_xprt *xprt, int status)
341{
342 if (status < 0)
343 rpc_wake_up_status(&xprt->pending, status);
344 else
345 rpc_wake_up(&xprt->pending);
346}
347
Chuck Leverc7b2cae2005-08-11 16:25:50 -0400348/**
349 * xprt_wait_for_buffer_space - wait for transport output buffer to clear
350 * @task: task to be put to sleep
351 *
352 */
353void xprt_wait_for_buffer_space(struct rpc_task *task)
354{
355 struct rpc_rqst *req = task->tk_rqstp;
356 struct rpc_xprt *xprt = req->rq_xprt;
357
358 task->tk_timeout = req->rq_timeout;
359 rpc_sleep_on(&xprt->pending, task, NULL, NULL);
360}
361
362/**
363 * xprt_write_space - wake the task waiting for transport output buffer space
364 * @xprt: transport with waiting tasks
365 *
366 * Can be called in a soft IRQ context, so xprt_write_space never sleeps.
367 */
368void xprt_write_space(struct rpc_xprt *xprt)
369{
370 if (unlikely(xprt->shutdown))
371 return;
372
373 spin_lock_bh(&xprt->transport_lock);
374 if (xprt->snd_task) {
375 dprintk("RPC: write space: waking waiting task on xprt %p\n",
376 xprt);
377 rpc_wake_up_task(xprt->snd_task);
378 }
379 spin_unlock_bh(&xprt->transport_lock);
380}
381
Chuck Leverfe3aca22005-08-25 16:25:50 -0700382/**
383 * xprt_set_retrans_timeout_def - set a request's retransmit timeout
384 * @task: task whose timeout is to be set
385 *
386 * Set a request's retransmit timeout based on the transport's
387 * default timeout parameters. Used by transports that don't adjust
388 * the retransmit timeout based on round-trip time estimation.
389 */
390void xprt_set_retrans_timeout_def(struct rpc_task *task)
391{
392 task->tk_timeout = task->tk_rqstp->rq_timeout;
393}
394
395/*
396 * xprt_set_retrans_timeout_rtt - set a request's retransmit timeout
397 * @task: task whose timeout is to be set
398 *
399 * Set a request's retransmit timeout using the RTT estimator.
400 */
401void xprt_set_retrans_timeout_rtt(struct rpc_task *task)
402{
403 int timer = task->tk_msg.rpc_proc->p_timer;
404 struct rpc_rtt *rtt = task->tk_client->cl_rtt;
405 struct rpc_rqst *req = task->tk_rqstp;
406 unsigned long max_timeout = req->rq_xprt->timeout.to_maxval;
407
408 task->tk_timeout = rpc_calc_rto(rtt, timer);
409 task->tk_timeout <<= rpc_ntimeo(rtt, timer) + req->rq_retries;
410 if (task->tk_timeout > max_timeout || task->tk_timeout == 0)
411 task->tk_timeout = max_timeout;
412}
413
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414static void xprt_reset_majortimeo(struct rpc_rqst *req)
415{
416 struct rpc_timeout *to = &req->rq_xprt->timeout;
417
418 req->rq_majortimeo = req->rq_timeout;
419 if (to->to_exponential)
420 req->rq_majortimeo <<= to->to_retries;
421 else
422 req->rq_majortimeo += to->to_increment * to->to_retries;
423 if (req->rq_majortimeo > to->to_maxval || req->rq_majortimeo == 0)
424 req->rq_majortimeo = to->to_maxval;
425 req->rq_majortimeo += jiffies;
426}
427
Chuck Lever9903cd12005-08-11 16:25:26 -0400428/**
429 * xprt_adjust_timeout - adjust timeout values for next retransmit
430 * @req: RPC request containing parameters to use for the adjustment
431 *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432 */
433int xprt_adjust_timeout(struct rpc_rqst *req)
434{
435 struct rpc_xprt *xprt = req->rq_xprt;
436 struct rpc_timeout *to = &xprt->timeout;
437 int status = 0;
438
439 if (time_before(jiffies, req->rq_majortimeo)) {
440 if (to->to_exponential)
441 req->rq_timeout <<= 1;
442 else
443 req->rq_timeout += to->to_increment;
444 if (to->to_maxval && req->rq_timeout >= to->to_maxval)
445 req->rq_timeout = to->to_maxval;
446 req->rq_retries++;
447 pprintk("RPC: %lu retrans\n", jiffies);
448 } else {
449 req->rq_timeout = to->to_initval;
450 req->rq_retries = 0;
451 xprt_reset_majortimeo(req);
452 /* Reset the RTT counters == "slow start" */
Chuck Lever4a0f8c02005-08-11 16:25:32 -0400453 spin_lock_bh(&xprt->transport_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454 rpc_init_rtt(req->rq_task->tk_client->cl_rtt, to->to_initval);
Chuck Lever4a0f8c02005-08-11 16:25:32 -0400455 spin_unlock_bh(&xprt->transport_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700456 pprintk("RPC: %lu timeout\n", jiffies);
457 status = -ETIMEDOUT;
458 }
459
460 if (req->rq_timeout == 0) {
461 printk(KERN_WARNING "xprt_adjust_timeout: rq_timeout = 0!\n");
462 req->rq_timeout = 5 * HZ;
463 }
464 return status;
465}
466
Chuck Lever55aa4f52005-08-11 16:25:47 -0400467static void xprt_autoclose(void *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468{
469 struct rpc_xprt *xprt = (struct rpc_xprt *)args;
470
471 xprt_disconnect(xprt);
Chuck Levera246b012005-08-11 16:25:23 -0400472 xprt->ops->close(xprt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473 xprt_release_write(xprt, NULL);
474}
475
Chuck Lever9903cd12005-08-11 16:25:26 -0400476/**
477 * xprt_disconnect - mark a transport as disconnected
478 * @xprt: transport to flag for disconnect
479 *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480 */
Chuck Levera246b012005-08-11 16:25:23 -0400481void xprt_disconnect(struct rpc_xprt *xprt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482{
483 dprintk("RPC: disconnected transport %p\n", xprt);
Chuck Lever4a0f8c02005-08-11 16:25:32 -0400484 spin_lock_bh(&xprt->transport_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485 xprt_clear_connected(xprt);
Chuck Lever44fbac22005-08-11 16:25:44 -0400486 xprt_wake_pending_tasks(xprt, -ENOTCONN);
Chuck Lever4a0f8c02005-08-11 16:25:32 -0400487 spin_unlock_bh(&xprt->transport_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488}
489
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490static void
491xprt_init_autodisconnect(unsigned long data)
492{
493 struct rpc_xprt *xprt = (struct rpc_xprt *)data;
494
Chuck Lever4a0f8c02005-08-11 16:25:32 -0400495 spin_lock(&xprt->transport_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496 if (!list_empty(&xprt->recv) || xprt->shutdown)
497 goto out_abort;
Chuck Lever2226feb2005-08-11 16:25:38 -0400498 if (test_and_set_bit(XPRT_LOCKED, &xprt->state))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499 goto out_abort;
Chuck Lever4a0f8c02005-08-11 16:25:32 -0400500 spin_unlock(&xprt->transport_lock);
Chuck Lever2226feb2005-08-11 16:25:38 -0400501 if (xprt_connecting(xprt))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502 xprt_release_write(xprt, NULL);
503 else
504 schedule_work(&xprt->task_cleanup);
505 return;
506out_abort:
Chuck Lever4a0f8c02005-08-11 16:25:32 -0400507 spin_unlock(&xprt->transport_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508}
509
Chuck Lever9903cd12005-08-11 16:25:26 -0400510/**
511 * xprt_connect - schedule a transport connect operation
512 * @task: RPC task that is requesting the connect
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513 *
514 */
515void xprt_connect(struct rpc_task *task)
516{
517 struct rpc_xprt *xprt = task->tk_xprt;
518
519 dprintk("RPC: %4d xprt_connect xprt %p %s connected\n", task->tk_pid,
520 xprt, (xprt_connected(xprt) ? "is" : "is not"));
521
522 if (xprt->shutdown) {
523 task->tk_status = -EIO;
524 return;
525 }
526 if (!xprt->addr.sin_port) {
527 task->tk_status = -EIO;
528 return;
529 }
530 if (!xprt_lock_write(xprt, task))
531 return;
532 if (xprt_connected(xprt))
Chuck Levera246b012005-08-11 16:25:23 -0400533 xprt_release_write(xprt, task);
534 else {
535 if (task->tk_rqstp)
536 task->tk_rqstp->rq_bytes_sent = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537
Chuck Levera246b012005-08-11 16:25:23 -0400538 task->tk_timeout = RPC_CONNECT_TIMEOUT;
539 rpc_sleep_on(&xprt->pending, task, xprt_connect_status, NULL);
540 xprt->ops->connect(task);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541 }
542 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543}
544
Chuck Lever9903cd12005-08-11 16:25:26 -0400545static void xprt_connect_status(struct rpc_task *task)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546{
547 struct rpc_xprt *xprt = task->tk_xprt;
548
549 if (task->tk_status >= 0) {
550 dprintk("RPC: %4d xprt_connect_status: connection established\n",
551 task->tk_pid);
552 return;
553 }
554
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555 switch (task->tk_status) {
556 case -ECONNREFUSED:
557 case -ECONNRESET:
Chuck Lever23475d62005-08-11 16:25:08 -0400558 dprintk("RPC: %4d xprt_connect_status: server %s refused connection\n",
559 task->tk_pid, task->tk_client->cl_server);
560 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561 case -ENOTCONN:
Chuck Lever23475d62005-08-11 16:25:08 -0400562 dprintk("RPC: %4d xprt_connect_status: connection broken\n",
563 task->tk_pid);
564 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565 case -ETIMEDOUT:
Chuck Lever23475d62005-08-11 16:25:08 -0400566 dprintk("RPC: %4d xprt_connect_status: connect attempt timed out\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567 task->tk_pid);
568 break;
569 default:
Chuck Lever23475d62005-08-11 16:25:08 -0400570 dprintk("RPC: %4d xprt_connect_status: error %d connecting to server %s\n",
571 task->tk_pid, -task->tk_status, task->tk_client->cl_server);
572 xprt_release_write(xprt, task);
573 task->tk_status = -EIO;
574 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575 }
Chuck Lever23475d62005-08-11 16:25:08 -0400576
577 /* if soft mounted, just cause this RPC to fail */
578 if (RPC_IS_SOFT(task)) {
579 xprt_release_write(xprt, task);
580 task->tk_status = -EIO;
581 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582}
583
Chuck Lever9903cd12005-08-11 16:25:26 -0400584/**
585 * xprt_lookup_rqst - find an RPC request corresponding to an XID
586 * @xprt: transport on which the original request was transmitted
587 * @xid: RPC XID of incoming reply
588 *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589 */
Chuck Levera246b012005-08-11 16:25:23 -0400590struct rpc_rqst *xprt_lookup_rqst(struct rpc_xprt *xprt, u32 xid)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700591{
592 struct list_head *pos;
593 struct rpc_rqst *req = NULL;
594
595 list_for_each(pos, &xprt->recv) {
596 struct rpc_rqst *entry = list_entry(pos, struct rpc_rqst, rq_list);
597 if (entry->rq_xid == xid) {
598 req = entry;
599 break;
600 }
601 }
602 return req;
603}
604
Chuck Lever9903cd12005-08-11 16:25:26 -0400605/**
Chuck Lever1570c1e2005-08-25 16:25:52 -0700606 * xprt_update_rtt - update an RPC client's RTT state after receiving a reply
607 * @task: RPC request that recently completed
Chuck Lever9903cd12005-08-11 16:25:26 -0400608 *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609 */
Chuck Lever1570c1e2005-08-25 16:25:52 -0700610void xprt_update_rtt(struct rpc_task *task)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611{
Chuck Lever1570c1e2005-08-25 16:25:52 -0700612 struct rpc_rqst *req = task->tk_rqstp;
613 struct rpc_rtt *rtt = task->tk_client->cl_rtt;
614 unsigned timer = task->tk_msg.rpc_proc->p_timer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615
Chuck Lever1570c1e2005-08-25 16:25:52 -0700616 if (timer) {
617 if (req->rq_ntrans == 1)
618 rpc_update_rtt(rtt, timer,
619 (long)jiffies - req->rq_xtime);
620 rpc_set_timeo(rtt, timer, req->rq_ntrans - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621 }
Chuck Lever1570c1e2005-08-25 16:25:52 -0700622}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623
Chuck Lever1570c1e2005-08-25 16:25:52 -0700624/**
625 * xprt_complete_rqst - called when reply processing is complete
626 * @task: RPC request that recently completed
627 * @copied: actual number of bytes received from the transport
628 *
629 * Caller holds transport lock.
630 */
631void xprt_complete_rqst(struct rpc_task *task, int copied)
632{
633 struct rpc_rqst *req = task->tk_rqstp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634
Chuck Lever1570c1e2005-08-25 16:25:52 -0700635 dprintk("RPC: %5u xid %08x complete (%d bytes received)\n",
636 task->tk_pid, ntohl(req->rq_xid), copied);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638 list_del_init(&req->rq_list);
639 req->rq_received = req->rq_private_buf.len = copied;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640 rpc_wake_up_task(task);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641}
642
Chuck Lever46c0ee82005-08-25 16:25:52 -0700643static void xprt_timer(struct rpc_task *task)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644{
Chuck Lever46c0ee82005-08-25 16:25:52 -0700645 struct rpc_rqst *req = task->tk_rqstp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646 struct rpc_xprt *xprt = req->rq_xprt;
647
Chuck Lever46c0ee82005-08-25 16:25:52 -0700648 dprintk("RPC: %4d xprt_timer\n", task->tk_pid);
649
Chuck Lever4a0f8c02005-08-11 16:25:32 -0400650 spin_lock(&xprt->transport_lock);
Chuck Lever46c0ee82005-08-25 16:25:52 -0700651 if (!req->rq_received) {
652 if (xprt->ops->timer)
653 xprt->ops->timer(task);
654 task->tk_status = -ETIMEDOUT;
655 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656 task->tk_timeout = 0;
657 rpc_wake_up_task(task);
Chuck Lever4a0f8c02005-08-11 16:25:32 -0400658 spin_unlock(&xprt->transport_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659}
660
Chuck Lever9903cd12005-08-11 16:25:26 -0400661/**
662 * xprt_prepare_transmit - reserve the transport before sending a request
663 * @task: RPC task about to send a request
664 *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665 */
Chuck Lever9903cd12005-08-11 16:25:26 -0400666int xprt_prepare_transmit(struct rpc_task *task)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667{
668 struct rpc_rqst *req = task->tk_rqstp;
669 struct rpc_xprt *xprt = req->rq_xprt;
670 int err = 0;
671
672 dprintk("RPC: %4d xprt_prepare_transmit\n", task->tk_pid);
673
674 if (xprt->shutdown)
675 return -EIO;
676
Chuck Lever4a0f8c02005-08-11 16:25:32 -0400677 spin_lock_bh(&xprt->transport_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678 if (req->rq_received && !req->rq_bytes_sent) {
679 err = req->rq_received;
680 goto out_unlock;
681 }
Chuck Lever12a80462005-08-25 16:25:51 -0700682 if (!xprt->ops->reserve_xprt(task)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683 err = -EAGAIN;
684 goto out_unlock;
685 }
686
687 if (!xprt_connected(xprt)) {
688 err = -ENOTCONN;
689 goto out_unlock;
690 }
691out_unlock:
Chuck Lever4a0f8c02005-08-11 16:25:32 -0400692 spin_unlock_bh(&xprt->transport_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693 return err;
694}
695
Chuck Lever9903cd12005-08-11 16:25:26 -0400696/**
697 * xprt_transmit - send an RPC request on a transport
698 * @task: controlling RPC task
699 *
700 * We have to copy the iovec because sendmsg fiddles with its contents.
701 */
702void xprt_transmit(struct rpc_task *task)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704 struct rpc_rqst *req = task->tk_rqstp;
705 struct rpc_xprt *xprt = req->rq_xprt;
Chuck Levera246b012005-08-11 16:25:23 -0400706 int status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707
708 dprintk("RPC: %4d xprt_transmit(%u)\n", task->tk_pid, req->rq_slen);
709
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710 smp_rmb();
711 if (!req->rq_received) {
712 if (list_empty(&req->rq_list)) {
Chuck Lever4a0f8c02005-08-11 16:25:32 -0400713 spin_lock_bh(&xprt->transport_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714 /* Update the softirq receive buffer */
715 memcpy(&req->rq_private_buf, &req->rq_rcv_buf,
716 sizeof(req->rq_private_buf));
717 /* Add request to the receive list */
718 list_add_tail(&req->rq_list, &xprt->recv);
Chuck Lever4a0f8c02005-08-11 16:25:32 -0400719 spin_unlock_bh(&xprt->transport_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720 xprt_reset_majortimeo(req);
Trond Myklebust0f9dc2b2005-06-22 17:16:28 +0000721 /* Turn off autodisconnect */
722 del_singleshot_timer_sync(&xprt->timer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723 }
724 } else if (!req->rq_bytes_sent)
725 return;
726
Chuck Levera246b012005-08-11 16:25:23 -0400727 status = xprt->ops->send_request(task);
Chuck Leverfe3aca22005-08-25 16:25:50 -0700728 if (status == 0) {
729 dprintk("RPC: %4d xmit complete\n", task->tk_pid);
730 spin_lock_bh(&xprt->transport_lock);
731 xprt->ops->set_retrans_timeout(task);
732 /* Don't race with disconnect */
733 if (!xprt_connected(xprt))
734 task->tk_status = -ENOTCONN;
735 else if (!req->rq_received)
736 rpc_sleep_on(&xprt->pending, task, NULL, xprt_timer);
Chuck Lever49e9a892005-08-25 16:25:51 -0700737 xprt->ops->release_xprt(xprt, task);
Chuck Leverfe3aca22005-08-25 16:25:50 -0700738 spin_unlock_bh(&xprt->transport_lock);
739 return;
740 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741
742 /* Note: at this point, task->tk_sleeping has not yet been set,
743 * hence there is no danger of the waking up task being put on
744 * schedq, and being picked up by a parallel run of rpciod().
745 */
746 task->tk_status = status;
747
748 switch (status) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749 case -ECONNREFUSED:
750 task->tk_timeout = RPC_REESTABLISH_TIMEOUT;
751 rpc_sleep_on(&xprt->sending, task, NULL, NULL);
Chuck Levera246b012005-08-11 16:25:23 -0400752 case -EAGAIN:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753 case -ENOTCONN:
754 return;
755 default:
Chuck Lever43118c22005-08-25 16:25:49 -0700756 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757 }
758 xprt_release_write(xprt, task);
759 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760}
761
Chuck Lever9903cd12005-08-11 16:25:26 -0400762static inline void do_xprt_reserve(struct rpc_task *task)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763{
764 struct rpc_xprt *xprt = task->tk_xprt;
765
766 task->tk_status = 0;
767 if (task->tk_rqstp)
768 return;
769 if (!list_empty(&xprt->free)) {
770 struct rpc_rqst *req = list_entry(xprt->free.next, struct rpc_rqst, rq_list);
771 list_del_init(&req->rq_list);
772 task->tk_rqstp = req;
773 xprt_request_init(task, xprt);
774 return;
775 }
776 dprintk("RPC: waiting for request slot\n");
777 task->tk_status = -EAGAIN;
778 task->tk_timeout = 0;
779 rpc_sleep_on(&xprt->backlog, task, NULL, NULL);
780}
781
Chuck Lever9903cd12005-08-11 16:25:26 -0400782/**
783 * xprt_reserve - allocate an RPC request slot
784 * @task: RPC task requesting a slot allocation
785 *
786 * If no more slots are available, place the task on the transport's
787 * backlog queue.
788 */
789void xprt_reserve(struct rpc_task *task)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790{
791 struct rpc_xprt *xprt = task->tk_xprt;
792
793 task->tk_status = -EIO;
794 if (!xprt->shutdown) {
Chuck Lever5dc07722005-08-11 16:25:35 -0400795 spin_lock(&xprt->reserve_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796 do_xprt_reserve(task);
Chuck Lever5dc07722005-08-11 16:25:35 -0400797 spin_unlock(&xprt->reserve_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798 }
799}
800
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801static inline u32 xprt_alloc_xid(struct rpc_xprt *xprt)
802{
803 return xprt->xid++;
804}
805
806static inline void xprt_init_xid(struct rpc_xprt *xprt)
807{
808 get_random_bytes(&xprt->xid, sizeof(xprt->xid));
809}
810
Chuck Lever9903cd12005-08-11 16:25:26 -0400811static void xprt_request_init(struct rpc_task *task, struct rpc_xprt *xprt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812{
813 struct rpc_rqst *req = task->tk_rqstp;
814
815 req->rq_timeout = xprt->timeout.to_initval;
816 req->rq_task = task;
817 req->rq_xprt = xprt;
818 req->rq_xid = xprt_alloc_xid(xprt);
819 dprintk("RPC: %4d reserved req %p xid %08x\n", task->tk_pid,
820 req, ntohl(req->rq_xid));
821}
822
Chuck Lever9903cd12005-08-11 16:25:26 -0400823/**
824 * xprt_release - release an RPC request slot
825 * @task: task which is finished with the slot
826 *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827 */
Chuck Lever9903cd12005-08-11 16:25:26 -0400828void xprt_release(struct rpc_task *task)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829{
830 struct rpc_xprt *xprt = task->tk_xprt;
831 struct rpc_rqst *req;
832
833 if (!(req = task->tk_rqstp))
834 return;
Chuck Lever4a0f8c02005-08-11 16:25:32 -0400835 spin_lock_bh(&xprt->transport_lock);
Chuck Lever49e9a892005-08-25 16:25:51 -0700836 xprt->ops->release_xprt(xprt, task);
Chuck Levera58dd392005-08-25 16:25:53 -0700837 if (xprt->ops->release_request)
838 xprt->ops->release_request(task);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839 if (!list_empty(&req->rq_list))
840 list_del(&req->rq_list);
841 xprt->last_used = jiffies;
842 if (list_empty(&xprt->recv) && !xprt->shutdown)
Chuck Levera246b012005-08-11 16:25:23 -0400843 mod_timer(&xprt->timer,
844 xprt->last_used + RPC_IDLE_DISCONNECT_TIMEOUT);
Chuck Lever4a0f8c02005-08-11 16:25:32 -0400845 spin_unlock_bh(&xprt->transport_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846 task->tk_rqstp = NULL;
847 memset(req, 0, sizeof(*req)); /* mark unused */
848
849 dprintk("RPC: %4d release request %p\n", task->tk_pid, req);
850
Chuck Lever5dc07722005-08-11 16:25:35 -0400851 spin_lock(&xprt->reserve_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700852 list_add(&req->rq_list, &xprt->free);
853 xprt_clear_backlog(xprt);
Chuck Lever5dc07722005-08-11 16:25:35 -0400854 spin_unlock(&xprt->reserve_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700855}
856
Chuck Lever9903cd12005-08-11 16:25:26 -0400857/**
858 * xprt_set_timeout - set constant RPC timeout
859 * @to: RPC timeout parameters to set up
860 * @retr: number of retries
861 * @incr: amount of increase after each retry
862 *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700863 */
Chuck Lever9903cd12005-08-11 16:25:26 -0400864void xprt_set_timeout(struct rpc_timeout *to, unsigned int retr, unsigned long incr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865{
866 to->to_initval =
867 to->to_increment = incr;
Chuck Levereab5c082005-08-11 16:25:14 -0400868 to->to_maxval = to->to_initval + (incr * retr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700869 to->to_retries = retr;
870 to->to_exponential = 0;
871}
872
Chuck Lever9903cd12005-08-11 16:25:26 -0400873static struct rpc_xprt *xprt_setup(int proto, struct sockaddr_in *ap, struct rpc_timeout *to)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874{
Chuck Levera246b012005-08-11 16:25:23 -0400875 int result;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700876 struct rpc_xprt *xprt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877 struct rpc_rqst *req;
878
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879 if ((xprt = kmalloc(sizeof(struct rpc_xprt), GFP_KERNEL)) == NULL)
880 return ERR_PTR(-ENOMEM);
881 memset(xprt, 0, sizeof(*xprt)); /* Nnnngh! */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882
883 xprt->addr = *ap;
Chuck Levera246b012005-08-11 16:25:23 -0400884
885 switch (proto) {
886 case IPPROTO_UDP:
887 result = xs_setup_udp(xprt, to);
888 break;
889 case IPPROTO_TCP:
890 result = xs_setup_tcp(xprt, to);
891 break;
892 default:
893 printk(KERN_ERR "RPC: unrecognized transport protocol: %d\n",
894 proto);
895 result = -EIO;
896 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897 }
Chuck Levera246b012005-08-11 16:25:23 -0400898 if (result) {
899 kfree(xprt);
900 return ERR_PTR(result);
901 }
902
Chuck Lever4a0f8c02005-08-11 16:25:32 -0400903 spin_lock_init(&xprt->transport_lock);
Chuck Lever5dc07722005-08-11 16:25:35 -0400904 spin_lock_init(&xprt->reserve_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905 init_waitqueue_head(&xprt->cong_wait);
906
907 INIT_LIST_HEAD(&xprt->free);
908 INIT_LIST_HEAD(&xprt->recv);
Chuck Lever55aa4f52005-08-11 16:25:47 -0400909 INIT_WORK(&xprt->task_cleanup, xprt_autoclose, xprt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910 init_timer(&xprt->timer);
911 xprt->timer.function = xprt_init_autodisconnect;
912 xprt->timer.data = (unsigned long) xprt;
913 xprt->last_used = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914
915 rpc_init_wait_queue(&xprt->pending, "xprt_pending");
916 rpc_init_wait_queue(&xprt->sending, "xprt_sending");
917 rpc_init_wait_queue(&xprt->resend, "xprt_resend");
918 rpc_init_priority_wait_queue(&xprt->backlog, "xprt_backlog");
919
920 /* initialize free list */
Chuck Levera246b012005-08-11 16:25:23 -0400921 for (req = &xprt->slot[xprt->max_reqs-1]; req >= &xprt->slot[0]; req--)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922 list_add(&req->rq_list, &xprt->free);
923
924 xprt_init_xid(xprt);
925
Linus Torvalds1da177e2005-04-16 15:20:36 -0700926 dprintk("RPC: created transport %p with %u slots\n", xprt,
927 xprt->max_reqs);
928
929 return xprt;
930}
931
Chuck Lever9903cd12005-08-11 16:25:26 -0400932/**
933 * xprt_create_proto - create an RPC client transport
934 * @proto: requested transport protocol
935 * @sap: remote peer's address
936 * @to: timeout parameters for new transport
937 *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700938 */
Chuck Lever9903cd12005-08-11 16:25:26 -0400939struct rpc_xprt *xprt_create_proto(int proto, struct sockaddr_in *sap, struct rpc_timeout *to)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940{
941 struct rpc_xprt *xprt;
942
943 xprt = xprt_setup(proto, sap, to);
944 if (IS_ERR(xprt))
945 dprintk("RPC: xprt_create_proto failed\n");
946 else
947 dprintk("RPC: xprt_create_proto created xprt %p\n", xprt);
948 return xprt;
949}
950
Chuck Lever9903cd12005-08-11 16:25:26 -0400951static void xprt_shutdown(struct rpc_xprt *xprt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952{
953 xprt->shutdown = 1;
954 rpc_wake_up(&xprt->sending);
955 rpc_wake_up(&xprt->resend);
Chuck Lever44fbac22005-08-11 16:25:44 -0400956 xprt_wake_pending_tasks(xprt, -EIO);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957 rpc_wake_up(&xprt->backlog);
958 wake_up(&xprt->cong_wait);
959 del_timer_sync(&xprt->timer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700960}
961
Chuck Lever9903cd12005-08-11 16:25:26 -0400962static int xprt_clear_backlog(struct rpc_xprt *xprt) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963 rpc_wake_up_next(&xprt->backlog);
964 wake_up(&xprt->cong_wait);
965 return 1;
966}
967
Chuck Lever9903cd12005-08-11 16:25:26 -0400968/**
969 * xprt_destroy - destroy an RPC transport, killing off all requests.
970 * @xprt: transport to destroy
971 *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700972 */
Chuck Lever9903cd12005-08-11 16:25:26 -0400973int xprt_destroy(struct rpc_xprt *xprt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974{
975 dprintk("RPC: destroying transport %p\n", xprt);
976 xprt_shutdown(xprt);
Chuck Levera246b012005-08-11 16:25:23 -0400977 xprt->ops->destroy(xprt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978 kfree(xprt);
979
980 return 0;
981}