162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *  linux/net/sunrpc/xprt.c
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci *  This is a generic RPC call interface supporting congestion avoidance,
662306a36Sopenharmony_ci *  and asynchronous calls.
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci *  The interface works like this:
962306a36Sopenharmony_ci *
1062306a36Sopenharmony_ci *  -	When a process places a call, it allocates a request slot if
1162306a36Sopenharmony_ci *	one is available. Otherwise, it sleeps on the backlog queue
1262306a36Sopenharmony_ci *	(xprt_reserve).
1362306a36Sopenharmony_ci *  -	Next, the caller puts together the RPC message, stuffs it into
1462306a36Sopenharmony_ci *	the request struct, and calls xprt_transmit().
1562306a36Sopenharmony_ci *  -	xprt_transmit sends the message and installs the caller on the
1662306a36Sopenharmony_ci *	transport's wait list. At the same time, if a reply is expected,
1762306a36Sopenharmony_ci *	it installs a timer that is run after the packet's timeout has
1862306a36Sopenharmony_ci *	expired.
1962306a36Sopenharmony_ci *  -	When a packet arrives, the data_ready handler walks the list of
2062306a36Sopenharmony_ci *	pending requests for that transport. If a matching XID is found, the
2162306a36Sopenharmony_ci *	caller is woken up, and the timer removed.
2262306a36Sopenharmony_ci *  -	When no reply arrives within the timeout interval, the timer is
2362306a36Sopenharmony_ci *	fired by the kernel and runs xprt_timer(). It either adjusts the
2462306a36Sopenharmony_ci *	timeout values (minor timeout) or wakes up the caller with a status
2562306a36Sopenharmony_ci *	of -ETIMEDOUT.
2662306a36Sopenharmony_ci *  -	When the caller receives a notification from RPC that a reply arrived,
2762306a36Sopenharmony_ci *	it should release the RPC slot, and process the reply.
2862306a36Sopenharmony_ci *	If the call timed out, it may choose to retry the operation by
2962306a36Sopenharmony_ci *	adjusting the initial timeout value, and simply calling rpc_call
3062306a36Sopenharmony_ci *	again.
3162306a36Sopenharmony_ci *
3262306a36Sopenharmony_ci *  Support for async RPC is done through a set of RPC-specific scheduling
3362306a36Sopenharmony_ci *  primitives that `transparently' work for processes as well as async
3462306a36Sopenharmony_ci *  tasks that rely on callbacks.
3562306a36Sopenharmony_ci *
3662306a36Sopenharmony_ci *  Copyright (C) 1995-1997, Olaf Kirch <okir@monad.swb.de>
3762306a36Sopenharmony_ci *
3862306a36Sopenharmony_ci *  Transport switch API copyright (C) 2005, Chuck Lever <cel@netapp.com>
3962306a36Sopenharmony_ci */
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci#include <linux/module.h>
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci#include <linux/types.h>
4462306a36Sopenharmony_ci#include <linux/interrupt.h>
4562306a36Sopenharmony_ci#include <linux/workqueue.h>
4662306a36Sopenharmony_ci#include <linux/net.h>
4762306a36Sopenharmony_ci#include <linux/ktime.h>
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci#include <linux/sunrpc/clnt.h>
5062306a36Sopenharmony_ci#include <linux/sunrpc/metrics.h>
5162306a36Sopenharmony_ci#include <linux/sunrpc/bc_xprt.h>
5262306a36Sopenharmony_ci#include <linux/rcupdate.h>
5362306a36Sopenharmony_ci#include <linux/sched/mm.h>
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci#include <trace/events/sunrpc.h>
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci#include "sunrpc.h"
5862306a36Sopenharmony_ci#include "sysfs.h"
5962306a36Sopenharmony_ci#include "fail.h"
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci/*
6262306a36Sopenharmony_ci * Local variables
6362306a36Sopenharmony_ci */
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
6662306a36Sopenharmony_ci# define RPCDBG_FACILITY	RPCDBG_XPRT
6762306a36Sopenharmony_ci#endif
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci/*
7062306a36Sopenharmony_ci * Local functions
7162306a36Sopenharmony_ci */
7262306a36Sopenharmony_cistatic void	xprt_init(struct rpc_xprt *xprt, struct net *net);
7362306a36Sopenharmony_cistatic __be32	xprt_alloc_xid(struct rpc_xprt *xprt);
7462306a36Sopenharmony_cistatic void	xprt_destroy(struct rpc_xprt *xprt);
7562306a36Sopenharmony_cistatic void	xprt_request_init(struct rpc_task *task);
7662306a36Sopenharmony_cistatic int	xprt_request_prepare(struct rpc_rqst *req, struct xdr_buf *buf);
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_cistatic DEFINE_SPINLOCK(xprt_list_lock);
7962306a36Sopenharmony_cistatic LIST_HEAD(xprt_list);
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_cistatic unsigned long xprt_request_timeout(const struct rpc_rqst *req)
8262306a36Sopenharmony_ci{
8362306a36Sopenharmony_ci	unsigned long timeout = jiffies + req->rq_timeout;
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	if (time_before(timeout, req->rq_majortimeo))
8662306a36Sopenharmony_ci		return timeout;
8762306a36Sopenharmony_ci	return req->rq_majortimeo;
8862306a36Sopenharmony_ci}
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci/**
9162306a36Sopenharmony_ci * xprt_register_transport - register a transport implementation
9262306a36Sopenharmony_ci * @transport: transport to register
9362306a36Sopenharmony_ci *
9462306a36Sopenharmony_ci * If a transport implementation is loaded as a kernel module, it can
9562306a36Sopenharmony_ci * call this interface to make itself known to the RPC client.
9662306a36Sopenharmony_ci *
9762306a36Sopenharmony_ci * Returns:
9862306a36Sopenharmony_ci * 0:		transport successfully registered
9962306a36Sopenharmony_ci * -EEXIST:	transport already registered
10062306a36Sopenharmony_ci * -EINVAL:	transport module being unloaded
10162306a36Sopenharmony_ci */
10262306a36Sopenharmony_ciint xprt_register_transport(struct xprt_class *transport)
10362306a36Sopenharmony_ci{
10462306a36Sopenharmony_ci	struct xprt_class *t;
10562306a36Sopenharmony_ci	int result;
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci	result = -EEXIST;
10862306a36Sopenharmony_ci	spin_lock(&xprt_list_lock);
10962306a36Sopenharmony_ci	list_for_each_entry(t, &xprt_list, list) {
11062306a36Sopenharmony_ci		/* don't register the same transport class twice */
11162306a36Sopenharmony_ci		if (t->ident == transport->ident)
11262306a36Sopenharmony_ci			goto out;
11362306a36Sopenharmony_ci	}
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci	list_add_tail(&transport->list, &xprt_list);
11662306a36Sopenharmony_ci	printk(KERN_INFO "RPC: Registered %s transport module.\n",
11762306a36Sopenharmony_ci	       transport->name);
11862306a36Sopenharmony_ci	result = 0;
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ciout:
12162306a36Sopenharmony_ci	spin_unlock(&xprt_list_lock);
12262306a36Sopenharmony_ci	return result;
12362306a36Sopenharmony_ci}
12462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(xprt_register_transport);
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci/**
12762306a36Sopenharmony_ci * xprt_unregister_transport - unregister a transport implementation
12862306a36Sopenharmony_ci * @transport: transport to unregister
12962306a36Sopenharmony_ci *
13062306a36Sopenharmony_ci * Returns:
13162306a36Sopenharmony_ci * 0:		transport successfully unregistered
13262306a36Sopenharmony_ci * -ENOENT:	transport never registered
13362306a36Sopenharmony_ci */
13462306a36Sopenharmony_ciint xprt_unregister_transport(struct xprt_class *transport)
13562306a36Sopenharmony_ci{
13662306a36Sopenharmony_ci	struct xprt_class *t;
13762306a36Sopenharmony_ci	int result;
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci	result = 0;
14062306a36Sopenharmony_ci	spin_lock(&xprt_list_lock);
14162306a36Sopenharmony_ci	list_for_each_entry(t, &xprt_list, list) {
14262306a36Sopenharmony_ci		if (t == transport) {
14362306a36Sopenharmony_ci			printk(KERN_INFO
14462306a36Sopenharmony_ci				"RPC: Unregistered %s transport module.\n",
14562306a36Sopenharmony_ci				transport->name);
14662306a36Sopenharmony_ci			list_del_init(&transport->list);
14762306a36Sopenharmony_ci			goto out;
14862306a36Sopenharmony_ci		}
14962306a36Sopenharmony_ci	}
15062306a36Sopenharmony_ci	result = -ENOENT;
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ciout:
15362306a36Sopenharmony_ci	spin_unlock(&xprt_list_lock);
15462306a36Sopenharmony_ci	return result;
15562306a36Sopenharmony_ci}
15662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(xprt_unregister_transport);
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_cistatic void
15962306a36Sopenharmony_cixprt_class_release(const struct xprt_class *t)
16062306a36Sopenharmony_ci{
16162306a36Sopenharmony_ci	module_put(t->owner);
16262306a36Sopenharmony_ci}
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_cistatic const struct xprt_class *
16562306a36Sopenharmony_cixprt_class_find_by_ident_locked(int ident)
16662306a36Sopenharmony_ci{
16762306a36Sopenharmony_ci	const struct xprt_class *t;
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci	list_for_each_entry(t, &xprt_list, list) {
17062306a36Sopenharmony_ci		if (t->ident != ident)
17162306a36Sopenharmony_ci			continue;
17262306a36Sopenharmony_ci		if (!try_module_get(t->owner))
17362306a36Sopenharmony_ci			continue;
17462306a36Sopenharmony_ci		return t;
17562306a36Sopenharmony_ci	}
17662306a36Sopenharmony_ci	return NULL;
17762306a36Sopenharmony_ci}
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_cistatic const struct xprt_class *
18062306a36Sopenharmony_cixprt_class_find_by_ident(int ident)
18162306a36Sopenharmony_ci{
18262306a36Sopenharmony_ci	const struct xprt_class *t;
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	spin_lock(&xprt_list_lock);
18562306a36Sopenharmony_ci	t = xprt_class_find_by_ident_locked(ident);
18662306a36Sopenharmony_ci	spin_unlock(&xprt_list_lock);
18762306a36Sopenharmony_ci	return t;
18862306a36Sopenharmony_ci}
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_cistatic const struct xprt_class *
19162306a36Sopenharmony_cixprt_class_find_by_netid_locked(const char *netid)
19262306a36Sopenharmony_ci{
19362306a36Sopenharmony_ci	const struct xprt_class *t;
19462306a36Sopenharmony_ci	unsigned int i;
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci	list_for_each_entry(t, &xprt_list, list) {
19762306a36Sopenharmony_ci		for (i = 0; t->netid[i][0] != '\0'; i++) {
19862306a36Sopenharmony_ci			if (strcmp(t->netid[i], netid) != 0)
19962306a36Sopenharmony_ci				continue;
20062306a36Sopenharmony_ci			if (!try_module_get(t->owner))
20162306a36Sopenharmony_ci				continue;
20262306a36Sopenharmony_ci			return t;
20362306a36Sopenharmony_ci		}
20462306a36Sopenharmony_ci	}
20562306a36Sopenharmony_ci	return NULL;
20662306a36Sopenharmony_ci}
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_cistatic const struct xprt_class *
20962306a36Sopenharmony_cixprt_class_find_by_netid(const char *netid)
21062306a36Sopenharmony_ci{
21162306a36Sopenharmony_ci	const struct xprt_class *t;
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci	spin_lock(&xprt_list_lock);
21462306a36Sopenharmony_ci	t = xprt_class_find_by_netid_locked(netid);
21562306a36Sopenharmony_ci	if (!t) {
21662306a36Sopenharmony_ci		spin_unlock(&xprt_list_lock);
21762306a36Sopenharmony_ci		request_module("rpc%s", netid);
21862306a36Sopenharmony_ci		spin_lock(&xprt_list_lock);
21962306a36Sopenharmony_ci		t = xprt_class_find_by_netid_locked(netid);
22062306a36Sopenharmony_ci	}
22162306a36Sopenharmony_ci	spin_unlock(&xprt_list_lock);
22262306a36Sopenharmony_ci	return t;
22362306a36Sopenharmony_ci}
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci/**
22662306a36Sopenharmony_ci * xprt_find_transport_ident - convert a netid into a transport identifier
22762306a36Sopenharmony_ci * @netid: transport to load
22862306a36Sopenharmony_ci *
22962306a36Sopenharmony_ci * Returns:
23062306a36Sopenharmony_ci * > 0:		transport identifier
23162306a36Sopenharmony_ci * -ENOENT:	transport module not available
23262306a36Sopenharmony_ci */
23362306a36Sopenharmony_ciint xprt_find_transport_ident(const char *netid)
23462306a36Sopenharmony_ci{
23562306a36Sopenharmony_ci	const struct xprt_class *t;
23662306a36Sopenharmony_ci	int ret;
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci	t = xprt_class_find_by_netid(netid);
23962306a36Sopenharmony_ci	if (!t)
24062306a36Sopenharmony_ci		return -ENOENT;
24162306a36Sopenharmony_ci	ret = t->ident;
24262306a36Sopenharmony_ci	xprt_class_release(t);
24362306a36Sopenharmony_ci	return ret;
24462306a36Sopenharmony_ci}
24562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(xprt_find_transport_ident);
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_cistatic void xprt_clear_locked(struct rpc_xprt *xprt)
24862306a36Sopenharmony_ci{
24962306a36Sopenharmony_ci	xprt->snd_task = NULL;
25062306a36Sopenharmony_ci	if (!test_bit(XPRT_CLOSE_WAIT, &xprt->state))
25162306a36Sopenharmony_ci		clear_bit_unlock(XPRT_LOCKED, &xprt->state);
25262306a36Sopenharmony_ci	else
25362306a36Sopenharmony_ci		queue_work(xprtiod_workqueue, &xprt->task_cleanup);
25462306a36Sopenharmony_ci}
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci/**
25762306a36Sopenharmony_ci * xprt_reserve_xprt - serialize write access to transports
25862306a36Sopenharmony_ci * @task: task that is requesting access to the transport
25962306a36Sopenharmony_ci * @xprt: pointer to the target transport
26062306a36Sopenharmony_ci *
26162306a36Sopenharmony_ci * This prevents mixing the payload of separate requests, and prevents
26262306a36Sopenharmony_ci * transport connects from colliding with writes.  No congestion control
26362306a36Sopenharmony_ci * is provided.
26462306a36Sopenharmony_ci */
26562306a36Sopenharmony_ciint xprt_reserve_xprt(struct rpc_xprt *xprt, struct rpc_task *task)
26662306a36Sopenharmony_ci{
26762306a36Sopenharmony_ci	struct rpc_rqst *req = task->tk_rqstp;
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci	if (test_and_set_bit(XPRT_LOCKED, &xprt->state)) {
27062306a36Sopenharmony_ci		if (task == xprt->snd_task)
27162306a36Sopenharmony_ci			goto out_locked;
27262306a36Sopenharmony_ci		goto out_sleep;
27362306a36Sopenharmony_ci	}
27462306a36Sopenharmony_ci	if (test_bit(XPRT_WRITE_SPACE, &xprt->state))
27562306a36Sopenharmony_ci		goto out_unlock;
27662306a36Sopenharmony_ci	xprt->snd_task = task;
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ciout_locked:
27962306a36Sopenharmony_ci	trace_xprt_reserve_xprt(xprt, task);
28062306a36Sopenharmony_ci	return 1;
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ciout_unlock:
28362306a36Sopenharmony_ci	xprt_clear_locked(xprt);
28462306a36Sopenharmony_ciout_sleep:
28562306a36Sopenharmony_ci	task->tk_status = -EAGAIN;
28662306a36Sopenharmony_ci	if  (RPC_IS_SOFT(task))
28762306a36Sopenharmony_ci		rpc_sleep_on_timeout(&xprt->sending, task, NULL,
28862306a36Sopenharmony_ci				xprt_request_timeout(req));
28962306a36Sopenharmony_ci	else
29062306a36Sopenharmony_ci		rpc_sleep_on(&xprt->sending, task, NULL);
29162306a36Sopenharmony_ci	return 0;
29262306a36Sopenharmony_ci}
29362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(xprt_reserve_xprt);
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_cistatic bool
29662306a36Sopenharmony_cixprt_need_congestion_window_wait(struct rpc_xprt *xprt)
29762306a36Sopenharmony_ci{
29862306a36Sopenharmony_ci	return test_bit(XPRT_CWND_WAIT, &xprt->state);
29962306a36Sopenharmony_ci}
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_cistatic void
30262306a36Sopenharmony_cixprt_set_congestion_window_wait(struct rpc_xprt *xprt)
30362306a36Sopenharmony_ci{
30462306a36Sopenharmony_ci	if (!list_empty(&xprt->xmit_queue)) {
30562306a36Sopenharmony_ci		/* Peek at head of queue to see if it can make progress */
30662306a36Sopenharmony_ci		if (list_first_entry(&xprt->xmit_queue, struct rpc_rqst,
30762306a36Sopenharmony_ci					rq_xmit)->rq_cong)
30862306a36Sopenharmony_ci			return;
30962306a36Sopenharmony_ci	}
31062306a36Sopenharmony_ci	set_bit(XPRT_CWND_WAIT, &xprt->state);
31162306a36Sopenharmony_ci}
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_cistatic void
31462306a36Sopenharmony_cixprt_test_and_clear_congestion_window_wait(struct rpc_xprt *xprt)
31562306a36Sopenharmony_ci{
31662306a36Sopenharmony_ci	if (!RPCXPRT_CONGESTED(xprt))
31762306a36Sopenharmony_ci		clear_bit(XPRT_CWND_WAIT, &xprt->state);
31862306a36Sopenharmony_ci}
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci/*
32162306a36Sopenharmony_ci * xprt_reserve_xprt_cong - serialize write access to transports
32262306a36Sopenharmony_ci * @task: task that is requesting access to the transport
32362306a36Sopenharmony_ci *
32462306a36Sopenharmony_ci * Same as xprt_reserve_xprt, but Van Jacobson congestion control is
32562306a36Sopenharmony_ci * integrated into the decision of whether a request is allowed to be
32662306a36Sopenharmony_ci * woken up and given access to the transport.
32762306a36Sopenharmony_ci * Note that the lock is only granted if we know there are free slots.
32862306a36Sopenharmony_ci */
32962306a36Sopenharmony_ciint xprt_reserve_xprt_cong(struct rpc_xprt *xprt, struct rpc_task *task)
33062306a36Sopenharmony_ci{
33162306a36Sopenharmony_ci	struct rpc_rqst *req = task->tk_rqstp;
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci	if (test_and_set_bit(XPRT_LOCKED, &xprt->state)) {
33462306a36Sopenharmony_ci		if (task == xprt->snd_task)
33562306a36Sopenharmony_ci			goto out_locked;
33662306a36Sopenharmony_ci		goto out_sleep;
33762306a36Sopenharmony_ci	}
33862306a36Sopenharmony_ci	if (req == NULL) {
33962306a36Sopenharmony_ci		xprt->snd_task = task;
34062306a36Sopenharmony_ci		goto out_locked;
34162306a36Sopenharmony_ci	}
34262306a36Sopenharmony_ci	if (test_bit(XPRT_WRITE_SPACE, &xprt->state))
34362306a36Sopenharmony_ci		goto out_unlock;
34462306a36Sopenharmony_ci	if (!xprt_need_congestion_window_wait(xprt)) {
34562306a36Sopenharmony_ci		xprt->snd_task = task;
34662306a36Sopenharmony_ci		goto out_locked;
34762306a36Sopenharmony_ci	}
34862306a36Sopenharmony_ciout_unlock:
34962306a36Sopenharmony_ci	xprt_clear_locked(xprt);
35062306a36Sopenharmony_ciout_sleep:
35162306a36Sopenharmony_ci	task->tk_status = -EAGAIN;
35262306a36Sopenharmony_ci	if (RPC_IS_SOFT(task))
35362306a36Sopenharmony_ci		rpc_sleep_on_timeout(&xprt->sending, task, NULL,
35462306a36Sopenharmony_ci				xprt_request_timeout(req));
35562306a36Sopenharmony_ci	else
35662306a36Sopenharmony_ci		rpc_sleep_on(&xprt->sending, task, NULL);
35762306a36Sopenharmony_ci	return 0;
35862306a36Sopenharmony_ciout_locked:
35962306a36Sopenharmony_ci	trace_xprt_reserve_cong(xprt, task);
36062306a36Sopenharmony_ci	return 1;
36162306a36Sopenharmony_ci}
36262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(xprt_reserve_xprt_cong);
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_cistatic inline int xprt_lock_write(struct rpc_xprt *xprt, struct rpc_task *task)
36562306a36Sopenharmony_ci{
36662306a36Sopenharmony_ci	int retval;
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_ci	if (test_bit(XPRT_LOCKED, &xprt->state) && xprt->snd_task == task)
36962306a36Sopenharmony_ci		return 1;
37062306a36Sopenharmony_ci	spin_lock(&xprt->transport_lock);
37162306a36Sopenharmony_ci	retval = xprt->ops->reserve_xprt(xprt, task);
37262306a36Sopenharmony_ci	spin_unlock(&xprt->transport_lock);
37362306a36Sopenharmony_ci	return retval;
37462306a36Sopenharmony_ci}
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_cistatic bool __xprt_lock_write_func(struct rpc_task *task, void *data)
37762306a36Sopenharmony_ci{
37862306a36Sopenharmony_ci	struct rpc_xprt *xprt = data;
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci	xprt->snd_task = task;
38162306a36Sopenharmony_ci	return true;
38262306a36Sopenharmony_ci}
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_cistatic void __xprt_lock_write_next(struct rpc_xprt *xprt)
38562306a36Sopenharmony_ci{
38662306a36Sopenharmony_ci	if (test_and_set_bit(XPRT_LOCKED, &xprt->state))
38762306a36Sopenharmony_ci		return;
38862306a36Sopenharmony_ci	if (test_bit(XPRT_WRITE_SPACE, &xprt->state))
38962306a36Sopenharmony_ci		goto out_unlock;
39062306a36Sopenharmony_ci	if (rpc_wake_up_first_on_wq(xprtiod_workqueue, &xprt->sending,
39162306a36Sopenharmony_ci				__xprt_lock_write_func, xprt))
39262306a36Sopenharmony_ci		return;
39362306a36Sopenharmony_ciout_unlock:
39462306a36Sopenharmony_ci	xprt_clear_locked(xprt);
39562306a36Sopenharmony_ci}
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_cistatic void __xprt_lock_write_next_cong(struct rpc_xprt *xprt)
39862306a36Sopenharmony_ci{
39962306a36Sopenharmony_ci	if (test_and_set_bit(XPRT_LOCKED, &xprt->state))
40062306a36Sopenharmony_ci		return;
40162306a36Sopenharmony_ci	if (test_bit(XPRT_WRITE_SPACE, &xprt->state))
40262306a36Sopenharmony_ci		goto out_unlock;
40362306a36Sopenharmony_ci	if (xprt_need_congestion_window_wait(xprt))
40462306a36Sopenharmony_ci		goto out_unlock;
40562306a36Sopenharmony_ci	if (rpc_wake_up_first_on_wq(xprtiod_workqueue, &xprt->sending,
40662306a36Sopenharmony_ci				__xprt_lock_write_func, xprt))
40762306a36Sopenharmony_ci		return;
40862306a36Sopenharmony_ciout_unlock:
40962306a36Sopenharmony_ci	xprt_clear_locked(xprt);
41062306a36Sopenharmony_ci}
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci/**
41362306a36Sopenharmony_ci * xprt_release_xprt - allow other requests to use a transport
41462306a36Sopenharmony_ci * @xprt: transport with other tasks potentially waiting
41562306a36Sopenharmony_ci * @task: task that is releasing access to the transport
41662306a36Sopenharmony_ci *
41762306a36Sopenharmony_ci * Note that "task" can be NULL.  No congestion control is provided.
41862306a36Sopenharmony_ci */
41962306a36Sopenharmony_civoid xprt_release_xprt(struct rpc_xprt *xprt, struct rpc_task *task)
42062306a36Sopenharmony_ci{
42162306a36Sopenharmony_ci	if (xprt->snd_task == task) {
42262306a36Sopenharmony_ci		xprt_clear_locked(xprt);
42362306a36Sopenharmony_ci		__xprt_lock_write_next(xprt);
42462306a36Sopenharmony_ci	}
42562306a36Sopenharmony_ci	trace_xprt_release_xprt(xprt, task);
42662306a36Sopenharmony_ci}
42762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(xprt_release_xprt);
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ci/**
43062306a36Sopenharmony_ci * xprt_release_xprt_cong - allow other requests to use a transport
43162306a36Sopenharmony_ci * @xprt: transport with other tasks potentially waiting
43262306a36Sopenharmony_ci * @task: task that is releasing access to the transport
43362306a36Sopenharmony_ci *
43462306a36Sopenharmony_ci * Note that "task" can be NULL.  Another task is awoken to use the
43562306a36Sopenharmony_ci * transport if the transport's congestion window allows it.
43662306a36Sopenharmony_ci */
43762306a36Sopenharmony_civoid xprt_release_xprt_cong(struct rpc_xprt *xprt, struct rpc_task *task)
43862306a36Sopenharmony_ci{
43962306a36Sopenharmony_ci	if (xprt->snd_task == task) {
44062306a36Sopenharmony_ci		xprt_clear_locked(xprt);
44162306a36Sopenharmony_ci		__xprt_lock_write_next_cong(xprt);
44262306a36Sopenharmony_ci	}
44362306a36Sopenharmony_ci	trace_xprt_release_cong(xprt, task);
44462306a36Sopenharmony_ci}
44562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(xprt_release_xprt_cong);
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_civoid xprt_release_write(struct rpc_xprt *xprt, struct rpc_task *task)
44862306a36Sopenharmony_ci{
44962306a36Sopenharmony_ci	if (xprt->snd_task != task)
45062306a36Sopenharmony_ci		return;
45162306a36Sopenharmony_ci	spin_lock(&xprt->transport_lock);
45262306a36Sopenharmony_ci	xprt->ops->release_xprt(xprt, task);
45362306a36Sopenharmony_ci	spin_unlock(&xprt->transport_lock);
45462306a36Sopenharmony_ci}
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_ci/*
45762306a36Sopenharmony_ci * Van Jacobson congestion avoidance. Check if the congestion window
45862306a36Sopenharmony_ci * overflowed. Put the task to sleep if this is the case.
45962306a36Sopenharmony_ci */
46062306a36Sopenharmony_cistatic int
46162306a36Sopenharmony_ci__xprt_get_cong(struct rpc_xprt *xprt, struct rpc_rqst *req)
46262306a36Sopenharmony_ci{
46362306a36Sopenharmony_ci	if (req->rq_cong)
46462306a36Sopenharmony_ci		return 1;
46562306a36Sopenharmony_ci	trace_xprt_get_cong(xprt, req->rq_task);
46662306a36Sopenharmony_ci	if (RPCXPRT_CONGESTED(xprt)) {
46762306a36Sopenharmony_ci		xprt_set_congestion_window_wait(xprt);
46862306a36Sopenharmony_ci		return 0;
46962306a36Sopenharmony_ci	}
47062306a36Sopenharmony_ci	req->rq_cong = 1;
47162306a36Sopenharmony_ci	xprt->cong += RPC_CWNDSCALE;
47262306a36Sopenharmony_ci	return 1;
47362306a36Sopenharmony_ci}
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci/*
47662306a36Sopenharmony_ci * Adjust the congestion window, and wake up the next task
47762306a36Sopenharmony_ci * that has been sleeping due to congestion
47862306a36Sopenharmony_ci */
47962306a36Sopenharmony_cistatic void
48062306a36Sopenharmony_ci__xprt_put_cong(struct rpc_xprt *xprt, struct rpc_rqst *req)
48162306a36Sopenharmony_ci{
48262306a36Sopenharmony_ci	if (!req->rq_cong)
48362306a36Sopenharmony_ci		return;
48462306a36Sopenharmony_ci	req->rq_cong = 0;
48562306a36Sopenharmony_ci	xprt->cong -= RPC_CWNDSCALE;
48662306a36Sopenharmony_ci	xprt_test_and_clear_congestion_window_wait(xprt);
48762306a36Sopenharmony_ci	trace_xprt_put_cong(xprt, req->rq_task);
48862306a36Sopenharmony_ci	__xprt_lock_write_next_cong(xprt);
48962306a36Sopenharmony_ci}
49062306a36Sopenharmony_ci
49162306a36Sopenharmony_ci/**
49262306a36Sopenharmony_ci * xprt_request_get_cong - Request congestion control credits
49362306a36Sopenharmony_ci * @xprt: pointer to transport
49462306a36Sopenharmony_ci * @req: pointer to RPC request
49562306a36Sopenharmony_ci *
49662306a36Sopenharmony_ci * Useful for transports that require congestion control.
49762306a36Sopenharmony_ci */
49862306a36Sopenharmony_cibool
49962306a36Sopenharmony_cixprt_request_get_cong(struct rpc_xprt *xprt, struct rpc_rqst *req)
50062306a36Sopenharmony_ci{
50162306a36Sopenharmony_ci	bool ret = false;
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_ci	if (req->rq_cong)
50462306a36Sopenharmony_ci		return true;
50562306a36Sopenharmony_ci	spin_lock(&xprt->transport_lock);
50662306a36Sopenharmony_ci	ret = __xprt_get_cong(xprt, req) != 0;
50762306a36Sopenharmony_ci	spin_unlock(&xprt->transport_lock);
50862306a36Sopenharmony_ci	return ret;
50962306a36Sopenharmony_ci}
51062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(xprt_request_get_cong);
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci/**
51362306a36Sopenharmony_ci * xprt_release_rqst_cong - housekeeping when request is complete
51462306a36Sopenharmony_ci * @task: RPC request that recently completed
51562306a36Sopenharmony_ci *
51662306a36Sopenharmony_ci * Useful for transports that require congestion control.
51762306a36Sopenharmony_ci */
51862306a36Sopenharmony_civoid xprt_release_rqst_cong(struct rpc_task *task)
51962306a36Sopenharmony_ci{
52062306a36Sopenharmony_ci	struct rpc_rqst *req = task->tk_rqstp;
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_ci	__xprt_put_cong(req->rq_xprt, req);
52362306a36Sopenharmony_ci}
52462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(xprt_release_rqst_cong);
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_cistatic void xprt_clear_congestion_window_wait_locked(struct rpc_xprt *xprt)
52762306a36Sopenharmony_ci{
52862306a36Sopenharmony_ci	if (test_and_clear_bit(XPRT_CWND_WAIT, &xprt->state))
52962306a36Sopenharmony_ci		__xprt_lock_write_next_cong(xprt);
53062306a36Sopenharmony_ci}
53162306a36Sopenharmony_ci
53262306a36Sopenharmony_ci/*
53362306a36Sopenharmony_ci * Clear the congestion window wait flag and wake up the next
53462306a36Sopenharmony_ci * entry on xprt->sending
53562306a36Sopenharmony_ci */
53662306a36Sopenharmony_cistatic void
53762306a36Sopenharmony_cixprt_clear_congestion_window_wait(struct rpc_xprt *xprt)
53862306a36Sopenharmony_ci{
53962306a36Sopenharmony_ci	if (test_and_clear_bit(XPRT_CWND_WAIT, &xprt->state)) {
54062306a36Sopenharmony_ci		spin_lock(&xprt->transport_lock);
54162306a36Sopenharmony_ci		__xprt_lock_write_next_cong(xprt);
54262306a36Sopenharmony_ci		spin_unlock(&xprt->transport_lock);
54362306a36Sopenharmony_ci	}
54462306a36Sopenharmony_ci}
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ci/**
54762306a36Sopenharmony_ci * xprt_adjust_cwnd - adjust transport congestion window
54862306a36Sopenharmony_ci * @xprt: pointer to xprt
54962306a36Sopenharmony_ci * @task: recently completed RPC request used to adjust window
55062306a36Sopenharmony_ci * @result: result code of completed RPC request
55162306a36Sopenharmony_ci *
55262306a36Sopenharmony_ci * The transport code maintains an estimate on the maximum number of out-
55362306a36Sopenharmony_ci * standing RPC requests, using a smoothed version of the congestion
55462306a36Sopenharmony_ci * avoidance implemented in 44BSD. This is basically the Van Jacobson
55562306a36Sopenharmony_ci * congestion algorithm: If a retransmit occurs, the congestion window is
55662306a36Sopenharmony_ci * halved; otherwise, it is incremented by 1/cwnd when
55762306a36Sopenharmony_ci *
55862306a36Sopenharmony_ci *	-	a reply is received and
55962306a36Sopenharmony_ci *	-	a full number of requests are outstanding and
56062306a36Sopenharmony_ci *	-	the congestion window hasn't been updated recently.
56162306a36Sopenharmony_ci */
56262306a36Sopenharmony_civoid xprt_adjust_cwnd(struct rpc_xprt *xprt, struct rpc_task *task, int result)
56362306a36Sopenharmony_ci{
56462306a36Sopenharmony_ci	struct rpc_rqst *req = task->tk_rqstp;
56562306a36Sopenharmony_ci	unsigned long cwnd = xprt->cwnd;
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_ci	if (result >= 0 && cwnd <= xprt->cong) {
56862306a36Sopenharmony_ci		/* The (cwnd >> 1) term makes sure
56962306a36Sopenharmony_ci		 * the result gets rounded properly. */
57062306a36Sopenharmony_ci		cwnd += (RPC_CWNDSCALE * RPC_CWNDSCALE + (cwnd >> 1)) / cwnd;
57162306a36Sopenharmony_ci		if (cwnd > RPC_MAXCWND(xprt))
57262306a36Sopenharmony_ci			cwnd = RPC_MAXCWND(xprt);
57362306a36Sopenharmony_ci		__xprt_lock_write_next_cong(xprt);
57462306a36Sopenharmony_ci	} else if (result == -ETIMEDOUT) {
57562306a36Sopenharmony_ci		cwnd >>= 1;
57662306a36Sopenharmony_ci		if (cwnd < RPC_CWNDSCALE)
57762306a36Sopenharmony_ci			cwnd = RPC_CWNDSCALE;
57862306a36Sopenharmony_ci	}
57962306a36Sopenharmony_ci	dprintk("RPC:       cong %ld, cwnd was %ld, now %ld\n",
58062306a36Sopenharmony_ci			xprt->cong, xprt->cwnd, cwnd);
58162306a36Sopenharmony_ci	xprt->cwnd = cwnd;
58262306a36Sopenharmony_ci	__xprt_put_cong(xprt, req);
58362306a36Sopenharmony_ci}
58462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(xprt_adjust_cwnd);
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_ci/**
58762306a36Sopenharmony_ci * xprt_wake_pending_tasks - wake all tasks on a transport's pending queue
58862306a36Sopenharmony_ci * @xprt: transport with waiting tasks
58962306a36Sopenharmony_ci * @status: result code to plant in each task before waking it
59062306a36Sopenharmony_ci *
59162306a36Sopenharmony_ci */
59262306a36Sopenharmony_civoid xprt_wake_pending_tasks(struct rpc_xprt *xprt, int status)
59362306a36Sopenharmony_ci{
59462306a36Sopenharmony_ci	if (status < 0)
59562306a36Sopenharmony_ci		rpc_wake_up_status(&xprt->pending, status);
59662306a36Sopenharmony_ci	else
59762306a36Sopenharmony_ci		rpc_wake_up(&xprt->pending);
59862306a36Sopenharmony_ci}
59962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(xprt_wake_pending_tasks);
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_ci/**
60262306a36Sopenharmony_ci * xprt_wait_for_buffer_space - wait for transport output buffer to clear
60362306a36Sopenharmony_ci * @xprt: transport
60462306a36Sopenharmony_ci *
60562306a36Sopenharmony_ci * Note that we only set the timer for the case of RPC_IS_SOFT(), since
60662306a36Sopenharmony_ci * we don't in general want to force a socket disconnection due to
60762306a36Sopenharmony_ci * an incomplete RPC call transmission.
60862306a36Sopenharmony_ci */
60962306a36Sopenharmony_civoid xprt_wait_for_buffer_space(struct rpc_xprt *xprt)
61062306a36Sopenharmony_ci{
61162306a36Sopenharmony_ci	set_bit(XPRT_WRITE_SPACE, &xprt->state);
61262306a36Sopenharmony_ci}
61362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(xprt_wait_for_buffer_space);
61462306a36Sopenharmony_ci
61562306a36Sopenharmony_cistatic bool
61662306a36Sopenharmony_cixprt_clear_write_space_locked(struct rpc_xprt *xprt)
61762306a36Sopenharmony_ci{
61862306a36Sopenharmony_ci	if (test_and_clear_bit(XPRT_WRITE_SPACE, &xprt->state)) {
61962306a36Sopenharmony_ci		__xprt_lock_write_next(xprt);
62062306a36Sopenharmony_ci		dprintk("RPC:       write space: waking waiting task on "
62162306a36Sopenharmony_ci				"xprt %p\n", xprt);
62262306a36Sopenharmony_ci		return true;
62362306a36Sopenharmony_ci	}
62462306a36Sopenharmony_ci	return false;
62562306a36Sopenharmony_ci}
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_ci/**
62862306a36Sopenharmony_ci * xprt_write_space - wake the task waiting for transport output buffer space
62962306a36Sopenharmony_ci * @xprt: transport with waiting tasks
63062306a36Sopenharmony_ci *
63162306a36Sopenharmony_ci * Can be called in a soft IRQ context, so xprt_write_space never sleeps.
63262306a36Sopenharmony_ci */
63362306a36Sopenharmony_cibool xprt_write_space(struct rpc_xprt *xprt)
63462306a36Sopenharmony_ci{
63562306a36Sopenharmony_ci	bool ret;
63662306a36Sopenharmony_ci
63762306a36Sopenharmony_ci	if (!test_bit(XPRT_WRITE_SPACE, &xprt->state))
63862306a36Sopenharmony_ci		return false;
63962306a36Sopenharmony_ci	spin_lock(&xprt->transport_lock);
64062306a36Sopenharmony_ci	ret = xprt_clear_write_space_locked(xprt);
64162306a36Sopenharmony_ci	spin_unlock(&xprt->transport_lock);
64262306a36Sopenharmony_ci	return ret;
64362306a36Sopenharmony_ci}
64462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(xprt_write_space);
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_cistatic unsigned long xprt_abs_ktime_to_jiffies(ktime_t abstime)
64762306a36Sopenharmony_ci{
64862306a36Sopenharmony_ci	s64 delta = ktime_to_ns(ktime_get() - abstime);
64962306a36Sopenharmony_ci	return likely(delta >= 0) ?
65062306a36Sopenharmony_ci		jiffies - nsecs_to_jiffies(delta) :
65162306a36Sopenharmony_ci		jiffies + nsecs_to_jiffies(-delta);
65262306a36Sopenharmony_ci}
65362306a36Sopenharmony_ci
65462306a36Sopenharmony_cistatic unsigned long xprt_calc_majortimeo(struct rpc_rqst *req)
65562306a36Sopenharmony_ci{
65662306a36Sopenharmony_ci	const struct rpc_timeout *to = req->rq_task->tk_client->cl_timeout;
65762306a36Sopenharmony_ci	unsigned long majortimeo = req->rq_timeout;
65862306a36Sopenharmony_ci
65962306a36Sopenharmony_ci	if (to->to_exponential)
66062306a36Sopenharmony_ci		majortimeo <<= to->to_retries;
66162306a36Sopenharmony_ci	else
66262306a36Sopenharmony_ci		majortimeo += to->to_increment * to->to_retries;
66362306a36Sopenharmony_ci	if (majortimeo > to->to_maxval || majortimeo == 0)
66462306a36Sopenharmony_ci		majortimeo = to->to_maxval;
66562306a36Sopenharmony_ci	return majortimeo;
66662306a36Sopenharmony_ci}
66762306a36Sopenharmony_ci
66862306a36Sopenharmony_cistatic void xprt_reset_majortimeo(struct rpc_rqst *req)
66962306a36Sopenharmony_ci{
67062306a36Sopenharmony_ci	req->rq_majortimeo += xprt_calc_majortimeo(req);
67162306a36Sopenharmony_ci}
67262306a36Sopenharmony_ci
67362306a36Sopenharmony_cistatic void xprt_reset_minortimeo(struct rpc_rqst *req)
67462306a36Sopenharmony_ci{
67562306a36Sopenharmony_ci	req->rq_minortimeo += req->rq_timeout;
67662306a36Sopenharmony_ci}
67762306a36Sopenharmony_ci
67862306a36Sopenharmony_cistatic void xprt_init_majortimeo(struct rpc_task *task, struct rpc_rqst *req)
67962306a36Sopenharmony_ci{
68062306a36Sopenharmony_ci	unsigned long time_init;
68162306a36Sopenharmony_ci	struct rpc_xprt *xprt = req->rq_xprt;
68262306a36Sopenharmony_ci
68362306a36Sopenharmony_ci	if (likely(xprt && xprt_connected(xprt)))
68462306a36Sopenharmony_ci		time_init = jiffies;
68562306a36Sopenharmony_ci	else
68662306a36Sopenharmony_ci		time_init = xprt_abs_ktime_to_jiffies(task->tk_start);
68762306a36Sopenharmony_ci	req->rq_timeout = task->tk_client->cl_timeout->to_initval;
68862306a36Sopenharmony_ci	req->rq_majortimeo = time_init + xprt_calc_majortimeo(req);
68962306a36Sopenharmony_ci	req->rq_minortimeo = time_init + req->rq_timeout;
69062306a36Sopenharmony_ci}
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_ci/**
69362306a36Sopenharmony_ci * xprt_adjust_timeout - adjust timeout values for next retransmit
69462306a36Sopenharmony_ci * @req: RPC request containing parameters to use for the adjustment
69562306a36Sopenharmony_ci *
69662306a36Sopenharmony_ci */
69762306a36Sopenharmony_ciint xprt_adjust_timeout(struct rpc_rqst *req)
69862306a36Sopenharmony_ci{
69962306a36Sopenharmony_ci	struct rpc_xprt *xprt = req->rq_xprt;
70062306a36Sopenharmony_ci	const struct rpc_timeout *to = req->rq_task->tk_client->cl_timeout;
70162306a36Sopenharmony_ci	int status = 0;
70262306a36Sopenharmony_ci
70362306a36Sopenharmony_ci	if (time_before(jiffies, req->rq_majortimeo)) {
70462306a36Sopenharmony_ci		if (time_before(jiffies, req->rq_minortimeo))
70562306a36Sopenharmony_ci			return status;
70662306a36Sopenharmony_ci		if (to->to_exponential)
70762306a36Sopenharmony_ci			req->rq_timeout <<= 1;
70862306a36Sopenharmony_ci		else
70962306a36Sopenharmony_ci			req->rq_timeout += to->to_increment;
71062306a36Sopenharmony_ci		if (to->to_maxval && req->rq_timeout >= to->to_maxval)
71162306a36Sopenharmony_ci			req->rq_timeout = to->to_maxval;
71262306a36Sopenharmony_ci		req->rq_retries++;
71362306a36Sopenharmony_ci	} else {
71462306a36Sopenharmony_ci		req->rq_timeout = to->to_initval;
71562306a36Sopenharmony_ci		req->rq_retries = 0;
71662306a36Sopenharmony_ci		xprt_reset_majortimeo(req);
71762306a36Sopenharmony_ci		/* Reset the RTT counters == "slow start" */
71862306a36Sopenharmony_ci		spin_lock(&xprt->transport_lock);
71962306a36Sopenharmony_ci		rpc_init_rtt(req->rq_task->tk_client->cl_rtt, to->to_initval);
72062306a36Sopenharmony_ci		spin_unlock(&xprt->transport_lock);
72162306a36Sopenharmony_ci		status = -ETIMEDOUT;
72262306a36Sopenharmony_ci	}
72362306a36Sopenharmony_ci	xprt_reset_minortimeo(req);
72462306a36Sopenharmony_ci
72562306a36Sopenharmony_ci	if (req->rq_timeout == 0) {
72662306a36Sopenharmony_ci		printk(KERN_WARNING "xprt_adjust_timeout: rq_timeout = 0!\n");
72762306a36Sopenharmony_ci		req->rq_timeout = 5 * HZ;
72862306a36Sopenharmony_ci	}
72962306a36Sopenharmony_ci	return status;
73062306a36Sopenharmony_ci}
73162306a36Sopenharmony_ci
73262306a36Sopenharmony_cistatic void xprt_autoclose(struct work_struct *work)
73362306a36Sopenharmony_ci{
73462306a36Sopenharmony_ci	struct rpc_xprt *xprt =
73562306a36Sopenharmony_ci		container_of(work, struct rpc_xprt, task_cleanup);
73662306a36Sopenharmony_ci	unsigned int pflags = memalloc_nofs_save();
73762306a36Sopenharmony_ci
73862306a36Sopenharmony_ci	trace_xprt_disconnect_auto(xprt);
73962306a36Sopenharmony_ci	xprt->connect_cookie++;
74062306a36Sopenharmony_ci	smp_mb__before_atomic();
74162306a36Sopenharmony_ci	clear_bit(XPRT_CLOSE_WAIT, &xprt->state);
74262306a36Sopenharmony_ci	xprt->ops->close(xprt);
74362306a36Sopenharmony_ci	xprt_release_write(xprt, NULL);
74462306a36Sopenharmony_ci	wake_up_bit(&xprt->state, XPRT_LOCKED);
74562306a36Sopenharmony_ci	memalloc_nofs_restore(pflags);
74662306a36Sopenharmony_ci}
74762306a36Sopenharmony_ci
74862306a36Sopenharmony_ci/**
74962306a36Sopenharmony_ci * xprt_disconnect_done - mark a transport as disconnected
75062306a36Sopenharmony_ci * @xprt: transport to flag for disconnect
75162306a36Sopenharmony_ci *
75262306a36Sopenharmony_ci */
75362306a36Sopenharmony_civoid xprt_disconnect_done(struct rpc_xprt *xprt)
75462306a36Sopenharmony_ci{
75562306a36Sopenharmony_ci	trace_xprt_disconnect_done(xprt);
75662306a36Sopenharmony_ci	spin_lock(&xprt->transport_lock);
75762306a36Sopenharmony_ci	xprt_clear_connected(xprt);
75862306a36Sopenharmony_ci	xprt_clear_write_space_locked(xprt);
75962306a36Sopenharmony_ci	xprt_clear_congestion_window_wait_locked(xprt);
76062306a36Sopenharmony_ci	xprt_wake_pending_tasks(xprt, -ENOTCONN);
76162306a36Sopenharmony_ci	spin_unlock(&xprt->transport_lock);
76262306a36Sopenharmony_ci}
76362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(xprt_disconnect_done);
76462306a36Sopenharmony_ci
76562306a36Sopenharmony_ci/**
76662306a36Sopenharmony_ci * xprt_schedule_autoclose_locked - Try to schedule an autoclose RPC call
76762306a36Sopenharmony_ci * @xprt: transport to disconnect
76862306a36Sopenharmony_ci */
76962306a36Sopenharmony_cistatic void xprt_schedule_autoclose_locked(struct rpc_xprt *xprt)
77062306a36Sopenharmony_ci{
77162306a36Sopenharmony_ci	if (test_and_set_bit(XPRT_CLOSE_WAIT, &xprt->state))
77262306a36Sopenharmony_ci		return;
77362306a36Sopenharmony_ci	if (test_and_set_bit(XPRT_LOCKED, &xprt->state) == 0)
77462306a36Sopenharmony_ci		queue_work(xprtiod_workqueue, &xprt->task_cleanup);
77562306a36Sopenharmony_ci	else if (xprt->snd_task && !test_bit(XPRT_SND_IS_COOKIE, &xprt->state))
77662306a36Sopenharmony_ci		rpc_wake_up_queued_task_set_status(&xprt->pending,
77762306a36Sopenharmony_ci						   xprt->snd_task, -ENOTCONN);
77862306a36Sopenharmony_ci}
77962306a36Sopenharmony_ci
78062306a36Sopenharmony_ci/**
78162306a36Sopenharmony_ci * xprt_force_disconnect - force a transport to disconnect
78262306a36Sopenharmony_ci * @xprt: transport to disconnect
78362306a36Sopenharmony_ci *
78462306a36Sopenharmony_ci */
78562306a36Sopenharmony_civoid xprt_force_disconnect(struct rpc_xprt *xprt)
78662306a36Sopenharmony_ci{
78762306a36Sopenharmony_ci	trace_xprt_disconnect_force(xprt);
78862306a36Sopenharmony_ci
78962306a36Sopenharmony_ci	/* Don't race with the test_bit() in xprt_clear_locked() */
79062306a36Sopenharmony_ci	spin_lock(&xprt->transport_lock);
79162306a36Sopenharmony_ci	xprt_schedule_autoclose_locked(xprt);
79262306a36Sopenharmony_ci	spin_unlock(&xprt->transport_lock);
79362306a36Sopenharmony_ci}
79462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(xprt_force_disconnect);
79562306a36Sopenharmony_ci
79662306a36Sopenharmony_cistatic unsigned int
79762306a36Sopenharmony_cixprt_connect_cookie(struct rpc_xprt *xprt)
79862306a36Sopenharmony_ci{
79962306a36Sopenharmony_ci	return READ_ONCE(xprt->connect_cookie);
80062306a36Sopenharmony_ci}
80162306a36Sopenharmony_ci
80262306a36Sopenharmony_cistatic bool
80362306a36Sopenharmony_cixprt_request_retransmit_after_disconnect(struct rpc_task *task)
80462306a36Sopenharmony_ci{
80562306a36Sopenharmony_ci	struct rpc_rqst *req = task->tk_rqstp;
80662306a36Sopenharmony_ci	struct rpc_xprt *xprt = req->rq_xprt;
80762306a36Sopenharmony_ci
80862306a36Sopenharmony_ci	return req->rq_connect_cookie != xprt_connect_cookie(xprt) ||
80962306a36Sopenharmony_ci		!xprt_connected(xprt);
81062306a36Sopenharmony_ci}
81162306a36Sopenharmony_ci
81262306a36Sopenharmony_ci/**
81362306a36Sopenharmony_ci * xprt_conditional_disconnect - force a transport to disconnect
81462306a36Sopenharmony_ci * @xprt: transport to disconnect
81562306a36Sopenharmony_ci * @cookie: 'connection cookie'
81662306a36Sopenharmony_ci *
81762306a36Sopenharmony_ci * This attempts to break the connection if and only if 'cookie' matches
81862306a36Sopenharmony_ci * the current transport 'connection cookie'. It ensures that we don't
81962306a36Sopenharmony_ci * try to break the connection more than once when we need to retransmit
82062306a36Sopenharmony_ci * a batch of RPC requests.
82162306a36Sopenharmony_ci *
82262306a36Sopenharmony_ci */
82362306a36Sopenharmony_civoid xprt_conditional_disconnect(struct rpc_xprt *xprt, unsigned int cookie)
82462306a36Sopenharmony_ci{
82562306a36Sopenharmony_ci	/* Don't race with the test_bit() in xprt_clear_locked() */
82662306a36Sopenharmony_ci	spin_lock(&xprt->transport_lock);
82762306a36Sopenharmony_ci	if (cookie != xprt->connect_cookie)
82862306a36Sopenharmony_ci		goto out;
82962306a36Sopenharmony_ci	if (test_bit(XPRT_CLOSING, &xprt->state))
83062306a36Sopenharmony_ci		goto out;
83162306a36Sopenharmony_ci	xprt_schedule_autoclose_locked(xprt);
83262306a36Sopenharmony_ciout:
83362306a36Sopenharmony_ci	spin_unlock(&xprt->transport_lock);
83462306a36Sopenharmony_ci}
83562306a36Sopenharmony_ci
83662306a36Sopenharmony_cistatic bool
83762306a36Sopenharmony_cixprt_has_timer(const struct rpc_xprt *xprt)
83862306a36Sopenharmony_ci{
83962306a36Sopenharmony_ci	return xprt->idle_timeout != 0;
84062306a36Sopenharmony_ci}
84162306a36Sopenharmony_ci
84262306a36Sopenharmony_cistatic void
84362306a36Sopenharmony_cixprt_schedule_autodisconnect(struct rpc_xprt *xprt)
84462306a36Sopenharmony_ci	__must_hold(&xprt->transport_lock)
84562306a36Sopenharmony_ci{
84662306a36Sopenharmony_ci	xprt->last_used = jiffies;
84762306a36Sopenharmony_ci	if (RB_EMPTY_ROOT(&xprt->recv_queue) && xprt_has_timer(xprt))
84862306a36Sopenharmony_ci		mod_timer(&xprt->timer, xprt->last_used + xprt->idle_timeout);
84962306a36Sopenharmony_ci}
85062306a36Sopenharmony_ci
85162306a36Sopenharmony_cistatic void
85262306a36Sopenharmony_cixprt_init_autodisconnect(struct timer_list *t)
85362306a36Sopenharmony_ci{
85462306a36Sopenharmony_ci	struct rpc_xprt *xprt = from_timer(xprt, t, timer);
85562306a36Sopenharmony_ci
85662306a36Sopenharmony_ci	if (!RB_EMPTY_ROOT(&xprt->recv_queue))
85762306a36Sopenharmony_ci		return;
85862306a36Sopenharmony_ci	/* Reset xprt->last_used to avoid connect/autodisconnect cycling */
85962306a36Sopenharmony_ci	xprt->last_used = jiffies;
86062306a36Sopenharmony_ci	if (test_and_set_bit(XPRT_LOCKED, &xprt->state))
86162306a36Sopenharmony_ci		return;
86262306a36Sopenharmony_ci	queue_work(xprtiod_workqueue, &xprt->task_cleanup);
86362306a36Sopenharmony_ci}
86462306a36Sopenharmony_ci
86562306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_FAIL_SUNRPC)
86662306a36Sopenharmony_cistatic void xprt_inject_disconnect(struct rpc_xprt *xprt)
86762306a36Sopenharmony_ci{
86862306a36Sopenharmony_ci	if (!fail_sunrpc.ignore_client_disconnect &&
86962306a36Sopenharmony_ci	    should_fail(&fail_sunrpc.attr, 1))
87062306a36Sopenharmony_ci		xprt->ops->inject_disconnect(xprt);
87162306a36Sopenharmony_ci}
87262306a36Sopenharmony_ci#else
87362306a36Sopenharmony_cistatic inline void xprt_inject_disconnect(struct rpc_xprt *xprt)
87462306a36Sopenharmony_ci{
87562306a36Sopenharmony_ci}
87662306a36Sopenharmony_ci#endif
87762306a36Sopenharmony_ci
87862306a36Sopenharmony_cibool xprt_lock_connect(struct rpc_xprt *xprt,
87962306a36Sopenharmony_ci		struct rpc_task *task,
88062306a36Sopenharmony_ci		void *cookie)
88162306a36Sopenharmony_ci{
88262306a36Sopenharmony_ci	bool ret = false;
88362306a36Sopenharmony_ci
88462306a36Sopenharmony_ci	spin_lock(&xprt->transport_lock);
88562306a36Sopenharmony_ci	if (!test_bit(XPRT_LOCKED, &xprt->state))
88662306a36Sopenharmony_ci		goto out;
88762306a36Sopenharmony_ci	if (xprt->snd_task != task)
88862306a36Sopenharmony_ci		goto out;
88962306a36Sopenharmony_ci	set_bit(XPRT_SND_IS_COOKIE, &xprt->state);
89062306a36Sopenharmony_ci	xprt->snd_task = cookie;
89162306a36Sopenharmony_ci	ret = true;
89262306a36Sopenharmony_ciout:
89362306a36Sopenharmony_ci	spin_unlock(&xprt->transport_lock);
89462306a36Sopenharmony_ci	return ret;
89562306a36Sopenharmony_ci}
89662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(xprt_lock_connect);
89762306a36Sopenharmony_ci
89862306a36Sopenharmony_civoid xprt_unlock_connect(struct rpc_xprt *xprt, void *cookie)
89962306a36Sopenharmony_ci{
90062306a36Sopenharmony_ci	spin_lock(&xprt->transport_lock);
90162306a36Sopenharmony_ci	if (xprt->snd_task != cookie)
90262306a36Sopenharmony_ci		goto out;
90362306a36Sopenharmony_ci	if (!test_bit(XPRT_LOCKED, &xprt->state))
90462306a36Sopenharmony_ci		goto out;
90562306a36Sopenharmony_ci	xprt->snd_task =NULL;
90662306a36Sopenharmony_ci	clear_bit(XPRT_SND_IS_COOKIE, &xprt->state);
90762306a36Sopenharmony_ci	xprt->ops->release_xprt(xprt, NULL);
90862306a36Sopenharmony_ci	xprt_schedule_autodisconnect(xprt);
90962306a36Sopenharmony_ciout:
91062306a36Sopenharmony_ci	spin_unlock(&xprt->transport_lock);
91162306a36Sopenharmony_ci	wake_up_bit(&xprt->state, XPRT_LOCKED);
91262306a36Sopenharmony_ci}
91362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(xprt_unlock_connect);
91462306a36Sopenharmony_ci
91562306a36Sopenharmony_ci/**
91662306a36Sopenharmony_ci * xprt_connect - schedule a transport connect operation
91762306a36Sopenharmony_ci * @task: RPC task that is requesting the connect
91862306a36Sopenharmony_ci *
91962306a36Sopenharmony_ci */
92062306a36Sopenharmony_civoid xprt_connect(struct rpc_task *task)
92162306a36Sopenharmony_ci{
92262306a36Sopenharmony_ci	struct rpc_xprt	*xprt = task->tk_rqstp->rq_xprt;
92362306a36Sopenharmony_ci
92462306a36Sopenharmony_ci	trace_xprt_connect(xprt);
92562306a36Sopenharmony_ci
92662306a36Sopenharmony_ci	if (!xprt_bound(xprt)) {
92762306a36Sopenharmony_ci		task->tk_status = -EAGAIN;
92862306a36Sopenharmony_ci		return;
92962306a36Sopenharmony_ci	}
93062306a36Sopenharmony_ci	if (!xprt_lock_write(xprt, task))
93162306a36Sopenharmony_ci		return;
93262306a36Sopenharmony_ci
93362306a36Sopenharmony_ci	if (!xprt_connected(xprt) && !test_bit(XPRT_CLOSE_WAIT, &xprt->state)) {
93462306a36Sopenharmony_ci		task->tk_rqstp->rq_connect_cookie = xprt->connect_cookie;
93562306a36Sopenharmony_ci		rpc_sleep_on_timeout(&xprt->pending, task, NULL,
93662306a36Sopenharmony_ci				xprt_request_timeout(task->tk_rqstp));
93762306a36Sopenharmony_ci
93862306a36Sopenharmony_ci		if (test_bit(XPRT_CLOSING, &xprt->state))
93962306a36Sopenharmony_ci			return;
94062306a36Sopenharmony_ci		if (xprt_test_and_set_connecting(xprt))
94162306a36Sopenharmony_ci			return;
94262306a36Sopenharmony_ci		/* Race breaker */
94362306a36Sopenharmony_ci		if (!xprt_connected(xprt)) {
94462306a36Sopenharmony_ci			xprt->stat.connect_start = jiffies;
94562306a36Sopenharmony_ci			xprt->ops->connect(xprt, task);
94662306a36Sopenharmony_ci		} else {
94762306a36Sopenharmony_ci			xprt_clear_connecting(xprt);
94862306a36Sopenharmony_ci			task->tk_status = 0;
94962306a36Sopenharmony_ci			rpc_wake_up_queued_task(&xprt->pending, task);
95062306a36Sopenharmony_ci		}
95162306a36Sopenharmony_ci	}
95262306a36Sopenharmony_ci	xprt_release_write(xprt, task);
95362306a36Sopenharmony_ci}
95462306a36Sopenharmony_ci
95562306a36Sopenharmony_ci/**
95662306a36Sopenharmony_ci * xprt_reconnect_delay - compute the wait before scheduling a connect
95762306a36Sopenharmony_ci * @xprt: transport instance
95862306a36Sopenharmony_ci *
95962306a36Sopenharmony_ci */
96062306a36Sopenharmony_ciunsigned long xprt_reconnect_delay(const struct rpc_xprt *xprt)
96162306a36Sopenharmony_ci{
96262306a36Sopenharmony_ci	unsigned long start, now = jiffies;
96362306a36Sopenharmony_ci
96462306a36Sopenharmony_ci	start = xprt->stat.connect_start + xprt->reestablish_timeout;
96562306a36Sopenharmony_ci	if (time_after(start, now))
96662306a36Sopenharmony_ci		return start - now;
96762306a36Sopenharmony_ci	return 0;
96862306a36Sopenharmony_ci}
96962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(xprt_reconnect_delay);
97062306a36Sopenharmony_ci
97162306a36Sopenharmony_ci/**
97262306a36Sopenharmony_ci * xprt_reconnect_backoff - compute the new re-establish timeout
97362306a36Sopenharmony_ci * @xprt: transport instance
97462306a36Sopenharmony_ci * @init_to: initial reestablish timeout
97562306a36Sopenharmony_ci *
97662306a36Sopenharmony_ci */
97762306a36Sopenharmony_civoid xprt_reconnect_backoff(struct rpc_xprt *xprt, unsigned long init_to)
97862306a36Sopenharmony_ci{
97962306a36Sopenharmony_ci	xprt->reestablish_timeout <<= 1;
98062306a36Sopenharmony_ci	if (xprt->reestablish_timeout > xprt->max_reconnect_timeout)
98162306a36Sopenharmony_ci		xprt->reestablish_timeout = xprt->max_reconnect_timeout;
98262306a36Sopenharmony_ci	if (xprt->reestablish_timeout < init_to)
98362306a36Sopenharmony_ci		xprt->reestablish_timeout = init_to;
98462306a36Sopenharmony_ci}
98562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(xprt_reconnect_backoff);
98662306a36Sopenharmony_ci
98762306a36Sopenharmony_cienum xprt_xid_rb_cmp {
98862306a36Sopenharmony_ci	XID_RB_EQUAL,
98962306a36Sopenharmony_ci	XID_RB_LEFT,
99062306a36Sopenharmony_ci	XID_RB_RIGHT,
99162306a36Sopenharmony_ci};
99262306a36Sopenharmony_cistatic enum xprt_xid_rb_cmp
99362306a36Sopenharmony_cixprt_xid_cmp(__be32 xid1, __be32 xid2)
99462306a36Sopenharmony_ci{
99562306a36Sopenharmony_ci	if (xid1 == xid2)
99662306a36Sopenharmony_ci		return XID_RB_EQUAL;
99762306a36Sopenharmony_ci	if ((__force u32)xid1 < (__force u32)xid2)
99862306a36Sopenharmony_ci		return XID_RB_LEFT;
99962306a36Sopenharmony_ci	return XID_RB_RIGHT;
100062306a36Sopenharmony_ci}
100162306a36Sopenharmony_ci
100262306a36Sopenharmony_cistatic struct rpc_rqst *
100362306a36Sopenharmony_cixprt_request_rb_find(struct rpc_xprt *xprt, __be32 xid)
100462306a36Sopenharmony_ci{
100562306a36Sopenharmony_ci	struct rb_node *n = xprt->recv_queue.rb_node;
100662306a36Sopenharmony_ci	struct rpc_rqst *req;
100762306a36Sopenharmony_ci
100862306a36Sopenharmony_ci	while (n != NULL) {
100962306a36Sopenharmony_ci		req = rb_entry(n, struct rpc_rqst, rq_recv);
101062306a36Sopenharmony_ci		switch (xprt_xid_cmp(xid, req->rq_xid)) {
101162306a36Sopenharmony_ci		case XID_RB_LEFT:
101262306a36Sopenharmony_ci			n = n->rb_left;
101362306a36Sopenharmony_ci			break;
101462306a36Sopenharmony_ci		case XID_RB_RIGHT:
101562306a36Sopenharmony_ci			n = n->rb_right;
101662306a36Sopenharmony_ci			break;
101762306a36Sopenharmony_ci		case XID_RB_EQUAL:
101862306a36Sopenharmony_ci			return req;
101962306a36Sopenharmony_ci		}
102062306a36Sopenharmony_ci	}
102162306a36Sopenharmony_ci	return NULL;
102262306a36Sopenharmony_ci}
102362306a36Sopenharmony_ci
102462306a36Sopenharmony_cistatic void
102562306a36Sopenharmony_cixprt_request_rb_insert(struct rpc_xprt *xprt, struct rpc_rqst *new)
102662306a36Sopenharmony_ci{
102762306a36Sopenharmony_ci	struct rb_node **p = &xprt->recv_queue.rb_node;
102862306a36Sopenharmony_ci	struct rb_node *n = NULL;
102962306a36Sopenharmony_ci	struct rpc_rqst *req;
103062306a36Sopenharmony_ci
103162306a36Sopenharmony_ci	while (*p != NULL) {
103262306a36Sopenharmony_ci		n = *p;
103362306a36Sopenharmony_ci		req = rb_entry(n, struct rpc_rqst, rq_recv);
103462306a36Sopenharmony_ci		switch(xprt_xid_cmp(new->rq_xid, req->rq_xid)) {
103562306a36Sopenharmony_ci		case XID_RB_LEFT:
103662306a36Sopenharmony_ci			p = &n->rb_left;
103762306a36Sopenharmony_ci			break;
103862306a36Sopenharmony_ci		case XID_RB_RIGHT:
103962306a36Sopenharmony_ci			p = &n->rb_right;
104062306a36Sopenharmony_ci			break;
104162306a36Sopenharmony_ci		case XID_RB_EQUAL:
104262306a36Sopenharmony_ci			WARN_ON_ONCE(new != req);
104362306a36Sopenharmony_ci			return;
104462306a36Sopenharmony_ci		}
104562306a36Sopenharmony_ci	}
104662306a36Sopenharmony_ci	rb_link_node(&new->rq_recv, n, p);
104762306a36Sopenharmony_ci	rb_insert_color(&new->rq_recv, &xprt->recv_queue);
104862306a36Sopenharmony_ci}
104962306a36Sopenharmony_ci
105062306a36Sopenharmony_cistatic void
105162306a36Sopenharmony_cixprt_request_rb_remove(struct rpc_xprt *xprt, struct rpc_rqst *req)
105262306a36Sopenharmony_ci{
105362306a36Sopenharmony_ci	rb_erase(&req->rq_recv, &xprt->recv_queue);
105462306a36Sopenharmony_ci}
105562306a36Sopenharmony_ci
105662306a36Sopenharmony_ci/**
105762306a36Sopenharmony_ci * xprt_lookup_rqst - find an RPC request corresponding to an XID
105862306a36Sopenharmony_ci * @xprt: transport on which the original request was transmitted
105962306a36Sopenharmony_ci * @xid: RPC XID of incoming reply
106062306a36Sopenharmony_ci *
106162306a36Sopenharmony_ci * Caller holds xprt->queue_lock.
106262306a36Sopenharmony_ci */
106362306a36Sopenharmony_cistruct rpc_rqst *xprt_lookup_rqst(struct rpc_xprt *xprt, __be32 xid)
106462306a36Sopenharmony_ci{
106562306a36Sopenharmony_ci	struct rpc_rqst *entry;
106662306a36Sopenharmony_ci
106762306a36Sopenharmony_ci	entry = xprt_request_rb_find(xprt, xid);
106862306a36Sopenharmony_ci	if (entry != NULL) {
106962306a36Sopenharmony_ci		trace_xprt_lookup_rqst(xprt, xid, 0);
107062306a36Sopenharmony_ci		entry->rq_rtt = ktime_sub(ktime_get(), entry->rq_xtime);
107162306a36Sopenharmony_ci		return entry;
107262306a36Sopenharmony_ci	}
107362306a36Sopenharmony_ci
107462306a36Sopenharmony_ci	dprintk("RPC:       xprt_lookup_rqst did not find xid %08x\n",
107562306a36Sopenharmony_ci			ntohl(xid));
107662306a36Sopenharmony_ci	trace_xprt_lookup_rqst(xprt, xid, -ENOENT);
107762306a36Sopenharmony_ci	xprt->stat.bad_xids++;
107862306a36Sopenharmony_ci	return NULL;
107962306a36Sopenharmony_ci}
108062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(xprt_lookup_rqst);
108162306a36Sopenharmony_ci
108262306a36Sopenharmony_cistatic bool
108362306a36Sopenharmony_cixprt_is_pinned_rqst(struct rpc_rqst *req)
108462306a36Sopenharmony_ci{
108562306a36Sopenharmony_ci	return atomic_read(&req->rq_pin) != 0;
108662306a36Sopenharmony_ci}
108762306a36Sopenharmony_ci
108862306a36Sopenharmony_ci/**
108962306a36Sopenharmony_ci * xprt_pin_rqst - Pin a request on the transport receive list
109062306a36Sopenharmony_ci * @req: Request to pin
109162306a36Sopenharmony_ci *
109262306a36Sopenharmony_ci * Caller must ensure this is atomic with the call to xprt_lookup_rqst()
109362306a36Sopenharmony_ci * so should be holding xprt->queue_lock.
109462306a36Sopenharmony_ci */
109562306a36Sopenharmony_civoid xprt_pin_rqst(struct rpc_rqst *req)
109662306a36Sopenharmony_ci{
109762306a36Sopenharmony_ci	atomic_inc(&req->rq_pin);
109862306a36Sopenharmony_ci}
109962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(xprt_pin_rqst);
110062306a36Sopenharmony_ci
110162306a36Sopenharmony_ci/**
110262306a36Sopenharmony_ci * xprt_unpin_rqst - Unpin a request on the transport receive list
110362306a36Sopenharmony_ci * @req: Request to pin
110462306a36Sopenharmony_ci *
110562306a36Sopenharmony_ci * Caller should be holding xprt->queue_lock.
110662306a36Sopenharmony_ci */
110762306a36Sopenharmony_civoid xprt_unpin_rqst(struct rpc_rqst *req)
110862306a36Sopenharmony_ci{
110962306a36Sopenharmony_ci	if (!test_bit(RPC_TASK_MSG_PIN_WAIT, &req->rq_task->tk_runstate)) {
111062306a36Sopenharmony_ci		atomic_dec(&req->rq_pin);
111162306a36Sopenharmony_ci		return;
111262306a36Sopenharmony_ci	}
111362306a36Sopenharmony_ci	if (atomic_dec_and_test(&req->rq_pin))
111462306a36Sopenharmony_ci		wake_up_var(&req->rq_pin);
111562306a36Sopenharmony_ci}
111662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(xprt_unpin_rqst);
111762306a36Sopenharmony_ci
111862306a36Sopenharmony_cistatic void xprt_wait_on_pinned_rqst(struct rpc_rqst *req)
111962306a36Sopenharmony_ci{
112062306a36Sopenharmony_ci	wait_var_event(&req->rq_pin, !xprt_is_pinned_rqst(req));
112162306a36Sopenharmony_ci}
112262306a36Sopenharmony_ci
112362306a36Sopenharmony_cistatic bool
112462306a36Sopenharmony_cixprt_request_data_received(struct rpc_task *task)
112562306a36Sopenharmony_ci{
112662306a36Sopenharmony_ci	return !test_bit(RPC_TASK_NEED_RECV, &task->tk_runstate) &&
112762306a36Sopenharmony_ci		READ_ONCE(task->tk_rqstp->rq_reply_bytes_recvd) != 0;
112862306a36Sopenharmony_ci}
112962306a36Sopenharmony_ci
113062306a36Sopenharmony_cistatic bool
113162306a36Sopenharmony_cixprt_request_need_enqueue_receive(struct rpc_task *task, struct rpc_rqst *req)
113262306a36Sopenharmony_ci{
113362306a36Sopenharmony_ci	return !test_bit(RPC_TASK_NEED_RECV, &task->tk_runstate) &&
113462306a36Sopenharmony_ci		READ_ONCE(task->tk_rqstp->rq_reply_bytes_recvd) == 0;
113562306a36Sopenharmony_ci}
113662306a36Sopenharmony_ci
113762306a36Sopenharmony_ci/**
113862306a36Sopenharmony_ci * xprt_request_enqueue_receive - Add an request to the receive queue
113962306a36Sopenharmony_ci * @task: RPC task
114062306a36Sopenharmony_ci *
114162306a36Sopenharmony_ci */
114262306a36Sopenharmony_ciint
114362306a36Sopenharmony_cixprt_request_enqueue_receive(struct rpc_task *task)
114462306a36Sopenharmony_ci{
114562306a36Sopenharmony_ci	struct rpc_rqst *req = task->tk_rqstp;
114662306a36Sopenharmony_ci	struct rpc_xprt *xprt = req->rq_xprt;
114762306a36Sopenharmony_ci	int ret;
114862306a36Sopenharmony_ci
114962306a36Sopenharmony_ci	if (!xprt_request_need_enqueue_receive(task, req))
115062306a36Sopenharmony_ci		return 0;
115162306a36Sopenharmony_ci
115262306a36Sopenharmony_ci	ret = xprt_request_prepare(task->tk_rqstp, &req->rq_rcv_buf);
115362306a36Sopenharmony_ci	if (ret)
115462306a36Sopenharmony_ci		return ret;
115562306a36Sopenharmony_ci	spin_lock(&xprt->queue_lock);
115662306a36Sopenharmony_ci
115762306a36Sopenharmony_ci	/* Update the softirq receive buffer */
115862306a36Sopenharmony_ci	memcpy(&req->rq_private_buf, &req->rq_rcv_buf,
115962306a36Sopenharmony_ci			sizeof(req->rq_private_buf));
116062306a36Sopenharmony_ci
116162306a36Sopenharmony_ci	/* Add request to the receive list */
116262306a36Sopenharmony_ci	xprt_request_rb_insert(xprt, req);
116362306a36Sopenharmony_ci	set_bit(RPC_TASK_NEED_RECV, &task->tk_runstate);
116462306a36Sopenharmony_ci	spin_unlock(&xprt->queue_lock);
116562306a36Sopenharmony_ci
116662306a36Sopenharmony_ci	/* Turn off autodisconnect */
116762306a36Sopenharmony_ci	del_timer_sync(&xprt->timer);
116862306a36Sopenharmony_ci	return 0;
116962306a36Sopenharmony_ci}
117062306a36Sopenharmony_ci
117162306a36Sopenharmony_ci/**
117262306a36Sopenharmony_ci * xprt_request_dequeue_receive_locked - Remove a request from the receive queue
117362306a36Sopenharmony_ci * @task: RPC task
117462306a36Sopenharmony_ci *
117562306a36Sopenharmony_ci * Caller must hold xprt->queue_lock.
117662306a36Sopenharmony_ci */
117762306a36Sopenharmony_cistatic void
117862306a36Sopenharmony_cixprt_request_dequeue_receive_locked(struct rpc_task *task)
117962306a36Sopenharmony_ci{
118062306a36Sopenharmony_ci	struct rpc_rqst *req = task->tk_rqstp;
118162306a36Sopenharmony_ci
118262306a36Sopenharmony_ci	if (test_and_clear_bit(RPC_TASK_NEED_RECV, &task->tk_runstate))
118362306a36Sopenharmony_ci		xprt_request_rb_remove(req->rq_xprt, req);
118462306a36Sopenharmony_ci}
118562306a36Sopenharmony_ci
118662306a36Sopenharmony_ci/**
118762306a36Sopenharmony_ci * xprt_update_rtt - Update RPC RTT statistics
118862306a36Sopenharmony_ci * @task: RPC request that recently completed
118962306a36Sopenharmony_ci *
119062306a36Sopenharmony_ci * Caller holds xprt->queue_lock.
119162306a36Sopenharmony_ci */
119262306a36Sopenharmony_civoid xprt_update_rtt(struct rpc_task *task)
119362306a36Sopenharmony_ci{
119462306a36Sopenharmony_ci	struct rpc_rqst *req = task->tk_rqstp;
119562306a36Sopenharmony_ci	struct rpc_rtt *rtt = task->tk_client->cl_rtt;
119662306a36Sopenharmony_ci	unsigned int timer = task->tk_msg.rpc_proc->p_timer;
119762306a36Sopenharmony_ci	long m = usecs_to_jiffies(ktime_to_us(req->rq_rtt));
119862306a36Sopenharmony_ci
119962306a36Sopenharmony_ci	if (timer) {
120062306a36Sopenharmony_ci		if (req->rq_ntrans == 1)
120162306a36Sopenharmony_ci			rpc_update_rtt(rtt, timer, m);
120262306a36Sopenharmony_ci		rpc_set_timeo(rtt, timer, req->rq_ntrans - 1);
120362306a36Sopenharmony_ci	}
120462306a36Sopenharmony_ci}
120562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(xprt_update_rtt);
120662306a36Sopenharmony_ci
120762306a36Sopenharmony_ci/**
120862306a36Sopenharmony_ci * xprt_complete_rqst - called when reply processing is complete
120962306a36Sopenharmony_ci * @task: RPC request that recently completed
121062306a36Sopenharmony_ci * @copied: actual number of bytes received from the transport
121162306a36Sopenharmony_ci *
121262306a36Sopenharmony_ci * Caller holds xprt->queue_lock.
121362306a36Sopenharmony_ci */
121462306a36Sopenharmony_civoid xprt_complete_rqst(struct rpc_task *task, int copied)
121562306a36Sopenharmony_ci{
121662306a36Sopenharmony_ci	struct rpc_rqst *req = task->tk_rqstp;
121762306a36Sopenharmony_ci	struct rpc_xprt *xprt = req->rq_xprt;
121862306a36Sopenharmony_ci
121962306a36Sopenharmony_ci	xprt->stat.recvs++;
122062306a36Sopenharmony_ci
122162306a36Sopenharmony_ci	xdr_free_bvec(&req->rq_rcv_buf);
122262306a36Sopenharmony_ci	req->rq_private_buf.bvec = NULL;
122362306a36Sopenharmony_ci	req->rq_private_buf.len = copied;
122462306a36Sopenharmony_ci	/* Ensure all writes are done before we update */
122562306a36Sopenharmony_ci	/* req->rq_reply_bytes_recvd */
122662306a36Sopenharmony_ci	smp_wmb();
122762306a36Sopenharmony_ci	req->rq_reply_bytes_recvd = copied;
122862306a36Sopenharmony_ci	xprt_request_dequeue_receive_locked(task);
122962306a36Sopenharmony_ci	rpc_wake_up_queued_task(&xprt->pending, task);
123062306a36Sopenharmony_ci}
123162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(xprt_complete_rqst);
123262306a36Sopenharmony_ci
123362306a36Sopenharmony_cistatic void xprt_timer(struct rpc_task *task)
123462306a36Sopenharmony_ci{
123562306a36Sopenharmony_ci	struct rpc_rqst *req = task->tk_rqstp;
123662306a36Sopenharmony_ci	struct rpc_xprt *xprt = req->rq_xprt;
123762306a36Sopenharmony_ci
123862306a36Sopenharmony_ci	if (task->tk_status != -ETIMEDOUT)
123962306a36Sopenharmony_ci		return;
124062306a36Sopenharmony_ci
124162306a36Sopenharmony_ci	trace_xprt_timer(xprt, req->rq_xid, task->tk_status);
124262306a36Sopenharmony_ci	if (!req->rq_reply_bytes_recvd) {
124362306a36Sopenharmony_ci		if (xprt->ops->timer)
124462306a36Sopenharmony_ci			xprt->ops->timer(xprt, task);
124562306a36Sopenharmony_ci	} else
124662306a36Sopenharmony_ci		task->tk_status = 0;
124762306a36Sopenharmony_ci}
124862306a36Sopenharmony_ci
124962306a36Sopenharmony_ci/**
125062306a36Sopenharmony_ci * xprt_wait_for_reply_request_def - wait for reply
125162306a36Sopenharmony_ci * @task: pointer to rpc_task
125262306a36Sopenharmony_ci *
125362306a36Sopenharmony_ci * Set a request's retransmit timeout based on the transport's
125462306a36Sopenharmony_ci * default timeout parameters.  Used by transports that don't adjust
125562306a36Sopenharmony_ci * the retransmit timeout based on round-trip time estimation,
125662306a36Sopenharmony_ci * and put the task to sleep on the pending queue.
125762306a36Sopenharmony_ci */
125862306a36Sopenharmony_civoid xprt_wait_for_reply_request_def(struct rpc_task *task)
125962306a36Sopenharmony_ci{
126062306a36Sopenharmony_ci	struct rpc_rqst *req = task->tk_rqstp;
126162306a36Sopenharmony_ci
126262306a36Sopenharmony_ci	rpc_sleep_on_timeout(&req->rq_xprt->pending, task, xprt_timer,
126362306a36Sopenharmony_ci			xprt_request_timeout(req));
126462306a36Sopenharmony_ci}
126562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(xprt_wait_for_reply_request_def);
126662306a36Sopenharmony_ci
126762306a36Sopenharmony_ci/**
126862306a36Sopenharmony_ci * xprt_wait_for_reply_request_rtt - wait for reply using RTT estimator
126962306a36Sopenharmony_ci * @task: pointer to rpc_task
127062306a36Sopenharmony_ci *
127162306a36Sopenharmony_ci * Set a request's retransmit timeout using the RTT estimator,
127262306a36Sopenharmony_ci * and put the task to sleep on the pending queue.
127362306a36Sopenharmony_ci */
127462306a36Sopenharmony_civoid xprt_wait_for_reply_request_rtt(struct rpc_task *task)
127562306a36Sopenharmony_ci{
127662306a36Sopenharmony_ci	int timer = task->tk_msg.rpc_proc->p_timer;
127762306a36Sopenharmony_ci	struct rpc_clnt *clnt = task->tk_client;
127862306a36Sopenharmony_ci	struct rpc_rtt *rtt = clnt->cl_rtt;
127962306a36Sopenharmony_ci	struct rpc_rqst *req = task->tk_rqstp;
128062306a36Sopenharmony_ci	unsigned long max_timeout = clnt->cl_timeout->to_maxval;
128162306a36Sopenharmony_ci	unsigned long timeout;
128262306a36Sopenharmony_ci
128362306a36Sopenharmony_ci	timeout = rpc_calc_rto(rtt, timer);
128462306a36Sopenharmony_ci	timeout <<= rpc_ntimeo(rtt, timer) + req->rq_retries;
128562306a36Sopenharmony_ci	if (timeout > max_timeout || timeout == 0)
128662306a36Sopenharmony_ci		timeout = max_timeout;
128762306a36Sopenharmony_ci	rpc_sleep_on_timeout(&req->rq_xprt->pending, task, xprt_timer,
128862306a36Sopenharmony_ci			jiffies + timeout);
128962306a36Sopenharmony_ci}
129062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(xprt_wait_for_reply_request_rtt);
129162306a36Sopenharmony_ci
129262306a36Sopenharmony_ci/**
129362306a36Sopenharmony_ci * xprt_request_wait_receive - wait for the reply to an RPC request
129462306a36Sopenharmony_ci * @task: RPC task about to send a request
129562306a36Sopenharmony_ci *
129662306a36Sopenharmony_ci */
129762306a36Sopenharmony_civoid xprt_request_wait_receive(struct rpc_task *task)
129862306a36Sopenharmony_ci{
129962306a36Sopenharmony_ci	struct rpc_rqst *req = task->tk_rqstp;
130062306a36Sopenharmony_ci	struct rpc_xprt *xprt = req->rq_xprt;
130162306a36Sopenharmony_ci
130262306a36Sopenharmony_ci	if (!test_bit(RPC_TASK_NEED_RECV, &task->tk_runstate))
130362306a36Sopenharmony_ci		return;
130462306a36Sopenharmony_ci	/*
130562306a36Sopenharmony_ci	 * Sleep on the pending queue if we're expecting a reply.
130662306a36Sopenharmony_ci	 * The spinlock ensures atomicity between the test of
130762306a36Sopenharmony_ci	 * req->rq_reply_bytes_recvd, and the call to rpc_sleep_on().
130862306a36Sopenharmony_ci	 */
130962306a36Sopenharmony_ci	spin_lock(&xprt->queue_lock);
131062306a36Sopenharmony_ci	if (test_bit(RPC_TASK_NEED_RECV, &task->tk_runstate)) {
131162306a36Sopenharmony_ci		xprt->ops->wait_for_reply_request(task);
131262306a36Sopenharmony_ci		/*
131362306a36Sopenharmony_ci		 * Send an extra queue wakeup call if the
131462306a36Sopenharmony_ci		 * connection was dropped in case the call to
131562306a36Sopenharmony_ci		 * rpc_sleep_on() raced.
131662306a36Sopenharmony_ci		 */
131762306a36Sopenharmony_ci		if (xprt_request_retransmit_after_disconnect(task))
131862306a36Sopenharmony_ci			rpc_wake_up_queued_task_set_status(&xprt->pending,
131962306a36Sopenharmony_ci					task, -ENOTCONN);
132062306a36Sopenharmony_ci	}
132162306a36Sopenharmony_ci	spin_unlock(&xprt->queue_lock);
132262306a36Sopenharmony_ci}
132362306a36Sopenharmony_ci
132462306a36Sopenharmony_cistatic bool
132562306a36Sopenharmony_cixprt_request_need_enqueue_transmit(struct rpc_task *task, struct rpc_rqst *req)
132662306a36Sopenharmony_ci{
132762306a36Sopenharmony_ci	return !test_bit(RPC_TASK_NEED_XMIT, &task->tk_runstate);
132862306a36Sopenharmony_ci}
132962306a36Sopenharmony_ci
133062306a36Sopenharmony_ci/**
133162306a36Sopenharmony_ci * xprt_request_enqueue_transmit - queue a task for transmission
133262306a36Sopenharmony_ci * @task: pointer to rpc_task
133362306a36Sopenharmony_ci *
133462306a36Sopenharmony_ci * Add a task to the transmission queue.
133562306a36Sopenharmony_ci */
133662306a36Sopenharmony_civoid
133762306a36Sopenharmony_cixprt_request_enqueue_transmit(struct rpc_task *task)
133862306a36Sopenharmony_ci{
133962306a36Sopenharmony_ci	struct rpc_rqst *pos, *req = task->tk_rqstp;
134062306a36Sopenharmony_ci	struct rpc_xprt *xprt = req->rq_xprt;
134162306a36Sopenharmony_ci	int ret;
134262306a36Sopenharmony_ci
134362306a36Sopenharmony_ci	if (xprt_request_need_enqueue_transmit(task, req)) {
134462306a36Sopenharmony_ci		ret = xprt_request_prepare(task->tk_rqstp, &req->rq_snd_buf);
134562306a36Sopenharmony_ci		if (ret) {
134662306a36Sopenharmony_ci			task->tk_status = ret;
134762306a36Sopenharmony_ci			return;
134862306a36Sopenharmony_ci		}
134962306a36Sopenharmony_ci		req->rq_bytes_sent = 0;
135062306a36Sopenharmony_ci		spin_lock(&xprt->queue_lock);
135162306a36Sopenharmony_ci		/*
135262306a36Sopenharmony_ci		 * Requests that carry congestion control credits are added
135362306a36Sopenharmony_ci		 * to the head of the list to avoid starvation issues.
135462306a36Sopenharmony_ci		 */
135562306a36Sopenharmony_ci		if (req->rq_cong) {
135662306a36Sopenharmony_ci			xprt_clear_congestion_window_wait(xprt);
135762306a36Sopenharmony_ci			list_for_each_entry(pos, &xprt->xmit_queue, rq_xmit) {
135862306a36Sopenharmony_ci				if (pos->rq_cong)
135962306a36Sopenharmony_ci					continue;
136062306a36Sopenharmony_ci				/* Note: req is added _before_ pos */
136162306a36Sopenharmony_ci				list_add_tail(&req->rq_xmit, &pos->rq_xmit);
136262306a36Sopenharmony_ci				INIT_LIST_HEAD(&req->rq_xmit2);
136362306a36Sopenharmony_ci				goto out;
136462306a36Sopenharmony_ci			}
136562306a36Sopenharmony_ci		} else if (!req->rq_seqno) {
136662306a36Sopenharmony_ci			list_for_each_entry(pos, &xprt->xmit_queue, rq_xmit) {
136762306a36Sopenharmony_ci				if (pos->rq_task->tk_owner != task->tk_owner)
136862306a36Sopenharmony_ci					continue;
136962306a36Sopenharmony_ci				list_add_tail(&req->rq_xmit2, &pos->rq_xmit2);
137062306a36Sopenharmony_ci				INIT_LIST_HEAD(&req->rq_xmit);
137162306a36Sopenharmony_ci				goto out;
137262306a36Sopenharmony_ci			}
137362306a36Sopenharmony_ci		}
137462306a36Sopenharmony_ci		list_add_tail(&req->rq_xmit, &xprt->xmit_queue);
137562306a36Sopenharmony_ci		INIT_LIST_HEAD(&req->rq_xmit2);
137662306a36Sopenharmony_ciout:
137762306a36Sopenharmony_ci		atomic_long_inc(&xprt->xmit_queuelen);
137862306a36Sopenharmony_ci		set_bit(RPC_TASK_NEED_XMIT, &task->tk_runstate);
137962306a36Sopenharmony_ci		spin_unlock(&xprt->queue_lock);
138062306a36Sopenharmony_ci	}
138162306a36Sopenharmony_ci}
138262306a36Sopenharmony_ci
138362306a36Sopenharmony_ci/**
138462306a36Sopenharmony_ci * xprt_request_dequeue_transmit_locked - remove a task from the transmission queue
138562306a36Sopenharmony_ci * @task: pointer to rpc_task
138662306a36Sopenharmony_ci *
138762306a36Sopenharmony_ci * Remove a task from the transmission queue
138862306a36Sopenharmony_ci * Caller must hold xprt->queue_lock
138962306a36Sopenharmony_ci */
139062306a36Sopenharmony_cistatic void
139162306a36Sopenharmony_cixprt_request_dequeue_transmit_locked(struct rpc_task *task)
139262306a36Sopenharmony_ci{
139362306a36Sopenharmony_ci	struct rpc_rqst *req = task->tk_rqstp;
139462306a36Sopenharmony_ci
139562306a36Sopenharmony_ci	if (!test_and_clear_bit(RPC_TASK_NEED_XMIT, &task->tk_runstate))
139662306a36Sopenharmony_ci		return;
139762306a36Sopenharmony_ci	if (!list_empty(&req->rq_xmit)) {
139862306a36Sopenharmony_ci		list_del(&req->rq_xmit);
139962306a36Sopenharmony_ci		if (!list_empty(&req->rq_xmit2)) {
140062306a36Sopenharmony_ci			struct rpc_rqst *next = list_first_entry(&req->rq_xmit2,
140162306a36Sopenharmony_ci					struct rpc_rqst, rq_xmit2);
140262306a36Sopenharmony_ci			list_del(&req->rq_xmit2);
140362306a36Sopenharmony_ci			list_add_tail(&next->rq_xmit, &next->rq_xprt->xmit_queue);
140462306a36Sopenharmony_ci		}
140562306a36Sopenharmony_ci	} else
140662306a36Sopenharmony_ci		list_del(&req->rq_xmit2);
140762306a36Sopenharmony_ci	atomic_long_dec(&req->rq_xprt->xmit_queuelen);
140862306a36Sopenharmony_ci	xdr_free_bvec(&req->rq_snd_buf);
140962306a36Sopenharmony_ci}
141062306a36Sopenharmony_ci
141162306a36Sopenharmony_ci/**
141262306a36Sopenharmony_ci * xprt_request_dequeue_transmit - remove a task from the transmission queue
141362306a36Sopenharmony_ci * @task: pointer to rpc_task
141462306a36Sopenharmony_ci *
141562306a36Sopenharmony_ci * Remove a task from the transmission queue
141662306a36Sopenharmony_ci */
141762306a36Sopenharmony_cistatic void
141862306a36Sopenharmony_cixprt_request_dequeue_transmit(struct rpc_task *task)
141962306a36Sopenharmony_ci{
142062306a36Sopenharmony_ci	struct rpc_rqst *req = task->tk_rqstp;
142162306a36Sopenharmony_ci	struct rpc_xprt *xprt = req->rq_xprt;
142262306a36Sopenharmony_ci
142362306a36Sopenharmony_ci	spin_lock(&xprt->queue_lock);
142462306a36Sopenharmony_ci	xprt_request_dequeue_transmit_locked(task);
142562306a36Sopenharmony_ci	spin_unlock(&xprt->queue_lock);
142662306a36Sopenharmony_ci}
142762306a36Sopenharmony_ci
142862306a36Sopenharmony_ci/**
142962306a36Sopenharmony_ci * xprt_request_dequeue_xprt - remove a task from the transmit+receive queue
143062306a36Sopenharmony_ci * @task: pointer to rpc_task
143162306a36Sopenharmony_ci *
143262306a36Sopenharmony_ci * Remove a task from the transmit and receive queues, and ensure that
143362306a36Sopenharmony_ci * it is not pinned by the receive work item.
143462306a36Sopenharmony_ci */
143562306a36Sopenharmony_civoid
143662306a36Sopenharmony_cixprt_request_dequeue_xprt(struct rpc_task *task)
143762306a36Sopenharmony_ci{
143862306a36Sopenharmony_ci	struct rpc_rqst	*req = task->tk_rqstp;
143962306a36Sopenharmony_ci	struct rpc_xprt *xprt = req->rq_xprt;
144062306a36Sopenharmony_ci
144162306a36Sopenharmony_ci	if (test_bit(RPC_TASK_NEED_XMIT, &task->tk_runstate) ||
144262306a36Sopenharmony_ci	    test_bit(RPC_TASK_NEED_RECV, &task->tk_runstate) ||
144362306a36Sopenharmony_ci	    xprt_is_pinned_rqst(req)) {
144462306a36Sopenharmony_ci		spin_lock(&xprt->queue_lock);
144562306a36Sopenharmony_ci		while (xprt_is_pinned_rqst(req)) {
144662306a36Sopenharmony_ci			set_bit(RPC_TASK_MSG_PIN_WAIT, &task->tk_runstate);
144762306a36Sopenharmony_ci			spin_unlock(&xprt->queue_lock);
144862306a36Sopenharmony_ci			xprt_wait_on_pinned_rqst(req);
144962306a36Sopenharmony_ci			spin_lock(&xprt->queue_lock);
145062306a36Sopenharmony_ci			clear_bit(RPC_TASK_MSG_PIN_WAIT, &task->tk_runstate);
145162306a36Sopenharmony_ci		}
145262306a36Sopenharmony_ci		xprt_request_dequeue_transmit_locked(task);
145362306a36Sopenharmony_ci		xprt_request_dequeue_receive_locked(task);
145462306a36Sopenharmony_ci		spin_unlock(&xprt->queue_lock);
145562306a36Sopenharmony_ci		xdr_free_bvec(&req->rq_rcv_buf);
145662306a36Sopenharmony_ci	}
145762306a36Sopenharmony_ci}
145862306a36Sopenharmony_ci
145962306a36Sopenharmony_ci/**
146062306a36Sopenharmony_ci * xprt_request_prepare - prepare an encoded request for transport
146162306a36Sopenharmony_ci * @req: pointer to rpc_rqst
146262306a36Sopenharmony_ci * @buf: pointer to send/rcv xdr_buf
146362306a36Sopenharmony_ci *
146462306a36Sopenharmony_ci * Calls into the transport layer to do whatever is needed to prepare
146562306a36Sopenharmony_ci * the request for transmission or receive.
146662306a36Sopenharmony_ci * Returns error, or zero.
146762306a36Sopenharmony_ci */
146862306a36Sopenharmony_cistatic int
146962306a36Sopenharmony_cixprt_request_prepare(struct rpc_rqst *req, struct xdr_buf *buf)
147062306a36Sopenharmony_ci{
147162306a36Sopenharmony_ci	struct rpc_xprt *xprt = req->rq_xprt;
147262306a36Sopenharmony_ci
147362306a36Sopenharmony_ci	if (xprt->ops->prepare_request)
147462306a36Sopenharmony_ci		return xprt->ops->prepare_request(req, buf);
147562306a36Sopenharmony_ci	return 0;
147662306a36Sopenharmony_ci}
147762306a36Sopenharmony_ci
147862306a36Sopenharmony_ci/**
147962306a36Sopenharmony_ci * xprt_request_need_retransmit - Test if a task needs retransmission
148062306a36Sopenharmony_ci * @task: pointer to rpc_task
148162306a36Sopenharmony_ci *
148262306a36Sopenharmony_ci * Test for whether a connection breakage requires the task to retransmit
148362306a36Sopenharmony_ci */
148462306a36Sopenharmony_cibool
148562306a36Sopenharmony_cixprt_request_need_retransmit(struct rpc_task *task)
148662306a36Sopenharmony_ci{
148762306a36Sopenharmony_ci	return xprt_request_retransmit_after_disconnect(task);
148862306a36Sopenharmony_ci}
148962306a36Sopenharmony_ci
149062306a36Sopenharmony_ci/**
149162306a36Sopenharmony_ci * xprt_prepare_transmit - reserve the transport before sending a request
149262306a36Sopenharmony_ci * @task: RPC task about to send a request
149362306a36Sopenharmony_ci *
149462306a36Sopenharmony_ci */
149562306a36Sopenharmony_cibool xprt_prepare_transmit(struct rpc_task *task)
149662306a36Sopenharmony_ci{
149762306a36Sopenharmony_ci	struct rpc_rqst	*req = task->tk_rqstp;
149862306a36Sopenharmony_ci	struct rpc_xprt	*xprt = req->rq_xprt;
149962306a36Sopenharmony_ci
150062306a36Sopenharmony_ci	if (!xprt_lock_write(xprt, task)) {
150162306a36Sopenharmony_ci		/* Race breaker: someone may have transmitted us */
150262306a36Sopenharmony_ci		if (!test_bit(RPC_TASK_NEED_XMIT, &task->tk_runstate))
150362306a36Sopenharmony_ci			rpc_wake_up_queued_task_set_status(&xprt->sending,
150462306a36Sopenharmony_ci					task, 0);
150562306a36Sopenharmony_ci		return false;
150662306a36Sopenharmony_ci
150762306a36Sopenharmony_ci	}
150862306a36Sopenharmony_ci	if (atomic_read(&xprt->swapper))
150962306a36Sopenharmony_ci		/* This will be clear in __rpc_execute */
151062306a36Sopenharmony_ci		current->flags |= PF_MEMALLOC;
151162306a36Sopenharmony_ci	return true;
151262306a36Sopenharmony_ci}
151362306a36Sopenharmony_ci
151462306a36Sopenharmony_civoid xprt_end_transmit(struct rpc_task *task)
151562306a36Sopenharmony_ci{
151662306a36Sopenharmony_ci	struct rpc_xprt	*xprt = task->tk_rqstp->rq_xprt;
151762306a36Sopenharmony_ci
151862306a36Sopenharmony_ci	xprt_inject_disconnect(xprt);
151962306a36Sopenharmony_ci	xprt_release_write(xprt, task);
152062306a36Sopenharmony_ci}
152162306a36Sopenharmony_ci
152262306a36Sopenharmony_ci/**
152362306a36Sopenharmony_ci * xprt_request_transmit - send an RPC request on a transport
152462306a36Sopenharmony_ci * @req: pointer to request to transmit
152562306a36Sopenharmony_ci * @snd_task: RPC task that owns the transport lock
152662306a36Sopenharmony_ci *
152762306a36Sopenharmony_ci * This performs the transmission of a single request.
152862306a36Sopenharmony_ci * Note that if the request is not the same as snd_task, then it
152962306a36Sopenharmony_ci * does need to be pinned.
153062306a36Sopenharmony_ci * Returns '0' on success.
153162306a36Sopenharmony_ci */
153262306a36Sopenharmony_cistatic int
153362306a36Sopenharmony_cixprt_request_transmit(struct rpc_rqst *req, struct rpc_task *snd_task)
153462306a36Sopenharmony_ci{
153562306a36Sopenharmony_ci	struct rpc_xprt *xprt = req->rq_xprt;
153662306a36Sopenharmony_ci	struct rpc_task *task = req->rq_task;
153762306a36Sopenharmony_ci	unsigned int connect_cookie;
153862306a36Sopenharmony_ci	int is_retrans = RPC_WAS_SENT(task);
153962306a36Sopenharmony_ci	int status;
154062306a36Sopenharmony_ci
154162306a36Sopenharmony_ci	if (!req->rq_bytes_sent) {
154262306a36Sopenharmony_ci		if (xprt_request_data_received(task)) {
154362306a36Sopenharmony_ci			status = 0;
154462306a36Sopenharmony_ci			goto out_dequeue;
154562306a36Sopenharmony_ci		}
154662306a36Sopenharmony_ci		/* Verify that our message lies in the RPCSEC_GSS window */
154762306a36Sopenharmony_ci		if (rpcauth_xmit_need_reencode(task)) {
154862306a36Sopenharmony_ci			status = -EBADMSG;
154962306a36Sopenharmony_ci			goto out_dequeue;
155062306a36Sopenharmony_ci		}
155162306a36Sopenharmony_ci		if (RPC_SIGNALLED(task)) {
155262306a36Sopenharmony_ci			status = -ERESTARTSYS;
155362306a36Sopenharmony_ci			goto out_dequeue;
155462306a36Sopenharmony_ci		}
155562306a36Sopenharmony_ci	}
155662306a36Sopenharmony_ci
155762306a36Sopenharmony_ci	/*
155862306a36Sopenharmony_ci	 * Update req->rq_ntrans before transmitting to avoid races with
155962306a36Sopenharmony_ci	 * xprt_update_rtt(), which needs to know that it is recording a
156062306a36Sopenharmony_ci	 * reply to the first transmission.
156162306a36Sopenharmony_ci	 */
156262306a36Sopenharmony_ci	req->rq_ntrans++;
156362306a36Sopenharmony_ci
156462306a36Sopenharmony_ci	trace_rpc_xdr_sendto(task, &req->rq_snd_buf);
156562306a36Sopenharmony_ci	connect_cookie = xprt->connect_cookie;
156662306a36Sopenharmony_ci	status = xprt->ops->send_request(req);
156762306a36Sopenharmony_ci	if (status != 0) {
156862306a36Sopenharmony_ci		req->rq_ntrans--;
156962306a36Sopenharmony_ci		trace_xprt_transmit(req, status);
157062306a36Sopenharmony_ci		return status;
157162306a36Sopenharmony_ci	}
157262306a36Sopenharmony_ci
157362306a36Sopenharmony_ci	if (is_retrans) {
157462306a36Sopenharmony_ci		task->tk_client->cl_stats->rpcretrans++;
157562306a36Sopenharmony_ci		trace_xprt_retransmit(req);
157662306a36Sopenharmony_ci	}
157762306a36Sopenharmony_ci
157862306a36Sopenharmony_ci	xprt_inject_disconnect(xprt);
157962306a36Sopenharmony_ci
158062306a36Sopenharmony_ci	task->tk_flags |= RPC_TASK_SENT;
158162306a36Sopenharmony_ci	spin_lock(&xprt->transport_lock);
158262306a36Sopenharmony_ci
158362306a36Sopenharmony_ci	xprt->stat.sends++;
158462306a36Sopenharmony_ci	xprt->stat.req_u += xprt->stat.sends - xprt->stat.recvs;
158562306a36Sopenharmony_ci	xprt->stat.bklog_u += xprt->backlog.qlen;
158662306a36Sopenharmony_ci	xprt->stat.sending_u += xprt->sending.qlen;
158762306a36Sopenharmony_ci	xprt->stat.pending_u += xprt->pending.qlen;
158862306a36Sopenharmony_ci	spin_unlock(&xprt->transport_lock);
158962306a36Sopenharmony_ci
159062306a36Sopenharmony_ci	req->rq_connect_cookie = connect_cookie;
159162306a36Sopenharmony_ciout_dequeue:
159262306a36Sopenharmony_ci	trace_xprt_transmit(req, status);
159362306a36Sopenharmony_ci	xprt_request_dequeue_transmit(task);
159462306a36Sopenharmony_ci	rpc_wake_up_queued_task_set_status(&xprt->sending, task, status);
159562306a36Sopenharmony_ci	return status;
159662306a36Sopenharmony_ci}
159762306a36Sopenharmony_ci
159862306a36Sopenharmony_ci/**
159962306a36Sopenharmony_ci * xprt_transmit - send an RPC request on a transport
160062306a36Sopenharmony_ci * @task: controlling RPC task
160162306a36Sopenharmony_ci *
160262306a36Sopenharmony_ci * Attempts to drain the transmit queue. On exit, either the transport
160362306a36Sopenharmony_ci * signalled an error that needs to be handled before transmission can
160462306a36Sopenharmony_ci * resume, or @task finished transmitting, and detected that it already
160562306a36Sopenharmony_ci * received a reply.
160662306a36Sopenharmony_ci */
160762306a36Sopenharmony_civoid
160862306a36Sopenharmony_cixprt_transmit(struct rpc_task *task)
160962306a36Sopenharmony_ci{
161062306a36Sopenharmony_ci	struct rpc_rqst *next, *req = task->tk_rqstp;
161162306a36Sopenharmony_ci	struct rpc_xprt	*xprt = req->rq_xprt;
161262306a36Sopenharmony_ci	int status;
161362306a36Sopenharmony_ci
161462306a36Sopenharmony_ci	spin_lock(&xprt->queue_lock);
161562306a36Sopenharmony_ci	for (;;) {
161662306a36Sopenharmony_ci		next = list_first_entry_or_null(&xprt->xmit_queue,
161762306a36Sopenharmony_ci						struct rpc_rqst, rq_xmit);
161862306a36Sopenharmony_ci		if (!next)
161962306a36Sopenharmony_ci			break;
162062306a36Sopenharmony_ci		xprt_pin_rqst(next);
162162306a36Sopenharmony_ci		spin_unlock(&xprt->queue_lock);
162262306a36Sopenharmony_ci		status = xprt_request_transmit(next, task);
162362306a36Sopenharmony_ci		if (status == -EBADMSG && next != req)
162462306a36Sopenharmony_ci			status = 0;
162562306a36Sopenharmony_ci		spin_lock(&xprt->queue_lock);
162662306a36Sopenharmony_ci		xprt_unpin_rqst(next);
162762306a36Sopenharmony_ci		if (status < 0) {
162862306a36Sopenharmony_ci			if (test_bit(RPC_TASK_NEED_XMIT, &task->tk_runstate))
162962306a36Sopenharmony_ci				task->tk_status = status;
163062306a36Sopenharmony_ci			break;
163162306a36Sopenharmony_ci		}
163262306a36Sopenharmony_ci		/* Was @task transmitted, and has it received a reply? */
163362306a36Sopenharmony_ci		if (xprt_request_data_received(task) &&
163462306a36Sopenharmony_ci		    !test_bit(RPC_TASK_NEED_XMIT, &task->tk_runstate))
163562306a36Sopenharmony_ci			break;
163662306a36Sopenharmony_ci		cond_resched_lock(&xprt->queue_lock);
163762306a36Sopenharmony_ci	}
163862306a36Sopenharmony_ci	spin_unlock(&xprt->queue_lock);
163962306a36Sopenharmony_ci}
164062306a36Sopenharmony_ci
164162306a36Sopenharmony_cistatic void xprt_complete_request_init(struct rpc_task *task)
164262306a36Sopenharmony_ci{
164362306a36Sopenharmony_ci	if (task->tk_rqstp)
164462306a36Sopenharmony_ci		xprt_request_init(task);
164562306a36Sopenharmony_ci}
164662306a36Sopenharmony_ci
164762306a36Sopenharmony_civoid xprt_add_backlog(struct rpc_xprt *xprt, struct rpc_task *task)
164862306a36Sopenharmony_ci{
164962306a36Sopenharmony_ci	set_bit(XPRT_CONGESTED, &xprt->state);
165062306a36Sopenharmony_ci	rpc_sleep_on(&xprt->backlog, task, xprt_complete_request_init);
165162306a36Sopenharmony_ci}
165262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(xprt_add_backlog);
165362306a36Sopenharmony_ci
165462306a36Sopenharmony_cistatic bool __xprt_set_rq(struct rpc_task *task, void *data)
165562306a36Sopenharmony_ci{
165662306a36Sopenharmony_ci	struct rpc_rqst *req = data;
165762306a36Sopenharmony_ci
165862306a36Sopenharmony_ci	if (task->tk_rqstp == NULL) {
165962306a36Sopenharmony_ci		memset(req, 0, sizeof(*req));	/* mark unused */
166062306a36Sopenharmony_ci		task->tk_rqstp = req;
166162306a36Sopenharmony_ci		return true;
166262306a36Sopenharmony_ci	}
166362306a36Sopenharmony_ci	return false;
166462306a36Sopenharmony_ci}
166562306a36Sopenharmony_ci
166662306a36Sopenharmony_cibool xprt_wake_up_backlog(struct rpc_xprt *xprt, struct rpc_rqst *req)
166762306a36Sopenharmony_ci{
166862306a36Sopenharmony_ci	if (rpc_wake_up_first(&xprt->backlog, __xprt_set_rq, req) == NULL) {
166962306a36Sopenharmony_ci		clear_bit(XPRT_CONGESTED, &xprt->state);
167062306a36Sopenharmony_ci		return false;
167162306a36Sopenharmony_ci	}
167262306a36Sopenharmony_ci	return true;
167362306a36Sopenharmony_ci}
167462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(xprt_wake_up_backlog);
167562306a36Sopenharmony_ci
167662306a36Sopenharmony_cistatic bool xprt_throttle_congested(struct rpc_xprt *xprt, struct rpc_task *task)
167762306a36Sopenharmony_ci{
167862306a36Sopenharmony_ci	bool ret = false;
167962306a36Sopenharmony_ci
168062306a36Sopenharmony_ci	if (!test_bit(XPRT_CONGESTED, &xprt->state))
168162306a36Sopenharmony_ci		goto out;
168262306a36Sopenharmony_ci	spin_lock(&xprt->reserve_lock);
168362306a36Sopenharmony_ci	if (test_bit(XPRT_CONGESTED, &xprt->state)) {
168462306a36Sopenharmony_ci		xprt_add_backlog(xprt, task);
168562306a36Sopenharmony_ci		ret = true;
168662306a36Sopenharmony_ci	}
168762306a36Sopenharmony_ci	spin_unlock(&xprt->reserve_lock);
168862306a36Sopenharmony_ciout:
168962306a36Sopenharmony_ci	return ret;
169062306a36Sopenharmony_ci}
169162306a36Sopenharmony_ci
169262306a36Sopenharmony_cistatic struct rpc_rqst *xprt_dynamic_alloc_slot(struct rpc_xprt *xprt)
169362306a36Sopenharmony_ci{
169462306a36Sopenharmony_ci	struct rpc_rqst *req = ERR_PTR(-EAGAIN);
169562306a36Sopenharmony_ci
169662306a36Sopenharmony_ci	if (xprt->num_reqs >= xprt->max_reqs)
169762306a36Sopenharmony_ci		goto out;
169862306a36Sopenharmony_ci	++xprt->num_reqs;
169962306a36Sopenharmony_ci	spin_unlock(&xprt->reserve_lock);
170062306a36Sopenharmony_ci	req = kzalloc(sizeof(*req), rpc_task_gfp_mask());
170162306a36Sopenharmony_ci	spin_lock(&xprt->reserve_lock);
170262306a36Sopenharmony_ci	if (req != NULL)
170362306a36Sopenharmony_ci		goto out;
170462306a36Sopenharmony_ci	--xprt->num_reqs;
170562306a36Sopenharmony_ci	req = ERR_PTR(-ENOMEM);
170662306a36Sopenharmony_ciout:
170762306a36Sopenharmony_ci	return req;
170862306a36Sopenharmony_ci}
170962306a36Sopenharmony_ci
171062306a36Sopenharmony_cistatic bool xprt_dynamic_free_slot(struct rpc_xprt *xprt, struct rpc_rqst *req)
171162306a36Sopenharmony_ci{
171262306a36Sopenharmony_ci	if (xprt->num_reqs > xprt->min_reqs) {
171362306a36Sopenharmony_ci		--xprt->num_reqs;
171462306a36Sopenharmony_ci		kfree(req);
171562306a36Sopenharmony_ci		return true;
171662306a36Sopenharmony_ci	}
171762306a36Sopenharmony_ci	return false;
171862306a36Sopenharmony_ci}
171962306a36Sopenharmony_ci
172062306a36Sopenharmony_civoid xprt_alloc_slot(struct rpc_xprt *xprt, struct rpc_task *task)
172162306a36Sopenharmony_ci{
172262306a36Sopenharmony_ci	struct rpc_rqst *req;
172362306a36Sopenharmony_ci
172462306a36Sopenharmony_ci	spin_lock(&xprt->reserve_lock);
172562306a36Sopenharmony_ci	if (!list_empty(&xprt->free)) {
172662306a36Sopenharmony_ci		req = list_entry(xprt->free.next, struct rpc_rqst, rq_list);
172762306a36Sopenharmony_ci		list_del(&req->rq_list);
172862306a36Sopenharmony_ci		goto out_init_req;
172962306a36Sopenharmony_ci	}
173062306a36Sopenharmony_ci	req = xprt_dynamic_alloc_slot(xprt);
173162306a36Sopenharmony_ci	if (!IS_ERR(req))
173262306a36Sopenharmony_ci		goto out_init_req;
173362306a36Sopenharmony_ci	switch (PTR_ERR(req)) {
173462306a36Sopenharmony_ci	case -ENOMEM:
173562306a36Sopenharmony_ci		dprintk("RPC:       dynamic allocation of request slot "
173662306a36Sopenharmony_ci				"failed! Retrying\n");
173762306a36Sopenharmony_ci		task->tk_status = -ENOMEM;
173862306a36Sopenharmony_ci		break;
173962306a36Sopenharmony_ci	case -EAGAIN:
174062306a36Sopenharmony_ci		xprt_add_backlog(xprt, task);
174162306a36Sopenharmony_ci		dprintk("RPC:       waiting for request slot\n");
174262306a36Sopenharmony_ci		fallthrough;
174362306a36Sopenharmony_ci	default:
174462306a36Sopenharmony_ci		task->tk_status = -EAGAIN;
174562306a36Sopenharmony_ci	}
174662306a36Sopenharmony_ci	spin_unlock(&xprt->reserve_lock);
174762306a36Sopenharmony_ci	return;
174862306a36Sopenharmony_ciout_init_req:
174962306a36Sopenharmony_ci	xprt->stat.max_slots = max_t(unsigned int, xprt->stat.max_slots,
175062306a36Sopenharmony_ci				     xprt->num_reqs);
175162306a36Sopenharmony_ci	spin_unlock(&xprt->reserve_lock);
175262306a36Sopenharmony_ci
175362306a36Sopenharmony_ci	task->tk_status = 0;
175462306a36Sopenharmony_ci	task->tk_rqstp = req;
175562306a36Sopenharmony_ci}
175662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(xprt_alloc_slot);
175762306a36Sopenharmony_ci
175862306a36Sopenharmony_civoid xprt_free_slot(struct rpc_xprt *xprt, struct rpc_rqst *req)
175962306a36Sopenharmony_ci{
176062306a36Sopenharmony_ci	spin_lock(&xprt->reserve_lock);
176162306a36Sopenharmony_ci	if (!xprt_wake_up_backlog(xprt, req) &&
176262306a36Sopenharmony_ci	    !xprt_dynamic_free_slot(xprt, req)) {
176362306a36Sopenharmony_ci		memset(req, 0, sizeof(*req));	/* mark unused */
176462306a36Sopenharmony_ci		list_add(&req->rq_list, &xprt->free);
176562306a36Sopenharmony_ci	}
176662306a36Sopenharmony_ci	spin_unlock(&xprt->reserve_lock);
176762306a36Sopenharmony_ci}
176862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(xprt_free_slot);
176962306a36Sopenharmony_ci
177062306a36Sopenharmony_cistatic void xprt_free_all_slots(struct rpc_xprt *xprt)
177162306a36Sopenharmony_ci{
177262306a36Sopenharmony_ci	struct rpc_rqst *req;
177362306a36Sopenharmony_ci	while (!list_empty(&xprt->free)) {
177462306a36Sopenharmony_ci		req = list_first_entry(&xprt->free, struct rpc_rqst, rq_list);
177562306a36Sopenharmony_ci		list_del(&req->rq_list);
177662306a36Sopenharmony_ci		kfree(req);
177762306a36Sopenharmony_ci	}
177862306a36Sopenharmony_ci}
177962306a36Sopenharmony_ci
178062306a36Sopenharmony_cistatic DEFINE_IDA(rpc_xprt_ids);
178162306a36Sopenharmony_ci
178262306a36Sopenharmony_civoid xprt_cleanup_ids(void)
178362306a36Sopenharmony_ci{
178462306a36Sopenharmony_ci	ida_destroy(&rpc_xprt_ids);
178562306a36Sopenharmony_ci}
178662306a36Sopenharmony_ci
178762306a36Sopenharmony_cistatic int xprt_alloc_id(struct rpc_xprt *xprt)
178862306a36Sopenharmony_ci{
178962306a36Sopenharmony_ci	int id;
179062306a36Sopenharmony_ci
179162306a36Sopenharmony_ci	id = ida_alloc(&rpc_xprt_ids, GFP_KERNEL);
179262306a36Sopenharmony_ci	if (id < 0)
179362306a36Sopenharmony_ci		return id;
179462306a36Sopenharmony_ci
179562306a36Sopenharmony_ci	xprt->id = id;
179662306a36Sopenharmony_ci	return 0;
179762306a36Sopenharmony_ci}
179862306a36Sopenharmony_ci
179962306a36Sopenharmony_cistatic void xprt_free_id(struct rpc_xprt *xprt)
180062306a36Sopenharmony_ci{
180162306a36Sopenharmony_ci	ida_free(&rpc_xprt_ids, xprt->id);
180262306a36Sopenharmony_ci}
180362306a36Sopenharmony_ci
180462306a36Sopenharmony_cistruct rpc_xprt *xprt_alloc(struct net *net, size_t size,
180562306a36Sopenharmony_ci		unsigned int num_prealloc,
180662306a36Sopenharmony_ci		unsigned int max_alloc)
180762306a36Sopenharmony_ci{
180862306a36Sopenharmony_ci	struct rpc_xprt *xprt;
180962306a36Sopenharmony_ci	struct rpc_rqst *req;
181062306a36Sopenharmony_ci	int i;
181162306a36Sopenharmony_ci
181262306a36Sopenharmony_ci	xprt = kzalloc(size, GFP_KERNEL);
181362306a36Sopenharmony_ci	if (xprt == NULL)
181462306a36Sopenharmony_ci		goto out;
181562306a36Sopenharmony_ci
181662306a36Sopenharmony_ci	xprt_alloc_id(xprt);
181762306a36Sopenharmony_ci	xprt_init(xprt, net);
181862306a36Sopenharmony_ci
181962306a36Sopenharmony_ci	for (i = 0; i < num_prealloc; i++) {
182062306a36Sopenharmony_ci		req = kzalloc(sizeof(struct rpc_rqst), GFP_KERNEL);
182162306a36Sopenharmony_ci		if (!req)
182262306a36Sopenharmony_ci			goto out_free;
182362306a36Sopenharmony_ci		list_add(&req->rq_list, &xprt->free);
182462306a36Sopenharmony_ci	}
182562306a36Sopenharmony_ci	xprt->max_reqs = max_t(unsigned int, max_alloc, num_prealloc);
182662306a36Sopenharmony_ci	xprt->min_reqs = num_prealloc;
182762306a36Sopenharmony_ci	xprt->num_reqs = num_prealloc;
182862306a36Sopenharmony_ci
182962306a36Sopenharmony_ci	return xprt;
183062306a36Sopenharmony_ci
183162306a36Sopenharmony_ciout_free:
183262306a36Sopenharmony_ci	xprt_free(xprt);
183362306a36Sopenharmony_ciout:
183462306a36Sopenharmony_ci	return NULL;
183562306a36Sopenharmony_ci}
183662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(xprt_alloc);
183762306a36Sopenharmony_ci
183862306a36Sopenharmony_civoid xprt_free(struct rpc_xprt *xprt)
183962306a36Sopenharmony_ci{
184062306a36Sopenharmony_ci	put_net_track(xprt->xprt_net, &xprt->ns_tracker);
184162306a36Sopenharmony_ci	xprt_free_all_slots(xprt);
184262306a36Sopenharmony_ci	xprt_free_id(xprt);
184362306a36Sopenharmony_ci	rpc_sysfs_xprt_destroy(xprt);
184462306a36Sopenharmony_ci	kfree_rcu(xprt, rcu);
184562306a36Sopenharmony_ci}
184662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(xprt_free);
184762306a36Sopenharmony_ci
184862306a36Sopenharmony_cistatic void
184962306a36Sopenharmony_cixprt_init_connect_cookie(struct rpc_rqst *req, struct rpc_xprt *xprt)
185062306a36Sopenharmony_ci{
185162306a36Sopenharmony_ci	req->rq_connect_cookie = xprt_connect_cookie(xprt) - 1;
185262306a36Sopenharmony_ci}
185362306a36Sopenharmony_ci
185462306a36Sopenharmony_cistatic __be32
185562306a36Sopenharmony_cixprt_alloc_xid(struct rpc_xprt *xprt)
185662306a36Sopenharmony_ci{
185762306a36Sopenharmony_ci	__be32 xid;
185862306a36Sopenharmony_ci
185962306a36Sopenharmony_ci	spin_lock(&xprt->reserve_lock);
186062306a36Sopenharmony_ci	xid = (__force __be32)xprt->xid++;
186162306a36Sopenharmony_ci	spin_unlock(&xprt->reserve_lock);
186262306a36Sopenharmony_ci	return xid;
186362306a36Sopenharmony_ci}
186462306a36Sopenharmony_ci
186562306a36Sopenharmony_cistatic void
186662306a36Sopenharmony_cixprt_init_xid(struct rpc_xprt *xprt)
186762306a36Sopenharmony_ci{
186862306a36Sopenharmony_ci	xprt->xid = get_random_u32();
186962306a36Sopenharmony_ci}
187062306a36Sopenharmony_ci
187162306a36Sopenharmony_cistatic void
187262306a36Sopenharmony_cixprt_request_init(struct rpc_task *task)
187362306a36Sopenharmony_ci{
187462306a36Sopenharmony_ci	struct rpc_xprt *xprt = task->tk_xprt;
187562306a36Sopenharmony_ci	struct rpc_rqst	*req = task->tk_rqstp;
187662306a36Sopenharmony_ci
187762306a36Sopenharmony_ci	req->rq_task	= task;
187862306a36Sopenharmony_ci	req->rq_xprt    = xprt;
187962306a36Sopenharmony_ci	req->rq_buffer  = NULL;
188062306a36Sopenharmony_ci	req->rq_xid	= xprt_alloc_xid(xprt);
188162306a36Sopenharmony_ci	xprt_init_connect_cookie(req, xprt);
188262306a36Sopenharmony_ci	req->rq_snd_buf.len = 0;
188362306a36Sopenharmony_ci	req->rq_snd_buf.buflen = 0;
188462306a36Sopenharmony_ci	req->rq_rcv_buf.len = 0;
188562306a36Sopenharmony_ci	req->rq_rcv_buf.buflen = 0;
188662306a36Sopenharmony_ci	req->rq_snd_buf.bvec = NULL;
188762306a36Sopenharmony_ci	req->rq_rcv_buf.bvec = NULL;
188862306a36Sopenharmony_ci	req->rq_release_snd_buf = NULL;
188962306a36Sopenharmony_ci	xprt_init_majortimeo(task, req);
189062306a36Sopenharmony_ci
189162306a36Sopenharmony_ci	trace_xprt_reserve(req);
189262306a36Sopenharmony_ci}
189362306a36Sopenharmony_ci
189462306a36Sopenharmony_cistatic void
189562306a36Sopenharmony_cixprt_do_reserve(struct rpc_xprt *xprt, struct rpc_task *task)
189662306a36Sopenharmony_ci{
189762306a36Sopenharmony_ci	xprt->ops->alloc_slot(xprt, task);
189862306a36Sopenharmony_ci	if (task->tk_rqstp != NULL)
189962306a36Sopenharmony_ci		xprt_request_init(task);
190062306a36Sopenharmony_ci}
190162306a36Sopenharmony_ci
190262306a36Sopenharmony_ci/**
190362306a36Sopenharmony_ci * xprt_reserve - allocate an RPC request slot
190462306a36Sopenharmony_ci * @task: RPC task requesting a slot allocation
190562306a36Sopenharmony_ci *
190662306a36Sopenharmony_ci * If the transport is marked as being congested, or if no more
190762306a36Sopenharmony_ci * slots are available, place the task on the transport's
190862306a36Sopenharmony_ci * backlog queue.
190962306a36Sopenharmony_ci */
191062306a36Sopenharmony_civoid xprt_reserve(struct rpc_task *task)
191162306a36Sopenharmony_ci{
191262306a36Sopenharmony_ci	struct rpc_xprt *xprt = task->tk_xprt;
191362306a36Sopenharmony_ci
191462306a36Sopenharmony_ci	task->tk_status = 0;
191562306a36Sopenharmony_ci	if (task->tk_rqstp != NULL)
191662306a36Sopenharmony_ci		return;
191762306a36Sopenharmony_ci
191862306a36Sopenharmony_ci	task->tk_status = -EAGAIN;
191962306a36Sopenharmony_ci	if (!xprt_throttle_congested(xprt, task))
192062306a36Sopenharmony_ci		xprt_do_reserve(xprt, task);
192162306a36Sopenharmony_ci}
192262306a36Sopenharmony_ci
192362306a36Sopenharmony_ci/**
192462306a36Sopenharmony_ci * xprt_retry_reserve - allocate an RPC request slot
192562306a36Sopenharmony_ci * @task: RPC task requesting a slot allocation
192662306a36Sopenharmony_ci *
192762306a36Sopenharmony_ci * If no more slots are available, place the task on the transport's
192862306a36Sopenharmony_ci * backlog queue.
192962306a36Sopenharmony_ci * Note that the only difference with xprt_reserve is that we now
193062306a36Sopenharmony_ci * ignore the value of the XPRT_CONGESTED flag.
193162306a36Sopenharmony_ci */
193262306a36Sopenharmony_civoid xprt_retry_reserve(struct rpc_task *task)
193362306a36Sopenharmony_ci{
193462306a36Sopenharmony_ci	struct rpc_xprt *xprt = task->tk_xprt;
193562306a36Sopenharmony_ci
193662306a36Sopenharmony_ci	task->tk_status = 0;
193762306a36Sopenharmony_ci	if (task->tk_rqstp != NULL)
193862306a36Sopenharmony_ci		return;
193962306a36Sopenharmony_ci
194062306a36Sopenharmony_ci	task->tk_status = -EAGAIN;
194162306a36Sopenharmony_ci	xprt_do_reserve(xprt, task);
194262306a36Sopenharmony_ci}
194362306a36Sopenharmony_ci
194462306a36Sopenharmony_ci/**
194562306a36Sopenharmony_ci * xprt_release - release an RPC request slot
194662306a36Sopenharmony_ci * @task: task which is finished with the slot
194762306a36Sopenharmony_ci *
194862306a36Sopenharmony_ci */
194962306a36Sopenharmony_civoid xprt_release(struct rpc_task *task)
195062306a36Sopenharmony_ci{
195162306a36Sopenharmony_ci	struct rpc_xprt	*xprt;
195262306a36Sopenharmony_ci	struct rpc_rqst	*req = task->tk_rqstp;
195362306a36Sopenharmony_ci
195462306a36Sopenharmony_ci	if (req == NULL) {
195562306a36Sopenharmony_ci		if (task->tk_client) {
195662306a36Sopenharmony_ci			xprt = task->tk_xprt;
195762306a36Sopenharmony_ci			xprt_release_write(xprt, task);
195862306a36Sopenharmony_ci		}
195962306a36Sopenharmony_ci		return;
196062306a36Sopenharmony_ci	}
196162306a36Sopenharmony_ci
196262306a36Sopenharmony_ci	xprt = req->rq_xprt;
196362306a36Sopenharmony_ci	xprt_request_dequeue_xprt(task);
196462306a36Sopenharmony_ci	spin_lock(&xprt->transport_lock);
196562306a36Sopenharmony_ci	xprt->ops->release_xprt(xprt, task);
196662306a36Sopenharmony_ci	if (xprt->ops->release_request)
196762306a36Sopenharmony_ci		xprt->ops->release_request(task);
196862306a36Sopenharmony_ci	xprt_schedule_autodisconnect(xprt);
196962306a36Sopenharmony_ci	spin_unlock(&xprt->transport_lock);
197062306a36Sopenharmony_ci	if (req->rq_buffer)
197162306a36Sopenharmony_ci		xprt->ops->buf_free(task);
197262306a36Sopenharmony_ci	if (req->rq_cred != NULL)
197362306a36Sopenharmony_ci		put_rpccred(req->rq_cred);
197462306a36Sopenharmony_ci	if (req->rq_release_snd_buf)
197562306a36Sopenharmony_ci		req->rq_release_snd_buf(req);
197662306a36Sopenharmony_ci
197762306a36Sopenharmony_ci	task->tk_rqstp = NULL;
197862306a36Sopenharmony_ci	if (likely(!bc_prealloc(req)))
197962306a36Sopenharmony_ci		xprt->ops->free_slot(xprt, req);
198062306a36Sopenharmony_ci	else
198162306a36Sopenharmony_ci		xprt_free_bc_request(req);
198262306a36Sopenharmony_ci}
198362306a36Sopenharmony_ci
198462306a36Sopenharmony_ci#ifdef CONFIG_SUNRPC_BACKCHANNEL
198562306a36Sopenharmony_civoid
198662306a36Sopenharmony_cixprt_init_bc_request(struct rpc_rqst *req, struct rpc_task *task)
198762306a36Sopenharmony_ci{
198862306a36Sopenharmony_ci	struct xdr_buf *xbufp = &req->rq_snd_buf;
198962306a36Sopenharmony_ci
199062306a36Sopenharmony_ci	task->tk_rqstp = req;
199162306a36Sopenharmony_ci	req->rq_task = task;
199262306a36Sopenharmony_ci	xprt_init_connect_cookie(req, req->rq_xprt);
199362306a36Sopenharmony_ci	/*
199462306a36Sopenharmony_ci	 * Set up the xdr_buf length.
199562306a36Sopenharmony_ci	 * This also indicates that the buffer is XDR encoded already.
199662306a36Sopenharmony_ci	 */
199762306a36Sopenharmony_ci	xbufp->len = xbufp->head[0].iov_len + xbufp->page_len +
199862306a36Sopenharmony_ci		xbufp->tail[0].iov_len;
199962306a36Sopenharmony_ci}
200062306a36Sopenharmony_ci#endif
200162306a36Sopenharmony_ci
200262306a36Sopenharmony_cistatic void xprt_init(struct rpc_xprt *xprt, struct net *net)
200362306a36Sopenharmony_ci{
200462306a36Sopenharmony_ci	kref_init(&xprt->kref);
200562306a36Sopenharmony_ci
200662306a36Sopenharmony_ci	spin_lock_init(&xprt->transport_lock);
200762306a36Sopenharmony_ci	spin_lock_init(&xprt->reserve_lock);
200862306a36Sopenharmony_ci	spin_lock_init(&xprt->queue_lock);
200962306a36Sopenharmony_ci
201062306a36Sopenharmony_ci	INIT_LIST_HEAD(&xprt->free);
201162306a36Sopenharmony_ci	xprt->recv_queue = RB_ROOT;
201262306a36Sopenharmony_ci	INIT_LIST_HEAD(&xprt->xmit_queue);
201362306a36Sopenharmony_ci#if defined(CONFIG_SUNRPC_BACKCHANNEL)
201462306a36Sopenharmony_ci	spin_lock_init(&xprt->bc_pa_lock);
201562306a36Sopenharmony_ci	INIT_LIST_HEAD(&xprt->bc_pa_list);
201662306a36Sopenharmony_ci#endif /* CONFIG_SUNRPC_BACKCHANNEL */
201762306a36Sopenharmony_ci	INIT_LIST_HEAD(&xprt->xprt_switch);
201862306a36Sopenharmony_ci
201962306a36Sopenharmony_ci	xprt->last_used = jiffies;
202062306a36Sopenharmony_ci	xprt->cwnd = RPC_INITCWND;
202162306a36Sopenharmony_ci	xprt->bind_index = 0;
202262306a36Sopenharmony_ci
202362306a36Sopenharmony_ci	rpc_init_wait_queue(&xprt->binding, "xprt_binding");
202462306a36Sopenharmony_ci	rpc_init_wait_queue(&xprt->pending, "xprt_pending");
202562306a36Sopenharmony_ci	rpc_init_wait_queue(&xprt->sending, "xprt_sending");
202662306a36Sopenharmony_ci	rpc_init_priority_wait_queue(&xprt->backlog, "xprt_backlog");
202762306a36Sopenharmony_ci
202862306a36Sopenharmony_ci	xprt_init_xid(xprt);
202962306a36Sopenharmony_ci
203062306a36Sopenharmony_ci	xprt->xprt_net = get_net_track(net, &xprt->ns_tracker, GFP_KERNEL);
203162306a36Sopenharmony_ci}
203262306a36Sopenharmony_ci
203362306a36Sopenharmony_ci/**
203462306a36Sopenharmony_ci * xprt_create_transport - create an RPC transport
203562306a36Sopenharmony_ci * @args: rpc transport creation arguments
203662306a36Sopenharmony_ci *
203762306a36Sopenharmony_ci */
203862306a36Sopenharmony_cistruct rpc_xprt *xprt_create_transport(struct xprt_create *args)
203962306a36Sopenharmony_ci{
204062306a36Sopenharmony_ci	struct rpc_xprt	*xprt;
204162306a36Sopenharmony_ci	const struct xprt_class *t;
204262306a36Sopenharmony_ci
204362306a36Sopenharmony_ci	t = xprt_class_find_by_ident(args->ident);
204462306a36Sopenharmony_ci	if (!t) {
204562306a36Sopenharmony_ci		dprintk("RPC: transport (%d) not supported\n", args->ident);
204662306a36Sopenharmony_ci		return ERR_PTR(-EIO);
204762306a36Sopenharmony_ci	}
204862306a36Sopenharmony_ci
204962306a36Sopenharmony_ci	xprt = t->setup(args);
205062306a36Sopenharmony_ci	xprt_class_release(t);
205162306a36Sopenharmony_ci
205262306a36Sopenharmony_ci	if (IS_ERR(xprt))
205362306a36Sopenharmony_ci		goto out;
205462306a36Sopenharmony_ci	if (args->flags & XPRT_CREATE_NO_IDLE_TIMEOUT)
205562306a36Sopenharmony_ci		xprt->idle_timeout = 0;
205662306a36Sopenharmony_ci	INIT_WORK(&xprt->task_cleanup, xprt_autoclose);
205762306a36Sopenharmony_ci	if (xprt_has_timer(xprt))
205862306a36Sopenharmony_ci		timer_setup(&xprt->timer, xprt_init_autodisconnect, 0);
205962306a36Sopenharmony_ci	else
206062306a36Sopenharmony_ci		timer_setup(&xprt->timer, NULL, 0);
206162306a36Sopenharmony_ci
206262306a36Sopenharmony_ci	if (strlen(args->servername) > RPC_MAXNETNAMELEN) {
206362306a36Sopenharmony_ci		xprt_destroy(xprt);
206462306a36Sopenharmony_ci		return ERR_PTR(-EINVAL);
206562306a36Sopenharmony_ci	}
206662306a36Sopenharmony_ci	xprt->servername = kstrdup(args->servername, GFP_KERNEL);
206762306a36Sopenharmony_ci	if (xprt->servername == NULL) {
206862306a36Sopenharmony_ci		xprt_destroy(xprt);
206962306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
207062306a36Sopenharmony_ci	}
207162306a36Sopenharmony_ci
207262306a36Sopenharmony_ci	rpc_xprt_debugfs_register(xprt);
207362306a36Sopenharmony_ci
207462306a36Sopenharmony_ci	trace_xprt_create(xprt);
207562306a36Sopenharmony_ciout:
207662306a36Sopenharmony_ci	return xprt;
207762306a36Sopenharmony_ci}
207862306a36Sopenharmony_ci
207962306a36Sopenharmony_cistatic void xprt_destroy_cb(struct work_struct *work)
208062306a36Sopenharmony_ci{
208162306a36Sopenharmony_ci	struct rpc_xprt *xprt =
208262306a36Sopenharmony_ci		container_of(work, struct rpc_xprt, task_cleanup);
208362306a36Sopenharmony_ci
208462306a36Sopenharmony_ci	trace_xprt_destroy(xprt);
208562306a36Sopenharmony_ci
208662306a36Sopenharmony_ci	rpc_xprt_debugfs_unregister(xprt);
208762306a36Sopenharmony_ci	rpc_destroy_wait_queue(&xprt->binding);
208862306a36Sopenharmony_ci	rpc_destroy_wait_queue(&xprt->pending);
208962306a36Sopenharmony_ci	rpc_destroy_wait_queue(&xprt->sending);
209062306a36Sopenharmony_ci	rpc_destroy_wait_queue(&xprt->backlog);
209162306a36Sopenharmony_ci	kfree(xprt->servername);
209262306a36Sopenharmony_ci	/*
209362306a36Sopenharmony_ci	 * Destroy any existing back channel
209462306a36Sopenharmony_ci	 */
209562306a36Sopenharmony_ci	xprt_destroy_backchannel(xprt, UINT_MAX);
209662306a36Sopenharmony_ci
209762306a36Sopenharmony_ci	/*
209862306a36Sopenharmony_ci	 * Tear down transport state and free the rpc_xprt
209962306a36Sopenharmony_ci	 */
210062306a36Sopenharmony_ci	xprt->ops->destroy(xprt);
210162306a36Sopenharmony_ci}
210262306a36Sopenharmony_ci
210362306a36Sopenharmony_ci/**
210462306a36Sopenharmony_ci * xprt_destroy - destroy an RPC transport, killing off all requests.
210562306a36Sopenharmony_ci * @xprt: transport to destroy
210662306a36Sopenharmony_ci *
210762306a36Sopenharmony_ci */
210862306a36Sopenharmony_cistatic void xprt_destroy(struct rpc_xprt *xprt)
210962306a36Sopenharmony_ci{
211062306a36Sopenharmony_ci	/*
211162306a36Sopenharmony_ci	 * Exclude transport connect/disconnect handlers and autoclose
211262306a36Sopenharmony_ci	 */
211362306a36Sopenharmony_ci	wait_on_bit_lock(&xprt->state, XPRT_LOCKED, TASK_UNINTERRUPTIBLE);
211462306a36Sopenharmony_ci
211562306a36Sopenharmony_ci	/*
211662306a36Sopenharmony_ci	 * xprt_schedule_autodisconnect() can run after XPRT_LOCKED
211762306a36Sopenharmony_ci	 * is cleared.  We use ->transport_lock to ensure the mod_timer()
211862306a36Sopenharmony_ci	 * can only run *before* del_time_sync(), never after.
211962306a36Sopenharmony_ci	 */
212062306a36Sopenharmony_ci	spin_lock(&xprt->transport_lock);
212162306a36Sopenharmony_ci	del_timer_sync(&xprt->timer);
212262306a36Sopenharmony_ci	spin_unlock(&xprt->transport_lock);
212362306a36Sopenharmony_ci
212462306a36Sopenharmony_ci	/*
212562306a36Sopenharmony_ci	 * Destroy sockets etc from the system workqueue so they can
212662306a36Sopenharmony_ci	 * safely flush receive work running on rpciod.
212762306a36Sopenharmony_ci	 */
212862306a36Sopenharmony_ci	INIT_WORK(&xprt->task_cleanup, xprt_destroy_cb);
212962306a36Sopenharmony_ci	schedule_work(&xprt->task_cleanup);
213062306a36Sopenharmony_ci}
213162306a36Sopenharmony_ci
213262306a36Sopenharmony_cistatic void xprt_destroy_kref(struct kref *kref)
213362306a36Sopenharmony_ci{
213462306a36Sopenharmony_ci	xprt_destroy(container_of(kref, struct rpc_xprt, kref));
213562306a36Sopenharmony_ci}
213662306a36Sopenharmony_ci
213762306a36Sopenharmony_ci/**
213862306a36Sopenharmony_ci * xprt_get - return a reference to an RPC transport.
213962306a36Sopenharmony_ci * @xprt: pointer to the transport
214062306a36Sopenharmony_ci *
214162306a36Sopenharmony_ci */
214262306a36Sopenharmony_cistruct rpc_xprt *xprt_get(struct rpc_xprt *xprt)
214362306a36Sopenharmony_ci{
214462306a36Sopenharmony_ci	if (xprt != NULL && kref_get_unless_zero(&xprt->kref))
214562306a36Sopenharmony_ci		return xprt;
214662306a36Sopenharmony_ci	return NULL;
214762306a36Sopenharmony_ci}
214862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(xprt_get);
214962306a36Sopenharmony_ci
215062306a36Sopenharmony_ci/**
215162306a36Sopenharmony_ci * xprt_put - release a reference to an RPC transport.
215262306a36Sopenharmony_ci * @xprt: pointer to the transport
215362306a36Sopenharmony_ci *
215462306a36Sopenharmony_ci */
215562306a36Sopenharmony_civoid xprt_put(struct rpc_xprt *xprt)
215662306a36Sopenharmony_ci{
215762306a36Sopenharmony_ci	if (xprt != NULL)
215862306a36Sopenharmony_ci		kref_put(&xprt->kref, xprt_destroy_kref);
215962306a36Sopenharmony_ci}
216062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(xprt_put);
216162306a36Sopenharmony_ci
216262306a36Sopenharmony_civoid xprt_set_offline_locked(struct rpc_xprt *xprt, struct rpc_xprt_switch *xps)
216362306a36Sopenharmony_ci{
216462306a36Sopenharmony_ci	if (!test_and_set_bit(XPRT_OFFLINE, &xprt->state)) {
216562306a36Sopenharmony_ci		spin_lock(&xps->xps_lock);
216662306a36Sopenharmony_ci		xps->xps_nactive--;
216762306a36Sopenharmony_ci		spin_unlock(&xps->xps_lock);
216862306a36Sopenharmony_ci	}
216962306a36Sopenharmony_ci}
217062306a36Sopenharmony_ci
217162306a36Sopenharmony_civoid xprt_set_online_locked(struct rpc_xprt *xprt, struct rpc_xprt_switch *xps)
217262306a36Sopenharmony_ci{
217362306a36Sopenharmony_ci	if (test_and_clear_bit(XPRT_OFFLINE, &xprt->state)) {
217462306a36Sopenharmony_ci		spin_lock(&xps->xps_lock);
217562306a36Sopenharmony_ci		xps->xps_nactive++;
217662306a36Sopenharmony_ci		spin_unlock(&xps->xps_lock);
217762306a36Sopenharmony_ci	}
217862306a36Sopenharmony_ci}
217962306a36Sopenharmony_ci
218062306a36Sopenharmony_civoid xprt_delete_locked(struct rpc_xprt *xprt, struct rpc_xprt_switch *xps)
218162306a36Sopenharmony_ci{
218262306a36Sopenharmony_ci	if (test_and_set_bit(XPRT_REMOVE, &xprt->state))
218362306a36Sopenharmony_ci		return;
218462306a36Sopenharmony_ci
218562306a36Sopenharmony_ci	xprt_force_disconnect(xprt);
218662306a36Sopenharmony_ci	if (!test_bit(XPRT_CONNECTED, &xprt->state))
218762306a36Sopenharmony_ci		return;
218862306a36Sopenharmony_ci
218962306a36Sopenharmony_ci	if (!xprt->sending.qlen && !xprt->pending.qlen &&
219062306a36Sopenharmony_ci	    !xprt->backlog.qlen && !atomic_long_read(&xprt->queuelen))
219162306a36Sopenharmony_ci		rpc_xprt_switch_remove_xprt(xps, xprt, true);
219262306a36Sopenharmony_ci}
2193