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