xref: /openbmc/linux/net/sunrpc/xprt.c (revision 95f7691d)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  *  linux/net/sunrpc/xprt.c
31da177e4SLinus Torvalds  *
41da177e4SLinus Torvalds  *  This is a generic RPC call interface supporting congestion avoidance,
51da177e4SLinus Torvalds  *  and asynchronous calls.
61da177e4SLinus Torvalds  *
71da177e4SLinus Torvalds  *  The interface works like this:
81da177e4SLinus Torvalds  *
91da177e4SLinus Torvalds  *  -	When a process places a call, it allocates a request slot if
101da177e4SLinus Torvalds  *	one is available. Otherwise, it sleeps on the backlog queue
111da177e4SLinus Torvalds  *	(xprt_reserve).
121da177e4SLinus Torvalds  *  -	Next, the caller puts together the RPC message, stuffs it into
1355aa4f58SChuck Lever  *	the request struct, and calls xprt_transmit().
1455aa4f58SChuck Lever  *  -	xprt_transmit sends the message and installs the caller on the
1555ae1aabSRicardo Labiaga  *	transport's wait list. At the same time, if a reply is expected,
1655ae1aabSRicardo Labiaga  *	it installs a timer that is run after the packet's timeout has
1755ae1aabSRicardo Labiaga  *	expired.
181da177e4SLinus Torvalds  *  -	When a packet arrives, the data_ready handler walks the list of
1955aa4f58SChuck Lever  *	pending requests for that transport. If a matching XID is found, the
201da177e4SLinus Torvalds  *	caller is woken up, and the timer removed.
211da177e4SLinus Torvalds  *  -	When no reply arrives within the timeout interval, the timer is
221da177e4SLinus Torvalds  *	fired by the kernel and runs xprt_timer(). It either adjusts the
231da177e4SLinus Torvalds  *	timeout values (minor timeout) or wakes up the caller with a status
241da177e4SLinus Torvalds  *	of -ETIMEDOUT.
251da177e4SLinus Torvalds  *  -	When the caller receives a notification from RPC that a reply arrived,
261da177e4SLinus Torvalds  *	it should release the RPC slot, and process the reply.
271da177e4SLinus Torvalds  *	If the call timed out, it may choose to retry the operation by
281da177e4SLinus Torvalds  *	adjusting the initial timeout value, and simply calling rpc_call
291da177e4SLinus Torvalds  *	again.
301da177e4SLinus Torvalds  *
311da177e4SLinus Torvalds  *  Support for async RPC is done through a set of RPC-specific scheduling
321da177e4SLinus Torvalds  *  primitives that `transparently' work for processes as well as async
331da177e4SLinus Torvalds  *  tasks that rely on callbacks.
341da177e4SLinus Torvalds  *
351da177e4SLinus Torvalds  *  Copyright (C) 1995-1997, Olaf Kirch <okir@monad.swb.de>
3655aa4f58SChuck Lever  *
3755aa4f58SChuck Lever  *  Transport switch API copyright (C) 2005, Chuck Lever <cel@netapp.com>
381da177e4SLinus Torvalds  */
391da177e4SLinus Torvalds 
40a246b010SChuck Lever #include <linux/module.h>
41a246b010SChuck Lever 
421da177e4SLinus Torvalds #include <linux/types.h>
43a246b010SChuck Lever #include <linux/interrupt.h>
441da177e4SLinus Torvalds #include <linux/workqueue.h>
45bf3fcf89SChuck Lever #include <linux/net.h>
46ff839970SChuck Lever #include <linux/ktime.h>
471da177e4SLinus Torvalds 
48a246b010SChuck Lever #include <linux/sunrpc/clnt.h>
4911c556b3SChuck Lever #include <linux/sunrpc/metrics.h>
50c9acb42eSTrond Myklebust #include <linux/sunrpc/bc_xprt.h>
51fda1bfefSTrond Myklebust #include <linux/rcupdate.h>
521da177e4SLinus Torvalds 
533705ad64SJeff Layton #include <trace/events/sunrpc.h>
543705ad64SJeff Layton 
5555ae1aabSRicardo Labiaga #include "sunrpc.h"
5655ae1aabSRicardo Labiaga 
571da177e4SLinus Torvalds /*
581da177e4SLinus Torvalds  * Local variables
591da177e4SLinus Torvalds  */
601da177e4SLinus Torvalds 
61f895b252SJeff Layton #if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
621da177e4SLinus Torvalds # define RPCDBG_FACILITY	RPCDBG_XPRT
631da177e4SLinus Torvalds #endif
641da177e4SLinus Torvalds 
651da177e4SLinus Torvalds /*
661da177e4SLinus Torvalds  * Local functions
671da177e4SLinus Torvalds  */
6821de0a95STrond Myklebust static void	 xprt_init(struct rpc_xprt *xprt, struct net *net);
6937ac86c3SChuck Lever static __be32	xprt_alloc_xid(struct rpc_xprt *xprt);
701da177e4SLinus Torvalds static void	xprt_connect_status(struct rpc_task *task);
714e0038b6STrond Myklebust static void	 xprt_destroy(struct rpc_xprt *xprt);
721da177e4SLinus Torvalds 
735ba03e82SJiri Slaby static DEFINE_SPINLOCK(xprt_list_lock);
7481c098afS\"Talpey, Thomas\ static LIST_HEAD(xprt_list);
7581c098afS\"Talpey, Thomas\ 
7612a80469SChuck Lever /**
7781c098afS\"Talpey, Thomas\  * xprt_register_transport - register a transport implementation
7881c098afS\"Talpey, Thomas\  * @transport: transport to register
7981c098afS\"Talpey, Thomas\  *
8081c098afS\"Talpey, Thomas\  * If a transport implementation is loaded as a kernel module, it can
8181c098afS\"Talpey, Thomas\  * call this interface to make itself known to the RPC client.
8281c098afS\"Talpey, Thomas\  *
8381c098afS\"Talpey, Thomas\  * Returns:
8481c098afS\"Talpey, Thomas\  * 0:		transport successfully registered
8581c098afS\"Talpey, Thomas\  * -EEXIST:	transport already registered
8681c098afS\"Talpey, Thomas\  * -EINVAL:	transport module being unloaded
8781c098afS\"Talpey, Thomas\  */
8881c098afS\"Talpey, Thomas\ int xprt_register_transport(struct xprt_class *transport)
8981c098afS\"Talpey, Thomas\ {
9081c098afS\"Talpey, Thomas\ 	struct xprt_class *t;
9181c098afS\"Talpey, Thomas\ 	int result;
9281c098afS\"Talpey, Thomas\ 
9381c098afS\"Talpey, Thomas\ 	result = -EEXIST;
9481c098afS\"Talpey, Thomas\ 	spin_lock(&xprt_list_lock);
9581c098afS\"Talpey, Thomas\ 	list_for_each_entry(t, &xprt_list, list) {
9681c098afS\"Talpey, Thomas\ 		/* don't register the same transport class twice */
974fa016ebS\"Talpey, Thomas\ 		if (t->ident == transport->ident)
9881c098afS\"Talpey, Thomas\ 			goto out;
9981c098afS\"Talpey, Thomas\ 	}
10081c098afS\"Talpey, Thomas\ 
10181c098afS\"Talpey, Thomas\ 	list_add_tail(&transport->list, &xprt_list);
10281c098afS\"Talpey, Thomas\ 	printk(KERN_INFO "RPC: Registered %s transport module.\n",
10381c098afS\"Talpey, Thomas\ 	       transport->name);
10481c098afS\"Talpey, Thomas\ 	result = 0;
10581c098afS\"Talpey, Thomas\ 
10681c098afS\"Talpey, Thomas\ out:
10781c098afS\"Talpey, Thomas\ 	spin_unlock(&xprt_list_lock);
10881c098afS\"Talpey, Thomas\ 	return result;
10981c098afS\"Talpey, Thomas\ }
11081c098afS\"Talpey, Thomas\ EXPORT_SYMBOL_GPL(xprt_register_transport);
11181c098afS\"Talpey, Thomas\ 
11281c098afS\"Talpey, Thomas\ /**
11381c098afS\"Talpey, Thomas\  * xprt_unregister_transport - unregister a transport implementation
11465b6e42cSRandy Dunlap  * @transport: transport to unregister
11581c098afS\"Talpey, Thomas\  *
11681c098afS\"Talpey, Thomas\  * Returns:
11781c098afS\"Talpey, Thomas\  * 0:		transport successfully unregistered
11881c098afS\"Talpey, Thomas\  * -ENOENT:	transport never registered
11981c098afS\"Talpey, Thomas\  */
12081c098afS\"Talpey, Thomas\ int xprt_unregister_transport(struct xprt_class *transport)
12181c098afS\"Talpey, Thomas\ {
12281c098afS\"Talpey, Thomas\ 	struct xprt_class *t;
12381c098afS\"Talpey, Thomas\ 	int result;
12481c098afS\"Talpey, Thomas\ 
12581c098afS\"Talpey, Thomas\ 	result = 0;
12681c098afS\"Talpey, Thomas\ 	spin_lock(&xprt_list_lock);
12781c098afS\"Talpey, Thomas\ 	list_for_each_entry(t, &xprt_list, list) {
12881c098afS\"Talpey, Thomas\ 		if (t == transport) {
12981c098afS\"Talpey, Thomas\ 			printk(KERN_INFO
13081c098afS\"Talpey, Thomas\ 				"RPC: Unregistered %s transport module.\n",
13181c098afS\"Talpey, Thomas\ 				transport->name);
13281c098afS\"Talpey, Thomas\ 			list_del_init(&transport->list);
13381c098afS\"Talpey, Thomas\ 			goto out;
13481c098afS\"Talpey, Thomas\ 		}
13581c098afS\"Talpey, Thomas\ 	}
13681c098afS\"Talpey, Thomas\ 	result = -ENOENT;
13781c098afS\"Talpey, Thomas\ 
13881c098afS\"Talpey, Thomas\ out:
13981c098afS\"Talpey, Thomas\ 	spin_unlock(&xprt_list_lock);
14081c098afS\"Talpey, Thomas\ 	return result;
14181c098afS\"Talpey, Thomas\ }
14281c098afS\"Talpey, Thomas\ EXPORT_SYMBOL_GPL(xprt_unregister_transport);
14381c098afS\"Talpey, Thomas\ 
14481c098afS\"Talpey, Thomas\ /**
145441e3e24STom Talpey  * xprt_load_transport - load a transport implementation
146441e3e24STom Talpey  * @transport_name: transport to load
147441e3e24STom Talpey  *
148441e3e24STom Talpey  * Returns:
149441e3e24STom Talpey  * 0:		transport successfully loaded
150441e3e24STom Talpey  * -ENOENT:	transport module not available
151441e3e24STom Talpey  */
152441e3e24STom Talpey int xprt_load_transport(const char *transport_name)
153441e3e24STom Talpey {
154441e3e24STom Talpey 	struct xprt_class *t;
155441e3e24STom Talpey 	int result;
156441e3e24STom Talpey 
157441e3e24STom Talpey 	result = 0;
158441e3e24STom Talpey 	spin_lock(&xprt_list_lock);
159441e3e24STom Talpey 	list_for_each_entry(t, &xprt_list, list) {
160441e3e24STom Talpey 		if (strcmp(t->name, transport_name) == 0) {
161441e3e24STom Talpey 			spin_unlock(&xprt_list_lock);
162441e3e24STom Talpey 			goto out;
163441e3e24STom Talpey 		}
164441e3e24STom Talpey 	}
165441e3e24STom Talpey 	spin_unlock(&xprt_list_lock);
166ef7ffe8fSAlex Riesen 	result = request_module("xprt%s", transport_name);
167441e3e24STom Talpey out:
168441e3e24STom Talpey 	return result;
169441e3e24STom Talpey }
170441e3e24STom Talpey EXPORT_SYMBOL_GPL(xprt_load_transport);
171441e3e24STom Talpey 
172c544577dSTrond Myklebust static void xprt_clear_locked(struct rpc_xprt *xprt)
173c544577dSTrond Myklebust {
174c544577dSTrond Myklebust 	xprt->snd_task = NULL;
175c544577dSTrond Myklebust 	if (!test_bit(XPRT_CLOSE_WAIT, &xprt->state)) {
176c544577dSTrond Myklebust 		smp_mb__before_atomic();
177c544577dSTrond Myklebust 		clear_bit(XPRT_LOCKED, &xprt->state);
178c544577dSTrond Myklebust 		smp_mb__after_atomic();
179c544577dSTrond Myklebust 	} else
180c544577dSTrond Myklebust 		queue_work(xprtiod_workqueue, &xprt->task_cleanup);
181c544577dSTrond Myklebust }
182c544577dSTrond Myklebust 
183441e3e24STom Talpey /**
18412a80469SChuck Lever  * xprt_reserve_xprt - serialize write access to transports
18512a80469SChuck Lever  * @task: task that is requesting access to the transport
186177c27bfSRandy Dunlap  * @xprt: pointer to the target transport
18712a80469SChuck Lever  *
18812a80469SChuck Lever  * This prevents mixing the payload of separate requests, and prevents
18912a80469SChuck Lever  * transport connects from colliding with writes.  No congestion control
19012a80469SChuck Lever  * is provided.
1911da177e4SLinus Torvalds  */
19243cedbf0STrond Myklebust int xprt_reserve_xprt(struct rpc_xprt *xprt, struct rpc_task *task)
1931da177e4SLinus Torvalds {
19412a80469SChuck Lever 	struct rpc_rqst *req = task->tk_rqstp;
19534006ceeSTrond Myklebust 	int priority;
19612a80469SChuck Lever 
19712a80469SChuck Lever 	if (test_and_set_bit(XPRT_LOCKED, &xprt->state)) {
19812a80469SChuck Lever 		if (task == xprt->snd_task)
19912a80469SChuck Lever 			return 1;
20012a80469SChuck Lever 		goto out_sleep;
20112a80469SChuck Lever 	}
202c544577dSTrond Myklebust 	if (test_bit(XPRT_WRITE_SPACE, &xprt->state))
203c544577dSTrond Myklebust 		goto out_unlock;
20412a80469SChuck Lever 	xprt->snd_task = task;
2054d4a76f3Sj223yang@asset.uwaterloo.ca 
20612a80469SChuck Lever 	return 1;
20712a80469SChuck Lever 
208c544577dSTrond Myklebust out_unlock:
209c544577dSTrond Myklebust 	xprt_clear_locked(xprt);
21012a80469SChuck Lever out_sleep:
21146121cf7SChuck Lever 	dprintk("RPC: %5u failed to lock transport %p\n",
21212a80469SChuck Lever 			task->tk_pid, xprt);
213f05d54ecSTrond Myklebust 	task->tk_timeout = RPC_IS_SOFT(task) ? req->rq_timeout : 0;
21412a80469SChuck Lever 	task->tk_status = -EAGAIN;
21534006ceeSTrond Myklebust 	if (req == NULL)
21634006ceeSTrond Myklebust 		priority = RPC_PRIORITY_LOW;
21734006ceeSTrond Myklebust 	else if (!req->rq_ntrans)
21834006ceeSTrond Myklebust 		priority = RPC_PRIORITY_NORMAL;
21912a80469SChuck Lever 	else
22034006ceeSTrond Myklebust 		priority = RPC_PRIORITY_HIGH;
22134006ceeSTrond Myklebust 	rpc_sleep_on_priority(&xprt->sending, task, NULL, priority);
22212a80469SChuck Lever 	return 0;
22312a80469SChuck Lever }
22412444809S\"Talpey, Thomas\ EXPORT_SYMBOL_GPL(xprt_reserve_xprt);
22512a80469SChuck Lever 
22675891f50STrond Myklebust static bool
22775891f50STrond Myklebust xprt_need_congestion_window_wait(struct rpc_xprt *xprt)
22875891f50STrond Myklebust {
22975891f50STrond Myklebust 	return test_bit(XPRT_CWND_WAIT, &xprt->state);
23075891f50STrond Myklebust }
23175891f50STrond Myklebust 
23275891f50STrond Myklebust static void
23375891f50STrond Myklebust xprt_set_congestion_window_wait(struct rpc_xprt *xprt)
23475891f50STrond Myklebust {
23575891f50STrond Myklebust 	if (!list_empty(&xprt->xmit_queue)) {
23675891f50STrond Myklebust 		/* Peek at head of queue to see if it can make progress */
23775891f50STrond Myklebust 		if (list_first_entry(&xprt->xmit_queue, struct rpc_rqst,
23875891f50STrond Myklebust 					rq_xmit)->rq_cong)
23975891f50STrond Myklebust 			return;
24075891f50STrond Myklebust 	}
24175891f50STrond Myklebust 	set_bit(XPRT_CWND_WAIT, &xprt->state);
24275891f50STrond Myklebust }
24375891f50STrond Myklebust 
24475891f50STrond Myklebust static void
24575891f50STrond Myklebust xprt_test_and_clear_congestion_window_wait(struct rpc_xprt *xprt)
24675891f50STrond Myklebust {
24775891f50STrond Myklebust 	if (!RPCXPRT_CONGESTED(xprt))
24875891f50STrond Myklebust 		clear_bit(XPRT_CWND_WAIT, &xprt->state);
24975891f50STrond Myklebust }
25075891f50STrond Myklebust 
25112a80469SChuck Lever /*
25212a80469SChuck Lever  * xprt_reserve_xprt_cong - serialize write access to transports
25312a80469SChuck Lever  * @task: task that is requesting access to the transport
25412a80469SChuck Lever  *
25512a80469SChuck Lever  * Same as xprt_reserve_xprt, but Van Jacobson congestion control is
25612a80469SChuck Lever  * integrated into the decision of whether a request is allowed to be
25712a80469SChuck Lever  * woken up and given access to the transport.
25875891f50STrond Myklebust  * Note that the lock is only granted if we know there are free slots.
25912a80469SChuck Lever  */
26043cedbf0STrond Myklebust int xprt_reserve_xprt_cong(struct rpc_xprt *xprt, struct rpc_task *task)
26112a80469SChuck Lever {
2621da177e4SLinus Torvalds 	struct rpc_rqst *req = task->tk_rqstp;
26334006ceeSTrond Myklebust 	int priority;
2641da177e4SLinus Torvalds 
2652226feb6SChuck Lever 	if (test_and_set_bit(XPRT_LOCKED, &xprt->state)) {
2661da177e4SLinus Torvalds 		if (task == xprt->snd_task)
2671da177e4SLinus Torvalds 			return 1;
2681da177e4SLinus Torvalds 		goto out_sleep;
2691da177e4SLinus Torvalds 	}
27043cedbf0STrond Myklebust 	if (req == NULL) {
27143cedbf0STrond Myklebust 		xprt->snd_task = task;
27243cedbf0STrond Myklebust 		return 1;
27343cedbf0STrond Myklebust 	}
274c544577dSTrond Myklebust 	if (test_bit(XPRT_WRITE_SPACE, &xprt->state))
275c544577dSTrond Myklebust 		goto out_unlock;
27675891f50STrond Myklebust 	if (!xprt_need_congestion_window_wait(xprt)) {
2771da177e4SLinus Torvalds 		xprt->snd_task = task;
2781da177e4SLinus Torvalds 		return 1;
2791da177e4SLinus Torvalds 	}
280c544577dSTrond Myklebust out_unlock:
281632e3bdcSTrond Myklebust 	xprt_clear_locked(xprt);
2821da177e4SLinus Torvalds out_sleep:
28346121cf7SChuck Lever 	dprintk("RPC: %5u failed to lock transport %p\n", task->tk_pid, xprt);
284f05d54ecSTrond Myklebust 	task->tk_timeout = RPC_IS_SOFT(task) ? req->rq_timeout : 0;
2851da177e4SLinus Torvalds 	task->tk_status = -EAGAIN;
28634006ceeSTrond Myklebust 	if (req == NULL)
28734006ceeSTrond Myklebust 		priority = RPC_PRIORITY_LOW;
28834006ceeSTrond Myklebust 	else if (!req->rq_ntrans)
28934006ceeSTrond Myklebust 		priority = RPC_PRIORITY_NORMAL;
2901da177e4SLinus Torvalds 	else
29134006ceeSTrond Myklebust 		priority = RPC_PRIORITY_HIGH;
29234006ceeSTrond Myklebust 	rpc_sleep_on_priority(&xprt->sending, task, NULL, priority);
2931da177e4SLinus Torvalds 	return 0;
2941da177e4SLinus Torvalds }
29512444809S\"Talpey, Thomas\ EXPORT_SYMBOL_GPL(xprt_reserve_xprt_cong);
2961da177e4SLinus Torvalds 
29712a80469SChuck Lever static inline int xprt_lock_write(struct rpc_xprt *xprt, struct rpc_task *task)
2981da177e4SLinus Torvalds {
2991da177e4SLinus Torvalds 	int retval;
3001da177e4SLinus Torvalds 
301bd79bc57STrond Myklebust 	if (test_bit(XPRT_LOCKED, &xprt->state) && xprt->snd_task == task)
302bd79bc57STrond Myklebust 		return 1;
3034a0f8c04SChuck Lever 	spin_lock_bh(&xprt->transport_lock);
30443cedbf0STrond Myklebust 	retval = xprt->ops->reserve_xprt(xprt, task);
3054a0f8c04SChuck Lever 	spin_unlock_bh(&xprt->transport_lock);
3061da177e4SLinus Torvalds 	return retval;
3071da177e4SLinus Torvalds }
3081da177e4SLinus Torvalds 
309961a828dSTrond Myklebust static bool __xprt_lock_write_func(struct rpc_task *task, void *data)
3101da177e4SLinus Torvalds {
311961a828dSTrond Myklebust 	struct rpc_xprt *xprt = data;
31249e9a890SChuck Lever 
31349e9a890SChuck Lever 	xprt->snd_task = task;
314961a828dSTrond Myklebust 	return true;
315961a828dSTrond Myklebust }
316961a828dSTrond Myklebust 
317961a828dSTrond Myklebust static void __xprt_lock_write_next(struct rpc_xprt *xprt)
318961a828dSTrond Myklebust {
319961a828dSTrond Myklebust 	if (test_and_set_bit(XPRT_LOCKED, &xprt->state))
32049e9a890SChuck Lever 		return;
321c544577dSTrond Myklebust 	if (test_bit(XPRT_WRITE_SPACE, &xprt->state))
322c544577dSTrond Myklebust 		goto out_unlock;
323f1dc237cSTrond Myklebust 	if (rpc_wake_up_first_on_wq(xprtiod_workqueue, &xprt->sending,
324f1dc237cSTrond Myklebust 				__xprt_lock_write_func, xprt))
325961a828dSTrond Myklebust 		return;
326c544577dSTrond Myklebust out_unlock:
327632e3bdcSTrond Myklebust 	xprt_clear_locked(xprt);
32849e9a890SChuck Lever }
32949e9a890SChuck Lever 
330961a828dSTrond Myklebust static void __xprt_lock_write_next_cong(struct rpc_xprt *xprt)
331961a828dSTrond Myklebust {
332961a828dSTrond Myklebust 	if (test_and_set_bit(XPRT_LOCKED, &xprt->state))
333961a828dSTrond Myklebust 		return;
334c544577dSTrond Myklebust 	if (test_bit(XPRT_WRITE_SPACE, &xprt->state))
335c544577dSTrond Myklebust 		goto out_unlock;
33675891f50STrond Myklebust 	if (xprt_need_congestion_window_wait(xprt))
337961a828dSTrond Myklebust 		goto out_unlock;
338f1dc237cSTrond Myklebust 	if (rpc_wake_up_first_on_wq(xprtiod_workqueue, &xprt->sending,
33975891f50STrond Myklebust 				__xprt_lock_write_func, xprt))
340961a828dSTrond Myklebust 		return;
3411da177e4SLinus Torvalds out_unlock:
342632e3bdcSTrond Myklebust 	xprt_clear_locked(xprt);
3431da177e4SLinus Torvalds }
3441da177e4SLinus Torvalds 
34549e9a890SChuck Lever /**
34649e9a890SChuck Lever  * xprt_release_xprt - allow other requests to use a transport
34749e9a890SChuck Lever  * @xprt: transport with other tasks potentially waiting
34849e9a890SChuck Lever  * @task: task that is releasing access to the transport
34949e9a890SChuck Lever  *
35049e9a890SChuck Lever  * Note that "task" can be NULL.  No congestion control is provided.
3511da177e4SLinus Torvalds  */
35249e9a890SChuck Lever void xprt_release_xprt(struct rpc_xprt *xprt, struct rpc_task *task)
3531da177e4SLinus Torvalds {
3541da177e4SLinus Torvalds 	if (xprt->snd_task == task) {
355632e3bdcSTrond Myklebust 		xprt_clear_locked(xprt);
3561da177e4SLinus Torvalds 		__xprt_lock_write_next(xprt);
3571da177e4SLinus Torvalds 	}
3581da177e4SLinus Torvalds }
35912444809S\"Talpey, Thomas\ EXPORT_SYMBOL_GPL(xprt_release_xprt);
3601da177e4SLinus Torvalds 
36149e9a890SChuck Lever /**
36249e9a890SChuck Lever  * xprt_release_xprt_cong - allow other requests to use a transport
36349e9a890SChuck Lever  * @xprt: transport with other tasks potentially waiting
36449e9a890SChuck Lever  * @task: task that is releasing access to the transport
36549e9a890SChuck Lever  *
36649e9a890SChuck Lever  * Note that "task" can be NULL.  Another task is awoken to use the
36749e9a890SChuck Lever  * transport if the transport's congestion window allows it.
36849e9a890SChuck Lever  */
36949e9a890SChuck Lever void xprt_release_xprt_cong(struct rpc_xprt *xprt, struct rpc_task *task)
37049e9a890SChuck Lever {
37149e9a890SChuck Lever 	if (xprt->snd_task == task) {
372632e3bdcSTrond Myklebust 		xprt_clear_locked(xprt);
37349e9a890SChuck Lever 		__xprt_lock_write_next_cong(xprt);
37449e9a890SChuck Lever 	}
37549e9a890SChuck Lever }
37612444809S\"Talpey, Thomas\ EXPORT_SYMBOL_GPL(xprt_release_xprt_cong);
37749e9a890SChuck Lever 
37849e9a890SChuck Lever static inline void xprt_release_write(struct rpc_xprt *xprt, struct rpc_task *task)
3791da177e4SLinus Torvalds {
380bd79bc57STrond Myklebust 	if (xprt->snd_task != task)
381bd79bc57STrond Myklebust 		return;
3824a0f8c04SChuck Lever 	spin_lock_bh(&xprt->transport_lock);
38349e9a890SChuck Lever 	xprt->ops->release_xprt(xprt, task);
3844a0f8c04SChuck Lever 	spin_unlock_bh(&xprt->transport_lock);
3851da177e4SLinus Torvalds }
3861da177e4SLinus Torvalds 
3871da177e4SLinus Torvalds /*
3881da177e4SLinus Torvalds  * Van Jacobson congestion avoidance. Check if the congestion window
3891da177e4SLinus Torvalds  * overflowed. Put the task to sleep if this is the case.
3901da177e4SLinus Torvalds  */
3911da177e4SLinus Torvalds static int
39275891f50STrond Myklebust __xprt_get_cong(struct rpc_xprt *xprt, struct rpc_rqst *req)
3931da177e4SLinus Torvalds {
3941da177e4SLinus Torvalds 	if (req->rq_cong)
3951da177e4SLinus Torvalds 		return 1;
39646121cf7SChuck Lever 	dprintk("RPC: %5u xprt_cwnd_limited cong = %lu cwnd = %lu\n",
39775891f50STrond Myklebust 			req->rq_task->tk_pid, xprt->cong, xprt->cwnd);
39875891f50STrond Myklebust 	if (RPCXPRT_CONGESTED(xprt)) {
39975891f50STrond Myklebust 		xprt_set_congestion_window_wait(xprt);
4001da177e4SLinus Torvalds 		return 0;
40175891f50STrond Myklebust 	}
4021da177e4SLinus Torvalds 	req->rq_cong = 1;
4031da177e4SLinus Torvalds 	xprt->cong += RPC_CWNDSCALE;
4041da177e4SLinus Torvalds 	return 1;
4051da177e4SLinus Torvalds }
4061da177e4SLinus Torvalds 
4071da177e4SLinus Torvalds /*
4081da177e4SLinus Torvalds  * Adjust the congestion window, and wake up the next task
4091da177e4SLinus Torvalds  * that has been sleeping due to congestion
4101da177e4SLinus Torvalds  */
4111da177e4SLinus Torvalds static void
4121da177e4SLinus Torvalds __xprt_put_cong(struct rpc_xprt *xprt, struct rpc_rqst *req)
4131da177e4SLinus Torvalds {
4141da177e4SLinus Torvalds 	if (!req->rq_cong)
4151da177e4SLinus Torvalds 		return;
4161da177e4SLinus Torvalds 	req->rq_cong = 0;
4171da177e4SLinus Torvalds 	xprt->cong -= RPC_CWNDSCALE;
41875891f50STrond Myklebust 	xprt_test_and_clear_congestion_window_wait(xprt);
41949e9a890SChuck Lever 	__xprt_lock_write_next_cong(xprt);
4201da177e4SLinus Torvalds }
4211da177e4SLinus Torvalds 
42246c0ee8bSChuck Lever /**
42375891f50STrond Myklebust  * xprt_request_get_cong - Request congestion control credits
42475891f50STrond Myklebust  * @xprt: pointer to transport
42575891f50STrond Myklebust  * @req: pointer to RPC request
42675891f50STrond Myklebust  *
42775891f50STrond Myklebust  * Useful for transports that require congestion control.
42875891f50STrond Myklebust  */
42975891f50STrond Myklebust bool
43075891f50STrond Myklebust xprt_request_get_cong(struct rpc_xprt *xprt, struct rpc_rqst *req)
43175891f50STrond Myklebust {
43275891f50STrond Myklebust 	bool ret = false;
43375891f50STrond Myklebust 
43475891f50STrond Myklebust 	if (req->rq_cong)
43575891f50STrond Myklebust 		return true;
43675891f50STrond Myklebust 	spin_lock_bh(&xprt->transport_lock);
43775891f50STrond Myklebust 	ret = __xprt_get_cong(xprt, req) != 0;
43875891f50STrond Myklebust 	spin_unlock_bh(&xprt->transport_lock);
43975891f50STrond Myklebust 	return ret;
44075891f50STrond Myklebust }
44175891f50STrond Myklebust EXPORT_SYMBOL_GPL(xprt_request_get_cong);
44275891f50STrond Myklebust 
44375891f50STrond Myklebust /**
444a58dd398SChuck Lever  * xprt_release_rqst_cong - housekeeping when request is complete
445a58dd398SChuck Lever  * @task: RPC request that recently completed
446a58dd398SChuck Lever  *
447a58dd398SChuck Lever  * Useful for transports that require congestion control.
448a58dd398SChuck Lever  */
449a58dd398SChuck Lever void xprt_release_rqst_cong(struct rpc_task *task)
450a58dd398SChuck Lever {
451a4f0835cSTrond Myklebust 	struct rpc_rqst *req = task->tk_rqstp;
452a4f0835cSTrond Myklebust 
453a4f0835cSTrond Myklebust 	__xprt_put_cong(req->rq_xprt, req);
454a58dd398SChuck Lever }
45512444809S\"Talpey, Thomas\ EXPORT_SYMBOL_GPL(xprt_release_rqst_cong);
456a58dd398SChuck Lever 
45775891f50STrond Myklebust /*
45875891f50STrond Myklebust  * Clear the congestion window wait flag and wake up the next
45975891f50STrond Myklebust  * entry on xprt->sending
46075891f50STrond Myklebust  */
46175891f50STrond Myklebust static void
46275891f50STrond Myklebust xprt_clear_congestion_window_wait(struct rpc_xprt *xprt)
46375891f50STrond Myklebust {
46475891f50STrond Myklebust 	if (test_and_clear_bit(XPRT_CWND_WAIT, &xprt->state)) {
46575891f50STrond Myklebust 		spin_lock_bh(&xprt->transport_lock);
46675891f50STrond Myklebust 		__xprt_lock_write_next_cong(xprt);
46775891f50STrond Myklebust 		spin_unlock_bh(&xprt->transport_lock);
46875891f50STrond Myklebust 	}
46975891f50STrond Myklebust }
47075891f50STrond Myklebust 
471a58dd398SChuck Lever /**
47246c0ee8bSChuck Lever  * xprt_adjust_cwnd - adjust transport congestion window
4736a24dfb6STrond Myklebust  * @xprt: pointer to xprt
47446c0ee8bSChuck Lever  * @task: recently completed RPC request used to adjust window
47546c0ee8bSChuck Lever  * @result: result code of completed RPC request
47646c0ee8bSChuck Lever  *
4774f4cf5adSChuck Lever  * The transport code maintains an estimate on the maximum number of out-
4784f4cf5adSChuck Lever  * standing RPC requests, using a smoothed version of the congestion
4794f4cf5adSChuck Lever  * avoidance implemented in 44BSD. This is basically the Van Jacobson
4804f4cf5adSChuck Lever  * congestion algorithm: If a retransmit occurs, the congestion window is
4814f4cf5adSChuck Lever  * halved; otherwise, it is incremented by 1/cwnd when
4824f4cf5adSChuck Lever  *
4834f4cf5adSChuck Lever  *	-	a reply is received and
4844f4cf5adSChuck Lever  *	-	a full number of requests are outstanding and
4854f4cf5adSChuck Lever  *	-	the congestion window hasn't been updated recently.
4861da177e4SLinus Torvalds  */
4876a24dfb6STrond Myklebust void xprt_adjust_cwnd(struct rpc_xprt *xprt, struct rpc_task *task, int result)
4881da177e4SLinus Torvalds {
48946c0ee8bSChuck Lever 	struct rpc_rqst *req = task->tk_rqstp;
49046c0ee8bSChuck Lever 	unsigned long cwnd = xprt->cwnd;
4911da177e4SLinus Torvalds 
4921da177e4SLinus Torvalds 	if (result >= 0 && cwnd <= xprt->cong) {
4931da177e4SLinus Torvalds 		/* The (cwnd >> 1) term makes sure
4941da177e4SLinus Torvalds 		 * the result gets rounded properly. */
4951da177e4SLinus Torvalds 		cwnd += (RPC_CWNDSCALE * RPC_CWNDSCALE + (cwnd >> 1)) / cwnd;
4961da177e4SLinus Torvalds 		if (cwnd > RPC_MAXCWND(xprt))
4971da177e4SLinus Torvalds 			cwnd = RPC_MAXCWND(xprt);
49849e9a890SChuck Lever 		__xprt_lock_write_next_cong(xprt);
4991da177e4SLinus Torvalds 	} else if (result == -ETIMEDOUT) {
5001da177e4SLinus Torvalds 		cwnd >>= 1;
5011da177e4SLinus Torvalds 		if (cwnd < RPC_CWNDSCALE)
5021da177e4SLinus Torvalds 			cwnd = RPC_CWNDSCALE;
5031da177e4SLinus Torvalds 	}
5041da177e4SLinus Torvalds 	dprintk("RPC:       cong %ld, cwnd was %ld, now %ld\n",
5051da177e4SLinus Torvalds 			xprt->cong, xprt->cwnd, cwnd);
5061da177e4SLinus Torvalds 	xprt->cwnd = cwnd;
50746c0ee8bSChuck Lever 	__xprt_put_cong(xprt, req);
5081da177e4SLinus Torvalds }
50912444809S\"Talpey, Thomas\ EXPORT_SYMBOL_GPL(xprt_adjust_cwnd);
5101da177e4SLinus Torvalds 
51144fbac22SChuck Lever /**
51244fbac22SChuck Lever  * xprt_wake_pending_tasks - wake all tasks on a transport's pending queue
51344fbac22SChuck Lever  * @xprt: transport with waiting tasks
51444fbac22SChuck Lever  * @status: result code to plant in each task before waking it
51544fbac22SChuck Lever  *
51644fbac22SChuck Lever  */
51744fbac22SChuck Lever void xprt_wake_pending_tasks(struct rpc_xprt *xprt, int status)
51844fbac22SChuck Lever {
51944fbac22SChuck Lever 	if (status < 0)
52044fbac22SChuck Lever 		rpc_wake_up_status(&xprt->pending, status);
52144fbac22SChuck Lever 	else
52244fbac22SChuck Lever 		rpc_wake_up(&xprt->pending);
52344fbac22SChuck Lever }
52412444809S\"Talpey, Thomas\ EXPORT_SYMBOL_GPL(xprt_wake_pending_tasks);
52544fbac22SChuck Lever 
526c7b2cae8SChuck Lever /**
527c7b2cae8SChuck Lever  * xprt_wait_for_buffer_space - wait for transport output buffer to clear
528c544577dSTrond Myklebust  * @xprt: transport
529a9a6b52eSTrond Myklebust  *
530a9a6b52eSTrond Myklebust  * Note that we only set the timer for the case of RPC_IS_SOFT(), since
531a9a6b52eSTrond Myklebust  * we don't in general want to force a socket disconnection due to
532a9a6b52eSTrond Myklebust  * an incomplete RPC call transmission.
533c7b2cae8SChuck Lever  */
534c544577dSTrond Myklebust void xprt_wait_for_buffer_space(struct rpc_xprt *xprt)
535c7b2cae8SChuck Lever {
536c544577dSTrond Myklebust 	set_bit(XPRT_WRITE_SPACE, &xprt->state);
537c7b2cae8SChuck Lever }
53812444809S\"Talpey, Thomas\ EXPORT_SYMBOL_GPL(xprt_wait_for_buffer_space);
539c7b2cae8SChuck Lever 
540c544577dSTrond Myklebust static bool
541c544577dSTrond Myklebust xprt_clear_write_space_locked(struct rpc_xprt *xprt)
542c544577dSTrond Myklebust {
543c544577dSTrond Myklebust 	if (test_and_clear_bit(XPRT_WRITE_SPACE, &xprt->state)) {
544c544577dSTrond Myklebust 		__xprt_lock_write_next(xprt);
545c544577dSTrond Myklebust 		dprintk("RPC:       write space: waking waiting task on "
546c544577dSTrond Myklebust 				"xprt %p\n", xprt);
547c544577dSTrond Myklebust 		return true;
548c544577dSTrond Myklebust 	}
549c544577dSTrond Myklebust 	return false;
550c544577dSTrond Myklebust }
551c544577dSTrond Myklebust 
552c7b2cae8SChuck Lever /**
553c7b2cae8SChuck Lever  * xprt_write_space - wake the task waiting for transport output buffer space
554c7b2cae8SChuck Lever  * @xprt: transport with waiting tasks
555c7b2cae8SChuck Lever  *
556c7b2cae8SChuck Lever  * Can be called in a soft IRQ context, so xprt_write_space never sleeps.
557c7b2cae8SChuck Lever  */
558c544577dSTrond Myklebust bool xprt_write_space(struct rpc_xprt *xprt)
559c7b2cae8SChuck Lever {
560c544577dSTrond Myklebust 	bool ret;
561c544577dSTrond Myklebust 
562c544577dSTrond Myklebust 	if (!test_bit(XPRT_WRITE_SPACE, &xprt->state))
563c544577dSTrond Myklebust 		return false;
564c7b2cae8SChuck Lever 	spin_lock_bh(&xprt->transport_lock);
565c544577dSTrond Myklebust 	ret = xprt_clear_write_space_locked(xprt);
566c7b2cae8SChuck Lever 	spin_unlock_bh(&xprt->transport_lock);
567c544577dSTrond Myklebust 	return ret;
568c7b2cae8SChuck Lever }
56912444809S\"Talpey, Thomas\ EXPORT_SYMBOL_GPL(xprt_write_space);
570c7b2cae8SChuck Lever 
571fe3aca29SChuck Lever /**
572fe3aca29SChuck Lever  * xprt_set_retrans_timeout_def - set a request's retransmit timeout
573fe3aca29SChuck Lever  * @task: task whose timeout is to be set
574fe3aca29SChuck Lever  *
575fe3aca29SChuck Lever  * Set a request's retransmit timeout based on the transport's
576fe3aca29SChuck Lever  * default timeout parameters.  Used by transports that don't adjust
577fe3aca29SChuck Lever  * the retransmit timeout based on round-trip time estimation.
578fe3aca29SChuck Lever  */
579fe3aca29SChuck Lever void xprt_set_retrans_timeout_def(struct rpc_task *task)
580fe3aca29SChuck Lever {
581fe3aca29SChuck Lever 	task->tk_timeout = task->tk_rqstp->rq_timeout;
582fe3aca29SChuck Lever }
58312444809S\"Talpey, Thomas\ EXPORT_SYMBOL_GPL(xprt_set_retrans_timeout_def);
584fe3aca29SChuck Lever 
5852c53040fSBen Hutchings /**
586fe3aca29SChuck Lever  * xprt_set_retrans_timeout_rtt - set a request's retransmit timeout
587fe3aca29SChuck Lever  * @task: task whose timeout is to be set
588fe3aca29SChuck Lever  *
589fe3aca29SChuck Lever  * Set a request's retransmit timeout using the RTT estimator.
590fe3aca29SChuck Lever  */
591fe3aca29SChuck Lever void xprt_set_retrans_timeout_rtt(struct rpc_task *task)
592fe3aca29SChuck Lever {
593fe3aca29SChuck Lever 	int timer = task->tk_msg.rpc_proc->p_timer;
594ba7392bbSTrond Myklebust 	struct rpc_clnt *clnt = task->tk_client;
595ba7392bbSTrond Myklebust 	struct rpc_rtt *rtt = clnt->cl_rtt;
596fe3aca29SChuck Lever 	struct rpc_rqst *req = task->tk_rqstp;
597ba7392bbSTrond Myklebust 	unsigned long max_timeout = clnt->cl_timeout->to_maxval;
598fe3aca29SChuck Lever 
599fe3aca29SChuck Lever 	task->tk_timeout = rpc_calc_rto(rtt, timer);
600fe3aca29SChuck Lever 	task->tk_timeout <<= rpc_ntimeo(rtt, timer) + req->rq_retries;
601fe3aca29SChuck Lever 	if (task->tk_timeout > max_timeout || task->tk_timeout == 0)
602fe3aca29SChuck Lever 		task->tk_timeout = max_timeout;
603fe3aca29SChuck Lever }
60412444809S\"Talpey, Thomas\ EXPORT_SYMBOL_GPL(xprt_set_retrans_timeout_rtt);
605fe3aca29SChuck Lever 
6061da177e4SLinus Torvalds static void xprt_reset_majortimeo(struct rpc_rqst *req)
6071da177e4SLinus Torvalds {
608ba7392bbSTrond Myklebust 	const struct rpc_timeout *to = req->rq_task->tk_client->cl_timeout;
6091da177e4SLinus Torvalds 
6101da177e4SLinus Torvalds 	req->rq_majortimeo = req->rq_timeout;
6111da177e4SLinus Torvalds 	if (to->to_exponential)
6121da177e4SLinus Torvalds 		req->rq_majortimeo <<= to->to_retries;
6131da177e4SLinus Torvalds 	else
6141da177e4SLinus Torvalds 		req->rq_majortimeo += to->to_increment * to->to_retries;
6151da177e4SLinus Torvalds 	if (req->rq_majortimeo > to->to_maxval || req->rq_majortimeo == 0)
6161da177e4SLinus Torvalds 		req->rq_majortimeo = to->to_maxval;
6171da177e4SLinus Torvalds 	req->rq_majortimeo += jiffies;
6181da177e4SLinus Torvalds }
6191da177e4SLinus Torvalds 
6209903cd1cSChuck Lever /**
6219903cd1cSChuck Lever  * xprt_adjust_timeout - adjust timeout values for next retransmit
6229903cd1cSChuck Lever  * @req: RPC request containing parameters to use for the adjustment
6239903cd1cSChuck Lever  *
6241da177e4SLinus Torvalds  */
6251da177e4SLinus Torvalds int xprt_adjust_timeout(struct rpc_rqst *req)
6261da177e4SLinus Torvalds {
6271da177e4SLinus Torvalds 	struct rpc_xprt *xprt = req->rq_xprt;
628ba7392bbSTrond Myklebust 	const struct rpc_timeout *to = req->rq_task->tk_client->cl_timeout;
6291da177e4SLinus Torvalds 	int status = 0;
6301da177e4SLinus Torvalds 
6311da177e4SLinus Torvalds 	if (time_before(jiffies, req->rq_majortimeo)) {
6321da177e4SLinus Torvalds 		if (to->to_exponential)
6331da177e4SLinus Torvalds 			req->rq_timeout <<= 1;
6341da177e4SLinus Torvalds 		else
6351da177e4SLinus Torvalds 			req->rq_timeout += to->to_increment;
6361da177e4SLinus Torvalds 		if (to->to_maxval && req->rq_timeout >= to->to_maxval)
6371da177e4SLinus Torvalds 			req->rq_timeout = to->to_maxval;
6381da177e4SLinus Torvalds 		req->rq_retries++;
6391da177e4SLinus Torvalds 	} else {
6401da177e4SLinus Torvalds 		req->rq_timeout = to->to_initval;
6411da177e4SLinus Torvalds 		req->rq_retries = 0;
6421da177e4SLinus Torvalds 		xprt_reset_majortimeo(req);
6431da177e4SLinus Torvalds 		/* Reset the RTT counters == "slow start" */
6444a0f8c04SChuck Lever 		spin_lock_bh(&xprt->transport_lock);
6451da177e4SLinus Torvalds 		rpc_init_rtt(req->rq_task->tk_client->cl_rtt, to->to_initval);
6464a0f8c04SChuck Lever 		spin_unlock_bh(&xprt->transport_lock);
6471da177e4SLinus Torvalds 		status = -ETIMEDOUT;
6481da177e4SLinus Torvalds 	}
6491da177e4SLinus Torvalds 
6501da177e4SLinus Torvalds 	if (req->rq_timeout == 0) {
6511da177e4SLinus Torvalds 		printk(KERN_WARNING "xprt_adjust_timeout: rq_timeout = 0!\n");
6521da177e4SLinus Torvalds 		req->rq_timeout = 5 * HZ;
6531da177e4SLinus Torvalds 	}
6541da177e4SLinus Torvalds 	return status;
6551da177e4SLinus Torvalds }
6561da177e4SLinus Torvalds 
65765f27f38SDavid Howells static void xprt_autoclose(struct work_struct *work)
6581da177e4SLinus Torvalds {
65965f27f38SDavid Howells 	struct rpc_xprt *xprt =
66065f27f38SDavid Howells 		container_of(work, struct rpc_xprt, task_cleanup);
6611da177e4SLinus Torvalds 
66266af1e55STrond Myklebust 	clear_bit(XPRT_CLOSE_WAIT, &xprt->state);
6634876cc77STrond Myklebust 	xprt->ops->close(xprt);
6641da177e4SLinus Torvalds 	xprt_release_write(xprt, NULL);
66579234c3dSTrond Myklebust 	wake_up_bit(&xprt->state, XPRT_LOCKED);
6661da177e4SLinus Torvalds }
6671da177e4SLinus Torvalds 
6689903cd1cSChuck Lever /**
66962da3b24STrond Myklebust  * xprt_disconnect_done - mark a transport as disconnected
6709903cd1cSChuck Lever  * @xprt: transport to flag for disconnect
6719903cd1cSChuck Lever  *
6721da177e4SLinus Torvalds  */
67362da3b24STrond Myklebust void xprt_disconnect_done(struct rpc_xprt *xprt)
6741da177e4SLinus Torvalds {
6751da177e4SLinus Torvalds 	dprintk("RPC:       disconnected transport %p\n", xprt);
6764a0f8c04SChuck Lever 	spin_lock_bh(&xprt->transport_lock);
6771da177e4SLinus Torvalds 	xprt_clear_connected(xprt);
678c544577dSTrond Myklebust 	xprt_clear_write_space_locked(xprt);
6792a491991STrond Myklebust 	xprt_wake_pending_tasks(xprt, -EAGAIN);
6804a0f8c04SChuck Lever 	spin_unlock_bh(&xprt->transport_lock);
6811da177e4SLinus Torvalds }
68262da3b24STrond Myklebust EXPORT_SYMBOL_GPL(xprt_disconnect_done);
6831da177e4SLinus Torvalds 
68466af1e55STrond Myklebust /**
68566af1e55STrond Myklebust  * xprt_force_disconnect - force a transport to disconnect
68666af1e55STrond Myklebust  * @xprt: transport to disconnect
68766af1e55STrond Myklebust  *
68866af1e55STrond Myklebust  */
68966af1e55STrond Myklebust void xprt_force_disconnect(struct rpc_xprt *xprt)
69066af1e55STrond Myklebust {
69166af1e55STrond Myklebust 	/* Don't race with the test_bit() in xprt_clear_locked() */
69266af1e55STrond Myklebust 	spin_lock_bh(&xprt->transport_lock);
69366af1e55STrond Myklebust 	set_bit(XPRT_CLOSE_WAIT, &xprt->state);
69466af1e55STrond Myklebust 	/* Try to schedule an autoclose RPC call */
69566af1e55STrond Myklebust 	if (test_and_set_bit(XPRT_LOCKED, &xprt->state) == 0)
69640a5f1b1STrond Myklebust 		queue_work(xprtiod_workqueue, &xprt->task_cleanup);
6972a491991STrond Myklebust 	xprt_wake_pending_tasks(xprt, -EAGAIN);
69866af1e55STrond Myklebust 	spin_unlock_bh(&xprt->transport_lock);
69966af1e55STrond Myklebust }
700e2a4f4fbSChuck Lever EXPORT_SYMBOL_GPL(xprt_force_disconnect);
70166af1e55STrond Myklebust 
7027f3a1d1eSTrond Myklebust static unsigned int
7037f3a1d1eSTrond Myklebust xprt_connect_cookie(struct rpc_xprt *xprt)
7047f3a1d1eSTrond Myklebust {
7057f3a1d1eSTrond Myklebust 	return READ_ONCE(xprt->connect_cookie);
7067f3a1d1eSTrond Myklebust }
7077f3a1d1eSTrond Myklebust 
7087f3a1d1eSTrond Myklebust static bool
7097f3a1d1eSTrond Myklebust xprt_request_retransmit_after_disconnect(struct rpc_task *task)
7107f3a1d1eSTrond Myklebust {
7117f3a1d1eSTrond Myklebust 	struct rpc_rqst *req = task->tk_rqstp;
7127f3a1d1eSTrond Myklebust 	struct rpc_xprt *xprt = req->rq_xprt;
7137f3a1d1eSTrond Myklebust 
7147f3a1d1eSTrond Myklebust 	return req->rq_connect_cookie != xprt_connect_cookie(xprt) ||
7157f3a1d1eSTrond Myklebust 		!xprt_connected(xprt);
7167f3a1d1eSTrond Myklebust }
7177f3a1d1eSTrond Myklebust 
7187c1d71cfSTrond Myklebust /**
7197c1d71cfSTrond Myklebust  * xprt_conditional_disconnect - force a transport to disconnect
7207c1d71cfSTrond Myklebust  * @xprt: transport to disconnect
7217c1d71cfSTrond Myklebust  * @cookie: 'connection cookie'
7227c1d71cfSTrond Myklebust  *
7237c1d71cfSTrond Myklebust  * This attempts to break the connection if and only if 'cookie' matches
7247c1d71cfSTrond Myklebust  * the current transport 'connection cookie'. It ensures that we don't
7257c1d71cfSTrond Myklebust  * try to break the connection more than once when we need to retransmit
7267c1d71cfSTrond Myklebust  * a batch of RPC requests.
7277c1d71cfSTrond Myklebust  *
7287c1d71cfSTrond Myklebust  */
7297c1d71cfSTrond Myklebust void xprt_conditional_disconnect(struct rpc_xprt *xprt, unsigned int cookie)
7307c1d71cfSTrond Myklebust {
7317c1d71cfSTrond Myklebust 	/* Don't race with the test_bit() in xprt_clear_locked() */
7327c1d71cfSTrond Myklebust 	spin_lock_bh(&xprt->transport_lock);
7337c1d71cfSTrond Myklebust 	if (cookie != xprt->connect_cookie)
7347c1d71cfSTrond Myklebust 		goto out;
7352c2ee6d2SNeilBrown 	if (test_bit(XPRT_CLOSING, &xprt->state))
7367c1d71cfSTrond Myklebust 		goto out;
7377c1d71cfSTrond Myklebust 	set_bit(XPRT_CLOSE_WAIT, &xprt->state);
7387c1d71cfSTrond Myklebust 	/* Try to schedule an autoclose RPC call */
7397c1d71cfSTrond Myklebust 	if (test_and_set_bit(XPRT_LOCKED, &xprt->state) == 0)
74040a5f1b1STrond Myklebust 		queue_work(xprtiod_workqueue, &xprt->task_cleanup);
7412a491991STrond Myklebust 	xprt_wake_pending_tasks(xprt, -EAGAIN);
7427c1d71cfSTrond Myklebust out:
7437c1d71cfSTrond Myklebust 	spin_unlock_bh(&xprt->transport_lock);
7447c1d71cfSTrond Myklebust }
7457c1d71cfSTrond Myklebust 
746ad3331acSTrond Myklebust static bool
747ad3331acSTrond Myklebust xprt_has_timer(const struct rpc_xprt *xprt)
748ad3331acSTrond Myklebust {
749ad3331acSTrond Myklebust 	return xprt->idle_timeout != 0;
750ad3331acSTrond Myklebust }
751ad3331acSTrond Myklebust 
752ad3331acSTrond Myklebust static void
753ad3331acSTrond Myklebust xprt_schedule_autodisconnect(struct rpc_xprt *xprt)
754ad3331acSTrond Myklebust 	__must_hold(&xprt->transport_lock)
755ad3331acSTrond Myklebust {
75695f7691dSTrond Myklebust 	if (RB_EMPTY_ROOT(&xprt->recv_queue) && xprt_has_timer(xprt))
757ad3331acSTrond Myklebust 		mod_timer(&xprt->timer, xprt->last_used + xprt->idle_timeout);
758ad3331acSTrond Myklebust }
759ad3331acSTrond Myklebust 
7601da177e4SLinus Torvalds static void
761ff861c4dSKees Cook xprt_init_autodisconnect(struct timer_list *t)
7621da177e4SLinus Torvalds {
763ff861c4dSKees Cook 	struct rpc_xprt *xprt = from_timer(xprt, t, timer);
7641da177e4SLinus Torvalds 
7654a0f8c04SChuck Lever 	spin_lock(&xprt->transport_lock);
76695f7691dSTrond Myklebust 	if (!RB_EMPTY_ROOT(&xprt->recv_queue))
7671da177e4SLinus Torvalds 		goto out_abort;
768ad3331acSTrond Myklebust 	/* Reset xprt->last_used to avoid connect/autodisconnect cycling */
769ad3331acSTrond Myklebust 	xprt->last_used = jiffies;
7702226feb6SChuck Lever 	if (test_and_set_bit(XPRT_LOCKED, &xprt->state))
7711da177e4SLinus Torvalds 		goto out_abort;
7724a0f8c04SChuck Lever 	spin_unlock(&xprt->transport_lock);
77340a5f1b1STrond Myklebust 	queue_work(xprtiod_workqueue, &xprt->task_cleanup);
7741da177e4SLinus Torvalds 	return;
7751da177e4SLinus Torvalds out_abort:
7764a0f8c04SChuck Lever 	spin_unlock(&xprt->transport_lock);
7771da177e4SLinus Torvalds }
7781da177e4SLinus Torvalds 
779718ba5b8STrond Myklebust bool xprt_lock_connect(struct rpc_xprt *xprt,
780718ba5b8STrond Myklebust 		struct rpc_task *task,
781718ba5b8STrond Myklebust 		void *cookie)
782718ba5b8STrond Myklebust {
783718ba5b8STrond Myklebust 	bool ret = false;
784718ba5b8STrond Myklebust 
785718ba5b8STrond Myklebust 	spin_lock_bh(&xprt->transport_lock);
786718ba5b8STrond Myklebust 	if (!test_bit(XPRT_LOCKED, &xprt->state))
787718ba5b8STrond Myklebust 		goto out;
788718ba5b8STrond Myklebust 	if (xprt->snd_task != task)
789718ba5b8STrond Myklebust 		goto out;
790718ba5b8STrond Myklebust 	xprt->snd_task = cookie;
791718ba5b8STrond Myklebust 	ret = true;
792718ba5b8STrond Myklebust out:
793718ba5b8STrond Myklebust 	spin_unlock_bh(&xprt->transport_lock);
794718ba5b8STrond Myklebust 	return ret;
795718ba5b8STrond Myklebust }
796718ba5b8STrond Myklebust 
797718ba5b8STrond Myklebust void xprt_unlock_connect(struct rpc_xprt *xprt, void *cookie)
798718ba5b8STrond Myklebust {
799718ba5b8STrond Myklebust 	spin_lock_bh(&xprt->transport_lock);
800718ba5b8STrond Myklebust 	if (xprt->snd_task != cookie)
801718ba5b8STrond Myklebust 		goto out;
802718ba5b8STrond Myklebust 	if (!test_bit(XPRT_LOCKED, &xprt->state))
803718ba5b8STrond Myklebust 		goto out;
804718ba5b8STrond Myklebust 	xprt->snd_task =NULL;
805718ba5b8STrond Myklebust 	xprt->ops->release_xprt(xprt, NULL);
806ad3331acSTrond Myklebust 	xprt_schedule_autodisconnect(xprt);
807718ba5b8STrond Myklebust out:
808718ba5b8STrond Myklebust 	spin_unlock_bh(&xprt->transport_lock);
80979234c3dSTrond Myklebust 	wake_up_bit(&xprt->state, XPRT_LOCKED);
810718ba5b8STrond Myklebust }
811718ba5b8STrond Myklebust 
8129903cd1cSChuck Lever /**
8139903cd1cSChuck Lever  * xprt_connect - schedule a transport connect operation
8149903cd1cSChuck Lever  * @task: RPC task that is requesting the connect
8151da177e4SLinus Torvalds  *
8161da177e4SLinus Torvalds  */
8171da177e4SLinus Torvalds void xprt_connect(struct rpc_task *task)
8181da177e4SLinus Torvalds {
819ad2368d6STrond Myklebust 	struct rpc_xprt	*xprt = task->tk_rqstp->rq_xprt;
8201da177e4SLinus Torvalds 
82146121cf7SChuck Lever 	dprintk("RPC: %5u xprt_connect xprt %p %s connected\n", task->tk_pid,
8221da177e4SLinus Torvalds 			xprt, (xprt_connected(xprt) ? "is" : "is not"));
8231da177e4SLinus Torvalds 
824ec739ef0SChuck Lever 	if (!xprt_bound(xprt)) {
82501d37c42STrond Myklebust 		task->tk_status = -EAGAIN;
8261da177e4SLinus Torvalds 		return;
8271da177e4SLinus Torvalds 	}
8281da177e4SLinus Torvalds 	if (!xprt_lock_write(xprt, task))
8291da177e4SLinus Torvalds 		return;
830feb8ca37STrond Myklebust 
831feb8ca37STrond Myklebust 	if (test_and_clear_bit(XPRT_CLOSE_WAIT, &xprt->state))
832feb8ca37STrond Myklebust 		xprt->ops->close(xprt);
833feb8ca37STrond Myklebust 
834718ba5b8STrond Myklebust 	if (!xprt_connected(xprt)) {
835a8ce4a8fSTrond Myklebust 		task->tk_timeout = task->tk_rqstp->rq_timeout;
8362c2ee6d2SNeilBrown 		task->tk_rqstp->rq_connect_cookie = xprt->connect_cookie;
8375d00837bSTrond Myklebust 		rpc_sleep_on(&xprt->pending, task, xprt_connect_status);
8380b9e7943STrond Myklebust 
8390b9e7943STrond Myklebust 		if (test_bit(XPRT_CLOSING, &xprt->state))
8400b9e7943STrond Myklebust 			return;
8410b9e7943STrond Myklebust 		if (xprt_test_and_set_connecting(xprt))
8420b9e7943STrond Myklebust 			return;
843262ca07dSChuck Lever 		xprt->stat.connect_start = jiffies;
8441b092092STrond Myklebust 		xprt->ops->connect(xprt, task);
8451da177e4SLinus Torvalds 	}
846718ba5b8STrond Myklebust 	xprt_release_write(xprt, task);
8471da177e4SLinus Torvalds }
8481da177e4SLinus Torvalds 
8499903cd1cSChuck Lever static void xprt_connect_status(struct rpc_task *task)
8501da177e4SLinus Torvalds {
851ad2368d6STrond Myklebust 	struct rpc_xprt	*xprt = task->tk_rqstp->rq_xprt;
8521da177e4SLinus Torvalds 
853cd983ef8SChuck Lever 	if (task->tk_status == 0) {
854262ca07dSChuck Lever 		xprt->stat.connect_count++;
855262ca07dSChuck Lever 		xprt->stat.connect_time += (long)jiffies - xprt->stat.connect_start;
85646121cf7SChuck Lever 		dprintk("RPC: %5u xprt_connect_status: connection established\n",
8571da177e4SLinus Torvalds 				task->tk_pid);
8581da177e4SLinus Torvalds 		return;
8591da177e4SLinus Torvalds 	}
8601da177e4SLinus Torvalds 
8611da177e4SLinus Torvalds 	switch (task->tk_status) {
8620fe8d04eSTrond Myklebust 	case -ECONNREFUSED:
8630fe8d04eSTrond Myklebust 	case -ECONNRESET:
8640fe8d04eSTrond Myklebust 	case -ECONNABORTED:
8650fe8d04eSTrond Myklebust 	case -ENETUNREACH:
8660fe8d04eSTrond Myklebust 	case -EHOSTUNREACH:
8672fc193cfSTrond Myklebust 	case -EPIPE:
8682a491991STrond Myklebust 	case -EAGAIN:
8692a491991STrond Myklebust 		dprintk("RPC: %5u xprt_connect_status: retrying\n", task->tk_pid);
87023475d66SChuck Lever 		break;
8711da177e4SLinus Torvalds 	case -ETIMEDOUT:
87246121cf7SChuck Lever 		dprintk("RPC: %5u xprt_connect_status: connect attempt timed "
87346121cf7SChuck Lever 				"out\n", task->tk_pid);
8741da177e4SLinus Torvalds 		break;
8751da177e4SLinus Torvalds 	default:
87646121cf7SChuck Lever 		dprintk("RPC: %5u xprt_connect_status: error %d connecting to "
87746121cf7SChuck Lever 				"server %s\n", task->tk_pid, -task->tk_status,
8784e0038b6STrond Myklebust 				xprt->servername);
87923475d66SChuck Lever 		task->tk_status = -EIO;
88023475d66SChuck Lever 	}
8811da177e4SLinus Torvalds }
8821da177e4SLinus Torvalds 
88395f7691dSTrond Myklebust enum xprt_xid_rb_cmp {
88495f7691dSTrond Myklebust 	XID_RB_EQUAL,
88595f7691dSTrond Myklebust 	XID_RB_LEFT,
88695f7691dSTrond Myklebust 	XID_RB_RIGHT,
88795f7691dSTrond Myklebust };
88895f7691dSTrond Myklebust static enum xprt_xid_rb_cmp
88995f7691dSTrond Myklebust xprt_xid_cmp(__be32 xid1, __be32 xid2)
89095f7691dSTrond Myklebust {
89195f7691dSTrond Myklebust 	if (xid1 == xid2)
89295f7691dSTrond Myklebust 		return XID_RB_EQUAL;
89395f7691dSTrond Myklebust 	if ((__force u32)xid1 < (__force u32)xid2)
89495f7691dSTrond Myklebust 		return XID_RB_LEFT;
89595f7691dSTrond Myklebust 	return XID_RB_RIGHT;
89695f7691dSTrond Myklebust }
89795f7691dSTrond Myklebust 
89895f7691dSTrond Myklebust static struct rpc_rqst *
89995f7691dSTrond Myklebust xprt_request_rb_find(struct rpc_xprt *xprt, __be32 xid)
90095f7691dSTrond Myklebust {
90195f7691dSTrond Myklebust 	struct rb_node *n = xprt->recv_queue.rb_node;
90295f7691dSTrond Myklebust 	struct rpc_rqst *req;
90395f7691dSTrond Myklebust 
90495f7691dSTrond Myklebust 	while (n != NULL) {
90595f7691dSTrond Myklebust 		req = rb_entry(n, struct rpc_rqst, rq_recv);
90695f7691dSTrond Myklebust 		switch (xprt_xid_cmp(xid, req->rq_xid)) {
90795f7691dSTrond Myklebust 		case XID_RB_LEFT:
90895f7691dSTrond Myklebust 			n = n->rb_left;
90995f7691dSTrond Myklebust 			break;
91095f7691dSTrond Myklebust 		case XID_RB_RIGHT:
91195f7691dSTrond Myklebust 			n = n->rb_right;
91295f7691dSTrond Myklebust 			break;
91395f7691dSTrond Myklebust 		case XID_RB_EQUAL:
91495f7691dSTrond Myklebust 			return req;
91595f7691dSTrond Myklebust 		}
91695f7691dSTrond Myklebust 	}
91795f7691dSTrond Myklebust 	return NULL;
91895f7691dSTrond Myklebust }
91995f7691dSTrond Myklebust 
92095f7691dSTrond Myklebust static void
92195f7691dSTrond Myklebust xprt_request_rb_insert(struct rpc_xprt *xprt, struct rpc_rqst *new)
92295f7691dSTrond Myklebust {
92395f7691dSTrond Myklebust 	struct rb_node **p = &xprt->recv_queue.rb_node;
92495f7691dSTrond Myklebust 	struct rb_node *n = NULL;
92595f7691dSTrond Myklebust 	struct rpc_rqst *req;
92695f7691dSTrond Myklebust 
92795f7691dSTrond Myklebust 	while (*p != NULL) {
92895f7691dSTrond Myklebust 		n = *p;
92995f7691dSTrond Myklebust 		req = rb_entry(n, struct rpc_rqst, rq_recv);
93095f7691dSTrond Myklebust 		switch(xprt_xid_cmp(new->rq_xid, req->rq_xid)) {
93195f7691dSTrond Myklebust 		case XID_RB_LEFT:
93295f7691dSTrond Myklebust 			p = &n->rb_left;
93395f7691dSTrond Myklebust 			break;
93495f7691dSTrond Myklebust 		case XID_RB_RIGHT:
93595f7691dSTrond Myklebust 			p = &n->rb_right;
93695f7691dSTrond Myklebust 			break;
93795f7691dSTrond Myklebust 		case XID_RB_EQUAL:
93895f7691dSTrond Myklebust 			WARN_ON_ONCE(new != req);
93995f7691dSTrond Myklebust 			return;
94095f7691dSTrond Myklebust 		}
94195f7691dSTrond Myklebust 	}
94295f7691dSTrond Myklebust 	rb_link_node(&new->rq_recv, n, p);
94395f7691dSTrond Myklebust 	rb_insert_color(&new->rq_recv, &xprt->recv_queue);
94495f7691dSTrond Myklebust }
94595f7691dSTrond Myklebust 
94695f7691dSTrond Myklebust static void
94795f7691dSTrond Myklebust xprt_request_rb_remove(struct rpc_xprt *xprt, struct rpc_rqst *req)
94895f7691dSTrond Myklebust {
94995f7691dSTrond Myklebust 	rb_erase(&req->rq_recv, &xprt->recv_queue);
95095f7691dSTrond Myklebust }
95195f7691dSTrond Myklebust 
9529903cd1cSChuck Lever /**
9539903cd1cSChuck Lever  * xprt_lookup_rqst - find an RPC request corresponding to an XID
9549903cd1cSChuck Lever  * @xprt: transport on which the original request was transmitted
9559903cd1cSChuck Lever  * @xid: RPC XID of incoming reply
9569903cd1cSChuck Lever  *
95775c84151STrond Myklebust  * Caller holds xprt->queue_lock.
9581da177e4SLinus Torvalds  */
959d8ed029dSAlexey Dobriyan struct rpc_rqst *xprt_lookup_rqst(struct rpc_xprt *xprt, __be32 xid)
9601da177e4SLinus Torvalds {
9618f3a6de3SPavel Emelyanov 	struct rpc_rqst *entry;
9621da177e4SLinus Torvalds 
96395f7691dSTrond Myklebust 	entry = xprt_request_rb_find(xprt, xid);
96495f7691dSTrond Myklebust 	if (entry != NULL) {
9653705ad64SJeff Layton 		trace_xprt_lookup_rqst(xprt, xid, 0);
9660b87a46bSChuck Lever 		entry->rq_rtt = ktime_sub(ktime_get(), entry->rq_xtime);
967262ca07dSChuck Lever 		return entry;
9683705ad64SJeff Layton 	}
96946121cf7SChuck Lever 
97046121cf7SChuck Lever 	dprintk("RPC:       xprt_lookup_rqst did not find xid %08x\n",
97146121cf7SChuck Lever 			ntohl(xid));
9723705ad64SJeff Layton 	trace_xprt_lookup_rqst(xprt, xid, -ENOENT);
973262ca07dSChuck Lever 	xprt->stat.bad_xids++;
974262ca07dSChuck Lever 	return NULL;
9751da177e4SLinus Torvalds }
97612444809S\"Talpey, Thomas\ EXPORT_SYMBOL_GPL(xprt_lookup_rqst);
9771da177e4SLinus Torvalds 
978cf9946cdSTrond Myklebust static bool
979cf9946cdSTrond Myklebust xprt_is_pinned_rqst(struct rpc_rqst *req)
980cf9946cdSTrond Myklebust {
981cf9946cdSTrond Myklebust 	return atomic_read(&req->rq_pin) != 0;
982cf9946cdSTrond Myklebust }
983cf9946cdSTrond Myklebust 
984729749bbSTrond Myklebust /**
985729749bbSTrond Myklebust  * xprt_pin_rqst - Pin a request on the transport receive list
986729749bbSTrond Myklebust  * @req: Request to pin
987729749bbSTrond Myklebust  *
988729749bbSTrond Myklebust  * Caller must ensure this is atomic with the call to xprt_lookup_rqst()
989cf9946cdSTrond Myklebust  * so should be holding the xprt receive lock.
990729749bbSTrond Myklebust  */
991729749bbSTrond Myklebust void xprt_pin_rqst(struct rpc_rqst *req)
992729749bbSTrond Myklebust {
993cf9946cdSTrond Myklebust 	atomic_inc(&req->rq_pin);
994729749bbSTrond Myklebust }
9959590d083SChuck Lever EXPORT_SYMBOL_GPL(xprt_pin_rqst);
996729749bbSTrond Myklebust 
997729749bbSTrond Myklebust /**
998729749bbSTrond Myklebust  * xprt_unpin_rqst - Unpin a request on the transport receive list
999729749bbSTrond Myklebust  * @req: Request to pin
1000729749bbSTrond Myklebust  *
1001cf9946cdSTrond Myklebust  * Caller should be holding the xprt receive lock.
1002729749bbSTrond Myklebust  */
1003729749bbSTrond Myklebust void xprt_unpin_rqst(struct rpc_rqst *req)
1004729749bbSTrond Myklebust {
1005cf9946cdSTrond Myklebust 	if (!test_bit(RPC_TASK_MSG_PIN_WAIT, &req->rq_task->tk_runstate)) {
1006cf9946cdSTrond Myklebust 		atomic_dec(&req->rq_pin);
1007cf9946cdSTrond Myklebust 		return;
1008cf9946cdSTrond Myklebust 	}
1009cf9946cdSTrond Myklebust 	if (atomic_dec_and_test(&req->rq_pin))
1010cf9946cdSTrond Myklebust 		wake_up_var(&req->rq_pin);
1011729749bbSTrond Myklebust }
10129590d083SChuck Lever EXPORT_SYMBOL_GPL(xprt_unpin_rqst);
1013729749bbSTrond Myklebust 
1014729749bbSTrond Myklebust static void xprt_wait_on_pinned_rqst(struct rpc_rqst *req)
1015729749bbSTrond Myklebust {
1016cf9946cdSTrond Myklebust 	wait_var_event(&req->rq_pin, !xprt_is_pinned_rqst(req));
1017729749bbSTrond Myklebust }
1018729749bbSTrond Myklebust 
1019edc81dcdSTrond Myklebust static bool
1020edc81dcdSTrond Myklebust xprt_request_data_received(struct rpc_task *task)
1021edc81dcdSTrond Myklebust {
1022edc81dcdSTrond Myklebust 	return !test_bit(RPC_TASK_NEED_RECV, &task->tk_runstate) &&
1023edc81dcdSTrond Myklebust 		READ_ONCE(task->tk_rqstp->rq_reply_bytes_recvd) != 0;
1024edc81dcdSTrond Myklebust }
1025edc81dcdSTrond Myklebust 
1026edc81dcdSTrond Myklebust static bool
1027edc81dcdSTrond Myklebust xprt_request_need_enqueue_receive(struct rpc_task *task, struct rpc_rqst *req)
1028edc81dcdSTrond Myklebust {
1029edc81dcdSTrond Myklebust 	return !test_bit(RPC_TASK_NEED_RECV, &task->tk_runstate) &&
1030edc81dcdSTrond Myklebust 		READ_ONCE(task->tk_rqstp->rq_reply_bytes_recvd) == 0;
1031edc81dcdSTrond Myklebust }
1032edc81dcdSTrond Myklebust 
1033edc81dcdSTrond Myklebust /**
1034edc81dcdSTrond Myklebust  * xprt_request_enqueue_receive - Add an request to the receive queue
1035edc81dcdSTrond Myklebust  * @task: RPC task
1036edc81dcdSTrond Myklebust  *
1037edc81dcdSTrond Myklebust  */
1038edc81dcdSTrond Myklebust void
1039edc81dcdSTrond Myklebust xprt_request_enqueue_receive(struct rpc_task *task)
1040edc81dcdSTrond Myklebust {
1041edc81dcdSTrond Myklebust 	struct rpc_rqst *req = task->tk_rqstp;
1042edc81dcdSTrond Myklebust 	struct rpc_xprt *xprt = req->rq_xprt;
1043edc81dcdSTrond Myklebust 
1044edc81dcdSTrond Myklebust 	if (!xprt_request_need_enqueue_receive(task, req))
1045edc81dcdSTrond Myklebust 		return;
1046edc81dcdSTrond Myklebust 	spin_lock(&xprt->queue_lock);
1047edc81dcdSTrond Myklebust 
1048edc81dcdSTrond Myklebust 	/* Update the softirq receive buffer */
1049edc81dcdSTrond Myklebust 	memcpy(&req->rq_private_buf, &req->rq_rcv_buf,
1050edc81dcdSTrond Myklebust 			sizeof(req->rq_private_buf));
1051edc81dcdSTrond Myklebust 
1052edc81dcdSTrond Myklebust 	/* Add request to the receive list */
105395f7691dSTrond Myklebust 	xprt_request_rb_insert(xprt, req);
1054edc81dcdSTrond Myklebust 	set_bit(RPC_TASK_NEED_RECV, &task->tk_runstate);
1055edc81dcdSTrond Myklebust 	spin_unlock(&xprt->queue_lock);
1056edc81dcdSTrond Myklebust 
1057edc81dcdSTrond Myklebust 	xprt_reset_majortimeo(req);
1058edc81dcdSTrond Myklebust 	/* Turn off autodisconnect */
1059edc81dcdSTrond Myklebust 	del_singleshot_timer_sync(&xprt->timer);
1060edc81dcdSTrond Myklebust }
1061edc81dcdSTrond Myklebust 
1062edc81dcdSTrond Myklebust /**
1063edc81dcdSTrond Myklebust  * xprt_request_dequeue_receive_locked - Remove a request from the receive queue
1064edc81dcdSTrond Myklebust  * @task: RPC task
1065edc81dcdSTrond Myklebust  *
1066edc81dcdSTrond Myklebust  * Caller must hold xprt->queue_lock.
1067edc81dcdSTrond Myklebust  */
1068edc81dcdSTrond Myklebust static void
1069edc81dcdSTrond Myklebust xprt_request_dequeue_receive_locked(struct rpc_task *task)
1070edc81dcdSTrond Myklebust {
107195f7691dSTrond Myklebust 	struct rpc_rqst *req = task->tk_rqstp;
107295f7691dSTrond Myklebust 
1073edc81dcdSTrond Myklebust 	if (test_and_clear_bit(RPC_TASK_NEED_RECV, &task->tk_runstate))
107495f7691dSTrond Myklebust 		xprt_request_rb_remove(req->rq_xprt, req);
1075edc81dcdSTrond Myklebust }
1076edc81dcdSTrond Myklebust 
1077ecd465eeSChuck Lever /**
1078ecd465eeSChuck Lever  * xprt_update_rtt - Update RPC RTT statistics
1079ecd465eeSChuck Lever  * @task: RPC request that recently completed
1080ecd465eeSChuck Lever  *
108175c84151STrond Myklebust  * Caller holds xprt->queue_lock.
1082ecd465eeSChuck Lever  */
1083ecd465eeSChuck Lever void xprt_update_rtt(struct rpc_task *task)
10841da177e4SLinus Torvalds {
10851570c1e4SChuck Lever 	struct rpc_rqst *req = task->tk_rqstp;
10861570c1e4SChuck Lever 	struct rpc_rtt *rtt = task->tk_client->cl_rtt;
108795c96174SEric Dumazet 	unsigned int timer = task->tk_msg.rpc_proc->p_timer;
1088d60dbb20STrond Myklebust 	long m = usecs_to_jiffies(ktime_to_us(req->rq_rtt));
10891570c1e4SChuck Lever 
10901da177e4SLinus Torvalds 	if (timer) {
10911da177e4SLinus Torvalds 		if (req->rq_ntrans == 1)
1092ff839970SChuck Lever 			rpc_update_rtt(rtt, timer, m);
10931570c1e4SChuck Lever 		rpc_set_timeo(rtt, timer, req->rq_ntrans - 1);
10941da177e4SLinus Torvalds 	}
10951da177e4SLinus Torvalds }
1096ecd465eeSChuck Lever EXPORT_SYMBOL_GPL(xprt_update_rtt);
10971da177e4SLinus Torvalds 
10981570c1e4SChuck Lever /**
10991570c1e4SChuck Lever  * xprt_complete_rqst - called when reply processing is complete
11001570c1e4SChuck Lever  * @task: RPC request that recently completed
11011570c1e4SChuck Lever  * @copied: actual number of bytes received from the transport
11021570c1e4SChuck Lever  *
110375c84151STrond Myklebust  * Caller holds xprt->queue_lock.
11041570c1e4SChuck Lever  */
11051570c1e4SChuck Lever void xprt_complete_rqst(struct rpc_task *task, int copied)
11061570c1e4SChuck Lever {
11071570c1e4SChuck Lever 	struct rpc_rqst *req = task->tk_rqstp;
1108fda13939STrond Myklebust 	struct rpc_xprt *xprt = req->rq_xprt;
11091da177e4SLinus Torvalds 
11101570c1e4SChuck Lever 	dprintk("RPC: %5u xid %08x complete (%d bytes received)\n",
11111570c1e4SChuck Lever 			task->tk_pid, ntohl(req->rq_xid), copied);
11123705ad64SJeff Layton 	trace_xprt_complete_rqst(xprt, req->rq_xid, copied);
11131da177e4SLinus Torvalds 
1114fda13939STrond Myklebust 	xprt->stat.recvs++;
1115ef759a2eSChuck Lever 
11161e799b67STrond Myklebust 	req->rq_private_buf.len = copied;
1117dd2b63d0SRicardo Labiaga 	/* Ensure all writes are done before we update */
1118dd2b63d0SRicardo Labiaga 	/* req->rq_reply_bytes_recvd */
111943ac3f29STrond Myklebust 	smp_wmb();
1120dd2b63d0SRicardo Labiaga 	req->rq_reply_bytes_recvd = copied;
1121edc81dcdSTrond Myklebust 	xprt_request_dequeue_receive_locked(task);
1122fda13939STrond Myklebust 	rpc_wake_up_queued_task(&xprt->pending, task);
11231da177e4SLinus Torvalds }
112412444809S\"Talpey, Thomas\ EXPORT_SYMBOL_GPL(xprt_complete_rqst);
11251da177e4SLinus Torvalds 
112646c0ee8bSChuck Lever static void xprt_timer(struct rpc_task *task)
11271da177e4SLinus Torvalds {
11281da177e4SLinus Torvalds 	struct rpc_rqst *req = task->tk_rqstp;
11291da177e4SLinus Torvalds 	struct rpc_xprt *xprt = req->rq_xprt;
11301da177e4SLinus Torvalds 
11315d00837bSTrond Myklebust 	if (task->tk_status != -ETIMEDOUT)
11325d00837bSTrond Myklebust 		return;
113346c0ee8bSChuck Lever 
113482476d9fSChuck Lever 	trace_xprt_timer(xprt, req->rq_xid, task->tk_status);
1135dd2b63d0SRicardo Labiaga 	if (!req->rq_reply_bytes_recvd) {
113646c0ee8bSChuck Lever 		if (xprt->ops->timer)
11376a24dfb6STrond Myklebust 			xprt->ops->timer(xprt, task);
11385d00837bSTrond Myklebust 	} else
11395d00837bSTrond Myklebust 		task->tk_status = 0;
11401da177e4SLinus Torvalds }
11411da177e4SLinus Torvalds 
11429903cd1cSChuck Lever /**
11437f3a1d1eSTrond Myklebust  * xprt_request_wait_receive - wait for the reply to an RPC request
11447f3a1d1eSTrond Myklebust  * @task: RPC task about to send a request
11457f3a1d1eSTrond Myklebust  *
11467f3a1d1eSTrond Myklebust  */
11477f3a1d1eSTrond Myklebust void xprt_request_wait_receive(struct rpc_task *task)
11487f3a1d1eSTrond Myklebust {
11497f3a1d1eSTrond Myklebust 	struct rpc_rqst *req = task->tk_rqstp;
11507f3a1d1eSTrond Myklebust 	struct rpc_xprt *xprt = req->rq_xprt;
11517f3a1d1eSTrond Myklebust 
11527f3a1d1eSTrond Myklebust 	if (!test_bit(RPC_TASK_NEED_RECV, &task->tk_runstate))
11537f3a1d1eSTrond Myklebust 		return;
11547f3a1d1eSTrond Myklebust 	/*
11557f3a1d1eSTrond Myklebust 	 * Sleep on the pending queue if we're expecting a reply.
11567f3a1d1eSTrond Myklebust 	 * The spinlock ensures atomicity between the test of
11577f3a1d1eSTrond Myklebust 	 * req->rq_reply_bytes_recvd, and the call to rpc_sleep_on().
11587f3a1d1eSTrond Myklebust 	 */
11597f3a1d1eSTrond Myklebust 	spin_lock(&xprt->queue_lock);
11607f3a1d1eSTrond Myklebust 	if (test_bit(RPC_TASK_NEED_RECV, &task->tk_runstate)) {
11617f3a1d1eSTrond Myklebust 		xprt->ops->set_retrans_timeout(task);
11627f3a1d1eSTrond Myklebust 		rpc_sleep_on(&xprt->pending, task, xprt_timer);
11637f3a1d1eSTrond Myklebust 		/*
11647f3a1d1eSTrond Myklebust 		 * Send an extra queue wakeup call if the
11657f3a1d1eSTrond Myklebust 		 * connection was dropped in case the call to
11667f3a1d1eSTrond Myklebust 		 * rpc_sleep_on() raced.
11677f3a1d1eSTrond Myklebust 		 */
11687f3a1d1eSTrond Myklebust 		if (xprt_request_retransmit_after_disconnect(task))
11697f3a1d1eSTrond Myklebust 			rpc_wake_up_queued_task_set_status(&xprt->pending,
11707f3a1d1eSTrond Myklebust 					task, -ENOTCONN);
11717f3a1d1eSTrond Myklebust 	}
11727f3a1d1eSTrond Myklebust 	spin_unlock(&xprt->queue_lock);
11737f3a1d1eSTrond Myklebust }
11747f3a1d1eSTrond Myklebust 
1175944b0429STrond Myklebust static bool
1176944b0429STrond Myklebust xprt_request_need_enqueue_transmit(struct rpc_task *task, struct rpc_rqst *req)
1177944b0429STrond Myklebust {
1178762e4e67STrond Myklebust 	return !test_bit(RPC_TASK_NEED_XMIT, &task->tk_runstate);
1179944b0429STrond Myklebust }
1180944b0429STrond Myklebust 
1181944b0429STrond Myklebust /**
1182944b0429STrond Myklebust  * xprt_request_enqueue_transmit - queue a task for transmission
1183944b0429STrond Myklebust  * @task: pointer to rpc_task
1184944b0429STrond Myklebust  *
1185944b0429STrond Myklebust  * Add a task to the transmission queue.
1186944b0429STrond Myklebust  */
1187944b0429STrond Myklebust void
1188944b0429STrond Myklebust xprt_request_enqueue_transmit(struct rpc_task *task)
1189944b0429STrond Myklebust {
1190918f3c1fSTrond Myklebust 	struct rpc_rqst *pos, *req = task->tk_rqstp;
1191944b0429STrond Myklebust 	struct rpc_xprt *xprt = req->rq_xprt;
1192944b0429STrond Myklebust 
1193944b0429STrond Myklebust 	if (xprt_request_need_enqueue_transmit(task, req)) {
1194944b0429STrond Myklebust 		spin_lock(&xprt->queue_lock);
119575891f50STrond Myklebust 		/*
119675891f50STrond Myklebust 		 * Requests that carry congestion control credits are added
119775891f50STrond Myklebust 		 * to the head of the list to avoid starvation issues.
119875891f50STrond Myklebust 		 */
119975891f50STrond Myklebust 		if (req->rq_cong) {
120075891f50STrond Myklebust 			xprt_clear_congestion_window_wait(xprt);
120175891f50STrond Myklebust 			list_for_each_entry(pos, &xprt->xmit_queue, rq_xmit) {
120275891f50STrond Myklebust 				if (pos->rq_cong)
120375891f50STrond Myklebust 					continue;
120475891f50STrond Myklebust 				/* Note: req is added _before_ pos */
120575891f50STrond Myklebust 				list_add_tail(&req->rq_xmit, &pos->rq_xmit);
120675891f50STrond Myklebust 				INIT_LIST_HEAD(&req->rq_xmit2);
120775891f50STrond Myklebust 				goto out;
120875891f50STrond Myklebust 			}
120986aeee0eSTrond Myklebust 		} else if (RPC_IS_SWAPPER(task)) {
121086aeee0eSTrond Myklebust 			list_for_each_entry(pos, &xprt->xmit_queue, rq_xmit) {
121186aeee0eSTrond Myklebust 				if (pos->rq_cong || pos->rq_bytes_sent)
121286aeee0eSTrond Myklebust 					continue;
121386aeee0eSTrond Myklebust 				if (RPC_IS_SWAPPER(pos->rq_task))
121486aeee0eSTrond Myklebust 					continue;
121586aeee0eSTrond Myklebust 				/* Note: req is added _before_ pos */
121686aeee0eSTrond Myklebust 				list_add_tail(&req->rq_xmit, &pos->rq_xmit);
121786aeee0eSTrond Myklebust 				INIT_LIST_HEAD(&req->rq_xmit2);
121886aeee0eSTrond Myklebust 				goto out;
121986aeee0eSTrond Myklebust 			}
122075891f50STrond Myklebust 		} else {
1221918f3c1fSTrond Myklebust 			list_for_each_entry(pos, &xprt->xmit_queue, rq_xmit) {
1222918f3c1fSTrond Myklebust 				if (pos->rq_task->tk_owner != task->tk_owner)
1223918f3c1fSTrond Myklebust 					continue;
1224918f3c1fSTrond Myklebust 				list_add_tail(&req->rq_xmit2, &pos->rq_xmit2);
1225918f3c1fSTrond Myklebust 				INIT_LIST_HEAD(&req->rq_xmit);
1226918f3c1fSTrond Myklebust 				goto out;
1227918f3c1fSTrond Myklebust 			}
122875891f50STrond Myklebust 		}
1229944b0429STrond Myklebust 		list_add_tail(&req->rq_xmit, &xprt->xmit_queue);
1230918f3c1fSTrond Myklebust 		INIT_LIST_HEAD(&req->rq_xmit2);
1231918f3c1fSTrond Myklebust out:
1232944b0429STrond Myklebust 		set_bit(RPC_TASK_NEED_XMIT, &task->tk_runstate);
1233944b0429STrond Myklebust 		spin_unlock(&xprt->queue_lock);
1234944b0429STrond Myklebust 	}
1235944b0429STrond Myklebust }
1236944b0429STrond Myklebust 
1237944b0429STrond Myklebust /**
1238944b0429STrond Myklebust  * xprt_request_dequeue_transmit_locked - remove a task from the transmission queue
1239944b0429STrond Myklebust  * @task: pointer to rpc_task
1240944b0429STrond Myklebust  *
1241944b0429STrond Myklebust  * Remove a task from the transmission queue
1242944b0429STrond Myklebust  * Caller must hold xprt->queue_lock
1243944b0429STrond Myklebust  */
1244944b0429STrond Myklebust static void
1245944b0429STrond Myklebust xprt_request_dequeue_transmit_locked(struct rpc_task *task)
1246944b0429STrond Myklebust {
1247918f3c1fSTrond Myklebust 	struct rpc_rqst *req = task->tk_rqstp;
1248918f3c1fSTrond Myklebust 
1249918f3c1fSTrond Myklebust 	if (!test_and_clear_bit(RPC_TASK_NEED_XMIT, &task->tk_runstate))
1250918f3c1fSTrond Myklebust 		return;
1251918f3c1fSTrond Myklebust 	if (!list_empty(&req->rq_xmit)) {
1252918f3c1fSTrond Myklebust 		list_del(&req->rq_xmit);
1253918f3c1fSTrond Myklebust 		if (!list_empty(&req->rq_xmit2)) {
1254918f3c1fSTrond Myklebust 			struct rpc_rqst *next = list_first_entry(&req->rq_xmit2,
1255918f3c1fSTrond Myklebust 					struct rpc_rqst, rq_xmit2);
1256918f3c1fSTrond Myklebust 			list_del(&req->rq_xmit2);
1257918f3c1fSTrond Myklebust 			list_add_tail(&next->rq_xmit, &next->rq_xprt->xmit_queue);
1258918f3c1fSTrond Myklebust 		}
1259918f3c1fSTrond Myklebust 	} else
1260918f3c1fSTrond Myklebust 		list_del(&req->rq_xmit2);
1261944b0429STrond Myklebust }
1262944b0429STrond Myklebust 
1263944b0429STrond Myklebust /**
1264944b0429STrond Myklebust  * xprt_request_dequeue_transmit - remove a task from the transmission queue
1265944b0429STrond Myklebust  * @task: pointer to rpc_task
1266944b0429STrond Myklebust  *
1267944b0429STrond Myklebust  * Remove a task from the transmission queue
1268944b0429STrond Myklebust  */
1269944b0429STrond Myklebust static void
1270944b0429STrond Myklebust xprt_request_dequeue_transmit(struct rpc_task *task)
1271944b0429STrond Myklebust {
1272944b0429STrond Myklebust 	struct rpc_rqst *req = task->tk_rqstp;
1273944b0429STrond Myklebust 	struct rpc_xprt *xprt = req->rq_xprt;
1274944b0429STrond Myklebust 
1275944b0429STrond Myklebust 	spin_lock(&xprt->queue_lock);
1276944b0429STrond Myklebust 	xprt_request_dequeue_transmit_locked(task);
1277944b0429STrond Myklebust 	spin_unlock(&xprt->queue_lock);
1278944b0429STrond Myklebust }
1279944b0429STrond Myklebust 
12807f3a1d1eSTrond Myklebust /**
1281762e4e67STrond Myklebust  * xprt_request_need_retransmit - Test if a task needs retransmission
1282762e4e67STrond Myklebust  * @task: pointer to rpc_task
1283762e4e67STrond Myklebust  *
1284762e4e67STrond Myklebust  * Test for whether a connection breakage requires the task to retransmit
1285762e4e67STrond Myklebust  */
1286762e4e67STrond Myklebust bool
1287762e4e67STrond Myklebust xprt_request_need_retransmit(struct rpc_task *task)
1288762e4e67STrond Myklebust {
1289762e4e67STrond Myklebust 	return xprt_request_retransmit_after_disconnect(task);
1290762e4e67STrond Myklebust }
1291762e4e67STrond Myklebust 
1292762e4e67STrond Myklebust /**
12939903cd1cSChuck Lever  * xprt_prepare_transmit - reserve the transport before sending a request
12949903cd1cSChuck Lever  * @task: RPC task about to send a request
12959903cd1cSChuck Lever  *
12961da177e4SLinus Torvalds  */
129790051ea7STrond Myklebust bool xprt_prepare_transmit(struct rpc_task *task)
12981da177e4SLinus Torvalds {
12991da177e4SLinus Torvalds 	struct rpc_rqst	*req = task->tk_rqstp;
13001da177e4SLinus Torvalds 	struct rpc_xprt	*xprt = req->rq_xprt;
13011da177e4SLinus Torvalds 
130246121cf7SChuck Lever 	dprintk("RPC: %5u xprt_prepare_transmit\n", task->tk_pid);
13031da177e4SLinus Torvalds 
13045f2f6bd9STrond Myklebust 	if (!xprt_lock_write(xprt, task)) {
13055f2f6bd9STrond Myklebust 		/* Race breaker: someone may have transmitted us */
1306944b0429STrond Myklebust 		if (!test_bit(RPC_TASK_NEED_XMIT, &task->tk_runstate))
13075f2f6bd9STrond Myklebust 			rpc_wake_up_queued_task_set_status(&xprt->sending,
13085f2f6bd9STrond Myklebust 					task, 0);
13095f2f6bd9STrond Myklebust 		return false;
13105f2f6bd9STrond Myklebust 
13118a19a0b6STrond Myklebust 	}
13125f2f6bd9STrond Myklebust 	return true;
13131da177e4SLinus Torvalds }
13141da177e4SLinus Torvalds 
1315e0ab53deSTrond Myklebust void xprt_end_transmit(struct rpc_task *task)
13165e5ce5beSTrond Myklebust {
1317343952faSRahul Iyer 	xprt_release_write(task->tk_rqstp->rq_xprt, task);
13185e5ce5beSTrond Myklebust }
13195e5ce5beSTrond Myklebust 
13209903cd1cSChuck Lever /**
132189f90fe1STrond Myklebust  * xprt_request_transmit - send an RPC request on a transport
132289f90fe1STrond Myklebust  * @req: pointer to request to transmit
132389f90fe1STrond Myklebust  * @snd_task: RPC task that owns the transport lock
13249903cd1cSChuck Lever  *
132589f90fe1STrond Myklebust  * This performs the transmission of a single request.
132689f90fe1STrond Myklebust  * Note that if the request is not the same as snd_task, then it
132789f90fe1STrond Myklebust  * does need to be pinned.
132889f90fe1STrond Myklebust  * Returns '0' on success.
13299903cd1cSChuck Lever  */
133089f90fe1STrond Myklebust static int
133189f90fe1STrond Myklebust xprt_request_transmit(struct rpc_rqst *req, struct rpc_task *snd_task)
13321da177e4SLinus Torvalds {
13331da177e4SLinus Torvalds 	struct rpc_xprt *xprt = req->rq_xprt;
133489f90fe1STrond Myklebust 	struct rpc_task *task = req->rq_task;
133590d91b0cSTrond Myklebust 	unsigned int connect_cookie;
1336dcbbeda8STrond Myklebust 	int is_retrans = RPC_WAS_SENT(task);
1337ff699ea8SChuck Lever 	int status;
13381da177e4SLinus Torvalds 
133946121cf7SChuck Lever 	dprintk("RPC: %5u xprt_transmit(%u)\n", task->tk_pid, req->rq_slen);
13401da177e4SLinus Torvalds 
1341edc81dcdSTrond Myklebust 	if (!req->rq_bytes_sent) {
134289f90fe1STrond Myklebust 		if (xprt_request_data_received(task)) {
134389f90fe1STrond Myklebust 			status = 0;
1344944b0429STrond Myklebust 			goto out_dequeue;
134589f90fe1STrond Myklebust 		}
13463021a5bbSTrond Myklebust 		/* Verify that our message lies in the RPCSEC_GSS window */
1347edc81dcdSTrond Myklebust 		if (rpcauth_xmit_need_reencode(task)) {
134889f90fe1STrond Myklebust 			status = -EBADMSG;
1349944b0429STrond Myklebust 			goto out_dequeue;
13503021a5bbSTrond Myklebust 		}
13511da177e4SLinus Torvalds 	}
13521da177e4SLinus Torvalds 
1353dcbbeda8STrond Myklebust 	/*
1354dcbbeda8STrond Myklebust 	 * Update req->rq_ntrans before transmitting to avoid races with
1355dcbbeda8STrond Myklebust 	 * xprt_update_rtt(), which needs to know that it is recording a
1356dcbbeda8STrond Myklebust 	 * reply to the first transmission.
1357dcbbeda8STrond Myklebust 	 */
1358dcbbeda8STrond Myklebust 	req->rq_ntrans++;
1359dcbbeda8STrond Myklebust 
136090d91b0cSTrond Myklebust 	connect_cookie = xprt->connect_cookie;
1361adfa7144STrond Myklebust 	status = xprt->ops->send_request(req);
13623705ad64SJeff Layton 	trace_xprt_transmit(xprt, req->rq_xid, status);
1363c8485e4dSTrond Myklebust 	if (status != 0) {
1364dcbbeda8STrond Myklebust 		req->rq_ntrans--;
136589f90fe1STrond Myklebust 		return status;
1366c8485e4dSTrond Myklebust 	}
13677ebbbc6eSTrond Myklebust 
1368dcbbeda8STrond Myklebust 	if (is_retrans)
1369dcbbeda8STrond Myklebust 		task->tk_client->cl_stats->rpcretrans++;
1370dcbbeda8STrond Myklebust 
13714a068258SChuck Lever 	xprt_inject_disconnect(xprt);
1372c8485e4dSTrond Myklebust 
137346121cf7SChuck Lever 	dprintk("RPC: %5u xmit complete\n", task->tk_pid);
1374468f8613SBryan Schumaker 	task->tk_flags |= RPC_TASK_SENT;
1375fe3aca29SChuck Lever 	spin_lock_bh(&xprt->transport_lock);
1376262ca07dSChuck Lever 
1377262ca07dSChuck Lever 	xprt->stat.sends++;
1378262ca07dSChuck Lever 	xprt->stat.req_u += xprt->stat.sends - xprt->stat.recvs;
1379262ca07dSChuck Lever 	xprt->stat.bklog_u += xprt->backlog.qlen;
138015a45206SAndy Adamson 	xprt->stat.sending_u += xprt->sending.qlen;
138115a45206SAndy Adamson 	xprt->stat.pending_u += xprt->pending.qlen;
1382fe3aca29SChuck Lever 	spin_unlock_bh(&xprt->transport_lock);
138390d91b0cSTrond Myklebust 
138490d91b0cSTrond Myklebust 	req->rq_connect_cookie = connect_cookie;
1385944b0429STrond Myklebust out_dequeue:
1386944b0429STrond Myklebust 	xprt_request_dequeue_transmit(task);
138789f90fe1STrond Myklebust 	rpc_wake_up_queued_task_set_status(&xprt->sending, task, status);
138889f90fe1STrond Myklebust 	return status;
138989f90fe1STrond Myklebust }
139089f90fe1STrond Myklebust 
139189f90fe1STrond Myklebust /**
139289f90fe1STrond Myklebust  * xprt_transmit - send an RPC request on a transport
139389f90fe1STrond Myklebust  * @task: controlling RPC task
139489f90fe1STrond Myklebust  *
139589f90fe1STrond Myklebust  * Attempts to drain the transmit queue. On exit, either the transport
139689f90fe1STrond Myklebust  * signalled an error that needs to be handled before transmission can
139789f90fe1STrond Myklebust  * resume, or @task finished transmitting, and detected that it already
139889f90fe1STrond Myklebust  * received a reply.
139989f90fe1STrond Myklebust  */
140089f90fe1STrond Myklebust void
140189f90fe1STrond Myklebust xprt_transmit(struct rpc_task *task)
140289f90fe1STrond Myklebust {
140389f90fe1STrond Myklebust 	struct rpc_rqst *next, *req = task->tk_rqstp;
140489f90fe1STrond Myklebust 	struct rpc_xprt	*xprt = req->rq_xprt;
140589f90fe1STrond Myklebust 	int status;
140689f90fe1STrond Myklebust 
140789f90fe1STrond Myklebust 	spin_lock(&xprt->queue_lock);
140889f90fe1STrond Myklebust 	while (!list_empty(&xprt->xmit_queue)) {
140989f90fe1STrond Myklebust 		next = list_first_entry(&xprt->xmit_queue,
141089f90fe1STrond Myklebust 				struct rpc_rqst, rq_xmit);
141189f90fe1STrond Myklebust 		xprt_pin_rqst(next);
141289f90fe1STrond Myklebust 		spin_unlock(&xprt->queue_lock);
141389f90fe1STrond Myklebust 		status = xprt_request_transmit(next, task);
141489f90fe1STrond Myklebust 		if (status == -EBADMSG && next != req)
141589f90fe1STrond Myklebust 			status = 0;
141689f90fe1STrond Myklebust 		cond_resched();
141789f90fe1STrond Myklebust 		spin_lock(&xprt->queue_lock);
141889f90fe1STrond Myklebust 		xprt_unpin_rqst(next);
141989f90fe1STrond Myklebust 		if (status == 0) {
142089f90fe1STrond Myklebust 			if (!xprt_request_data_received(task) ||
142189f90fe1STrond Myklebust 			    test_bit(RPC_TASK_NEED_XMIT, &task->tk_runstate))
142289f90fe1STrond Myklebust 				continue;
1423c544577dSTrond Myklebust 		} else if (test_bit(RPC_TASK_NEED_XMIT, &task->tk_runstate))
142489f90fe1STrond Myklebust 			task->tk_status = status;
142589f90fe1STrond Myklebust 		break;
142689f90fe1STrond Myklebust 	}
142789f90fe1STrond Myklebust 	spin_unlock(&xprt->queue_lock);
14281da177e4SLinus Torvalds }
14291da177e4SLinus Torvalds 
1430ba60eb25STrond Myklebust static void xprt_add_backlog(struct rpc_xprt *xprt, struct rpc_task *task)
1431ba60eb25STrond Myklebust {
1432ba60eb25STrond Myklebust 	set_bit(XPRT_CONGESTED, &xprt->state);
1433ba60eb25STrond Myklebust 	rpc_sleep_on(&xprt->backlog, task, NULL);
1434ba60eb25STrond Myklebust }
1435ba60eb25STrond Myklebust 
1436ba60eb25STrond Myklebust static void xprt_wake_up_backlog(struct rpc_xprt *xprt)
1437ba60eb25STrond Myklebust {
1438ba60eb25STrond Myklebust 	if (rpc_wake_up_next(&xprt->backlog) == NULL)
1439ba60eb25STrond Myklebust 		clear_bit(XPRT_CONGESTED, &xprt->state);
1440ba60eb25STrond Myklebust }
1441ba60eb25STrond Myklebust 
1442ba60eb25STrond Myklebust static bool xprt_throttle_congested(struct rpc_xprt *xprt, struct rpc_task *task)
1443ba60eb25STrond Myklebust {
1444ba60eb25STrond Myklebust 	bool ret = false;
1445ba60eb25STrond Myklebust 
1446ba60eb25STrond Myklebust 	if (!test_bit(XPRT_CONGESTED, &xprt->state))
1447ba60eb25STrond Myklebust 		goto out;
1448ba60eb25STrond Myklebust 	spin_lock(&xprt->reserve_lock);
1449ba60eb25STrond Myklebust 	if (test_bit(XPRT_CONGESTED, &xprt->state)) {
1450ba60eb25STrond Myklebust 		rpc_sleep_on(&xprt->backlog, task, NULL);
1451ba60eb25STrond Myklebust 		ret = true;
1452ba60eb25STrond Myklebust 	}
1453ba60eb25STrond Myklebust 	spin_unlock(&xprt->reserve_lock);
1454ba60eb25STrond Myklebust out:
1455ba60eb25STrond Myklebust 	return ret;
1456ba60eb25STrond Myklebust }
1457ba60eb25STrond Myklebust 
145892ea011fSTrond Myklebust static struct rpc_rqst *xprt_dynamic_alloc_slot(struct rpc_xprt *xprt)
1459d9ba131dSTrond Myklebust {
1460d9ba131dSTrond Myklebust 	struct rpc_rqst *req = ERR_PTR(-EAGAIN);
1461d9ba131dSTrond Myklebust 
1462ff699ea8SChuck Lever 	if (xprt->num_reqs >= xprt->max_reqs)
1463d9ba131dSTrond Myklebust 		goto out;
1464ff699ea8SChuck Lever 	++xprt->num_reqs;
146592ea011fSTrond Myklebust 	spin_unlock(&xprt->reserve_lock);
146692ea011fSTrond Myklebust 	req = kzalloc(sizeof(struct rpc_rqst), GFP_NOFS);
146792ea011fSTrond Myklebust 	spin_lock(&xprt->reserve_lock);
1468d9ba131dSTrond Myklebust 	if (req != NULL)
1469d9ba131dSTrond Myklebust 		goto out;
1470ff699ea8SChuck Lever 	--xprt->num_reqs;
1471d9ba131dSTrond Myklebust 	req = ERR_PTR(-ENOMEM);
1472d9ba131dSTrond Myklebust out:
1473d9ba131dSTrond Myklebust 	return req;
1474d9ba131dSTrond Myklebust }
1475d9ba131dSTrond Myklebust 
1476d9ba131dSTrond Myklebust static bool xprt_dynamic_free_slot(struct rpc_xprt *xprt, struct rpc_rqst *req)
1477d9ba131dSTrond Myklebust {
1478ff699ea8SChuck Lever 	if (xprt->num_reqs > xprt->min_reqs) {
1479ff699ea8SChuck Lever 		--xprt->num_reqs;
1480d9ba131dSTrond Myklebust 		kfree(req);
1481d9ba131dSTrond Myklebust 		return true;
1482d9ba131dSTrond Myklebust 	}
1483d9ba131dSTrond Myklebust 	return false;
1484d9ba131dSTrond Myklebust }
1485d9ba131dSTrond Myklebust 
1486f39c1bfbSTrond Myklebust void xprt_alloc_slot(struct rpc_xprt *xprt, struct rpc_task *task)
14871da177e4SLinus Torvalds {
1488d9ba131dSTrond Myklebust 	struct rpc_rqst *req;
14891da177e4SLinus Torvalds 
1490f39c1bfbSTrond Myklebust 	spin_lock(&xprt->reserve_lock);
14911da177e4SLinus Torvalds 	if (!list_empty(&xprt->free)) {
1492d9ba131dSTrond Myklebust 		req = list_entry(xprt->free.next, struct rpc_rqst, rq_list);
1493d9ba131dSTrond Myklebust 		list_del(&req->rq_list);
1494d9ba131dSTrond Myklebust 		goto out_init_req;
1495d9ba131dSTrond Myklebust 	}
149692ea011fSTrond Myklebust 	req = xprt_dynamic_alloc_slot(xprt);
1497d9ba131dSTrond Myklebust 	if (!IS_ERR(req))
1498d9ba131dSTrond Myklebust 		goto out_init_req;
1499d9ba131dSTrond Myklebust 	switch (PTR_ERR(req)) {
1500d9ba131dSTrond Myklebust 	case -ENOMEM:
1501d9ba131dSTrond Myklebust 		dprintk("RPC:       dynamic allocation of request slot "
1502d9ba131dSTrond Myklebust 				"failed! Retrying\n");
15031afeaf5cSTrond Myklebust 		task->tk_status = -ENOMEM;
1504d9ba131dSTrond Myklebust 		break;
1505d9ba131dSTrond Myklebust 	case -EAGAIN:
1506ba60eb25STrond Myklebust 		xprt_add_backlog(xprt, task);
1507d9ba131dSTrond Myklebust 		dprintk("RPC:       waiting for request slot\n");
1508e9d47639SGustavo A. R. Silva 		/* fall through */
15091afeaf5cSTrond Myklebust 	default:
1510d9ba131dSTrond Myklebust 		task->tk_status = -EAGAIN;
15111afeaf5cSTrond Myklebust 	}
1512f39c1bfbSTrond Myklebust 	spin_unlock(&xprt->reserve_lock);
1513d9ba131dSTrond Myklebust 	return;
1514d9ba131dSTrond Myklebust out_init_req:
1515ff699ea8SChuck Lever 	xprt->stat.max_slots = max_t(unsigned int, xprt->stat.max_slots,
1516ff699ea8SChuck Lever 				     xprt->num_reqs);
151737ac86c3SChuck Lever 	spin_unlock(&xprt->reserve_lock);
151837ac86c3SChuck Lever 
1519d9ba131dSTrond Myklebust 	task->tk_status = 0;
15201da177e4SLinus Torvalds 	task->tk_rqstp = req;
15211da177e4SLinus Torvalds }
1522f39c1bfbSTrond Myklebust EXPORT_SYMBOL_GPL(xprt_alloc_slot);
1523f39c1bfbSTrond Myklebust 
1524a9cde23aSChuck Lever void xprt_free_slot(struct rpc_xprt *xprt, struct rpc_rqst *req)
1525ee5ebe85STrond Myklebust {
1526ee5ebe85STrond Myklebust 	spin_lock(&xprt->reserve_lock);
1527c25573b5STrond Myklebust 	if (!xprt_dynamic_free_slot(xprt, req)) {
1528c25573b5STrond Myklebust 		memset(req, 0, sizeof(*req));	/* mark unused */
1529ee5ebe85STrond Myklebust 		list_add(&req->rq_list, &xprt->free);
1530c25573b5STrond Myklebust 	}
1531ba60eb25STrond Myklebust 	xprt_wake_up_backlog(xprt);
1532ee5ebe85STrond Myklebust 	spin_unlock(&xprt->reserve_lock);
1533ee5ebe85STrond Myklebust }
1534a9cde23aSChuck Lever EXPORT_SYMBOL_GPL(xprt_free_slot);
1535ee5ebe85STrond Myklebust 
153621de0a95STrond Myklebust static void xprt_free_all_slots(struct rpc_xprt *xprt)
153721de0a95STrond Myklebust {
153821de0a95STrond Myklebust 	struct rpc_rqst *req;
153921de0a95STrond Myklebust 	while (!list_empty(&xprt->free)) {
154021de0a95STrond Myklebust 		req = list_first_entry(&xprt->free, struct rpc_rqst, rq_list);
154121de0a95STrond Myklebust 		list_del(&req->rq_list);
154221de0a95STrond Myklebust 		kfree(req);
154321de0a95STrond Myklebust 	}
154421de0a95STrond Myklebust }
154521de0a95STrond Myklebust 
1546d9ba131dSTrond Myklebust struct rpc_xprt *xprt_alloc(struct net *net, size_t size,
1547d9ba131dSTrond Myklebust 		unsigned int num_prealloc,
1548d9ba131dSTrond Myklebust 		unsigned int max_alloc)
1549bd1722d4SPavel Emelyanov {
1550bd1722d4SPavel Emelyanov 	struct rpc_xprt *xprt;
155121de0a95STrond Myklebust 	struct rpc_rqst *req;
155221de0a95STrond Myklebust 	int i;
1553bd1722d4SPavel Emelyanov 
1554bd1722d4SPavel Emelyanov 	xprt = kzalloc(size, GFP_KERNEL);
1555bd1722d4SPavel Emelyanov 	if (xprt == NULL)
1556bd1722d4SPavel Emelyanov 		goto out;
1557bd1722d4SPavel Emelyanov 
155821de0a95STrond Myklebust 	xprt_init(xprt, net);
155921de0a95STrond Myklebust 
156021de0a95STrond Myklebust 	for (i = 0; i < num_prealloc; i++) {
156121de0a95STrond Myklebust 		req = kzalloc(sizeof(struct rpc_rqst), GFP_KERNEL);
156221de0a95STrond Myklebust 		if (!req)
15638313164cSwangweidong 			goto out_free;
156421de0a95STrond Myklebust 		list_add(&req->rq_list, &xprt->free);
156521de0a95STrond Myklebust 	}
1566d9ba131dSTrond Myklebust 	if (max_alloc > num_prealloc)
1567d9ba131dSTrond Myklebust 		xprt->max_reqs = max_alloc;
1568d9ba131dSTrond Myklebust 	else
156921de0a95STrond Myklebust 		xprt->max_reqs = num_prealloc;
1570d9ba131dSTrond Myklebust 	xprt->min_reqs = num_prealloc;
1571ff699ea8SChuck Lever 	xprt->num_reqs = num_prealloc;
1572bd1722d4SPavel Emelyanov 
1573bd1722d4SPavel Emelyanov 	return xprt;
1574bd1722d4SPavel Emelyanov 
1575bd1722d4SPavel Emelyanov out_free:
157621de0a95STrond Myklebust 	xprt_free(xprt);
1577bd1722d4SPavel Emelyanov out:
1578bd1722d4SPavel Emelyanov 	return NULL;
1579bd1722d4SPavel Emelyanov }
1580bd1722d4SPavel Emelyanov EXPORT_SYMBOL_GPL(xprt_alloc);
1581bd1722d4SPavel Emelyanov 
1582e204e621SPavel Emelyanov void xprt_free(struct rpc_xprt *xprt)
1583e204e621SPavel Emelyanov {
158437aa2133SPavel Emelyanov 	put_net(xprt->xprt_net);
158521de0a95STrond Myklebust 	xprt_free_all_slots(xprt);
1586fda1bfefSTrond Myklebust 	kfree_rcu(xprt, rcu);
1587e204e621SPavel Emelyanov }
1588e204e621SPavel Emelyanov EXPORT_SYMBOL_GPL(xprt_free);
1589e204e621SPavel Emelyanov 
1590902c5887STrond Myklebust static void
1591902c5887STrond Myklebust xprt_init_connect_cookie(struct rpc_rqst *req, struct rpc_xprt *xprt)
1592902c5887STrond Myklebust {
1593902c5887STrond Myklebust 	req->rq_connect_cookie = xprt_connect_cookie(xprt) - 1;
1594902c5887STrond Myklebust }
1595902c5887STrond Myklebust 
15969dc6edcfSTrond Myklebust static __be32
15979dc6edcfSTrond Myklebust xprt_alloc_xid(struct rpc_xprt *xprt)
15989dc6edcfSTrond Myklebust {
15999dc6edcfSTrond Myklebust 	__be32 xid;
16009dc6edcfSTrond Myklebust 
16019dc6edcfSTrond Myklebust 	spin_lock(&xprt->reserve_lock);
16029dc6edcfSTrond Myklebust 	xid = (__force __be32)xprt->xid++;
16039dc6edcfSTrond Myklebust 	spin_unlock(&xprt->reserve_lock);
16049dc6edcfSTrond Myklebust 	return xid;
16059dc6edcfSTrond Myklebust }
16069dc6edcfSTrond Myklebust 
16079dc6edcfSTrond Myklebust static void
16089dc6edcfSTrond Myklebust xprt_init_xid(struct rpc_xprt *xprt)
16099dc6edcfSTrond Myklebust {
16109dc6edcfSTrond Myklebust 	xprt->xid = prandom_u32();
16119dc6edcfSTrond Myklebust }
16129dc6edcfSTrond Myklebust 
16139dc6edcfSTrond Myklebust static void
16149dc6edcfSTrond Myklebust xprt_request_init(struct rpc_task *task)
16159dc6edcfSTrond Myklebust {
16169dc6edcfSTrond Myklebust 	struct rpc_xprt *xprt = task->tk_xprt;
16179dc6edcfSTrond Myklebust 	struct rpc_rqst	*req = task->tk_rqstp;
16189dc6edcfSTrond Myklebust 
16199dc6edcfSTrond Myklebust 	req->rq_timeout = task->tk_client->cl_timeout->to_initval;
16209dc6edcfSTrond Myklebust 	req->rq_task	= task;
16219dc6edcfSTrond Myklebust 	req->rq_xprt    = xprt;
16229dc6edcfSTrond Myklebust 	req->rq_buffer  = NULL;
16239dc6edcfSTrond Myklebust 	req->rq_xid	= xprt_alloc_xid(xprt);
1624902c5887STrond Myklebust 	xprt_init_connect_cookie(req, xprt);
16259dc6edcfSTrond Myklebust 	req->rq_bytes_sent = 0;
16269dc6edcfSTrond Myklebust 	req->rq_snd_buf.len = 0;
16279dc6edcfSTrond Myklebust 	req->rq_snd_buf.buflen = 0;
16289dc6edcfSTrond Myklebust 	req->rq_rcv_buf.len = 0;
16299dc6edcfSTrond Myklebust 	req->rq_rcv_buf.buflen = 0;
16309dc6edcfSTrond Myklebust 	req->rq_release_snd_buf = NULL;
16319dc6edcfSTrond Myklebust 	xprt_reset_majortimeo(req);
16329dc6edcfSTrond Myklebust 	dprintk("RPC: %5u reserved req %p xid %08x\n", task->tk_pid,
16339dc6edcfSTrond Myklebust 			req, ntohl(req->rq_xid));
16349dc6edcfSTrond Myklebust }
16359dc6edcfSTrond Myklebust 
16369dc6edcfSTrond Myklebust static void
16379dc6edcfSTrond Myklebust xprt_do_reserve(struct rpc_xprt *xprt, struct rpc_task *task)
16389dc6edcfSTrond Myklebust {
16399dc6edcfSTrond Myklebust 	xprt->ops->alloc_slot(xprt, task);
16409dc6edcfSTrond Myklebust 	if (task->tk_rqstp != NULL)
16419dc6edcfSTrond Myklebust 		xprt_request_init(task);
16429dc6edcfSTrond Myklebust }
16439dc6edcfSTrond Myklebust 
16449903cd1cSChuck Lever /**
16459903cd1cSChuck Lever  * xprt_reserve - allocate an RPC request slot
16469903cd1cSChuck Lever  * @task: RPC task requesting a slot allocation
16479903cd1cSChuck Lever  *
1648ba60eb25STrond Myklebust  * If the transport is marked as being congested, or if no more
1649ba60eb25STrond Myklebust  * slots are available, place the task on the transport's
16509903cd1cSChuck Lever  * backlog queue.
16519903cd1cSChuck Lever  */
16529903cd1cSChuck Lever void xprt_reserve(struct rpc_task *task)
16531da177e4SLinus Torvalds {
1654fb43d172STrond Myklebust 	struct rpc_xprt *xprt = task->tk_xprt;
16551da177e4SLinus Torvalds 
165643cedbf0STrond Myklebust 	task->tk_status = 0;
165743cedbf0STrond Myklebust 	if (task->tk_rqstp != NULL)
165843cedbf0STrond Myklebust 		return;
165943cedbf0STrond Myklebust 
166043cedbf0STrond Myklebust 	task->tk_timeout = 0;
166143cedbf0STrond Myklebust 	task->tk_status = -EAGAIN;
1662ba60eb25STrond Myklebust 	if (!xprt_throttle_congested(xprt, task))
16639dc6edcfSTrond Myklebust 		xprt_do_reserve(xprt, task);
1664ba60eb25STrond Myklebust }
1665ba60eb25STrond Myklebust 
1666ba60eb25STrond Myklebust /**
1667ba60eb25STrond Myklebust  * xprt_retry_reserve - allocate an RPC request slot
1668ba60eb25STrond Myklebust  * @task: RPC task requesting a slot allocation
1669ba60eb25STrond Myklebust  *
1670ba60eb25STrond Myklebust  * If no more slots are available, place the task on the transport's
1671ba60eb25STrond Myklebust  * backlog queue.
1672ba60eb25STrond Myklebust  * Note that the only difference with xprt_reserve is that we now
1673ba60eb25STrond Myklebust  * ignore the value of the XPRT_CONGESTED flag.
1674ba60eb25STrond Myklebust  */
1675ba60eb25STrond Myklebust void xprt_retry_reserve(struct rpc_task *task)
1676ba60eb25STrond Myklebust {
1677fb43d172STrond Myklebust 	struct rpc_xprt *xprt = task->tk_xprt;
1678ba60eb25STrond Myklebust 
1679ba60eb25STrond Myklebust 	task->tk_status = 0;
1680ba60eb25STrond Myklebust 	if (task->tk_rqstp != NULL)
1681ba60eb25STrond Myklebust 		return;
1682ba60eb25STrond Myklebust 
1683ba60eb25STrond Myklebust 	task->tk_timeout = 0;
1684ba60eb25STrond Myklebust 	task->tk_status = -EAGAIN;
16859dc6edcfSTrond Myklebust 	xprt_do_reserve(xprt, task);
16861da177e4SLinus Torvalds }
16871da177e4SLinus Torvalds 
1688edc81dcdSTrond Myklebust static void
1689edc81dcdSTrond Myklebust xprt_request_dequeue_all(struct rpc_task *task, struct rpc_rqst *req)
1690edc81dcdSTrond Myklebust {
1691edc81dcdSTrond Myklebust 	struct rpc_xprt *xprt = req->rq_xprt;
1692edc81dcdSTrond Myklebust 
1693944b0429STrond Myklebust 	if (test_bit(RPC_TASK_NEED_XMIT, &task->tk_runstate) ||
1694944b0429STrond Myklebust 	    test_bit(RPC_TASK_NEED_RECV, &task->tk_runstate) ||
1695edc81dcdSTrond Myklebust 	    xprt_is_pinned_rqst(req)) {
1696edc81dcdSTrond Myklebust 		spin_lock(&xprt->queue_lock);
1697944b0429STrond Myklebust 		xprt_request_dequeue_transmit_locked(task);
1698edc81dcdSTrond Myklebust 		xprt_request_dequeue_receive_locked(task);
1699edc81dcdSTrond Myklebust 		while (xprt_is_pinned_rqst(req)) {
1700edc81dcdSTrond Myklebust 			set_bit(RPC_TASK_MSG_PIN_WAIT, &task->tk_runstate);
1701edc81dcdSTrond Myklebust 			spin_unlock(&xprt->queue_lock);
1702edc81dcdSTrond Myklebust 			xprt_wait_on_pinned_rqst(req);
1703edc81dcdSTrond Myklebust 			spin_lock(&xprt->queue_lock);
1704edc81dcdSTrond Myklebust 			clear_bit(RPC_TASK_MSG_PIN_WAIT, &task->tk_runstate);
1705edc81dcdSTrond Myklebust 		}
1706edc81dcdSTrond Myklebust 		spin_unlock(&xprt->queue_lock);
1707edc81dcdSTrond Myklebust 	}
1708edc81dcdSTrond Myklebust }
1709edc81dcdSTrond Myklebust 
17109903cd1cSChuck Lever /**
17119903cd1cSChuck Lever  * xprt_release - release an RPC request slot
17129903cd1cSChuck Lever  * @task: task which is finished with the slot
17139903cd1cSChuck Lever  *
17141da177e4SLinus Torvalds  */
17159903cd1cSChuck Lever void xprt_release(struct rpc_task *task)
17161da177e4SLinus Torvalds {
171755ae1aabSRicardo Labiaga 	struct rpc_xprt	*xprt;
171887ed5003STrond Myklebust 	struct rpc_rqst	*req = task->tk_rqstp;
17191da177e4SLinus Torvalds 
172087ed5003STrond Myklebust 	if (req == NULL) {
172187ed5003STrond Myklebust 		if (task->tk_client) {
1722fb43d172STrond Myklebust 			xprt = task->tk_xprt;
172387ed5003STrond Myklebust 			xprt_release_write(xprt, task);
172487ed5003STrond Myklebust 		}
17251da177e4SLinus Torvalds 		return;
172687ed5003STrond Myklebust 	}
172755ae1aabSRicardo Labiaga 
172855ae1aabSRicardo Labiaga 	xprt = req->rq_xprt;
17290a702195SWeston Andros Adamson 	if (task->tk_ops->rpc_count_stats != NULL)
17300a702195SWeston Andros Adamson 		task->tk_ops->rpc_count_stats(task, task->tk_calldata);
17310a702195SWeston Andros Adamson 	else if (task->tk_client)
17320a702195SWeston Andros Adamson 		rpc_count_iostats(task, task->tk_client->cl_metrics);
1733edc81dcdSTrond Myklebust 	xprt_request_dequeue_all(task, req);
17344a0f8c04SChuck Lever 	spin_lock_bh(&xprt->transport_lock);
173549e9a890SChuck Lever 	xprt->ops->release_xprt(xprt, task);
1736a58dd398SChuck Lever 	if (xprt->ops->release_request)
1737a58dd398SChuck Lever 		xprt->ops->release_request(task);
17381da177e4SLinus Torvalds 	xprt->last_used = jiffies;
1739ad3331acSTrond Myklebust 	xprt_schedule_autodisconnect(xprt);
17404a0f8c04SChuck Lever 	spin_unlock_bh(&xprt->transport_lock);
1741ee5ebe85STrond Myklebust 	if (req->rq_buffer)
17423435c74aSChuck Lever 		xprt->ops->buf_free(task);
17434a068258SChuck Lever 	xprt_inject_disconnect(xprt);
1744a17c2153STrond Myklebust 	if (req->rq_cred != NULL)
1745a17c2153STrond Myklebust 		put_rpccred(req->rq_cred);
17461da177e4SLinus Torvalds 	task->tk_rqstp = NULL;
1747ead5e1c2SJ. Bruce Fields 	if (req->rq_release_snd_buf)
1748ead5e1c2SJ. Bruce Fields 		req->rq_release_snd_buf(req);
174955ae1aabSRicardo Labiaga 
175046121cf7SChuck Lever 	dprintk("RPC: %5u release request %p\n", task->tk_pid, req);
1751ee5ebe85STrond Myklebust 	if (likely(!bc_prealloc(req)))
1752a9cde23aSChuck Lever 		xprt->ops->free_slot(xprt, req);
1753ee5ebe85STrond Myklebust 	else
1754c9acb42eSTrond Myklebust 		xprt_free_bc_request(req);
17551da177e4SLinus Torvalds }
17561da177e4SLinus Torvalds 
1757902c5887STrond Myklebust #ifdef CONFIG_SUNRPC_BACKCHANNEL
1758902c5887STrond Myklebust void
1759902c5887STrond Myklebust xprt_init_bc_request(struct rpc_rqst *req, struct rpc_task *task)
1760902c5887STrond Myklebust {
1761902c5887STrond Myklebust 	struct xdr_buf *xbufp = &req->rq_snd_buf;
1762902c5887STrond Myklebust 
1763902c5887STrond Myklebust 	task->tk_rqstp = req;
1764902c5887STrond Myklebust 	req->rq_task = task;
1765902c5887STrond Myklebust 	xprt_init_connect_cookie(req, req->rq_xprt);
1766902c5887STrond Myklebust 	/*
1767902c5887STrond Myklebust 	 * Set up the xdr_buf length.
1768902c5887STrond Myklebust 	 * This also indicates that the buffer is XDR encoded already.
1769902c5887STrond Myklebust 	 */
1770902c5887STrond Myklebust 	xbufp->len = xbufp->head[0].iov_len + xbufp->page_len +
1771902c5887STrond Myklebust 		xbufp->tail[0].iov_len;
1772902c5887STrond Myklebust 	req->rq_bytes_sent = 0;
1773902c5887STrond Myklebust }
1774902c5887STrond Myklebust #endif
1775902c5887STrond Myklebust 
177621de0a95STrond Myklebust static void xprt_init(struct rpc_xprt *xprt, struct net *net)
1777c2866763SChuck Lever {
177830c5116bSTrond Myklebust 	kref_init(&xprt->kref);
1779c2866763SChuck Lever 
1780c2866763SChuck Lever 	spin_lock_init(&xprt->transport_lock);
1781c2866763SChuck Lever 	spin_lock_init(&xprt->reserve_lock);
178275c84151STrond Myklebust 	spin_lock_init(&xprt->queue_lock);
1783c2866763SChuck Lever 
1784c2866763SChuck Lever 	INIT_LIST_HEAD(&xprt->free);
178595f7691dSTrond Myklebust 	xprt->recv_queue = RB_ROOT;
1786944b0429STrond Myklebust 	INIT_LIST_HEAD(&xprt->xmit_queue);
17879e00abc3STrond Myklebust #if defined(CONFIG_SUNRPC_BACKCHANNEL)
1788f9acac1aSRicardo Labiaga 	spin_lock_init(&xprt->bc_pa_lock);
1789f9acac1aSRicardo Labiaga 	INIT_LIST_HEAD(&xprt->bc_pa_list);
17909e00abc3STrond Myklebust #endif /* CONFIG_SUNRPC_BACKCHANNEL */
179180b14d5eSTrond Myklebust 	INIT_LIST_HEAD(&xprt->xprt_switch);
1792f9acac1aSRicardo Labiaga 
1793c2866763SChuck Lever 	xprt->last_used = jiffies;
1794c2866763SChuck Lever 	xprt->cwnd = RPC_INITCWND;
1795a509050bSChuck Lever 	xprt->bind_index = 0;
1796c2866763SChuck Lever 
1797c2866763SChuck Lever 	rpc_init_wait_queue(&xprt->binding, "xprt_binding");
1798c2866763SChuck Lever 	rpc_init_wait_queue(&xprt->pending, "xprt_pending");
179934006ceeSTrond Myklebust 	rpc_init_priority_wait_queue(&xprt->sending, "xprt_sending");
1800c2866763SChuck Lever 	rpc_init_priority_wait_queue(&xprt->backlog, "xprt_backlog");
1801c2866763SChuck Lever 
1802c2866763SChuck Lever 	xprt_init_xid(xprt);
1803c2866763SChuck Lever 
180421de0a95STrond Myklebust 	xprt->xprt_net = get_net(net);
18058d9266ffSTrond Myklebust }
18068d9266ffSTrond Myklebust 
18078d9266ffSTrond Myklebust /**
18088d9266ffSTrond Myklebust  * xprt_create_transport - create an RPC transport
18098d9266ffSTrond Myklebust  * @args: rpc transport creation arguments
18108d9266ffSTrond Myklebust  *
18118d9266ffSTrond Myklebust  */
18128d9266ffSTrond Myklebust struct rpc_xprt *xprt_create_transport(struct xprt_create *args)
18138d9266ffSTrond Myklebust {
18148d9266ffSTrond Myklebust 	struct rpc_xprt	*xprt;
18158d9266ffSTrond Myklebust 	struct xprt_class *t;
18168d9266ffSTrond Myklebust 
18178d9266ffSTrond Myklebust 	spin_lock(&xprt_list_lock);
18188d9266ffSTrond Myklebust 	list_for_each_entry(t, &xprt_list, list) {
18198d9266ffSTrond Myklebust 		if (t->ident == args->ident) {
18208d9266ffSTrond Myklebust 			spin_unlock(&xprt_list_lock);
18218d9266ffSTrond Myklebust 			goto found;
18228d9266ffSTrond Myklebust 		}
18238d9266ffSTrond Myklebust 	}
18248d9266ffSTrond Myklebust 	spin_unlock(&xprt_list_lock);
18253c45ddf8SChuck Lever 	dprintk("RPC: transport (%d) not supported\n", args->ident);
18268d9266ffSTrond Myklebust 	return ERR_PTR(-EIO);
18278d9266ffSTrond Myklebust 
18288d9266ffSTrond Myklebust found:
18298d9266ffSTrond Myklebust 	xprt = t->setup(args);
18308d9266ffSTrond Myklebust 	if (IS_ERR(xprt)) {
18318d9266ffSTrond Myklebust 		dprintk("RPC:       xprt_create_transport: failed, %ld\n",
18328d9266ffSTrond Myklebust 				-PTR_ERR(xprt));
183321de0a95STrond Myklebust 		goto out;
18348d9266ffSTrond Myklebust 	}
183533d90ac0SJ. Bruce Fields 	if (args->flags & XPRT_CREATE_NO_IDLE_TIMEOUT)
183633d90ac0SJ. Bruce Fields 		xprt->idle_timeout = 0;
183721de0a95STrond Myklebust 	INIT_WORK(&xprt->task_cleanup, xprt_autoclose);
183821de0a95STrond Myklebust 	if (xprt_has_timer(xprt))
1839ff861c4dSKees Cook 		timer_setup(&xprt->timer, xprt_init_autodisconnect, 0);
184021de0a95STrond Myklebust 	else
1841ff861c4dSKees Cook 		timer_setup(&xprt->timer, NULL, 0);
18424e0038b6STrond Myklebust 
18434e0038b6STrond Myklebust 	if (strlen(args->servername) > RPC_MAXNETNAMELEN) {
18444e0038b6STrond Myklebust 		xprt_destroy(xprt);
18454e0038b6STrond Myklebust 		return ERR_PTR(-EINVAL);
18464e0038b6STrond Myklebust 	}
18474e0038b6STrond Myklebust 	xprt->servername = kstrdup(args->servername, GFP_KERNEL);
18484e0038b6STrond Myklebust 	if (xprt->servername == NULL) {
18494e0038b6STrond Myklebust 		xprt_destroy(xprt);
18504e0038b6STrond Myklebust 		return ERR_PTR(-ENOMEM);
18514e0038b6STrond Myklebust 	}
18524e0038b6STrond Myklebust 
18533f940098SJeff Layton 	rpc_xprt_debugfs_register(xprt);
1854388f0c77SJeff Layton 
1855c2866763SChuck Lever 	dprintk("RPC:       created transport %p with %u slots\n", xprt,
1856c2866763SChuck Lever 			xprt->max_reqs);
185721de0a95STrond Myklebust out:
1858c2866763SChuck Lever 	return xprt;
1859c2866763SChuck Lever }
1860c2866763SChuck Lever 
1861528fd354STrond Myklebust static void xprt_destroy_cb(struct work_struct *work)
1862528fd354STrond Myklebust {
1863528fd354STrond Myklebust 	struct rpc_xprt *xprt =
1864528fd354STrond Myklebust 		container_of(work, struct rpc_xprt, task_cleanup);
1865528fd354STrond Myklebust 
1866528fd354STrond Myklebust 	rpc_xprt_debugfs_unregister(xprt);
1867528fd354STrond Myklebust 	rpc_destroy_wait_queue(&xprt->binding);
1868528fd354STrond Myklebust 	rpc_destroy_wait_queue(&xprt->pending);
1869528fd354STrond Myklebust 	rpc_destroy_wait_queue(&xprt->sending);
1870528fd354STrond Myklebust 	rpc_destroy_wait_queue(&xprt->backlog);
1871528fd354STrond Myklebust 	kfree(xprt->servername);
1872528fd354STrond Myklebust 	/*
1873528fd354STrond Myklebust 	 * Tear down transport state and free the rpc_xprt
1874528fd354STrond Myklebust 	 */
1875528fd354STrond Myklebust 	xprt->ops->destroy(xprt);
1876528fd354STrond Myklebust }
1877528fd354STrond Myklebust 
18789903cd1cSChuck Lever /**
18799903cd1cSChuck Lever  * xprt_destroy - destroy an RPC transport, killing off all requests.
1880a8de240aSTrond Myklebust  * @xprt: transport to destroy
18819903cd1cSChuck Lever  *
18821da177e4SLinus Torvalds  */
1883a8de240aSTrond Myklebust static void xprt_destroy(struct rpc_xprt *xprt)
18841da177e4SLinus Torvalds {
18851da177e4SLinus Torvalds 	dprintk("RPC:       destroying transport %p\n", xprt);
188679234c3dSTrond Myklebust 
1887528fd354STrond Myklebust 	/*
1888528fd354STrond Myklebust 	 * Exclude transport connect/disconnect handlers and autoclose
1889528fd354STrond Myklebust 	 */
189079234c3dSTrond Myklebust 	wait_on_bit_lock(&xprt->state, XPRT_LOCKED, TASK_UNINTERRUPTIBLE);
189179234c3dSTrond Myklebust 
18920065db32STrond Myklebust 	del_timer_sync(&xprt->timer);
1893c8541ecdSChuck Lever 
1894c8541ecdSChuck Lever 	/*
1895528fd354STrond Myklebust 	 * Destroy sockets etc from the system workqueue so they can
1896528fd354STrond Myklebust 	 * safely flush receive work running on rpciod.
1897c8541ecdSChuck Lever 	 */
1898528fd354STrond Myklebust 	INIT_WORK(&xprt->task_cleanup, xprt_destroy_cb);
1899528fd354STrond Myklebust 	schedule_work(&xprt->task_cleanup);
19006b6ca86bSTrond Myklebust }
19011da177e4SLinus Torvalds 
190230c5116bSTrond Myklebust static void xprt_destroy_kref(struct kref *kref)
190330c5116bSTrond Myklebust {
190430c5116bSTrond Myklebust 	xprt_destroy(container_of(kref, struct rpc_xprt, kref));
190530c5116bSTrond Myklebust }
190630c5116bSTrond Myklebust 
190730c5116bSTrond Myklebust /**
190830c5116bSTrond Myklebust  * xprt_get - return a reference to an RPC transport.
190930c5116bSTrond Myklebust  * @xprt: pointer to the transport
191030c5116bSTrond Myklebust  *
191130c5116bSTrond Myklebust  */
191230c5116bSTrond Myklebust struct rpc_xprt *xprt_get(struct rpc_xprt *xprt)
191330c5116bSTrond Myklebust {
191430c5116bSTrond Myklebust 	if (xprt != NULL && kref_get_unless_zero(&xprt->kref))
191530c5116bSTrond Myklebust 		return xprt;
191630c5116bSTrond Myklebust 	return NULL;
191730c5116bSTrond Myklebust }
191830c5116bSTrond Myklebust EXPORT_SYMBOL_GPL(xprt_get);
191930c5116bSTrond Myklebust 
19206b6ca86bSTrond Myklebust /**
19216b6ca86bSTrond Myklebust  * xprt_put - release a reference to an RPC transport.
19226b6ca86bSTrond Myklebust  * @xprt: pointer to the transport
19236b6ca86bSTrond Myklebust  *
19246b6ca86bSTrond Myklebust  */
19256b6ca86bSTrond Myklebust void xprt_put(struct rpc_xprt *xprt)
19266b6ca86bSTrond Myklebust {
192730c5116bSTrond Myklebust 	if (xprt != NULL)
192830c5116bSTrond Myklebust 		kref_put(&xprt->kref, xprt_destroy_kref);
19296b6ca86bSTrond Myklebust }
19305d252f90SChuck Lever EXPORT_SYMBOL_GPL(xprt_put);
1931