18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *  linux/net/sunrpc/clnt.c
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci *  This file contains the high-level RPC interface.
68c2ecf20Sopenharmony_ci *  It is modeled as a finite state machine to support both synchronous
78c2ecf20Sopenharmony_ci *  and asynchronous requests.
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci *  -	RPC header generation and argument serialization.
108c2ecf20Sopenharmony_ci *  -	Credential refresh.
118c2ecf20Sopenharmony_ci *  -	TCP connect handling.
128c2ecf20Sopenharmony_ci *  -	Retry of operation when it is suspected the operation failed because
138c2ecf20Sopenharmony_ci *	of uid squashing on the server, or when the credentials were stale
148c2ecf20Sopenharmony_ci *	and need to be refreshed, or when a packet was damaged in transit.
158c2ecf20Sopenharmony_ci *	This may be have to be moved to the VFS layer.
168c2ecf20Sopenharmony_ci *
178c2ecf20Sopenharmony_ci *  Copyright (C) 1992,1993 Rick Sladkey <jrs@world.std.com>
188c2ecf20Sopenharmony_ci *  Copyright (C) 1995,1996 Olaf Kirch <okir@monad.swb.de>
198c2ecf20Sopenharmony_ci */
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci#include <linux/module.h>
238c2ecf20Sopenharmony_ci#include <linux/types.h>
248c2ecf20Sopenharmony_ci#include <linux/kallsyms.h>
258c2ecf20Sopenharmony_ci#include <linux/mm.h>
268c2ecf20Sopenharmony_ci#include <linux/namei.h>
278c2ecf20Sopenharmony_ci#include <linux/mount.h>
288c2ecf20Sopenharmony_ci#include <linux/slab.h>
298c2ecf20Sopenharmony_ci#include <linux/rcupdate.h>
308c2ecf20Sopenharmony_ci#include <linux/utsname.h>
318c2ecf20Sopenharmony_ci#include <linux/workqueue.h>
328c2ecf20Sopenharmony_ci#include <linux/in.h>
338c2ecf20Sopenharmony_ci#include <linux/in6.h>
348c2ecf20Sopenharmony_ci#include <linux/un.h>
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci#include <linux/sunrpc/clnt.h>
378c2ecf20Sopenharmony_ci#include <linux/sunrpc/addr.h>
388c2ecf20Sopenharmony_ci#include <linux/sunrpc/rpc_pipe_fs.h>
398c2ecf20Sopenharmony_ci#include <linux/sunrpc/metrics.h>
408c2ecf20Sopenharmony_ci#include <linux/sunrpc/bc_xprt.h>
418c2ecf20Sopenharmony_ci#include <trace/events/sunrpc.h>
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci#include "sunrpc.h"
448c2ecf20Sopenharmony_ci#include "netns.h"
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
478c2ecf20Sopenharmony_ci# define RPCDBG_FACILITY	RPCDBG_CALL
488c2ecf20Sopenharmony_ci#endif
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci/*
518c2ecf20Sopenharmony_ci * All RPC clients are linked into this list
528c2ecf20Sopenharmony_ci */
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_cistatic DECLARE_WAIT_QUEUE_HEAD(destroy_wait);
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_cistatic void	call_start(struct rpc_task *task);
588c2ecf20Sopenharmony_cistatic void	call_reserve(struct rpc_task *task);
598c2ecf20Sopenharmony_cistatic void	call_reserveresult(struct rpc_task *task);
608c2ecf20Sopenharmony_cistatic void	call_allocate(struct rpc_task *task);
618c2ecf20Sopenharmony_cistatic void	call_encode(struct rpc_task *task);
628c2ecf20Sopenharmony_cistatic void	call_decode(struct rpc_task *task);
638c2ecf20Sopenharmony_cistatic void	call_bind(struct rpc_task *task);
648c2ecf20Sopenharmony_cistatic void	call_bind_status(struct rpc_task *task);
658c2ecf20Sopenharmony_cistatic void	call_transmit(struct rpc_task *task);
668c2ecf20Sopenharmony_cistatic void	call_status(struct rpc_task *task);
678c2ecf20Sopenharmony_cistatic void	call_transmit_status(struct rpc_task *task);
688c2ecf20Sopenharmony_cistatic void	call_refresh(struct rpc_task *task);
698c2ecf20Sopenharmony_cistatic void	call_refreshresult(struct rpc_task *task);
708c2ecf20Sopenharmony_cistatic void	call_connect(struct rpc_task *task);
718c2ecf20Sopenharmony_cistatic void	call_connect_status(struct rpc_task *task);
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_cistatic int	rpc_encode_header(struct rpc_task *task,
748c2ecf20Sopenharmony_ci				  struct xdr_stream *xdr);
758c2ecf20Sopenharmony_cistatic int	rpc_decode_header(struct rpc_task *task,
768c2ecf20Sopenharmony_ci				  struct xdr_stream *xdr);
778c2ecf20Sopenharmony_cistatic int	rpc_ping(struct rpc_clnt *clnt);
788c2ecf20Sopenharmony_cistatic void	rpc_check_timeout(struct rpc_task *task);
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_cistatic void rpc_register_client(struct rpc_clnt *clnt)
818c2ecf20Sopenharmony_ci{
828c2ecf20Sopenharmony_ci	struct net *net = rpc_net_ns(clnt);
838c2ecf20Sopenharmony_ci	struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci	spin_lock(&sn->rpc_client_lock);
868c2ecf20Sopenharmony_ci	list_add(&clnt->cl_clients, &sn->all_clients);
878c2ecf20Sopenharmony_ci	spin_unlock(&sn->rpc_client_lock);
888c2ecf20Sopenharmony_ci}
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_cistatic void rpc_unregister_client(struct rpc_clnt *clnt)
918c2ecf20Sopenharmony_ci{
928c2ecf20Sopenharmony_ci	struct net *net = rpc_net_ns(clnt);
938c2ecf20Sopenharmony_ci	struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci	spin_lock(&sn->rpc_client_lock);
968c2ecf20Sopenharmony_ci	list_del(&clnt->cl_clients);
978c2ecf20Sopenharmony_ci	spin_unlock(&sn->rpc_client_lock);
988c2ecf20Sopenharmony_ci}
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_cistatic void __rpc_clnt_remove_pipedir(struct rpc_clnt *clnt)
1018c2ecf20Sopenharmony_ci{
1028c2ecf20Sopenharmony_ci	rpc_remove_client_dir(clnt);
1038c2ecf20Sopenharmony_ci}
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_cistatic void rpc_clnt_remove_pipedir(struct rpc_clnt *clnt)
1068c2ecf20Sopenharmony_ci{
1078c2ecf20Sopenharmony_ci	struct net *net = rpc_net_ns(clnt);
1088c2ecf20Sopenharmony_ci	struct super_block *pipefs_sb;
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ci	pipefs_sb = rpc_get_sb_net(net);
1118c2ecf20Sopenharmony_ci	if (pipefs_sb) {
1128c2ecf20Sopenharmony_ci		if (pipefs_sb == clnt->pipefs_sb)
1138c2ecf20Sopenharmony_ci			__rpc_clnt_remove_pipedir(clnt);
1148c2ecf20Sopenharmony_ci		rpc_put_sb_net(net);
1158c2ecf20Sopenharmony_ci	}
1168c2ecf20Sopenharmony_ci}
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_cistatic struct dentry *rpc_setup_pipedir_sb(struct super_block *sb,
1198c2ecf20Sopenharmony_ci				    struct rpc_clnt *clnt)
1208c2ecf20Sopenharmony_ci{
1218c2ecf20Sopenharmony_ci	static uint32_t clntid;
1228c2ecf20Sopenharmony_ci	const char *dir_name = clnt->cl_program->pipe_dir_name;
1238c2ecf20Sopenharmony_ci	char name[15];
1248c2ecf20Sopenharmony_ci	struct dentry *dir, *dentry;
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci	dir = rpc_d_lookup_sb(sb, dir_name);
1278c2ecf20Sopenharmony_ci	if (dir == NULL) {
1288c2ecf20Sopenharmony_ci		pr_info("RPC: pipefs directory doesn't exist: %s\n", dir_name);
1298c2ecf20Sopenharmony_ci		return dir;
1308c2ecf20Sopenharmony_ci	}
1318c2ecf20Sopenharmony_ci	for (;;) {
1328c2ecf20Sopenharmony_ci		snprintf(name, sizeof(name), "clnt%x", (unsigned int)clntid++);
1338c2ecf20Sopenharmony_ci		name[sizeof(name) - 1] = '\0';
1348c2ecf20Sopenharmony_ci		dentry = rpc_create_client_dir(dir, name, clnt);
1358c2ecf20Sopenharmony_ci		if (!IS_ERR(dentry))
1368c2ecf20Sopenharmony_ci			break;
1378c2ecf20Sopenharmony_ci		if (dentry == ERR_PTR(-EEXIST))
1388c2ecf20Sopenharmony_ci			continue;
1398c2ecf20Sopenharmony_ci		printk(KERN_INFO "RPC: Couldn't create pipefs entry"
1408c2ecf20Sopenharmony_ci				" %s/%s, error %ld\n",
1418c2ecf20Sopenharmony_ci				dir_name, name, PTR_ERR(dentry));
1428c2ecf20Sopenharmony_ci		break;
1438c2ecf20Sopenharmony_ci	}
1448c2ecf20Sopenharmony_ci	dput(dir);
1458c2ecf20Sopenharmony_ci	return dentry;
1468c2ecf20Sopenharmony_ci}
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_cistatic int
1498c2ecf20Sopenharmony_cirpc_setup_pipedir(struct super_block *pipefs_sb, struct rpc_clnt *clnt)
1508c2ecf20Sopenharmony_ci{
1518c2ecf20Sopenharmony_ci	struct dentry *dentry;
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci	clnt->pipefs_sb = pipefs_sb;
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci	if (clnt->cl_program->pipe_dir_name != NULL) {
1568c2ecf20Sopenharmony_ci		dentry = rpc_setup_pipedir_sb(pipefs_sb, clnt);
1578c2ecf20Sopenharmony_ci		if (IS_ERR(dentry))
1588c2ecf20Sopenharmony_ci			return PTR_ERR(dentry);
1598c2ecf20Sopenharmony_ci	}
1608c2ecf20Sopenharmony_ci	return 0;
1618c2ecf20Sopenharmony_ci}
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_cistatic int rpc_clnt_skip_event(struct rpc_clnt *clnt, unsigned long event)
1648c2ecf20Sopenharmony_ci{
1658c2ecf20Sopenharmony_ci	if (clnt->cl_program->pipe_dir_name == NULL)
1668c2ecf20Sopenharmony_ci		return 1;
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci	switch (event) {
1698c2ecf20Sopenharmony_ci	case RPC_PIPEFS_MOUNT:
1708c2ecf20Sopenharmony_ci		if (clnt->cl_pipedir_objects.pdh_dentry != NULL)
1718c2ecf20Sopenharmony_ci			return 1;
1728c2ecf20Sopenharmony_ci		if (atomic_read(&clnt->cl_count) == 0)
1738c2ecf20Sopenharmony_ci			return 1;
1748c2ecf20Sopenharmony_ci		break;
1758c2ecf20Sopenharmony_ci	case RPC_PIPEFS_UMOUNT:
1768c2ecf20Sopenharmony_ci		if (clnt->cl_pipedir_objects.pdh_dentry == NULL)
1778c2ecf20Sopenharmony_ci			return 1;
1788c2ecf20Sopenharmony_ci		break;
1798c2ecf20Sopenharmony_ci	}
1808c2ecf20Sopenharmony_ci	return 0;
1818c2ecf20Sopenharmony_ci}
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_cistatic int __rpc_clnt_handle_event(struct rpc_clnt *clnt, unsigned long event,
1848c2ecf20Sopenharmony_ci				   struct super_block *sb)
1858c2ecf20Sopenharmony_ci{
1868c2ecf20Sopenharmony_ci	struct dentry *dentry;
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci	switch (event) {
1898c2ecf20Sopenharmony_ci	case RPC_PIPEFS_MOUNT:
1908c2ecf20Sopenharmony_ci		dentry = rpc_setup_pipedir_sb(sb, clnt);
1918c2ecf20Sopenharmony_ci		if (!dentry)
1928c2ecf20Sopenharmony_ci			return -ENOENT;
1938c2ecf20Sopenharmony_ci		if (IS_ERR(dentry))
1948c2ecf20Sopenharmony_ci			return PTR_ERR(dentry);
1958c2ecf20Sopenharmony_ci		break;
1968c2ecf20Sopenharmony_ci	case RPC_PIPEFS_UMOUNT:
1978c2ecf20Sopenharmony_ci		__rpc_clnt_remove_pipedir(clnt);
1988c2ecf20Sopenharmony_ci		break;
1998c2ecf20Sopenharmony_ci	default:
2008c2ecf20Sopenharmony_ci		printk(KERN_ERR "%s: unknown event: %ld\n", __func__, event);
2018c2ecf20Sopenharmony_ci		return -ENOTSUPP;
2028c2ecf20Sopenharmony_ci	}
2038c2ecf20Sopenharmony_ci	return 0;
2048c2ecf20Sopenharmony_ci}
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_cistatic int __rpc_pipefs_event(struct rpc_clnt *clnt, unsigned long event,
2078c2ecf20Sopenharmony_ci				struct super_block *sb)
2088c2ecf20Sopenharmony_ci{
2098c2ecf20Sopenharmony_ci	int error = 0;
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci	for (;; clnt = clnt->cl_parent) {
2128c2ecf20Sopenharmony_ci		if (!rpc_clnt_skip_event(clnt, event))
2138c2ecf20Sopenharmony_ci			error = __rpc_clnt_handle_event(clnt, event, sb);
2148c2ecf20Sopenharmony_ci		if (error || clnt == clnt->cl_parent)
2158c2ecf20Sopenharmony_ci			break;
2168c2ecf20Sopenharmony_ci	}
2178c2ecf20Sopenharmony_ci	return error;
2188c2ecf20Sopenharmony_ci}
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_cistatic struct rpc_clnt *rpc_get_client_for_event(struct net *net, int event)
2218c2ecf20Sopenharmony_ci{
2228c2ecf20Sopenharmony_ci	struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
2238c2ecf20Sopenharmony_ci	struct rpc_clnt *clnt;
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci	spin_lock(&sn->rpc_client_lock);
2268c2ecf20Sopenharmony_ci	list_for_each_entry(clnt, &sn->all_clients, cl_clients) {
2278c2ecf20Sopenharmony_ci		if (rpc_clnt_skip_event(clnt, event))
2288c2ecf20Sopenharmony_ci			continue;
2298c2ecf20Sopenharmony_ci		spin_unlock(&sn->rpc_client_lock);
2308c2ecf20Sopenharmony_ci		return clnt;
2318c2ecf20Sopenharmony_ci	}
2328c2ecf20Sopenharmony_ci	spin_unlock(&sn->rpc_client_lock);
2338c2ecf20Sopenharmony_ci	return NULL;
2348c2ecf20Sopenharmony_ci}
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_cistatic int rpc_pipefs_event(struct notifier_block *nb, unsigned long event,
2378c2ecf20Sopenharmony_ci			    void *ptr)
2388c2ecf20Sopenharmony_ci{
2398c2ecf20Sopenharmony_ci	struct super_block *sb = ptr;
2408c2ecf20Sopenharmony_ci	struct rpc_clnt *clnt;
2418c2ecf20Sopenharmony_ci	int error = 0;
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_ci	while ((clnt = rpc_get_client_for_event(sb->s_fs_info, event))) {
2448c2ecf20Sopenharmony_ci		error = __rpc_pipefs_event(clnt, event, sb);
2458c2ecf20Sopenharmony_ci		if (error)
2468c2ecf20Sopenharmony_ci			break;
2478c2ecf20Sopenharmony_ci	}
2488c2ecf20Sopenharmony_ci	return error;
2498c2ecf20Sopenharmony_ci}
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_cistatic struct notifier_block rpc_clients_block = {
2528c2ecf20Sopenharmony_ci	.notifier_call	= rpc_pipefs_event,
2538c2ecf20Sopenharmony_ci	.priority	= SUNRPC_PIPEFS_RPC_PRIO,
2548c2ecf20Sopenharmony_ci};
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_ciint rpc_clients_notifier_register(void)
2578c2ecf20Sopenharmony_ci{
2588c2ecf20Sopenharmony_ci	return rpc_pipefs_notifier_register(&rpc_clients_block);
2598c2ecf20Sopenharmony_ci}
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_civoid rpc_clients_notifier_unregister(void)
2628c2ecf20Sopenharmony_ci{
2638c2ecf20Sopenharmony_ci	return rpc_pipefs_notifier_unregister(&rpc_clients_block);
2648c2ecf20Sopenharmony_ci}
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_cistatic struct rpc_xprt *rpc_clnt_set_transport(struct rpc_clnt *clnt,
2678c2ecf20Sopenharmony_ci		struct rpc_xprt *xprt,
2688c2ecf20Sopenharmony_ci		const struct rpc_timeout *timeout)
2698c2ecf20Sopenharmony_ci{
2708c2ecf20Sopenharmony_ci	struct rpc_xprt *old;
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_ci	spin_lock(&clnt->cl_lock);
2738c2ecf20Sopenharmony_ci	old = rcu_dereference_protected(clnt->cl_xprt,
2748c2ecf20Sopenharmony_ci			lockdep_is_held(&clnt->cl_lock));
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_ci	if (!xprt_bound(xprt))
2778c2ecf20Sopenharmony_ci		clnt->cl_autobind = 1;
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci	clnt->cl_timeout = timeout;
2808c2ecf20Sopenharmony_ci	rcu_assign_pointer(clnt->cl_xprt, xprt);
2818c2ecf20Sopenharmony_ci	spin_unlock(&clnt->cl_lock);
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci	return old;
2848c2ecf20Sopenharmony_ci}
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_cistatic void rpc_clnt_set_nodename(struct rpc_clnt *clnt, const char *nodename)
2878c2ecf20Sopenharmony_ci{
2888c2ecf20Sopenharmony_ci	clnt->cl_nodelen = strlcpy(clnt->cl_nodename,
2898c2ecf20Sopenharmony_ci			nodename, sizeof(clnt->cl_nodename));
2908c2ecf20Sopenharmony_ci}
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_cistatic int rpc_client_register(struct rpc_clnt *clnt,
2938c2ecf20Sopenharmony_ci			       rpc_authflavor_t pseudoflavor,
2948c2ecf20Sopenharmony_ci			       const char *client_name)
2958c2ecf20Sopenharmony_ci{
2968c2ecf20Sopenharmony_ci	struct rpc_auth_create_args auth_args = {
2978c2ecf20Sopenharmony_ci		.pseudoflavor = pseudoflavor,
2988c2ecf20Sopenharmony_ci		.target_name = client_name,
2998c2ecf20Sopenharmony_ci	};
3008c2ecf20Sopenharmony_ci	struct rpc_auth *auth;
3018c2ecf20Sopenharmony_ci	struct net *net = rpc_net_ns(clnt);
3028c2ecf20Sopenharmony_ci	struct super_block *pipefs_sb;
3038c2ecf20Sopenharmony_ci	int err;
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_ci	rpc_clnt_debugfs_register(clnt);
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci	pipefs_sb = rpc_get_sb_net(net);
3088c2ecf20Sopenharmony_ci	if (pipefs_sb) {
3098c2ecf20Sopenharmony_ci		err = rpc_setup_pipedir(pipefs_sb, clnt);
3108c2ecf20Sopenharmony_ci		if (err)
3118c2ecf20Sopenharmony_ci			goto out;
3128c2ecf20Sopenharmony_ci	}
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci	rpc_register_client(clnt);
3158c2ecf20Sopenharmony_ci	if (pipefs_sb)
3168c2ecf20Sopenharmony_ci		rpc_put_sb_net(net);
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ci	auth = rpcauth_create(&auth_args, clnt);
3198c2ecf20Sopenharmony_ci	if (IS_ERR(auth)) {
3208c2ecf20Sopenharmony_ci		dprintk("RPC:       Couldn't create auth handle (flavor %u)\n",
3218c2ecf20Sopenharmony_ci				pseudoflavor);
3228c2ecf20Sopenharmony_ci		err = PTR_ERR(auth);
3238c2ecf20Sopenharmony_ci		goto err_auth;
3248c2ecf20Sopenharmony_ci	}
3258c2ecf20Sopenharmony_ci	return 0;
3268c2ecf20Sopenharmony_cierr_auth:
3278c2ecf20Sopenharmony_ci	pipefs_sb = rpc_get_sb_net(net);
3288c2ecf20Sopenharmony_ci	rpc_unregister_client(clnt);
3298c2ecf20Sopenharmony_ci	__rpc_clnt_remove_pipedir(clnt);
3308c2ecf20Sopenharmony_ciout:
3318c2ecf20Sopenharmony_ci	if (pipefs_sb)
3328c2ecf20Sopenharmony_ci		rpc_put_sb_net(net);
3338c2ecf20Sopenharmony_ci	rpc_clnt_debugfs_unregister(clnt);
3348c2ecf20Sopenharmony_ci	return err;
3358c2ecf20Sopenharmony_ci}
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_cistatic DEFINE_IDA(rpc_clids);
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_civoid rpc_cleanup_clids(void)
3408c2ecf20Sopenharmony_ci{
3418c2ecf20Sopenharmony_ci	ida_destroy(&rpc_clids);
3428c2ecf20Sopenharmony_ci}
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_cistatic int rpc_alloc_clid(struct rpc_clnt *clnt)
3458c2ecf20Sopenharmony_ci{
3468c2ecf20Sopenharmony_ci	int clid;
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ci	clid = ida_simple_get(&rpc_clids, 0, 0, GFP_KERNEL);
3498c2ecf20Sopenharmony_ci	if (clid < 0)
3508c2ecf20Sopenharmony_ci		return clid;
3518c2ecf20Sopenharmony_ci	clnt->cl_clid = clid;
3528c2ecf20Sopenharmony_ci	return 0;
3538c2ecf20Sopenharmony_ci}
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_cistatic void rpc_free_clid(struct rpc_clnt *clnt)
3568c2ecf20Sopenharmony_ci{
3578c2ecf20Sopenharmony_ci	ida_simple_remove(&rpc_clids, clnt->cl_clid);
3588c2ecf20Sopenharmony_ci}
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_cistatic struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args,
3618c2ecf20Sopenharmony_ci		struct rpc_xprt_switch *xps,
3628c2ecf20Sopenharmony_ci		struct rpc_xprt *xprt,
3638c2ecf20Sopenharmony_ci		struct rpc_clnt *parent)
3648c2ecf20Sopenharmony_ci{
3658c2ecf20Sopenharmony_ci	const struct rpc_program *program = args->program;
3668c2ecf20Sopenharmony_ci	const struct rpc_version *version;
3678c2ecf20Sopenharmony_ci	struct rpc_clnt *clnt = NULL;
3688c2ecf20Sopenharmony_ci	const struct rpc_timeout *timeout;
3698c2ecf20Sopenharmony_ci	const char *nodename = args->nodename;
3708c2ecf20Sopenharmony_ci	int err;
3718c2ecf20Sopenharmony_ci
3728c2ecf20Sopenharmony_ci	err = rpciod_up();
3738c2ecf20Sopenharmony_ci	if (err)
3748c2ecf20Sopenharmony_ci		goto out_no_rpciod;
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_ci	err = -EINVAL;
3778c2ecf20Sopenharmony_ci	if (args->version >= program->nrvers)
3788c2ecf20Sopenharmony_ci		goto out_err;
3798c2ecf20Sopenharmony_ci	version = program->version[args->version];
3808c2ecf20Sopenharmony_ci	if (version == NULL)
3818c2ecf20Sopenharmony_ci		goto out_err;
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_ci	err = -ENOMEM;
3848c2ecf20Sopenharmony_ci	clnt = kzalloc(sizeof(*clnt), GFP_KERNEL);
3858c2ecf20Sopenharmony_ci	if (!clnt)
3868c2ecf20Sopenharmony_ci		goto out_err;
3878c2ecf20Sopenharmony_ci	clnt->cl_parent = parent ? : clnt;
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_ci	err = rpc_alloc_clid(clnt);
3908c2ecf20Sopenharmony_ci	if (err)
3918c2ecf20Sopenharmony_ci		goto out_no_clid;
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_ci	clnt->cl_cred	  = get_cred(args->cred);
3948c2ecf20Sopenharmony_ci	clnt->cl_procinfo = version->procs;
3958c2ecf20Sopenharmony_ci	clnt->cl_maxproc  = version->nrprocs;
3968c2ecf20Sopenharmony_ci	clnt->cl_prog     = args->prognumber ? : program->number;
3978c2ecf20Sopenharmony_ci	clnt->cl_vers     = version->number;
3988c2ecf20Sopenharmony_ci	clnt->cl_stats    = args->stats ? : program->stats;
3998c2ecf20Sopenharmony_ci	clnt->cl_metrics  = rpc_alloc_iostats(clnt);
4008c2ecf20Sopenharmony_ci	rpc_init_pipe_dir_head(&clnt->cl_pipedir_objects);
4018c2ecf20Sopenharmony_ci	err = -ENOMEM;
4028c2ecf20Sopenharmony_ci	if (clnt->cl_metrics == NULL)
4038c2ecf20Sopenharmony_ci		goto out_no_stats;
4048c2ecf20Sopenharmony_ci	clnt->cl_program  = program;
4058c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&clnt->cl_tasks);
4068c2ecf20Sopenharmony_ci	spin_lock_init(&clnt->cl_lock);
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_ci	timeout = xprt->timeout;
4098c2ecf20Sopenharmony_ci	if (args->timeout != NULL) {
4108c2ecf20Sopenharmony_ci		memcpy(&clnt->cl_timeout_default, args->timeout,
4118c2ecf20Sopenharmony_ci				sizeof(clnt->cl_timeout_default));
4128c2ecf20Sopenharmony_ci		timeout = &clnt->cl_timeout_default;
4138c2ecf20Sopenharmony_ci	}
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_ci	rpc_clnt_set_transport(clnt, xprt, timeout);
4168c2ecf20Sopenharmony_ci	xprt_iter_init(&clnt->cl_xpi, xps);
4178c2ecf20Sopenharmony_ci	xprt_switch_put(xps);
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_ci	clnt->cl_rtt = &clnt->cl_rtt_default;
4208c2ecf20Sopenharmony_ci	rpc_init_rtt(&clnt->cl_rtt_default, clnt->cl_timeout->to_initval);
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_ci	atomic_set(&clnt->cl_count, 1);
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_ci	if (nodename == NULL)
4258c2ecf20Sopenharmony_ci		nodename = utsname()->nodename;
4268c2ecf20Sopenharmony_ci	/* save the nodename */
4278c2ecf20Sopenharmony_ci	rpc_clnt_set_nodename(clnt, nodename);
4288c2ecf20Sopenharmony_ci
4298c2ecf20Sopenharmony_ci	err = rpc_client_register(clnt, args->authflavor, args->client_name);
4308c2ecf20Sopenharmony_ci	if (err)
4318c2ecf20Sopenharmony_ci		goto out_no_path;
4328c2ecf20Sopenharmony_ci	if (parent)
4338c2ecf20Sopenharmony_ci		atomic_inc(&parent->cl_count);
4348c2ecf20Sopenharmony_ci
4358c2ecf20Sopenharmony_ci	trace_rpc_clnt_new(clnt, xprt, program->name, args->servername);
4368c2ecf20Sopenharmony_ci	return clnt;
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_ciout_no_path:
4398c2ecf20Sopenharmony_ci	rpc_free_iostats(clnt->cl_metrics);
4408c2ecf20Sopenharmony_ciout_no_stats:
4418c2ecf20Sopenharmony_ci	put_cred(clnt->cl_cred);
4428c2ecf20Sopenharmony_ci	rpc_free_clid(clnt);
4438c2ecf20Sopenharmony_ciout_no_clid:
4448c2ecf20Sopenharmony_ci	kfree(clnt);
4458c2ecf20Sopenharmony_ciout_err:
4468c2ecf20Sopenharmony_ci	rpciod_down();
4478c2ecf20Sopenharmony_ciout_no_rpciod:
4488c2ecf20Sopenharmony_ci	xprt_switch_put(xps);
4498c2ecf20Sopenharmony_ci	xprt_put(xprt);
4508c2ecf20Sopenharmony_ci	trace_rpc_clnt_new_err(program->name, args->servername, err);
4518c2ecf20Sopenharmony_ci	return ERR_PTR(err);
4528c2ecf20Sopenharmony_ci}
4538c2ecf20Sopenharmony_ci
4548c2ecf20Sopenharmony_cistatic struct rpc_clnt *rpc_create_xprt(struct rpc_create_args *args,
4558c2ecf20Sopenharmony_ci					struct rpc_xprt *xprt)
4568c2ecf20Sopenharmony_ci{
4578c2ecf20Sopenharmony_ci	struct rpc_clnt *clnt = NULL;
4588c2ecf20Sopenharmony_ci	struct rpc_xprt_switch *xps;
4598c2ecf20Sopenharmony_ci
4608c2ecf20Sopenharmony_ci	if (args->bc_xprt && args->bc_xprt->xpt_bc_xps) {
4618c2ecf20Sopenharmony_ci		WARN_ON_ONCE(!(args->protocol & XPRT_TRANSPORT_BC));
4628c2ecf20Sopenharmony_ci		xps = args->bc_xprt->xpt_bc_xps;
4638c2ecf20Sopenharmony_ci		xprt_switch_get(xps);
4648c2ecf20Sopenharmony_ci	} else {
4658c2ecf20Sopenharmony_ci		xps = xprt_switch_alloc(xprt, GFP_KERNEL);
4668c2ecf20Sopenharmony_ci		if (xps == NULL) {
4678c2ecf20Sopenharmony_ci			xprt_put(xprt);
4688c2ecf20Sopenharmony_ci			return ERR_PTR(-ENOMEM);
4698c2ecf20Sopenharmony_ci		}
4708c2ecf20Sopenharmony_ci		if (xprt->bc_xprt) {
4718c2ecf20Sopenharmony_ci			xprt_switch_get(xps);
4728c2ecf20Sopenharmony_ci			xprt->bc_xprt->xpt_bc_xps = xps;
4738c2ecf20Sopenharmony_ci		}
4748c2ecf20Sopenharmony_ci	}
4758c2ecf20Sopenharmony_ci	clnt = rpc_new_client(args, xps, xprt, NULL);
4768c2ecf20Sopenharmony_ci	if (IS_ERR(clnt))
4778c2ecf20Sopenharmony_ci		return clnt;
4788c2ecf20Sopenharmony_ci
4798c2ecf20Sopenharmony_ci	if (!(args->flags & RPC_CLNT_CREATE_NOPING)) {
4808c2ecf20Sopenharmony_ci		int err = rpc_ping(clnt);
4818c2ecf20Sopenharmony_ci		if (err != 0) {
4828c2ecf20Sopenharmony_ci			rpc_shutdown_client(clnt);
4838c2ecf20Sopenharmony_ci			return ERR_PTR(err);
4848c2ecf20Sopenharmony_ci		}
4858c2ecf20Sopenharmony_ci	}
4868c2ecf20Sopenharmony_ci
4878c2ecf20Sopenharmony_ci	clnt->cl_softrtry = 1;
4888c2ecf20Sopenharmony_ci	if (args->flags & (RPC_CLNT_CREATE_HARDRTRY|RPC_CLNT_CREATE_SOFTERR)) {
4898c2ecf20Sopenharmony_ci		clnt->cl_softrtry = 0;
4908c2ecf20Sopenharmony_ci		if (args->flags & RPC_CLNT_CREATE_SOFTERR)
4918c2ecf20Sopenharmony_ci			clnt->cl_softerr = 1;
4928c2ecf20Sopenharmony_ci	}
4938c2ecf20Sopenharmony_ci
4948c2ecf20Sopenharmony_ci	if (args->flags & RPC_CLNT_CREATE_AUTOBIND)
4958c2ecf20Sopenharmony_ci		clnt->cl_autobind = 1;
4968c2ecf20Sopenharmony_ci	if (args->flags & RPC_CLNT_CREATE_NO_RETRANS_TIMEOUT)
4978c2ecf20Sopenharmony_ci		clnt->cl_noretranstimeo = 1;
4988c2ecf20Sopenharmony_ci	if (args->flags & RPC_CLNT_CREATE_DISCRTRY)
4998c2ecf20Sopenharmony_ci		clnt->cl_discrtry = 1;
5008c2ecf20Sopenharmony_ci	if (!(args->flags & RPC_CLNT_CREATE_QUIET))
5018c2ecf20Sopenharmony_ci		clnt->cl_chatty = 1;
5028c2ecf20Sopenharmony_ci
5038c2ecf20Sopenharmony_ci	return clnt;
5048c2ecf20Sopenharmony_ci}
5058c2ecf20Sopenharmony_ci
5068c2ecf20Sopenharmony_ci/**
5078c2ecf20Sopenharmony_ci * rpc_create - create an RPC client and transport with one call
5088c2ecf20Sopenharmony_ci * @args: rpc_clnt create argument structure
5098c2ecf20Sopenharmony_ci *
5108c2ecf20Sopenharmony_ci * Creates and initializes an RPC transport and an RPC client.
5118c2ecf20Sopenharmony_ci *
5128c2ecf20Sopenharmony_ci * It can ping the server in order to determine if it is up, and to see if
5138c2ecf20Sopenharmony_ci * it supports this program and version.  RPC_CLNT_CREATE_NOPING disables
5148c2ecf20Sopenharmony_ci * this behavior so asynchronous tasks can also use rpc_create.
5158c2ecf20Sopenharmony_ci */
5168c2ecf20Sopenharmony_cistruct rpc_clnt *rpc_create(struct rpc_create_args *args)
5178c2ecf20Sopenharmony_ci{
5188c2ecf20Sopenharmony_ci	struct rpc_xprt *xprt;
5198c2ecf20Sopenharmony_ci	struct xprt_create xprtargs = {
5208c2ecf20Sopenharmony_ci		.net = args->net,
5218c2ecf20Sopenharmony_ci		.ident = args->protocol,
5228c2ecf20Sopenharmony_ci		.srcaddr = args->saddress,
5238c2ecf20Sopenharmony_ci		.dstaddr = args->address,
5248c2ecf20Sopenharmony_ci		.addrlen = args->addrsize,
5258c2ecf20Sopenharmony_ci		.servername = args->servername,
5268c2ecf20Sopenharmony_ci		.bc_xprt = args->bc_xprt,
5278c2ecf20Sopenharmony_ci	};
5288c2ecf20Sopenharmony_ci	char servername[48];
5298c2ecf20Sopenharmony_ci	struct rpc_clnt *clnt;
5308c2ecf20Sopenharmony_ci	int i;
5318c2ecf20Sopenharmony_ci
5328c2ecf20Sopenharmony_ci	if (args->bc_xprt) {
5338c2ecf20Sopenharmony_ci		WARN_ON_ONCE(!(args->protocol & XPRT_TRANSPORT_BC));
5348c2ecf20Sopenharmony_ci		xprt = args->bc_xprt->xpt_bc_xprt;
5358c2ecf20Sopenharmony_ci		if (xprt) {
5368c2ecf20Sopenharmony_ci			xprt_get(xprt);
5378c2ecf20Sopenharmony_ci			return rpc_create_xprt(args, xprt);
5388c2ecf20Sopenharmony_ci		}
5398c2ecf20Sopenharmony_ci	}
5408c2ecf20Sopenharmony_ci
5418c2ecf20Sopenharmony_ci	if (args->flags & RPC_CLNT_CREATE_INFINITE_SLOTS)
5428c2ecf20Sopenharmony_ci		xprtargs.flags |= XPRT_CREATE_INFINITE_SLOTS;
5438c2ecf20Sopenharmony_ci	if (args->flags & RPC_CLNT_CREATE_NO_IDLE_TIMEOUT)
5448c2ecf20Sopenharmony_ci		xprtargs.flags |= XPRT_CREATE_NO_IDLE_TIMEOUT;
5458c2ecf20Sopenharmony_ci	/*
5468c2ecf20Sopenharmony_ci	 * If the caller chooses not to specify a hostname, whip
5478c2ecf20Sopenharmony_ci	 * up a string representation of the passed-in address.
5488c2ecf20Sopenharmony_ci	 */
5498c2ecf20Sopenharmony_ci	if (xprtargs.servername == NULL) {
5508c2ecf20Sopenharmony_ci		struct sockaddr_un *sun =
5518c2ecf20Sopenharmony_ci				(struct sockaddr_un *)args->address;
5528c2ecf20Sopenharmony_ci		struct sockaddr_in *sin =
5538c2ecf20Sopenharmony_ci				(struct sockaddr_in *)args->address;
5548c2ecf20Sopenharmony_ci		struct sockaddr_in6 *sin6 =
5558c2ecf20Sopenharmony_ci				(struct sockaddr_in6 *)args->address;
5568c2ecf20Sopenharmony_ci
5578c2ecf20Sopenharmony_ci		servername[0] = '\0';
5588c2ecf20Sopenharmony_ci		switch (args->address->sa_family) {
5598c2ecf20Sopenharmony_ci		case AF_LOCAL:
5608c2ecf20Sopenharmony_ci			snprintf(servername, sizeof(servername), "%s",
5618c2ecf20Sopenharmony_ci				 sun->sun_path);
5628c2ecf20Sopenharmony_ci			break;
5638c2ecf20Sopenharmony_ci		case AF_INET:
5648c2ecf20Sopenharmony_ci			snprintf(servername, sizeof(servername), "%pI4",
5658c2ecf20Sopenharmony_ci				 &sin->sin_addr.s_addr);
5668c2ecf20Sopenharmony_ci			break;
5678c2ecf20Sopenharmony_ci		case AF_INET6:
5688c2ecf20Sopenharmony_ci			snprintf(servername, sizeof(servername), "%pI6",
5698c2ecf20Sopenharmony_ci				 &sin6->sin6_addr);
5708c2ecf20Sopenharmony_ci			break;
5718c2ecf20Sopenharmony_ci		default:
5728c2ecf20Sopenharmony_ci			/* caller wants default server name, but
5738c2ecf20Sopenharmony_ci			 * address family isn't recognized. */
5748c2ecf20Sopenharmony_ci			return ERR_PTR(-EINVAL);
5758c2ecf20Sopenharmony_ci		}
5768c2ecf20Sopenharmony_ci		xprtargs.servername = servername;
5778c2ecf20Sopenharmony_ci	}
5788c2ecf20Sopenharmony_ci
5798c2ecf20Sopenharmony_ci	xprt = xprt_create_transport(&xprtargs);
5808c2ecf20Sopenharmony_ci	if (IS_ERR(xprt))
5818c2ecf20Sopenharmony_ci		return (struct rpc_clnt *)xprt;
5828c2ecf20Sopenharmony_ci
5838c2ecf20Sopenharmony_ci	/*
5848c2ecf20Sopenharmony_ci	 * By default, kernel RPC client connects from a reserved port.
5858c2ecf20Sopenharmony_ci	 * CAP_NET_BIND_SERVICE will not be set for unprivileged requesters,
5868c2ecf20Sopenharmony_ci	 * but it is always enabled for rpciod, which handles the connect
5878c2ecf20Sopenharmony_ci	 * operation.
5888c2ecf20Sopenharmony_ci	 */
5898c2ecf20Sopenharmony_ci	xprt->resvport = 1;
5908c2ecf20Sopenharmony_ci	if (args->flags & RPC_CLNT_CREATE_NONPRIVPORT)
5918c2ecf20Sopenharmony_ci		xprt->resvport = 0;
5928c2ecf20Sopenharmony_ci	xprt->reuseport = 0;
5938c2ecf20Sopenharmony_ci	if (args->flags & RPC_CLNT_CREATE_REUSEPORT)
5948c2ecf20Sopenharmony_ci		xprt->reuseport = 1;
5958c2ecf20Sopenharmony_ci
5968c2ecf20Sopenharmony_ci	clnt = rpc_create_xprt(args, xprt);
5978c2ecf20Sopenharmony_ci	if (IS_ERR(clnt) || args->nconnect <= 1)
5988c2ecf20Sopenharmony_ci		return clnt;
5998c2ecf20Sopenharmony_ci
6008c2ecf20Sopenharmony_ci	for (i = 0; i < args->nconnect - 1; i++) {
6018c2ecf20Sopenharmony_ci		if (rpc_clnt_add_xprt(clnt, &xprtargs, NULL, NULL) < 0)
6028c2ecf20Sopenharmony_ci			break;
6038c2ecf20Sopenharmony_ci	}
6048c2ecf20Sopenharmony_ci	return clnt;
6058c2ecf20Sopenharmony_ci}
6068c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_create);
6078c2ecf20Sopenharmony_ci
6088c2ecf20Sopenharmony_ci/*
6098c2ecf20Sopenharmony_ci * This function clones the RPC client structure. It allows us to share the
6108c2ecf20Sopenharmony_ci * same transport while varying parameters such as the authentication
6118c2ecf20Sopenharmony_ci * flavour.
6128c2ecf20Sopenharmony_ci */
6138c2ecf20Sopenharmony_cistatic struct rpc_clnt *__rpc_clone_client(struct rpc_create_args *args,
6148c2ecf20Sopenharmony_ci					   struct rpc_clnt *clnt)
6158c2ecf20Sopenharmony_ci{
6168c2ecf20Sopenharmony_ci	struct rpc_xprt_switch *xps;
6178c2ecf20Sopenharmony_ci	struct rpc_xprt *xprt;
6188c2ecf20Sopenharmony_ci	struct rpc_clnt *new;
6198c2ecf20Sopenharmony_ci	int err;
6208c2ecf20Sopenharmony_ci
6218c2ecf20Sopenharmony_ci	err = -ENOMEM;
6228c2ecf20Sopenharmony_ci	rcu_read_lock();
6238c2ecf20Sopenharmony_ci	xprt = xprt_get(rcu_dereference(clnt->cl_xprt));
6248c2ecf20Sopenharmony_ci	xps = xprt_switch_get(rcu_dereference(clnt->cl_xpi.xpi_xpswitch));
6258c2ecf20Sopenharmony_ci	rcu_read_unlock();
6268c2ecf20Sopenharmony_ci	if (xprt == NULL || xps == NULL) {
6278c2ecf20Sopenharmony_ci		xprt_put(xprt);
6288c2ecf20Sopenharmony_ci		xprt_switch_put(xps);
6298c2ecf20Sopenharmony_ci		goto out_err;
6308c2ecf20Sopenharmony_ci	}
6318c2ecf20Sopenharmony_ci	args->servername = xprt->servername;
6328c2ecf20Sopenharmony_ci	args->nodename = clnt->cl_nodename;
6338c2ecf20Sopenharmony_ci
6348c2ecf20Sopenharmony_ci	new = rpc_new_client(args, xps, xprt, clnt);
6358c2ecf20Sopenharmony_ci	if (IS_ERR(new))
6368c2ecf20Sopenharmony_ci		return new;
6378c2ecf20Sopenharmony_ci
6388c2ecf20Sopenharmony_ci	/* Turn off autobind on clones */
6398c2ecf20Sopenharmony_ci	new->cl_autobind = 0;
6408c2ecf20Sopenharmony_ci	new->cl_softrtry = clnt->cl_softrtry;
6418c2ecf20Sopenharmony_ci	new->cl_softerr = clnt->cl_softerr;
6428c2ecf20Sopenharmony_ci	new->cl_noretranstimeo = clnt->cl_noretranstimeo;
6438c2ecf20Sopenharmony_ci	new->cl_discrtry = clnt->cl_discrtry;
6448c2ecf20Sopenharmony_ci	new->cl_chatty = clnt->cl_chatty;
6458c2ecf20Sopenharmony_ci	new->cl_principal = clnt->cl_principal;
6468c2ecf20Sopenharmony_ci	return new;
6478c2ecf20Sopenharmony_ci
6488c2ecf20Sopenharmony_ciout_err:
6498c2ecf20Sopenharmony_ci	trace_rpc_clnt_clone_err(clnt, err);
6508c2ecf20Sopenharmony_ci	return ERR_PTR(err);
6518c2ecf20Sopenharmony_ci}
6528c2ecf20Sopenharmony_ci
6538c2ecf20Sopenharmony_ci/**
6548c2ecf20Sopenharmony_ci * rpc_clone_client - Clone an RPC client structure
6558c2ecf20Sopenharmony_ci *
6568c2ecf20Sopenharmony_ci * @clnt: RPC client whose parameters are copied
6578c2ecf20Sopenharmony_ci *
6588c2ecf20Sopenharmony_ci * Returns a fresh RPC client or an ERR_PTR.
6598c2ecf20Sopenharmony_ci */
6608c2ecf20Sopenharmony_cistruct rpc_clnt *rpc_clone_client(struct rpc_clnt *clnt)
6618c2ecf20Sopenharmony_ci{
6628c2ecf20Sopenharmony_ci	struct rpc_create_args args = {
6638c2ecf20Sopenharmony_ci		.program	= clnt->cl_program,
6648c2ecf20Sopenharmony_ci		.prognumber	= clnt->cl_prog,
6658c2ecf20Sopenharmony_ci		.version	= clnt->cl_vers,
6668c2ecf20Sopenharmony_ci		.authflavor	= clnt->cl_auth->au_flavor,
6678c2ecf20Sopenharmony_ci		.cred		= clnt->cl_cred,
6688c2ecf20Sopenharmony_ci		.stats		= clnt->cl_stats,
6698c2ecf20Sopenharmony_ci	};
6708c2ecf20Sopenharmony_ci	return __rpc_clone_client(&args, clnt);
6718c2ecf20Sopenharmony_ci}
6728c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_clone_client);
6738c2ecf20Sopenharmony_ci
6748c2ecf20Sopenharmony_ci/**
6758c2ecf20Sopenharmony_ci * rpc_clone_client_set_auth - Clone an RPC client structure and set its auth
6768c2ecf20Sopenharmony_ci *
6778c2ecf20Sopenharmony_ci * @clnt: RPC client whose parameters are copied
6788c2ecf20Sopenharmony_ci * @flavor: security flavor for new client
6798c2ecf20Sopenharmony_ci *
6808c2ecf20Sopenharmony_ci * Returns a fresh RPC client or an ERR_PTR.
6818c2ecf20Sopenharmony_ci */
6828c2ecf20Sopenharmony_cistruct rpc_clnt *
6838c2ecf20Sopenharmony_cirpc_clone_client_set_auth(struct rpc_clnt *clnt, rpc_authflavor_t flavor)
6848c2ecf20Sopenharmony_ci{
6858c2ecf20Sopenharmony_ci	struct rpc_create_args args = {
6868c2ecf20Sopenharmony_ci		.program	= clnt->cl_program,
6878c2ecf20Sopenharmony_ci		.prognumber	= clnt->cl_prog,
6888c2ecf20Sopenharmony_ci		.version	= clnt->cl_vers,
6898c2ecf20Sopenharmony_ci		.authflavor	= flavor,
6908c2ecf20Sopenharmony_ci		.cred		= clnt->cl_cred,
6918c2ecf20Sopenharmony_ci		.stats		= clnt->cl_stats,
6928c2ecf20Sopenharmony_ci	};
6938c2ecf20Sopenharmony_ci	return __rpc_clone_client(&args, clnt);
6948c2ecf20Sopenharmony_ci}
6958c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_clone_client_set_auth);
6968c2ecf20Sopenharmony_ci
6978c2ecf20Sopenharmony_ci/**
6988c2ecf20Sopenharmony_ci * rpc_switch_client_transport: switch the RPC transport on the fly
6998c2ecf20Sopenharmony_ci * @clnt: pointer to a struct rpc_clnt
7008c2ecf20Sopenharmony_ci * @args: pointer to the new transport arguments
7018c2ecf20Sopenharmony_ci * @timeout: pointer to the new timeout parameters
7028c2ecf20Sopenharmony_ci *
7038c2ecf20Sopenharmony_ci * This function allows the caller to switch the RPC transport for the
7048c2ecf20Sopenharmony_ci * rpc_clnt structure 'clnt' to allow it to connect to a mirrored NFS
7058c2ecf20Sopenharmony_ci * server, for instance.  It assumes that the caller has ensured that
7068c2ecf20Sopenharmony_ci * there are no active RPC tasks by using some form of locking.
7078c2ecf20Sopenharmony_ci *
7088c2ecf20Sopenharmony_ci * Returns zero if "clnt" is now using the new xprt.  Otherwise a
7098c2ecf20Sopenharmony_ci * negative errno is returned, and "clnt" continues to use the old
7108c2ecf20Sopenharmony_ci * xprt.
7118c2ecf20Sopenharmony_ci */
7128c2ecf20Sopenharmony_ciint rpc_switch_client_transport(struct rpc_clnt *clnt,
7138c2ecf20Sopenharmony_ci		struct xprt_create *args,
7148c2ecf20Sopenharmony_ci		const struct rpc_timeout *timeout)
7158c2ecf20Sopenharmony_ci{
7168c2ecf20Sopenharmony_ci	const struct rpc_timeout *old_timeo;
7178c2ecf20Sopenharmony_ci	rpc_authflavor_t pseudoflavor;
7188c2ecf20Sopenharmony_ci	struct rpc_xprt_switch *xps, *oldxps;
7198c2ecf20Sopenharmony_ci	struct rpc_xprt *xprt, *old;
7208c2ecf20Sopenharmony_ci	struct rpc_clnt *parent;
7218c2ecf20Sopenharmony_ci	int err;
7228c2ecf20Sopenharmony_ci
7238c2ecf20Sopenharmony_ci	xprt = xprt_create_transport(args);
7248c2ecf20Sopenharmony_ci	if (IS_ERR(xprt))
7258c2ecf20Sopenharmony_ci		return PTR_ERR(xprt);
7268c2ecf20Sopenharmony_ci
7278c2ecf20Sopenharmony_ci	xps = xprt_switch_alloc(xprt, GFP_KERNEL);
7288c2ecf20Sopenharmony_ci	if (xps == NULL) {
7298c2ecf20Sopenharmony_ci		xprt_put(xprt);
7308c2ecf20Sopenharmony_ci		return -ENOMEM;
7318c2ecf20Sopenharmony_ci	}
7328c2ecf20Sopenharmony_ci
7338c2ecf20Sopenharmony_ci	pseudoflavor = clnt->cl_auth->au_flavor;
7348c2ecf20Sopenharmony_ci
7358c2ecf20Sopenharmony_ci	old_timeo = clnt->cl_timeout;
7368c2ecf20Sopenharmony_ci	old = rpc_clnt_set_transport(clnt, xprt, timeout);
7378c2ecf20Sopenharmony_ci	oldxps = xprt_iter_xchg_switch(&clnt->cl_xpi, xps);
7388c2ecf20Sopenharmony_ci
7398c2ecf20Sopenharmony_ci	rpc_unregister_client(clnt);
7408c2ecf20Sopenharmony_ci	__rpc_clnt_remove_pipedir(clnt);
7418c2ecf20Sopenharmony_ci	rpc_clnt_debugfs_unregister(clnt);
7428c2ecf20Sopenharmony_ci
7438c2ecf20Sopenharmony_ci	/*
7448c2ecf20Sopenharmony_ci	 * A new transport was created.  "clnt" therefore
7458c2ecf20Sopenharmony_ci	 * becomes the root of a new cl_parent tree.  clnt's
7468c2ecf20Sopenharmony_ci	 * children, if it has any, still point to the old xprt.
7478c2ecf20Sopenharmony_ci	 */
7488c2ecf20Sopenharmony_ci	parent = clnt->cl_parent;
7498c2ecf20Sopenharmony_ci	clnt->cl_parent = clnt;
7508c2ecf20Sopenharmony_ci
7518c2ecf20Sopenharmony_ci	/*
7528c2ecf20Sopenharmony_ci	 * The old rpc_auth cache cannot be re-used.  GSS
7538c2ecf20Sopenharmony_ci	 * contexts in particular are between a single
7548c2ecf20Sopenharmony_ci	 * client and server.
7558c2ecf20Sopenharmony_ci	 */
7568c2ecf20Sopenharmony_ci	err = rpc_client_register(clnt, pseudoflavor, NULL);
7578c2ecf20Sopenharmony_ci	if (err)
7588c2ecf20Sopenharmony_ci		goto out_revert;
7598c2ecf20Sopenharmony_ci
7608c2ecf20Sopenharmony_ci	synchronize_rcu();
7618c2ecf20Sopenharmony_ci	if (parent != clnt)
7628c2ecf20Sopenharmony_ci		rpc_release_client(parent);
7638c2ecf20Sopenharmony_ci	xprt_switch_put(oldxps);
7648c2ecf20Sopenharmony_ci	xprt_put(old);
7658c2ecf20Sopenharmony_ci	trace_rpc_clnt_replace_xprt(clnt);
7668c2ecf20Sopenharmony_ci	return 0;
7678c2ecf20Sopenharmony_ci
7688c2ecf20Sopenharmony_ciout_revert:
7698c2ecf20Sopenharmony_ci	xps = xprt_iter_xchg_switch(&clnt->cl_xpi, oldxps);
7708c2ecf20Sopenharmony_ci	rpc_clnt_set_transport(clnt, old, old_timeo);
7718c2ecf20Sopenharmony_ci	clnt->cl_parent = parent;
7728c2ecf20Sopenharmony_ci	rpc_client_register(clnt, pseudoflavor, NULL);
7738c2ecf20Sopenharmony_ci	xprt_switch_put(xps);
7748c2ecf20Sopenharmony_ci	xprt_put(xprt);
7758c2ecf20Sopenharmony_ci	trace_rpc_clnt_replace_xprt_err(clnt);
7768c2ecf20Sopenharmony_ci	return err;
7778c2ecf20Sopenharmony_ci}
7788c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_switch_client_transport);
7798c2ecf20Sopenharmony_ci
7808c2ecf20Sopenharmony_cistatic
7818c2ecf20Sopenharmony_ciint rpc_clnt_xprt_iter_init(struct rpc_clnt *clnt, struct rpc_xprt_iter *xpi)
7828c2ecf20Sopenharmony_ci{
7838c2ecf20Sopenharmony_ci	struct rpc_xprt_switch *xps;
7848c2ecf20Sopenharmony_ci
7858c2ecf20Sopenharmony_ci	rcu_read_lock();
7868c2ecf20Sopenharmony_ci	xps = xprt_switch_get(rcu_dereference(clnt->cl_xpi.xpi_xpswitch));
7878c2ecf20Sopenharmony_ci	rcu_read_unlock();
7888c2ecf20Sopenharmony_ci	if (xps == NULL)
7898c2ecf20Sopenharmony_ci		return -EAGAIN;
7908c2ecf20Sopenharmony_ci	xprt_iter_init_listall(xpi, xps);
7918c2ecf20Sopenharmony_ci	xprt_switch_put(xps);
7928c2ecf20Sopenharmony_ci	return 0;
7938c2ecf20Sopenharmony_ci}
7948c2ecf20Sopenharmony_ci
7958c2ecf20Sopenharmony_ci/**
7968c2ecf20Sopenharmony_ci * rpc_clnt_iterate_for_each_xprt - Apply a function to all transports
7978c2ecf20Sopenharmony_ci * @clnt: pointer to client
7988c2ecf20Sopenharmony_ci * @fn: function to apply
7998c2ecf20Sopenharmony_ci * @data: void pointer to function data
8008c2ecf20Sopenharmony_ci *
8018c2ecf20Sopenharmony_ci * Iterates through the list of RPC transports currently attached to the
8028c2ecf20Sopenharmony_ci * client and applies the function fn(clnt, xprt, data).
8038c2ecf20Sopenharmony_ci *
8048c2ecf20Sopenharmony_ci * On error, the iteration stops, and the function returns the error value.
8058c2ecf20Sopenharmony_ci */
8068c2ecf20Sopenharmony_ciint rpc_clnt_iterate_for_each_xprt(struct rpc_clnt *clnt,
8078c2ecf20Sopenharmony_ci		int (*fn)(struct rpc_clnt *, struct rpc_xprt *, void *),
8088c2ecf20Sopenharmony_ci		void *data)
8098c2ecf20Sopenharmony_ci{
8108c2ecf20Sopenharmony_ci	struct rpc_xprt_iter xpi;
8118c2ecf20Sopenharmony_ci	int ret;
8128c2ecf20Sopenharmony_ci
8138c2ecf20Sopenharmony_ci	ret = rpc_clnt_xprt_iter_init(clnt, &xpi);
8148c2ecf20Sopenharmony_ci	if (ret)
8158c2ecf20Sopenharmony_ci		return ret;
8168c2ecf20Sopenharmony_ci	for (;;) {
8178c2ecf20Sopenharmony_ci		struct rpc_xprt *xprt = xprt_iter_get_next(&xpi);
8188c2ecf20Sopenharmony_ci
8198c2ecf20Sopenharmony_ci		if (!xprt)
8208c2ecf20Sopenharmony_ci			break;
8218c2ecf20Sopenharmony_ci		ret = fn(clnt, xprt, data);
8228c2ecf20Sopenharmony_ci		xprt_put(xprt);
8238c2ecf20Sopenharmony_ci		if (ret < 0)
8248c2ecf20Sopenharmony_ci			break;
8258c2ecf20Sopenharmony_ci	}
8268c2ecf20Sopenharmony_ci	xprt_iter_destroy(&xpi);
8278c2ecf20Sopenharmony_ci	return ret;
8288c2ecf20Sopenharmony_ci}
8298c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_clnt_iterate_for_each_xprt);
8308c2ecf20Sopenharmony_ci
8318c2ecf20Sopenharmony_ci/*
8328c2ecf20Sopenharmony_ci * Kill all tasks for the given client.
8338c2ecf20Sopenharmony_ci * XXX: kill their descendants as well?
8348c2ecf20Sopenharmony_ci */
8358c2ecf20Sopenharmony_civoid rpc_killall_tasks(struct rpc_clnt *clnt)
8368c2ecf20Sopenharmony_ci{
8378c2ecf20Sopenharmony_ci	struct rpc_task	*rovr;
8388c2ecf20Sopenharmony_ci
8398c2ecf20Sopenharmony_ci
8408c2ecf20Sopenharmony_ci	if (list_empty(&clnt->cl_tasks))
8418c2ecf20Sopenharmony_ci		return;
8428c2ecf20Sopenharmony_ci
8438c2ecf20Sopenharmony_ci	/*
8448c2ecf20Sopenharmony_ci	 * Spin lock all_tasks to prevent changes...
8458c2ecf20Sopenharmony_ci	 */
8468c2ecf20Sopenharmony_ci	trace_rpc_clnt_killall(clnt);
8478c2ecf20Sopenharmony_ci	spin_lock(&clnt->cl_lock);
8488c2ecf20Sopenharmony_ci	list_for_each_entry(rovr, &clnt->cl_tasks, tk_task)
8498c2ecf20Sopenharmony_ci		rpc_signal_task(rovr);
8508c2ecf20Sopenharmony_ci	spin_unlock(&clnt->cl_lock);
8518c2ecf20Sopenharmony_ci}
8528c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_killall_tasks);
8538c2ecf20Sopenharmony_ci
8548c2ecf20Sopenharmony_ci/*
8558c2ecf20Sopenharmony_ci * Properly shut down an RPC client, terminating all outstanding
8568c2ecf20Sopenharmony_ci * requests.
8578c2ecf20Sopenharmony_ci */
8588c2ecf20Sopenharmony_civoid rpc_shutdown_client(struct rpc_clnt *clnt)
8598c2ecf20Sopenharmony_ci{
8608c2ecf20Sopenharmony_ci	might_sleep();
8618c2ecf20Sopenharmony_ci
8628c2ecf20Sopenharmony_ci	trace_rpc_clnt_shutdown(clnt);
8638c2ecf20Sopenharmony_ci
8648c2ecf20Sopenharmony_ci	while (!list_empty(&clnt->cl_tasks)) {
8658c2ecf20Sopenharmony_ci		rpc_killall_tasks(clnt);
8668c2ecf20Sopenharmony_ci		wait_event_timeout(destroy_wait,
8678c2ecf20Sopenharmony_ci			list_empty(&clnt->cl_tasks), 1*HZ);
8688c2ecf20Sopenharmony_ci	}
8698c2ecf20Sopenharmony_ci
8708c2ecf20Sopenharmony_ci	rpc_release_client(clnt);
8718c2ecf20Sopenharmony_ci}
8728c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_shutdown_client);
8738c2ecf20Sopenharmony_ci
8748c2ecf20Sopenharmony_ci/*
8758c2ecf20Sopenharmony_ci * Free an RPC client
8768c2ecf20Sopenharmony_ci */
8778c2ecf20Sopenharmony_cistatic void rpc_free_client_work(struct work_struct *work)
8788c2ecf20Sopenharmony_ci{
8798c2ecf20Sopenharmony_ci	struct rpc_clnt *clnt = container_of(work, struct rpc_clnt, cl_work);
8808c2ecf20Sopenharmony_ci
8818c2ecf20Sopenharmony_ci	trace_rpc_clnt_free(clnt);
8828c2ecf20Sopenharmony_ci
8838c2ecf20Sopenharmony_ci	/* These might block on processes that might allocate memory,
8848c2ecf20Sopenharmony_ci	 * so they cannot be called in rpciod, so they are handled separately
8858c2ecf20Sopenharmony_ci	 * here.
8868c2ecf20Sopenharmony_ci	 */
8878c2ecf20Sopenharmony_ci	rpc_clnt_debugfs_unregister(clnt);
8888c2ecf20Sopenharmony_ci	rpc_free_clid(clnt);
8898c2ecf20Sopenharmony_ci	rpc_clnt_remove_pipedir(clnt);
8908c2ecf20Sopenharmony_ci	xprt_put(rcu_dereference_raw(clnt->cl_xprt));
8918c2ecf20Sopenharmony_ci
8928c2ecf20Sopenharmony_ci	kfree(clnt);
8938c2ecf20Sopenharmony_ci	rpciod_down();
8948c2ecf20Sopenharmony_ci}
8958c2ecf20Sopenharmony_cistatic struct rpc_clnt *
8968c2ecf20Sopenharmony_cirpc_free_client(struct rpc_clnt *clnt)
8978c2ecf20Sopenharmony_ci{
8988c2ecf20Sopenharmony_ci	struct rpc_clnt *parent = NULL;
8998c2ecf20Sopenharmony_ci
9008c2ecf20Sopenharmony_ci	trace_rpc_clnt_release(clnt);
9018c2ecf20Sopenharmony_ci	if (clnt->cl_parent != clnt)
9028c2ecf20Sopenharmony_ci		parent = clnt->cl_parent;
9038c2ecf20Sopenharmony_ci	rpc_unregister_client(clnt);
9048c2ecf20Sopenharmony_ci	rpc_free_iostats(clnt->cl_metrics);
9058c2ecf20Sopenharmony_ci	clnt->cl_metrics = NULL;
9068c2ecf20Sopenharmony_ci	xprt_iter_destroy(&clnt->cl_xpi);
9078c2ecf20Sopenharmony_ci	put_cred(clnt->cl_cred);
9088c2ecf20Sopenharmony_ci
9098c2ecf20Sopenharmony_ci	INIT_WORK(&clnt->cl_work, rpc_free_client_work);
9108c2ecf20Sopenharmony_ci	schedule_work(&clnt->cl_work);
9118c2ecf20Sopenharmony_ci	return parent;
9128c2ecf20Sopenharmony_ci}
9138c2ecf20Sopenharmony_ci
9148c2ecf20Sopenharmony_ci/*
9158c2ecf20Sopenharmony_ci * Free an RPC client
9168c2ecf20Sopenharmony_ci */
9178c2ecf20Sopenharmony_cistatic struct rpc_clnt *
9188c2ecf20Sopenharmony_cirpc_free_auth(struct rpc_clnt *clnt)
9198c2ecf20Sopenharmony_ci{
9208c2ecf20Sopenharmony_ci	if (clnt->cl_auth == NULL)
9218c2ecf20Sopenharmony_ci		return rpc_free_client(clnt);
9228c2ecf20Sopenharmony_ci
9238c2ecf20Sopenharmony_ci	/*
9248c2ecf20Sopenharmony_ci	 * Note: RPCSEC_GSS may need to send NULL RPC calls in order to
9258c2ecf20Sopenharmony_ci	 *       release remaining GSS contexts. This mechanism ensures
9268c2ecf20Sopenharmony_ci	 *       that it can do so safely.
9278c2ecf20Sopenharmony_ci	 */
9288c2ecf20Sopenharmony_ci	atomic_inc(&clnt->cl_count);
9298c2ecf20Sopenharmony_ci	rpcauth_release(clnt->cl_auth);
9308c2ecf20Sopenharmony_ci	clnt->cl_auth = NULL;
9318c2ecf20Sopenharmony_ci	if (atomic_dec_and_test(&clnt->cl_count))
9328c2ecf20Sopenharmony_ci		return rpc_free_client(clnt);
9338c2ecf20Sopenharmony_ci	return NULL;
9348c2ecf20Sopenharmony_ci}
9358c2ecf20Sopenharmony_ci
9368c2ecf20Sopenharmony_ci/*
9378c2ecf20Sopenharmony_ci * Release reference to the RPC client
9388c2ecf20Sopenharmony_ci */
9398c2ecf20Sopenharmony_civoid
9408c2ecf20Sopenharmony_cirpc_release_client(struct rpc_clnt *clnt)
9418c2ecf20Sopenharmony_ci{
9428c2ecf20Sopenharmony_ci	do {
9438c2ecf20Sopenharmony_ci		if (list_empty(&clnt->cl_tasks))
9448c2ecf20Sopenharmony_ci			wake_up(&destroy_wait);
9458c2ecf20Sopenharmony_ci		if (!atomic_dec_and_test(&clnt->cl_count))
9468c2ecf20Sopenharmony_ci			break;
9478c2ecf20Sopenharmony_ci		clnt = rpc_free_auth(clnt);
9488c2ecf20Sopenharmony_ci	} while (clnt != NULL);
9498c2ecf20Sopenharmony_ci}
9508c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_release_client);
9518c2ecf20Sopenharmony_ci
9528c2ecf20Sopenharmony_ci/**
9538c2ecf20Sopenharmony_ci * rpc_bind_new_program - bind a new RPC program to an existing client
9548c2ecf20Sopenharmony_ci * @old: old rpc_client
9558c2ecf20Sopenharmony_ci * @program: rpc program to set
9568c2ecf20Sopenharmony_ci * @vers: rpc program version
9578c2ecf20Sopenharmony_ci *
9588c2ecf20Sopenharmony_ci * Clones the rpc client and sets up a new RPC program. This is mainly
9598c2ecf20Sopenharmony_ci * of use for enabling different RPC programs to share the same transport.
9608c2ecf20Sopenharmony_ci * The Sun NFSv2/v3 ACL protocol can do this.
9618c2ecf20Sopenharmony_ci */
9628c2ecf20Sopenharmony_cistruct rpc_clnt *rpc_bind_new_program(struct rpc_clnt *old,
9638c2ecf20Sopenharmony_ci				      const struct rpc_program *program,
9648c2ecf20Sopenharmony_ci				      u32 vers)
9658c2ecf20Sopenharmony_ci{
9668c2ecf20Sopenharmony_ci	struct rpc_create_args args = {
9678c2ecf20Sopenharmony_ci		.program	= program,
9688c2ecf20Sopenharmony_ci		.prognumber	= program->number,
9698c2ecf20Sopenharmony_ci		.version	= vers,
9708c2ecf20Sopenharmony_ci		.authflavor	= old->cl_auth->au_flavor,
9718c2ecf20Sopenharmony_ci		.cred		= old->cl_cred,
9728c2ecf20Sopenharmony_ci		.stats		= old->cl_stats,
9738c2ecf20Sopenharmony_ci	};
9748c2ecf20Sopenharmony_ci	struct rpc_clnt *clnt;
9758c2ecf20Sopenharmony_ci	int err;
9768c2ecf20Sopenharmony_ci
9778c2ecf20Sopenharmony_ci	clnt = __rpc_clone_client(&args, old);
9788c2ecf20Sopenharmony_ci	if (IS_ERR(clnt))
9798c2ecf20Sopenharmony_ci		goto out;
9808c2ecf20Sopenharmony_ci	err = rpc_ping(clnt);
9818c2ecf20Sopenharmony_ci	if (err != 0) {
9828c2ecf20Sopenharmony_ci		rpc_shutdown_client(clnt);
9838c2ecf20Sopenharmony_ci		clnt = ERR_PTR(err);
9848c2ecf20Sopenharmony_ci	}
9858c2ecf20Sopenharmony_ciout:
9868c2ecf20Sopenharmony_ci	return clnt;
9878c2ecf20Sopenharmony_ci}
9888c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_bind_new_program);
9898c2ecf20Sopenharmony_ci
9908c2ecf20Sopenharmony_cistruct rpc_xprt *
9918c2ecf20Sopenharmony_cirpc_task_get_xprt(struct rpc_clnt *clnt, struct rpc_xprt *xprt)
9928c2ecf20Sopenharmony_ci{
9938c2ecf20Sopenharmony_ci	struct rpc_xprt_switch *xps;
9948c2ecf20Sopenharmony_ci
9958c2ecf20Sopenharmony_ci	if (!xprt)
9968c2ecf20Sopenharmony_ci		return NULL;
9978c2ecf20Sopenharmony_ci	rcu_read_lock();
9988c2ecf20Sopenharmony_ci	xps = rcu_dereference(clnt->cl_xpi.xpi_xpswitch);
9998c2ecf20Sopenharmony_ci	atomic_long_inc(&xps->xps_queuelen);
10008c2ecf20Sopenharmony_ci	rcu_read_unlock();
10018c2ecf20Sopenharmony_ci	atomic_long_inc(&xprt->queuelen);
10028c2ecf20Sopenharmony_ci
10038c2ecf20Sopenharmony_ci	return xprt;
10048c2ecf20Sopenharmony_ci}
10058c2ecf20Sopenharmony_ci
10068c2ecf20Sopenharmony_cistatic void
10078c2ecf20Sopenharmony_cirpc_task_release_xprt(struct rpc_clnt *clnt, struct rpc_xprt *xprt)
10088c2ecf20Sopenharmony_ci{
10098c2ecf20Sopenharmony_ci	struct rpc_xprt_switch *xps;
10108c2ecf20Sopenharmony_ci
10118c2ecf20Sopenharmony_ci	atomic_long_dec(&xprt->queuelen);
10128c2ecf20Sopenharmony_ci	rcu_read_lock();
10138c2ecf20Sopenharmony_ci	xps = rcu_dereference(clnt->cl_xpi.xpi_xpswitch);
10148c2ecf20Sopenharmony_ci	atomic_long_dec(&xps->xps_queuelen);
10158c2ecf20Sopenharmony_ci	rcu_read_unlock();
10168c2ecf20Sopenharmony_ci
10178c2ecf20Sopenharmony_ci	xprt_put(xprt);
10188c2ecf20Sopenharmony_ci}
10198c2ecf20Sopenharmony_ci
10208c2ecf20Sopenharmony_civoid rpc_task_release_transport(struct rpc_task *task)
10218c2ecf20Sopenharmony_ci{
10228c2ecf20Sopenharmony_ci	struct rpc_xprt *xprt = task->tk_xprt;
10238c2ecf20Sopenharmony_ci
10248c2ecf20Sopenharmony_ci	if (xprt) {
10258c2ecf20Sopenharmony_ci		task->tk_xprt = NULL;
10268c2ecf20Sopenharmony_ci		if (task->tk_client)
10278c2ecf20Sopenharmony_ci			rpc_task_release_xprt(task->tk_client, xprt);
10288c2ecf20Sopenharmony_ci		else
10298c2ecf20Sopenharmony_ci			xprt_put(xprt);
10308c2ecf20Sopenharmony_ci	}
10318c2ecf20Sopenharmony_ci}
10328c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_task_release_transport);
10338c2ecf20Sopenharmony_ci
10348c2ecf20Sopenharmony_civoid rpc_task_release_client(struct rpc_task *task)
10358c2ecf20Sopenharmony_ci{
10368c2ecf20Sopenharmony_ci	struct rpc_clnt *clnt = task->tk_client;
10378c2ecf20Sopenharmony_ci
10388c2ecf20Sopenharmony_ci	rpc_task_release_transport(task);
10398c2ecf20Sopenharmony_ci	if (clnt != NULL) {
10408c2ecf20Sopenharmony_ci		/* Remove from client task list */
10418c2ecf20Sopenharmony_ci		spin_lock(&clnt->cl_lock);
10428c2ecf20Sopenharmony_ci		list_del(&task->tk_task);
10438c2ecf20Sopenharmony_ci		spin_unlock(&clnt->cl_lock);
10448c2ecf20Sopenharmony_ci		task->tk_client = NULL;
10458c2ecf20Sopenharmony_ci
10468c2ecf20Sopenharmony_ci		rpc_release_client(clnt);
10478c2ecf20Sopenharmony_ci	}
10488c2ecf20Sopenharmony_ci}
10498c2ecf20Sopenharmony_ci
10508c2ecf20Sopenharmony_cistatic struct rpc_xprt *
10518c2ecf20Sopenharmony_cirpc_task_get_first_xprt(struct rpc_clnt *clnt)
10528c2ecf20Sopenharmony_ci{
10538c2ecf20Sopenharmony_ci	struct rpc_xprt *xprt;
10548c2ecf20Sopenharmony_ci
10558c2ecf20Sopenharmony_ci	rcu_read_lock();
10568c2ecf20Sopenharmony_ci	xprt = xprt_get(rcu_dereference(clnt->cl_xprt));
10578c2ecf20Sopenharmony_ci	rcu_read_unlock();
10588c2ecf20Sopenharmony_ci	return rpc_task_get_xprt(clnt, xprt);
10598c2ecf20Sopenharmony_ci}
10608c2ecf20Sopenharmony_ci
10618c2ecf20Sopenharmony_cistatic struct rpc_xprt *
10628c2ecf20Sopenharmony_cirpc_task_get_next_xprt(struct rpc_clnt *clnt)
10638c2ecf20Sopenharmony_ci{
10648c2ecf20Sopenharmony_ci	return rpc_task_get_xprt(clnt, xprt_iter_get_next(&clnt->cl_xpi));
10658c2ecf20Sopenharmony_ci}
10668c2ecf20Sopenharmony_ci
10678c2ecf20Sopenharmony_cistatic
10688c2ecf20Sopenharmony_civoid rpc_task_set_transport(struct rpc_task *task, struct rpc_clnt *clnt)
10698c2ecf20Sopenharmony_ci{
10708c2ecf20Sopenharmony_ci	if (task->tk_xprt)
10718c2ecf20Sopenharmony_ci		return;
10728c2ecf20Sopenharmony_ci	if (task->tk_flags & RPC_TASK_NO_ROUND_ROBIN)
10738c2ecf20Sopenharmony_ci		task->tk_xprt = rpc_task_get_first_xprt(clnt);
10748c2ecf20Sopenharmony_ci	else
10758c2ecf20Sopenharmony_ci		task->tk_xprt = rpc_task_get_next_xprt(clnt);
10768c2ecf20Sopenharmony_ci}
10778c2ecf20Sopenharmony_ci
10788c2ecf20Sopenharmony_cistatic
10798c2ecf20Sopenharmony_civoid rpc_task_set_client(struct rpc_task *task, struct rpc_clnt *clnt)
10808c2ecf20Sopenharmony_ci{
10818c2ecf20Sopenharmony_ci
10828c2ecf20Sopenharmony_ci	if (clnt != NULL) {
10838c2ecf20Sopenharmony_ci		rpc_task_set_transport(task, clnt);
10848c2ecf20Sopenharmony_ci		task->tk_client = clnt;
10858c2ecf20Sopenharmony_ci		atomic_inc(&clnt->cl_count);
10868c2ecf20Sopenharmony_ci		if (clnt->cl_softrtry)
10878c2ecf20Sopenharmony_ci			task->tk_flags |= RPC_TASK_SOFT;
10888c2ecf20Sopenharmony_ci		if (clnt->cl_softerr)
10898c2ecf20Sopenharmony_ci			task->tk_flags |= RPC_TASK_TIMEOUT;
10908c2ecf20Sopenharmony_ci		if (clnt->cl_noretranstimeo)
10918c2ecf20Sopenharmony_ci			task->tk_flags |= RPC_TASK_NO_RETRANS_TIMEOUT;
10928c2ecf20Sopenharmony_ci		if (atomic_read(&clnt->cl_swapper))
10938c2ecf20Sopenharmony_ci			task->tk_flags |= RPC_TASK_SWAPPER;
10948c2ecf20Sopenharmony_ci		/* Add to the client's list of all tasks */
10958c2ecf20Sopenharmony_ci		spin_lock(&clnt->cl_lock);
10968c2ecf20Sopenharmony_ci		list_add_tail(&task->tk_task, &clnt->cl_tasks);
10978c2ecf20Sopenharmony_ci		spin_unlock(&clnt->cl_lock);
10988c2ecf20Sopenharmony_ci	}
10998c2ecf20Sopenharmony_ci}
11008c2ecf20Sopenharmony_ci
11018c2ecf20Sopenharmony_cistatic void
11028c2ecf20Sopenharmony_cirpc_task_set_rpc_message(struct rpc_task *task, const struct rpc_message *msg)
11038c2ecf20Sopenharmony_ci{
11048c2ecf20Sopenharmony_ci	if (msg != NULL) {
11058c2ecf20Sopenharmony_ci		task->tk_msg.rpc_proc = msg->rpc_proc;
11068c2ecf20Sopenharmony_ci		task->tk_msg.rpc_argp = msg->rpc_argp;
11078c2ecf20Sopenharmony_ci		task->tk_msg.rpc_resp = msg->rpc_resp;
11088c2ecf20Sopenharmony_ci		task->tk_msg.rpc_cred = msg->rpc_cred;
11098c2ecf20Sopenharmony_ci		if (!(task->tk_flags & RPC_TASK_CRED_NOREF))
11108c2ecf20Sopenharmony_ci			get_cred(task->tk_msg.rpc_cred);
11118c2ecf20Sopenharmony_ci	}
11128c2ecf20Sopenharmony_ci}
11138c2ecf20Sopenharmony_ci
11148c2ecf20Sopenharmony_ci/*
11158c2ecf20Sopenharmony_ci * Default callback for async RPC calls
11168c2ecf20Sopenharmony_ci */
11178c2ecf20Sopenharmony_cistatic void
11188c2ecf20Sopenharmony_cirpc_default_callback(struct rpc_task *task, void *data)
11198c2ecf20Sopenharmony_ci{
11208c2ecf20Sopenharmony_ci}
11218c2ecf20Sopenharmony_ci
11228c2ecf20Sopenharmony_cistatic const struct rpc_call_ops rpc_default_ops = {
11238c2ecf20Sopenharmony_ci	.rpc_call_done = rpc_default_callback,
11248c2ecf20Sopenharmony_ci};
11258c2ecf20Sopenharmony_ci
11268c2ecf20Sopenharmony_ci/**
11278c2ecf20Sopenharmony_ci * rpc_run_task - Allocate a new RPC task, then run rpc_execute against it
11288c2ecf20Sopenharmony_ci * @task_setup_data: pointer to task initialisation data
11298c2ecf20Sopenharmony_ci */
11308c2ecf20Sopenharmony_cistruct rpc_task *rpc_run_task(const struct rpc_task_setup *task_setup_data)
11318c2ecf20Sopenharmony_ci{
11328c2ecf20Sopenharmony_ci	struct rpc_task *task;
11338c2ecf20Sopenharmony_ci
11348c2ecf20Sopenharmony_ci	task = rpc_new_task(task_setup_data);
11358c2ecf20Sopenharmony_ci
11368c2ecf20Sopenharmony_ci	if (!RPC_IS_ASYNC(task))
11378c2ecf20Sopenharmony_ci		task->tk_flags |= RPC_TASK_CRED_NOREF;
11388c2ecf20Sopenharmony_ci
11398c2ecf20Sopenharmony_ci	rpc_task_set_client(task, task_setup_data->rpc_client);
11408c2ecf20Sopenharmony_ci	rpc_task_set_rpc_message(task, task_setup_data->rpc_message);
11418c2ecf20Sopenharmony_ci
11428c2ecf20Sopenharmony_ci	if (task->tk_action == NULL)
11438c2ecf20Sopenharmony_ci		rpc_call_start(task);
11448c2ecf20Sopenharmony_ci
11458c2ecf20Sopenharmony_ci	atomic_inc(&task->tk_count);
11468c2ecf20Sopenharmony_ci	rpc_execute(task);
11478c2ecf20Sopenharmony_ci	return task;
11488c2ecf20Sopenharmony_ci}
11498c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_run_task);
11508c2ecf20Sopenharmony_ci
11518c2ecf20Sopenharmony_ci/**
11528c2ecf20Sopenharmony_ci * rpc_call_sync - Perform a synchronous RPC call
11538c2ecf20Sopenharmony_ci * @clnt: pointer to RPC client
11548c2ecf20Sopenharmony_ci * @msg: RPC call parameters
11558c2ecf20Sopenharmony_ci * @flags: RPC call flags
11568c2ecf20Sopenharmony_ci */
11578c2ecf20Sopenharmony_ciint rpc_call_sync(struct rpc_clnt *clnt, const struct rpc_message *msg, int flags)
11588c2ecf20Sopenharmony_ci{
11598c2ecf20Sopenharmony_ci	struct rpc_task	*task;
11608c2ecf20Sopenharmony_ci	struct rpc_task_setup task_setup_data = {
11618c2ecf20Sopenharmony_ci		.rpc_client = clnt,
11628c2ecf20Sopenharmony_ci		.rpc_message = msg,
11638c2ecf20Sopenharmony_ci		.callback_ops = &rpc_default_ops,
11648c2ecf20Sopenharmony_ci		.flags = flags,
11658c2ecf20Sopenharmony_ci	};
11668c2ecf20Sopenharmony_ci	int status;
11678c2ecf20Sopenharmony_ci
11688c2ecf20Sopenharmony_ci	WARN_ON_ONCE(flags & RPC_TASK_ASYNC);
11698c2ecf20Sopenharmony_ci	if (flags & RPC_TASK_ASYNC) {
11708c2ecf20Sopenharmony_ci		rpc_release_calldata(task_setup_data.callback_ops,
11718c2ecf20Sopenharmony_ci			task_setup_data.callback_data);
11728c2ecf20Sopenharmony_ci		return -EINVAL;
11738c2ecf20Sopenharmony_ci	}
11748c2ecf20Sopenharmony_ci
11758c2ecf20Sopenharmony_ci	task = rpc_run_task(&task_setup_data);
11768c2ecf20Sopenharmony_ci	if (IS_ERR(task))
11778c2ecf20Sopenharmony_ci		return PTR_ERR(task);
11788c2ecf20Sopenharmony_ci	status = task->tk_status;
11798c2ecf20Sopenharmony_ci	rpc_put_task(task);
11808c2ecf20Sopenharmony_ci	return status;
11818c2ecf20Sopenharmony_ci}
11828c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_call_sync);
11838c2ecf20Sopenharmony_ci
11848c2ecf20Sopenharmony_ci/**
11858c2ecf20Sopenharmony_ci * rpc_call_async - Perform an asynchronous RPC call
11868c2ecf20Sopenharmony_ci * @clnt: pointer to RPC client
11878c2ecf20Sopenharmony_ci * @msg: RPC call parameters
11888c2ecf20Sopenharmony_ci * @flags: RPC call flags
11898c2ecf20Sopenharmony_ci * @tk_ops: RPC call ops
11908c2ecf20Sopenharmony_ci * @data: user call data
11918c2ecf20Sopenharmony_ci */
11928c2ecf20Sopenharmony_ciint
11938c2ecf20Sopenharmony_cirpc_call_async(struct rpc_clnt *clnt, const struct rpc_message *msg, int flags,
11948c2ecf20Sopenharmony_ci	       const struct rpc_call_ops *tk_ops, void *data)
11958c2ecf20Sopenharmony_ci{
11968c2ecf20Sopenharmony_ci	struct rpc_task	*task;
11978c2ecf20Sopenharmony_ci	struct rpc_task_setup task_setup_data = {
11988c2ecf20Sopenharmony_ci		.rpc_client = clnt,
11998c2ecf20Sopenharmony_ci		.rpc_message = msg,
12008c2ecf20Sopenharmony_ci		.callback_ops = tk_ops,
12018c2ecf20Sopenharmony_ci		.callback_data = data,
12028c2ecf20Sopenharmony_ci		.flags = flags|RPC_TASK_ASYNC,
12038c2ecf20Sopenharmony_ci	};
12048c2ecf20Sopenharmony_ci
12058c2ecf20Sopenharmony_ci	task = rpc_run_task(&task_setup_data);
12068c2ecf20Sopenharmony_ci	if (IS_ERR(task))
12078c2ecf20Sopenharmony_ci		return PTR_ERR(task);
12088c2ecf20Sopenharmony_ci	rpc_put_task(task);
12098c2ecf20Sopenharmony_ci	return 0;
12108c2ecf20Sopenharmony_ci}
12118c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_call_async);
12128c2ecf20Sopenharmony_ci
12138c2ecf20Sopenharmony_ci#if defined(CONFIG_SUNRPC_BACKCHANNEL)
12148c2ecf20Sopenharmony_cistatic void call_bc_encode(struct rpc_task *task);
12158c2ecf20Sopenharmony_ci
12168c2ecf20Sopenharmony_ci/**
12178c2ecf20Sopenharmony_ci * rpc_run_bc_task - Allocate a new RPC task for backchannel use, then run
12188c2ecf20Sopenharmony_ci * rpc_execute against it
12198c2ecf20Sopenharmony_ci * @req: RPC request
12208c2ecf20Sopenharmony_ci */
12218c2ecf20Sopenharmony_cistruct rpc_task *rpc_run_bc_task(struct rpc_rqst *req)
12228c2ecf20Sopenharmony_ci{
12238c2ecf20Sopenharmony_ci	struct rpc_task *task;
12248c2ecf20Sopenharmony_ci	struct rpc_task_setup task_setup_data = {
12258c2ecf20Sopenharmony_ci		.callback_ops = &rpc_default_ops,
12268c2ecf20Sopenharmony_ci		.flags = RPC_TASK_SOFTCONN |
12278c2ecf20Sopenharmony_ci			RPC_TASK_NO_RETRANS_TIMEOUT,
12288c2ecf20Sopenharmony_ci	};
12298c2ecf20Sopenharmony_ci
12308c2ecf20Sopenharmony_ci	dprintk("RPC: rpc_run_bc_task req= %p\n", req);
12318c2ecf20Sopenharmony_ci	/*
12328c2ecf20Sopenharmony_ci	 * Create an rpc_task to send the data
12338c2ecf20Sopenharmony_ci	 */
12348c2ecf20Sopenharmony_ci	task = rpc_new_task(&task_setup_data);
12358c2ecf20Sopenharmony_ci	xprt_init_bc_request(req, task);
12368c2ecf20Sopenharmony_ci
12378c2ecf20Sopenharmony_ci	task->tk_action = call_bc_encode;
12388c2ecf20Sopenharmony_ci	atomic_inc(&task->tk_count);
12398c2ecf20Sopenharmony_ci	WARN_ON_ONCE(atomic_read(&task->tk_count) != 2);
12408c2ecf20Sopenharmony_ci	rpc_execute(task);
12418c2ecf20Sopenharmony_ci
12428c2ecf20Sopenharmony_ci	dprintk("RPC: rpc_run_bc_task: task= %p\n", task);
12438c2ecf20Sopenharmony_ci	return task;
12448c2ecf20Sopenharmony_ci}
12458c2ecf20Sopenharmony_ci#endif /* CONFIG_SUNRPC_BACKCHANNEL */
12468c2ecf20Sopenharmony_ci
12478c2ecf20Sopenharmony_ci/**
12488c2ecf20Sopenharmony_ci * rpc_prepare_reply_pages - Prepare to receive a reply data payload into pages
12498c2ecf20Sopenharmony_ci * @req: RPC request to prepare
12508c2ecf20Sopenharmony_ci * @pages: vector of struct page pointers
12518c2ecf20Sopenharmony_ci * @base: offset in first page where receive should start, in bytes
12528c2ecf20Sopenharmony_ci * @len: expected size of the upper layer data payload, in bytes
12538c2ecf20Sopenharmony_ci * @hdrsize: expected size of upper layer reply header, in XDR words
12548c2ecf20Sopenharmony_ci *
12558c2ecf20Sopenharmony_ci */
12568c2ecf20Sopenharmony_civoid rpc_prepare_reply_pages(struct rpc_rqst *req, struct page **pages,
12578c2ecf20Sopenharmony_ci			     unsigned int base, unsigned int len,
12588c2ecf20Sopenharmony_ci			     unsigned int hdrsize)
12598c2ecf20Sopenharmony_ci{
12608c2ecf20Sopenharmony_ci	/* Subtract one to force an extra word of buffer space for the
12618c2ecf20Sopenharmony_ci	 * payload's XDR pad to fall into the rcv_buf's tail iovec.
12628c2ecf20Sopenharmony_ci	 */
12638c2ecf20Sopenharmony_ci	hdrsize += RPC_REPHDRSIZE + req->rq_cred->cr_auth->au_ralign - 1;
12648c2ecf20Sopenharmony_ci
12658c2ecf20Sopenharmony_ci	xdr_inline_pages(&req->rq_rcv_buf, hdrsize << 2, pages, base, len);
12668c2ecf20Sopenharmony_ci	trace_rpc_xdr_reply_pages(req->rq_task, &req->rq_rcv_buf);
12678c2ecf20Sopenharmony_ci}
12688c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_prepare_reply_pages);
12698c2ecf20Sopenharmony_ci
12708c2ecf20Sopenharmony_civoid
12718c2ecf20Sopenharmony_cirpc_call_start(struct rpc_task *task)
12728c2ecf20Sopenharmony_ci{
12738c2ecf20Sopenharmony_ci	task->tk_action = call_start;
12748c2ecf20Sopenharmony_ci}
12758c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_call_start);
12768c2ecf20Sopenharmony_ci
12778c2ecf20Sopenharmony_ci/**
12788c2ecf20Sopenharmony_ci * rpc_peeraddr - extract remote peer address from clnt's xprt
12798c2ecf20Sopenharmony_ci * @clnt: RPC client structure
12808c2ecf20Sopenharmony_ci * @buf: target buffer
12818c2ecf20Sopenharmony_ci * @bufsize: length of target buffer
12828c2ecf20Sopenharmony_ci *
12838c2ecf20Sopenharmony_ci * Returns the number of bytes that are actually in the stored address.
12848c2ecf20Sopenharmony_ci */
12858c2ecf20Sopenharmony_cisize_t rpc_peeraddr(struct rpc_clnt *clnt, struct sockaddr *buf, size_t bufsize)
12868c2ecf20Sopenharmony_ci{
12878c2ecf20Sopenharmony_ci	size_t bytes;
12888c2ecf20Sopenharmony_ci	struct rpc_xprt *xprt;
12898c2ecf20Sopenharmony_ci
12908c2ecf20Sopenharmony_ci	rcu_read_lock();
12918c2ecf20Sopenharmony_ci	xprt = rcu_dereference(clnt->cl_xprt);
12928c2ecf20Sopenharmony_ci
12938c2ecf20Sopenharmony_ci	bytes = xprt->addrlen;
12948c2ecf20Sopenharmony_ci	if (bytes > bufsize)
12958c2ecf20Sopenharmony_ci		bytes = bufsize;
12968c2ecf20Sopenharmony_ci	memcpy(buf, &xprt->addr, bytes);
12978c2ecf20Sopenharmony_ci	rcu_read_unlock();
12988c2ecf20Sopenharmony_ci
12998c2ecf20Sopenharmony_ci	return bytes;
13008c2ecf20Sopenharmony_ci}
13018c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_peeraddr);
13028c2ecf20Sopenharmony_ci
13038c2ecf20Sopenharmony_ci/**
13048c2ecf20Sopenharmony_ci * rpc_peeraddr2str - return remote peer address in printable format
13058c2ecf20Sopenharmony_ci * @clnt: RPC client structure
13068c2ecf20Sopenharmony_ci * @format: address format
13078c2ecf20Sopenharmony_ci *
13088c2ecf20Sopenharmony_ci * NB: the lifetime of the memory referenced by the returned pointer is
13098c2ecf20Sopenharmony_ci * the same as the rpc_xprt itself.  As long as the caller uses this
13108c2ecf20Sopenharmony_ci * pointer, it must hold the RCU read lock.
13118c2ecf20Sopenharmony_ci */
13128c2ecf20Sopenharmony_ciconst char *rpc_peeraddr2str(struct rpc_clnt *clnt,
13138c2ecf20Sopenharmony_ci			     enum rpc_display_format_t format)
13148c2ecf20Sopenharmony_ci{
13158c2ecf20Sopenharmony_ci	struct rpc_xprt *xprt;
13168c2ecf20Sopenharmony_ci
13178c2ecf20Sopenharmony_ci	xprt = rcu_dereference(clnt->cl_xprt);
13188c2ecf20Sopenharmony_ci
13198c2ecf20Sopenharmony_ci	if (xprt->address_strings[format] != NULL)
13208c2ecf20Sopenharmony_ci		return xprt->address_strings[format];
13218c2ecf20Sopenharmony_ci	else
13228c2ecf20Sopenharmony_ci		return "unprintable";
13238c2ecf20Sopenharmony_ci}
13248c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_peeraddr2str);
13258c2ecf20Sopenharmony_ci
13268c2ecf20Sopenharmony_cistatic const struct sockaddr_in rpc_inaddr_loopback = {
13278c2ecf20Sopenharmony_ci	.sin_family		= AF_INET,
13288c2ecf20Sopenharmony_ci	.sin_addr.s_addr	= htonl(INADDR_ANY),
13298c2ecf20Sopenharmony_ci};
13308c2ecf20Sopenharmony_ci
13318c2ecf20Sopenharmony_cistatic const struct sockaddr_in6 rpc_in6addr_loopback = {
13328c2ecf20Sopenharmony_ci	.sin6_family		= AF_INET6,
13338c2ecf20Sopenharmony_ci	.sin6_addr		= IN6ADDR_ANY_INIT,
13348c2ecf20Sopenharmony_ci};
13358c2ecf20Sopenharmony_ci
13368c2ecf20Sopenharmony_ci/*
13378c2ecf20Sopenharmony_ci * Try a getsockname() on a connected datagram socket.  Using a
13388c2ecf20Sopenharmony_ci * connected datagram socket prevents leaving a socket in TIME_WAIT.
13398c2ecf20Sopenharmony_ci * This conserves the ephemeral port number space.
13408c2ecf20Sopenharmony_ci *
13418c2ecf20Sopenharmony_ci * Returns zero and fills in "buf" if successful; otherwise, a
13428c2ecf20Sopenharmony_ci * negative errno is returned.
13438c2ecf20Sopenharmony_ci */
13448c2ecf20Sopenharmony_cistatic int rpc_sockname(struct net *net, struct sockaddr *sap, size_t salen,
13458c2ecf20Sopenharmony_ci			struct sockaddr *buf)
13468c2ecf20Sopenharmony_ci{
13478c2ecf20Sopenharmony_ci	struct socket *sock;
13488c2ecf20Sopenharmony_ci	int err;
13498c2ecf20Sopenharmony_ci
13508c2ecf20Sopenharmony_ci	err = __sock_create(net, sap->sa_family,
13518c2ecf20Sopenharmony_ci				SOCK_DGRAM, IPPROTO_UDP, &sock, 1);
13528c2ecf20Sopenharmony_ci	if (err < 0) {
13538c2ecf20Sopenharmony_ci		dprintk("RPC:       can't create UDP socket (%d)\n", err);
13548c2ecf20Sopenharmony_ci		goto out;
13558c2ecf20Sopenharmony_ci	}
13568c2ecf20Sopenharmony_ci
13578c2ecf20Sopenharmony_ci	switch (sap->sa_family) {
13588c2ecf20Sopenharmony_ci	case AF_INET:
13598c2ecf20Sopenharmony_ci		err = kernel_bind(sock,
13608c2ecf20Sopenharmony_ci				(struct sockaddr *)&rpc_inaddr_loopback,
13618c2ecf20Sopenharmony_ci				sizeof(rpc_inaddr_loopback));
13628c2ecf20Sopenharmony_ci		break;
13638c2ecf20Sopenharmony_ci	case AF_INET6:
13648c2ecf20Sopenharmony_ci		err = kernel_bind(sock,
13658c2ecf20Sopenharmony_ci				(struct sockaddr *)&rpc_in6addr_loopback,
13668c2ecf20Sopenharmony_ci				sizeof(rpc_in6addr_loopback));
13678c2ecf20Sopenharmony_ci		break;
13688c2ecf20Sopenharmony_ci	default:
13698c2ecf20Sopenharmony_ci		err = -EAFNOSUPPORT;
13708c2ecf20Sopenharmony_ci		goto out_release;
13718c2ecf20Sopenharmony_ci	}
13728c2ecf20Sopenharmony_ci	if (err < 0) {
13738c2ecf20Sopenharmony_ci		dprintk("RPC:       can't bind UDP socket (%d)\n", err);
13748c2ecf20Sopenharmony_ci		goto out_release;
13758c2ecf20Sopenharmony_ci	}
13768c2ecf20Sopenharmony_ci
13778c2ecf20Sopenharmony_ci	err = kernel_connect(sock, sap, salen, 0);
13788c2ecf20Sopenharmony_ci	if (err < 0) {
13798c2ecf20Sopenharmony_ci		dprintk("RPC:       can't connect UDP socket (%d)\n", err);
13808c2ecf20Sopenharmony_ci		goto out_release;
13818c2ecf20Sopenharmony_ci	}
13828c2ecf20Sopenharmony_ci
13838c2ecf20Sopenharmony_ci	err = kernel_getsockname(sock, buf);
13848c2ecf20Sopenharmony_ci	if (err < 0) {
13858c2ecf20Sopenharmony_ci		dprintk("RPC:       getsockname failed (%d)\n", err);
13868c2ecf20Sopenharmony_ci		goto out_release;
13878c2ecf20Sopenharmony_ci	}
13888c2ecf20Sopenharmony_ci
13898c2ecf20Sopenharmony_ci	err = 0;
13908c2ecf20Sopenharmony_ci	if (buf->sa_family == AF_INET6) {
13918c2ecf20Sopenharmony_ci		struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)buf;
13928c2ecf20Sopenharmony_ci		sin6->sin6_scope_id = 0;
13938c2ecf20Sopenharmony_ci	}
13948c2ecf20Sopenharmony_ci	dprintk("RPC:       %s succeeded\n", __func__);
13958c2ecf20Sopenharmony_ci
13968c2ecf20Sopenharmony_ciout_release:
13978c2ecf20Sopenharmony_ci	sock_release(sock);
13988c2ecf20Sopenharmony_ciout:
13998c2ecf20Sopenharmony_ci	return err;
14008c2ecf20Sopenharmony_ci}
14018c2ecf20Sopenharmony_ci
14028c2ecf20Sopenharmony_ci/*
14038c2ecf20Sopenharmony_ci * Scraping a connected socket failed, so we don't have a useable
14048c2ecf20Sopenharmony_ci * local address.  Fallback: generate an address that will prevent
14058c2ecf20Sopenharmony_ci * the server from calling us back.
14068c2ecf20Sopenharmony_ci *
14078c2ecf20Sopenharmony_ci * Returns zero and fills in "buf" if successful; otherwise, a
14088c2ecf20Sopenharmony_ci * negative errno is returned.
14098c2ecf20Sopenharmony_ci */
14108c2ecf20Sopenharmony_cistatic int rpc_anyaddr(int family, struct sockaddr *buf, size_t buflen)
14118c2ecf20Sopenharmony_ci{
14128c2ecf20Sopenharmony_ci	switch (family) {
14138c2ecf20Sopenharmony_ci	case AF_INET:
14148c2ecf20Sopenharmony_ci		if (buflen < sizeof(rpc_inaddr_loopback))
14158c2ecf20Sopenharmony_ci			return -EINVAL;
14168c2ecf20Sopenharmony_ci		memcpy(buf, &rpc_inaddr_loopback,
14178c2ecf20Sopenharmony_ci				sizeof(rpc_inaddr_loopback));
14188c2ecf20Sopenharmony_ci		break;
14198c2ecf20Sopenharmony_ci	case AF_INET6:
14208c2ecf20Sopenharmony_ci		if (buflen < sizeof(rpc_in6addr_loopback))
14218c2ecf20Sopenharmony_ci			return -EINVAL;
14228c2ecf20Sopenharmony_ci		memcpy(buf, &rpc_in6addr_loopback,
14238c2ecf20Sopenharmony_ci				sizeof(rpc_in6addr_loopback));
14248c2ecf20Sopenharmony_ci		break;
14258c2ecf20Sopenharmony_ci	default:
14268c2ecf20Sopenharmony_ci		dprintk("RPC:       %s: address family not supported\n",
14278c2ecf20Sopenharmony_ci			__func__);
14288c2ecf20Sopenharmony_ci		return -EAFNOSUPPORT;
14298c2ecf20Sopenharmony_ci	}
14308c2ecf20Sopenharmony_ci	dprintk("RPC:       %s: succeeded\n", __func__);
14318c2ecf20Sopenharmony_ci	return 0;
14328c2ecf20Sopenharmony_ci}
14338c2ecf20Sopenharmony_ci
14348c2ecf20Sopenharmony_ci/**
14358c2ecf20Sopenharmony_ci * rpc_localaddr - discover local endpoint address for an RPC client
14368c2ecf20Sopenharmony_ci * @clnt: RPC client structure
14378c2ecf20Sopenharmony_ci * @buf: target buffer
14388c2ecf20Sopenharmony_ci * @buflen: size of target buffer, in bytes
14398c2ecf20Sopenharmony_ci *
14408c2ecf20Sopenharmony_ci * Returns zero and fills in "buf" and "buflen" if successful;
14418c2ecf20Sopenharmony_ci * otherwise, a negative errno is returned.
14428c2ecf20Sopenharmony_ci *
14438c2ecf20Sopenharmony_ci * This works even if the underlying transport is not currently connected,
14448c2ecf20Sopenharmony_ci * or if the upper layer never previously provided a source address.
14458c2ecf20Sopenharmony_ci *
14468c2ecf20Sopenharmony_ci * The result of this function call is transient: multiple calls in
14478c2ecf20Sopenharmony_ci * succession may give different results, depending on how local
14488c2ecf20Sopenharmony_ci * networking configuration changes over time.
14498c2ecf20Sopenharmony_ci */
14508c2ecf20Sopenharmony_ciint rpc_localaddr(struct rpc_clnt *clnt, struct sockaddr *buf, size_t buflen)
14518c2ecf20Sopenharmony_ci{
14528c2ecf20Sopenharmony_ci	struct sockaddr_storage address;
14538c2ecf20Sopenharmony_ci	struct sockaddr *sap = (struct sockaddr *)&address;
14548c2ecf20Sopenharmony_ci	struct rpc_xprt *xprt;
14558c2ecf20Sopenharmony_ci	struct net *net;
14568c2ecf20Sopenharmony_ci	size_t salen;
14578c2ecf20Sopenharmony_ci	int err;
14588c2ecf20Sopenharmony_ci
14598c2ecf20Sopenharmony_ci	rcu_read_lock();
14608c2ecf20Sopenharmony_ci	xprt = rcu_dereference(clnt->cl_xprt);
14618c2ecf20Sopenharmony_ci	salen = xprt->addrlen;
14628c2ecf20Sopenharmony_ci	memcpy(sap, &xprt->addr, salen);
14638c2ecf20Sopenharmony_ci	net = get_net(xprt->xprt_net);
14648c2ecf20Sopenharmony_ci	rcu_read_unlock();
14658c2ecf20Sopenharmony_ci
14668c2ecf20Sopenharmony_ci	rpc_set_port(sap, 0);
14678c2ecf20Sopenharmony_ci	err = rpc_sockname(net, sap, salen, buf);
14688c2ecf20Sopenharmony_ci	put_net(net);
14698c2ecf20Sopenharmony_ci	if (err != 0)
14708c2ecf20Sopenharmony_ci		/* Couldn't discover local address, return ANYADDR */
14718c2ecf20Sopenharmony_ci		return rpc_anyaddr(sap->sa_family, buf, buflen);
14728c2ecf20Sopenharmony_ci	return 0;
14738c2ecf20Sopenharmony_ci}
14748c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_localaddr);
14758c2ecf20Sopenharmony_ci
14768c2ecf20Sopenharmony_civoid
14778c2ecf20Sopenharmony_cirpc_setbufsize(struct rpc_clnt *clnt, unsigned int sndsize, unsigned int rcvsize)
14788c2ecf20Sopenharmony_ci{
14798c2ecf20Sopenharmony_ci	struct rpc_xprt *xprt;
14808c2ecf20Sopenharmony_ci
14818c2ecf20Sopenharmony_ci	rcu_read_lock();
14828c2ecf20Sopenharmony_ci	xprt = rcu_dereference(clnt->cl_xprt);
14838c2ecf20Sopenharmony_ci	if (xprt->ops->set_buffer_size)
14848c2ecf20Sopenharmony_ci		xprt->ops->set_buffer_size(xprt, sndsize, rcvsize);
14858c2ecf20Sopenharmony_ci	rcu_read_unlock();
14868c2ecf20Sopenharmony_ci}
14878c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_setbufsize);
14888c2ecf20Sopenharmony_ci
14898c2ecf20Sopenharmony_ci/**
14908c2ecf20Sopenharmony_ci * rpc_net_ns - Get the network namespace for this RPC client
14918c2ecf20Sopenharmony_ci * @clnt: RPC client to query
14928c2ecf20Sopenharmony_ci *
14938c2ecf20Sopenharmony_ci */
14948c2ecf20Sopenharmony_cistruct net *rpc_net_ns(struct rpc_clnt *clnt)
14958c2ecf20Sopenharmony_ci{
14968c2ecf20Sopenharmony_ci	struct net *ret;
14978c2ecf20Sopenharmony_ci
14988c2ecf20Sopenharmony_ci	rcu_read_lock();
14998c2ecf20Sopenharmony_ci	ret = rcu_dereference(clnt->cl_xprt)->xprt_net;
15008c2ecf20Sopenharmony_ci	rcu_read_unlock();
15018c2ecf20Sopenharmony_ci	return ret;
15028c2ecf20Sopenharmony_ci}
15038c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_net_ns);
15048c2ecf20Sopenharmony_ci
15058c2ecf20Sopenharmony_ci/**
15068c2ecf20Sopenharmony_ci * rpc_max_payload - Get maximum payload size for a transport, in bytes
15078c2ecf20Sopenharmony_ci * @clnt: RPC client to query
15088c2ecf20Sopenharmony_ci *
15098c2ecf20Sopenharmony_ci * For stream transports, this is one RPC record fragment (see RFC
15108c2ecf20Sopenharmony_ci * 1831), as we don't support multi-record requests yet.  For datagram
15118c2ecf20Sopenharmony_ci * transports, this is the size of an IP packet minus the IP, UDP, and
15128c2ecf20Sopenharmony_ci * RPC header sizes.
15138c2ecf20Sopenharmony_ci */
15148c2ecf20Sopenharmony_cisize_t rpc_max_payload(struct rpc_clnt *clnt)
15158c2ecf20Sopenharmony_ci{
15168c2ecf20Sopenharmony_ci	size_t ret;
15178c2ecf20Sopenharmony_ci
15188c2ecf20Sopenharmony_ci	rcu_read_lock();
15198c2ecf20Sopenharmony_ci	ret = rcu_dereference(clnt->cl_xprt)->max_payload;
15208c2ecf20Sopenharmony_ci	rcu_read_unlock();
15218c2ecf20Sopenharmony_ci	return ret;
15228c2ecf20Sopenharmony_ci}
15238c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_max_payload);
15248c2ecf20Sopenharmony_ci
15258c2ecf20Sopenharmony_ci/**
15268c2ecf20Sopenharmony_ci * rpc_max_bc_payload - Get maximum backchannel payload size, in bytes
15278c2ecf20Sopenharmony_ci * @clnt: RPC client to query
15288c2ecf20Sopenharmony_ci */
15298c2ecf20Sopenharmony_cisize_t rpc_max_bc_payload(struct rpc_clnt *clnt)
15308c2ecf20Sopenharmony_ci{
15318c2ecf20Sopenharmony_ci	struct rpc_xprt *xprt;
15328c2ecf20Sopenharmony_ci	size_t ret;
15338c2ecf20Sopenharmony_ci
15348c2ecf20Sopenharmony_ci	rcu_read_lock();
15358c2ecf20Sopenharmony_ci	xprt = rcu_dereference(clnt->cl_xprt);
15368c2ecf20Sopenharmony_ci	ret = xprt->ops->bc_maxpayload(xprt);
15378c2ecf20Sopenharmony_ci	rcu_read_unlock();
15388c2ecf20Sopenharmony_ci	return ret;
15398c2ecf20Sopenharmony_ci}
15408c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_max_bc_payload);
15418c2ecf20Sopenharmony_ci
15428c2ecf20Sopenharmony_ciunsigned int rpc_num_bc_slots(struct rpc_clnt *clnt)
15438c2ecf20Sopenharmony_ci{
15448c2ecf20Sopenharmony_ci	struct rpc_xprt *xprt;
15458c2ecf20Sopenharmony_ci	unsigned int ret;
15468c2ecf20Sopenharmony_ci
15478c2ecf20Sopenharmony_ci	rcu_read_lock();
15488c2ecf20Sopenharmony_ci	xprt = rcu_dereference(clnt->cl_xprt);
15498c2ecf20Sopenharmony_ci	ret = xprt->ops->bc_num_slots(xprt);
15508c2ecf20Sopenharmony_ci	rcu_read_unlock();
15518c2ecf20Sopenharmony_ci	return ret;
15528c2ecf20Sopenharmony_ci}
15538c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_num_bc_slots);
15548c2ecf20Sopenharmony_ci
15558c2ecf20Sopenharmony_ci/**
15568c2ecf20Sopenharmony_ci * rpc_force_rebind - force transport to check that remote port is unchanged
15578c2ecf20Sopenharmony_ci * @clnt: client to rebind
15588c2ecf20Sopenharmony_ci *
15598c2ecf20Sopenharmony_ci */
15608c2ecf20Sopenharmony_civoid rpc_force_rebind(struct rpc_clnt *clnt)
15618c2ecf20Sopenharmony_ci{
15628c2ecf20Sopenharmony_ci	if (clnt->cl_autobind) {
15638c2ecf20Sopenharmony_ci		rcu_read_lock();
15648c2ecf20Sopenharmony_ci		xprt_clear_bound(rcu_dereference(clnt->cl_xprt));
15658c2ecf20Sopenharmony_ci		rcu_read_unlock();
15668c2ecf20Sopenharmony_ci	}
15678c2ecf20Sopenharmony_ci}
15688c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_force_rebind);
15698c2ecf20Sopenharmony_ci
15708c2ecf20Sopenharmony_cistatic int
15718c2ecf20Sopenharmony_ci__rpc_restart_call(struct rpc_task *task, void (*action)(struct rpc_task *))
15728c2ecf20Sopenharmony_ci{
15738c2ecf20Sopenharmony_ci	task->tk_status = 0;
15748c2ecf20Sopenharmony_ci	task->tk_rpc_status = 0;
15758c2ecf20Sopenharmony_ci	task->tk_action = action;
15768c2ecf20Sopenharmony_ci	return 1;
15778c2ecf20Sopenharmony_ci}
15788c2ecf20Sopenharmony_ci
15798c2ecf20Sopenharmony_ci/*
15808c2ecf20Sopenharmony_ci * Restart an (async) RPC call. Usually called from within the
15818c2ecf20Sopenharmony_ci * exit handler.
15828c2ecf20Sopenharmony_ci */
15838c2ecf20Sopenharmony_ciint
15848c2ecf20Sopenharmony_cirpc_restart_call(struct rpc_task *task)
15858c2ecf20Sopenharmony_ci{
15868c2ecf20Sopenharmony_ci	return __rpc_restart_call(task, call_start);
15878c2ecf20Sopenharmony_ci}
15888c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_restart_call);
15898c2ecf20Sopenharmony_ci
15908c2ecf20Sopenharmony_ci/*
15918c2ecf20Sopenharmony_ci * Restart an (async) RPC call from the call_prepare state.
15928c2ecf20Sopenharmony_ci * Usually called from within the exit handler.
15938c2ecf20Sopenharmony_ci */
15948c2ecf20Sopenharmony_ciint
15958c2ecf20Sopenharmony_cirpc_restart_call_prepare(struct rpc_task *task)
15968c2ecf20Sopenharmony_ci{
15978c2ecf20Sopenharmony_ci	if (task->tk_ops->rpc_call_prepare != NULL)
15988c2ecf20Sopenharmony_ci		return __rpc_restart_call(task, rpc_prepare_task);
15998c2ecf20Sopenharmony_ci	return rpc_restart_call(task);
16008c2ecf20Sopenharmony_ci}
16018c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_restart_call_prepare);
16028c2ecf20Sopenharmony_ci
16038c2ecf20Sopenharmony_ciconst char
16048c2ecf20Sopenharmony_ci*rpc_proc_name(const struct rpc_task *task)
16058c2ecf20Sopenharmony_ci{
16068c2ecf20Sopenharmony_ci	const struct rpc_procinfo *proc = task->tk_msg.rpc_proc;
16078c2ecf20Sopenharmony_ci
16088c2ecf20Sopenharmony_ci	if (proc) {
16098c2ecf20Sopenharmony_ci		if (proc->p_name)
16108c2ecf20Sopenharmony_ci			return proc->p_name;
16118c2ecf20Sopenharmony_ci		else
16128c2ecf20Sopenharmony_ci			return "NULL";
16138c2ecf20Sopenharmony_ci	} else
16148c2ecf20Sopenharmony_ci		return "no proc";
16158c2ecf20Sopenharmony_ci}
16168c2ecf20Sopenharmony_ci
16178c2ecf20Sopenharmony_cistatic void
16188c2ecf20Sopenharmony_ci__rpc_call_rpcerror(struct rpc_task *task, int tk_status, int rpc_status)
16198c2ecf20Sopenharmony_ci{
16208c2ecf20Sopenharmony_ci	trace_rpc_call_rpcerror(task, tk_status, rpc_status);
16218c2ecf20Sopenharmony_ci	task->tk_rpc_status = rpc_status;
16228c2ecf20Sopenharmony_ci	rpc_exit(task, tk_status);
16238c2ecf20Sopenharmony_ci}
16248c2ecf20Sopenharmony_ci
16258c2ecf20Sopenharmony_cistatic void
16268c2ecf20Sopenharmony_cirpc_call_rpcerror(struct rpc_task *task, int status)
16278c2ecf20Sopenharmony_ci{
16288c2ecf20Sopenharmony_ci	__rpc_call_rpcerror(task, status, status);
16298c2ecf20Sopenharmony_ci}
16308c2ecf20Sopenharmony_ci
16318c2ecf20Sopenharmony_ci/*
16328c2ecf20Sopenharmony_ci * 0.  Initial state
16338c2ecf20Sopenharmony_ci *
16348c2ecf20Sopenharmony_ci *     Other FSM states can be visited zero or more times, but
16358c2ecf20Sopenharmony_ci *     this state is visited exactly once for each RPC.
16368c2ecf20Sopenharmony_ci */
16378c2ecf20Sopenharmony_cistatic void
16388c2ecf20Sopenharmony_cicall_start(struct rpc_task *task)
16398c2ecf20Sopenharmony_ci{
16408c2ecf20Sopenharmony_ci	struct rpc_clnt	*clnt = task->tk_client;
16418c2ecf20Sopenharmony_ci	int idx = task->tk_msg.rpc_proc->p_statidx;
16428c2ecf20Sopenharmony_ci
16438c2ecf20Sopenharmony_ci	trace_rpc_request(task);
16448c2ecf20Sopenharmony_ci
16458c2ecf20Sopenharmony_ci	/* Increment call count (version might not be valid for ping) */
16468c2ecf20Sopenharmony_ci	if (clnt->cl_program->version[clnt->cl_vers])
16478c2ecf20Sopenharmony_ci		clnt->cl_program->version[clnt->cl_vers]->counts[idx]++;
16488c2ecf20Sopenharmony_ci	clnt->cl_stats->rpccnt++;
16498c2ecf20Sopenharmony_ci	task->tk_action = call_reserve;
16508c2ecf20Sopenharmony_ci	rpc_task_set_transport(task, clnt);
16518c2ecf20Sopenharmony_ci}
16528c2ecf20Sopenharmony_ci
16538c2ecf20Sopenharmony_ci/*
16548c2ecf20Sopenharmony_ci * 1.	Reserve an RPC call slot
16558c2ecf20Sopenharmony_ci */
16568c2ecf20Sopenharmony_cistatic void
16578c2ecf20Sopenharmony_cicall_reserve(struct rpc_task *task)
16588c2ecf20Sopenharmony_ci{
16598c2ecf20Sopenharmony_ci	task->tk_status  = 0;
16608c2ecf20Sopenharmony_ci	task->tk_action  = call_reserveresult;
16618c2ecf20Sopenharmony_ci	xprt_reserve(task);
16628c2ecf20Sopenharmony_ci}
16638c2ecf20Sopenharmony_ci
16648c2ecf20Sopenharmony_cistatic void call_retry_reserve(struct rpc_task *task);
16658c2ecf20Sopenharmony_ci
16668c2ecf20Sopenharmony_ci/*
16678c2ecf20Sopenharmony_ci * 1b.	Grok the result of xprt_reserve()
16688c2ecf20Sopenharmony_ci */
16698c2ecf20Sopenharmony_cistatic void
16708c2ecf20Sopenharmony_cicall_reserveresult(struct rpc_task *task)
16718c2ecf20Sopenharmony_ci{
16728c2ecf20Sopenharmony_ci	int status = task->tk_status;
16738c2ecf20Sopenharmony_ci
16748c2ecf20Sopenharmony_ci	/*
16758c2ecf20Sopenharmony_ci	 * After a call to xprt_reserve(), we must have either
16768c2ecf20Sopenharmony_ci	 * a request slot or else an error status.
16778c2ecf20Sopenharmony_ci	 */
16788c2ecf20Sopenharmony_ci	task->tk_status = 0;
16798c2ecf20Sopenharmony_ci	if (status >= 0) {
16808c2ecf20Sopenharmony_ci		if (task->tk_rqstp) {
16818c2ecf20Sopenharmony_ci			task->tk_action = call_refresh;
16828c2ecf20Sopenharmony_ci			return;
16838c2ecf20Sopenharmony_ci		}
16848c2ecf20Sopenharmony_ci
16858c2ecf20Sopenharmony_ci		rpc_call_rpcerror(task, -EIO);
16868c2ecf20Sopenharmony_ci		return;
16878c2ecf20Sopenharmony_ci	}
16888c2ecf20Sopenharmony_ci
16898c2ecf20Sopenharmony_ci	switch (status) {
16908c2ecf20Sopenharmony_ci	case -ENOMEM:
16918c2ecf20Sopenharmony_ci		rpc_delay(task, HZ >> 2);
16928c2ecf20Sopenharmony_ci		fallthrough;
16938c2ecf20Sopenharmony_ci	case -EAGAIN:	/* woken up; retry */
16948c2ecf20Sopenharmony_ci		task->tk_action = call_retry_reserve;
16958c2ecf20Sopenharmony_ci		return;
16968c2ecf20Sopenharmony_ci	default:
16978c2ecf20Sopenharmony_ci		rpc_call_rpcerror(task, status);
16988c2ecf20Sopenharmony_ci	}
16998c2ecf20Sopenharmony_ci}
17008c2ecf20Sopenharmony_ci
17018c2ecf20Sopenharmony_ci/*
17028c2ecf20Sopenharmony_ci * 1c.	Retry reserving an RPC call slot
17038c2ecf20Sopenharmony_ci */
17048c2ecf20Sopenharmony_cistatic void
17058c2ecf20Sopenharmony_cicall_retry_reserve(struct rpc_task *task)
17068c2ecf20Sopenharmony_ci{
17078c2ecf20Sopenharmony_ci	task->tk_status  = 0;
17088c2ecf20Sopenharmony_ci	task->tk_action  = call_reserveresult;
17098c2ecf20Sopenharmony_ci	xprt_retry_reserve(task);
17108c2ecf20Sopenharmony_ci}
17118c2ecf20Sopenharmony_ci
17128c2ecf20Sopenharmony_ci/*
17138c2ecf20Sopenharmony_ci * 2.	Bind and/or refresh the credentials
17148c2ecf20Sopenharmony_ci */
17158c2ecf20Sopenharmony_cistatic void
17168c2ecf20Sopenharmony_cicall_refresh(struct rpc_task *task)
17178c2ecf20Sopenharmony_ci{
17188c2ecf20Sopenharmony_ci	task->tk_action = call_refreshresult;
17198c2ecf20Sopenharmony_ci	task->tk_status = 0;
17208c2ecf20Sopenharmony_ci	task->tk_client->cl_stats->rpcauthrefresh++;
17218c2ecf20Sopenharmony_ci	rpcauth_refreshcred(task);
17228c2ecf20Sopenharmony_ci}
17238c2ecf20Sopenharmony_ci
17248c2ecf20Sopenharmony_ci/*
17258c2ecf20Sopenharmony_ci * 2a.	Process the results of a credential refresh
17268c2ecf20Sopenharmony_ci */
17278c2ecf20Sopenharmony_cistatic void
17288c2ecf20Sopenharmony_cicall_refreshresult(struct rpc_task *task)
17298c2ecf20Sopenharmony_ci{
17308c2ecf20Sopenharmony_ci	int status = task->tk_status;
17318c2ecf20Sopenharmony_ci
17328c2ecf20Sopenharmony_ci	task->tk_status = 0;
17338c2ecf20Sopenharmony_ci	task->tk_action = call_refresh;
17348c2ecf20Sopenharmony_ci	switch (status) {
17358c2ecf20Sopenharmony_ci	case 0:
17368c2ecf20Sopenharmony_ci		if (rpcauth_uptodatecred(task)) {
17378c2ecf20Sopenharmony_ci			task->tk_action = call_allocate;
17388c2ecf20Sopenharmony_ci			return;
17398c2ecf20Sopenharmony_ci		}
17408c2ecf20Sopenharmony_ci		/* Use rate-limiting and a max number of retries if refresh
17418c2ecf20Sopenharmony_ci		 * had status 0 but failed to update the cred.
17428c2ecf20Sopenharmony_ci		 */
17438c2ecf20Sopenharmony_ci		fallthrough;
17448c2ecf20Sopenharmony_ci	case -ETIMEDOUT:
17458c2ecf20Sopenharmony_ci		rpc_delay(task, 3*HZ);
17468c2ecf20Sopenharmony_ci		fallthrough;
17478c2ecf20Sopenharmony_ci	case -EAGAIN:
17488c2ecf20Sopenharmony_ci		status = -EACCES;
17498c2ecf20Sopenharmony_ci		fallthrough;
17508c2ecf20Sopenharmony_ci	case -EKEYEXPIRED:
17518c2ecf20Sopenharmony_ci		if (!task->tk_cred_retry)
17528c2ecf20Sopenharmony_ci			break;
17538c2ecf20Sopenharmony_ci		task->tk_cred_retry--;
17548c2ecf20Sopenharmony_ci		trace_rpc_retry_refresh_status(task);
17558c2ecf20Sopenharmony_ci		return;
17568c2ecf20Sopenharmony_ci	}
17578c2ecf20Sopenharmony_ci	trace_rpc_refresh_status(task);
17588c2ecf20Sopenharmony_ci	rpc_call_rpcerror(task, status);
17598c2ecf20Sopenharmony_ci}
17608c2ecf20Sopenharmony_ci
17618c2ecf20Sopenharmony_ci/*
17628c2ecf20Sopenharmony_ci * 2b.	Allocate the buffer. For details, see sched.c:rpc_malloc.
17638c2ecf20Sopenharmony_ci *	(Note: buffer memory is freed in xprt_release).
17648c2ecf20Sopenharmony_ci */
17658c2ecf20Sopenharmony_cistatic void
17668c2ecf20Sopenharmony_cicall_allocate(struct rpc_task *task)
17678c2ecf20Sopenharmony_ci{
17688c2ecf20Sopenharmony_ci	const struct rpc_auth *auth = task->tk_rqstp->rq_cred->cr_auth;
17698c2ecf20Sopenharmony_ci	struct rpc_rqst *req = task->tk_rqstp;
17708c2ecf20Sopenharmony_ci	struct rpc_xprt *xprt = req->rq_xprt;
17718c2ecf20Sopenharmony_ci	const struct rpc_procinfo *proc = task->tk_msg.rpc_proc;
17728c2ecf20Sopenharmony_ci	int status;
17738c2ecf20Sopenharmony_ci
17748c2ecf20Sopenharmony_ci	task->tk_status = 0;
17758c2ecf20Sopenharmony_ci	task->tk_action = call_encode;
17768c2ecf20Sopenharmony_ci
17778c2ecf20Sopenharmony_ci	if (req->rq_buffer)
17788c2ecf20Sopenharmony_ci		return;
17798c2ecf20Sopenharmony_ci
17808c2ecf20Sopenharmony_ci	if (proc->p_proc != 0) {
17818c2ecf20Sopenharmony_ci		BUG_ON(proc->p_arglen == 0);
17828c2ecf20Sopenharmony_ci		if (proc->p_decode != NULL)
17838c2ecf20Sopenharmony_ci			BUG_ON(proc->p_replen == 0);
17848c2ecf20Sopenharmony_ci	}
17858c2ecf20Sopenharmony_ci
17868c2ecf20Sopenharmony_ci	/*
17878c2ecf20Sopenharmony_ci	 * Calculate the size (in quads) of the RPC call
17888c2ecf20Sopenharmony_ci	 * and reply headers, and convert both values
17898c2ecf20Sopenharmony_ci	 * to byte sizes.
17908c2ecf20Sopenharmony_ci	 */
17918c2ecf20Sopenharmony_ci	req->rq_callsize = RPC_CALLHDRSIZE + (auth->au_cslack << 1) +
17928c2ecf20Sopenharmony_ci			   proc->p_arglen;
17938c2ecf20Sopenharmony_ci	req->rq_callsize <<= 2;
17948c2ecf20Sopenharmony_ci	/*
17958c2ecf20Sopenharmony_ci	 * Note: the reply buffer must at minimum allocate enough space
17968c2ecf20Sopenharmony_ci	 * for the 'struct accepted_reply' from RFC5531.
17978c2ecf20Sopenharmony_ci	 */
17988c2ecf20Sopenharmony_ci	req->rq_rcvsize = RPC_REPHDRSIZE + auth->au_rslack + \
17998c2ecf20Sopenharmony_ci			max_t(size_t, proc->p_replen, 2);
18008c2ecf20Sopenharmony_ci	req->rq_rcvsize <<= 2;
18018c2ecf20Sopenharmony_ci
18028c2ecf20Sopenharmony_ci	status = xprt->ops->buf_alloc(task);
18038c2ecf20Sopenharmony_ci	trace_rpc_buf_alloc(task, status);
18048c2ecf20Sopenharmony_ci	if (status == 0)
18058c2ecf20Sopenharmony_ci		return;
18068c2ecf20Sopenharmony_ci	if (status != -ENOMEM) {
18078c2ecf20Sopenharmony_ci		rpc_call_rpcerror(task, status);
18088c2ecf20Sopenharmony_ci		return;
18098c2ecf20Sopenharmony_ci	}
18108c2ecf20Sopenharmony_ci
18118c2ecf20Sopenharmony_ci	if (RPC_IS_ASYNC(task) || !fatal_signal_pending(current)) {
18128c2ecf20Sopenharmony_ci		task->tk_action = call_allocate;
18138c2ecf20Sopenharmony_ci		rpc_delay(task, HZ>>4);
18148c2ecf20Sopenharmony_ci		return;
18158c2ecf20Sopenharmony_ci	}
18168c2ecf20Sopenharmony_ci
18178c2ecf20Sopenharmony_ci	rpc_call_rpcerror(task, -ERESTARTSYS);
18188c2ecf20Sopenharmony_ci}
18198c2ecf20Sopenharmony_ci
18208c2ecf20Sopenharmony_cistatic int
18218c2ecf20Sopenharmony_cirpc_task_need_encode(struct rpc_task *task)
18228c2ecf20Sopenharmony_ci{
18238c2ecf20Sopenharmony_ci	return test_bit(RPC_TASK_NEED_XMIT, &task->tk_runstate) == 0 &&
18248c2ecf20Sopenharmony_ci		(!(task->tk_flags & RPC_TASK_SENT) ||
18258c2ecf20Sopenharmony_ci		 !(task->tk_flags & RPC_TASK_NO_RETRANS_TIMEOUT) ||
18268c2ecf20Sopenharmony_ci		 xprt_request_need_retransmit(task));
18278c2ecf20Sopenharmony_ci}
18288c2ecf20Sopenharmony_ci
18298c2ecf20Sopenharmony_cistatic void
18308c2ecf20Sopenharmony_cirpc_xdr_encode(struct rpc_task *task)
18318c2ecf20Sopenharmony_ci{
18328c2ecf20Sopenharmony_ci	struct rpc_rqst	*req = task->tk_rqstp;
18338c2ecf20Sopenharmony_ci	struct xdr_stream xdr;
18348c2ecf20Sopenharmony_ci
18358c2ecf20Sopenharmony_ci	xdr_buf_init(&req->rq_snd_buf,
18368c2ecf20Sopenharmony_ci		     req->rq_buffer,
18378c2ecf20Sopenharmony_ci		     req->rq_callsize);
18388c2ecf20Sopenharmony_ci	xdr_buf_init(&req->rq_rcv_buf,
18398c2ecf20Sopenharmony_ci		     req->rq_rbuffer,
18408c2ecf20Sopenharmony_ci		     req->rq_rcvsize);
18418c2ecf20Sopenharmony_ci
18428c2ecf20Sopenharmony_ci	req->rq_reply_bytes_recvd = 0;
18438c2ecf20Sopenharmony_ci	req->rq_snd_buf.head[0].iov_len = 0;
18448c2ecf20Sopenharmony_ci	xdr_init_encode(&xdr, &req->rq_snd_buf,
18458c2ecf20Sopenharmony_ci			req->rq_snd_buf.head[0].iov_base, req);
18468c2ecf20Sopenharmony_ci	xdr_free_bvec(&req->rq_snd_buf);
18478c2ecf20Sopenharmony_ci	if (rpc_encode_header(task, &xdr))
18488c2ecf20Sopenharmony_ci		return;
18498c2ecf20Sopenharmony_ci
18508c2ecf20Sopenharmony_ci	task->tk_status = rpcauth_wrap_req(task, &xdr);
18518c2ecf20Sopenharmony_ci}
18528c2ecf20Sopenharmony_ci
18538c2ecf20Sopenharmony_ci/*
18548c2ecf20Sopenharmony_ci * 3.	Encode arguments of an RPC call
18558c2ecf20Sopenharmony_ci */
18568c2ecf20Sopenharmony_cistatic void
18578c2ecf20Sopenharmony_cicall_encode(struct rpc_task *task)
18588c2ecf20Sopenharmony_ci{
18598c2ecf20Sopenharmony_ci	if (!rpc_task_need_encode(task))
18608c2ecf20Sopenharmony_ci		goto out;
18618c2ecf20Sopenharmony_ci
18628c2ecf20Sopenharmony_ci	/* Dequeue task from the receive queue while we're encoding */
18638c2ecf20Sopenharmony_ci	xprt_request_dequeue_xprt(task);
18648c2ecf20Sopenharmony_ci	/* Encode here so that rpcsec_gss can use correct sequence number. */
18658c2ecf20Sopenharmony_ci	rpc_xdr_encode(task);
18668c2ecf20Sopenharmony_ci	/* Did the encode result in an error condition? */
18678c2ecf20Sopenharmony_ci	if (task->tk_status != 0) {
18688c2ecf20Sopenharmony_ci		/* Was the error nonfatal? */
18698c2ecf20Sopenharmony_ci		switch (task->tk_status) {
18708c2ecf20Sopenharmony_ci		case -EAGAIN:
18718c2ecf20Sopenharmony_ci		case -ENOMEM:
18728c2ecf20Sopenharmony_ci			rpc_delay(task, HZ >> 4);
18738c2ecf20Sopenharmony_ci			break;
18748c2ecf20Sopenharmony_ci		case -EKEYEXPIRED:
18758c2ecf20Sopenharmony_ci			if (!task->tk_cred_retry) {
18768c2ecf20Sopenharmony_ci				rpc_call_rpcerror(task, task->tk_status);
18778c2ecf20Sopenharmony_ci			} else {
18788c2ecf20Sopenharmony_ci				task->tk_action = call_refresh;
18798c2ecf20Sopenharmony_ci				task->tk_cred_retry--;
18808c2ecf20Sopenharmony_ci				trace_rpc_retry_refresh_status(task);
18818c2ecf20Sopenharmony_ci			}
18828c2ecf20Sopenharmony_ci			break;
18838c2ecf20Sopenharmony_ci		default:
18848c2ecf20Sopenharmony_ci			rpc_call_rpcerror(task, task->tk_status);
18858c2ecf20Sopenharmony_ci		}
18868c2ecf20Sopenharmony_ci		return;
18878c2ecf20Sopenharmony_ci	}
18888c2ecf20Sopenharmony_ci
18898c2ecf20Sopenharmony_ci	/* Add task to reply queue before transmission to avoid races */
18908c2ecf20Sopenharmony_ci	if (rpc_reply_expected(task))
18918c2ecf20Sopenharmony_ci		xprt_request_enqueue_receive(task);
18928c2ecf20Sopenharmony_ci	xprt_request_enqueue_transmit(task);
18938c2ecf20Sopenharmony_ciout:
18948c2ecf20Sopenharmony_ci	task->tk_action = call_transmit;
18958c2ecf20Sopenharmony_ci	/* Check that the connection is OK */
18968c2ecf20Sopenharmony_ci	if (!xprt_bound(task->tk_xprt))
18978c2ecf20Sopenharmony_ci		task->tk_action = call_bind;
18988c2ecf20Sopenharmony_ci	else if (!xprt_connected(task->tk_xprt))
18998c2ecf20Sopenharmony_ci		task->tk_action = call_connect;
19008c2ecf20Sopenharmony_ci}
19018c2ecf20Sopenharmony_ci
19028c2ecf20Sopenharmony_ci/*
19038c2ecf20Sopenharmony_ci * Helpers to check if the task was already transmitted, and
19048c2ecf20Sopenharmony_ci * to take action when that is the case.
19058c2ecf20Sopenharmony_ci */
19068c2ecf20Sopenharmony_cistatic bool
19078c2ecf20Sopenharmony_cirpc_task_transmitted(struct rpc_task *task)
19088c2ecf20Sopenharmony_ci{
19098c2ecf20Sopenharmony_ci	return !test_bit(RPC_TASK_NEED_XMIT, &task->tk_runstate);
19108c2ecf20Sopenharmony_ci}
19118c2ecf20Sopenharmony_ci
19128c2ecf20Sopenharmony_cistatic void
19138c2ecf20Sopenharmony_cirpc_task_handle_transmitted(struct rpc_task *task)
19148c2ecf20Sopenharmony_ci{
19158c2ecf20Sopenharmony_ci	xprt_end_transmit(task);
19168c2ecf20Sopenharmony_ci	task->tk_action = call_transmit_status;
19178c2ecf20Sopenharmony_ci}
19188c2ecf20Sopenharmony_ci
19198c2ecf20Sopenharmony_ci/*
19208c2ecf20Sopenharmony_ci * 4.	Get the server port number if not yet set
19218c2ecf20Sopenharmony_ci */
19228c2ecf20Sopenharmony_cistatic void
19238c2ecf20Sopenharmony_cicall_bind(struct rpc_task *task)
19248c2ecf20Sopenharmony_ci{
19258c2ecf20Sopenharmony_ci	struct rpc_xprt *xprt = task->tk_rqstp->rq_xprt;
19268c2ecf20Sopenharmony_ci
19278c2ecf20Sopenharmony_ci	if (rpc_task_transmitted(task)) {
19288c2ecf20Sopenharmony_ci		rpc_task_handle_transmitted(task);
19298c2ecf20Sopenharmony_ci		return;
19308c2ecf20Sopenharmony_ci	}
19318c2ecf20Sopenharmony_ci
19328c2ecf20Sopenharmony_ci	if (xprt_bound(xprt)) {
19338c2ecf20Sopenharmony_ci		task->tk_action = call_connect;
19348c2ecf20Sopenharmony_ci		return;
19358c2ecf20Sopenharmony_ci	}
19368c2ecf20Sopenharmony_ci
19378c2ecf20Sopenharmony_ci	task->tk_action = call_bind_status;
19388c2ecf20Sopenharmony_ci	if (!xprt_prepare_transmit(task))
19398c2ecf20Sopenharmony_ci		return;
19408c2ecf20Sopenharmony_ci
19418c2ecf20Sopenharmony_ci	xprt->ops->rpcbind(task);
19428c2ecf20Sopenharmony_ci}
19438c2ecf20Sopenharmony_ci
19448c2ecf20Sopenharmony_ci/*
19458c2ecf20Sopenharmony_ci * 4a.	Sort out bind result
19468c2ecf20Sopenharmony_ci */
19478c2ecf20Sopenharmony_cistatic void
19488c2ecf20Sopenharmony_cicall_bind_status(struct rpc_task *task)
19498c2ecf20Sopenharmony_ci{
19508c2ecf20Sopenharmony_ci	struct rpc_xprt *xprt = task->tk_rqstp->rq_xprt;
19518c2ecf20Sopenharmony_ci	int status = -EIO;
19528c2ecf20Sopenharmony_ci
19538c2ecf20Sopenharmony_ci	if (rpc_task_transmitted(task)) {
19548c2ecf20Sopenharmony_ci		rpc_task_handle_transmitted(task);
19558c2ecf20Sopenharmony_ci		return;
19568c2ecf20Sopenharmony_ci	}
19578c2ecf20Sopenharmony_ci
19588c2ecf20Sopenharmony_ci	if (task->tk_status >= 0)
19598c2ecf20Sopenharmony_ci		goto out_next;
19608c2ecf20Sopenharmony_ci	if (xprt_bound(xprt)) {
19618c2ecf20Sopenharmony_ci		task->tk_status = 0;
19628c2ecf20Sopenharmony_ci		goto out_next;
19638c2ecf20Sopenharmony_ci	}
19648c2ecf20Sopenharmony_ci
19658c2ecf20Sopenharmony_ci	switch (task->tk_status) {
19668c2ecf20Sopenharmony_ci	case -ENOMEM:
19678c2ecf20Sopenharmony_ci		rpc_delay(task, HZ >> 2);
19688c2ecf20Sopenharmony_ci		goto retry_timeout;
19698c2ecf20Sopenharmony_ci	case -EACCES:
19708c2ecf20Sopenharmony_ci		trace_rpcb_prog_unavail_err(task);
19718c2ecf20Sopenharmony_ci		/* fail immediately if this is an RPC ping */
19728c2ecf20Sopenharmony_ci		if (task->tk_msg.rpc_proc->p_proc == 0) {
19738c2ecf20Sopenharmony_ci			status = -EOPNOTSUPP;
19748c2ecf20Sopenharmony_ci			break;
19758c2ecf20Sopenharmony_ci		}
19768c2ecf20Sopenharmony_ci		rpc_delay(task, 3*HZ);
19778c2ecf20Sopenharmony_ci		goto retry_timeout;
19788c2ecf20Sopenharmony_ci	case -ENOBUFS:
19798c2ecf20Sopenharmony_ci		rpc_delay(task, HZ >> 2);
19808c2ecf20Sopenharmony_ci		goto retry_timeout;
19818c2ecf20Sopenharmony_ci	case -EAGAIN:
19828c2ecf20Sopenharmony_ci		goto retry_timeout;
19838c2ecf20Sopenharmony_ci	case -ETIMEDOUT:
19848c2ecf20Sopenharmony_ci		trace_rpcb_timeout_err(task);
19858c2ecf20Sopenharmony_ci		goto retry_timeout;
19868c2ecf20Sopenharmony_ci	case -EPFNOSUPPORT:
19878c2ecf20Sopenharmony_ci		/* server doesn't support any rpcbind version we know of */
19888c2ecf20Sopenharmony_ci		trace_rpcb_bind_version_err(task);
19898c2ecf20Sopenharmony_ci		break;
19908c2ecf20Sopenharmony_ci	case -EPROTONOSUPPORT:
19918c2ecf20Sopenharmony_ci		trace_rpcb_bind_version_err(task);
19928c2ecf20Sopenharmony_ci		goto retry_timeout;
19938c2ecf20Sopenharmony_ci	case -ECONNREFUSED:		/* connection problems */
19948c2ecf20Sopenharmony_ci	case -ECONNRESET:
19958c2ecf20Sopenharmony_ci	case -ECONNABORTED:
19968c2ecf20Sopenharmony_ci	case -ENOTCONN:
19978c2ecf20Sopenharmony_ci	case -EHOSTDOWN:
19988c2ecf20Sopenharmony_ci	case -ENETDOWN:
19998c2ecf20Sopenharmony_ci	case -EHOSTUNREACH:
20008c2ecf20Sopenharmony_ci	case -ENETUNREACH:
20018c2ecf20Sopenharmony_ci	case -EPIPE:
20028c2ecf20Sopenharmony_ci		trace_rpcb_unreachable_err(task);
20038c2ecf20Sopenharmony_ci		if (!RPC_IS_SOFTCONN(task)) {
20048c2ecf20Sopenharmony_ci			rpc_delay(task, 5*HZ);
20058c2ecf20Sopenharmony_ci			goto retry_timeout;
20068c2ecf20Sopenharmony_ci		}
20078c2ecf20Sopenharmony_ci		status = task->tk_status;
20088c2ecf20Sopenharmony_ci		break;
20098c2ecf20Sopenharmony_ci	default:
20108c2ecf20Sopenharmony_ci		trace_rpcb_unrecognized_err(task);
20118c2ecf20Sopenharmony_ci	}
20128c2ecf20Sopenharmony_ci
20138c2ecf20Sopenharmony_ci	rpc_call_rpcerror(task, status);
20148c2ecf20Sopenharmony_ci	return;
20158c2ecf20Sopenharmony_ciout_next:
20168c2ecf20Sopenharmony_ci	task->tk_action = call_connect;
20178c2ecf20Sopenharmony_ci	return;
20188c2ecf20Sopenharmony_ciretry_timeout:
20198c2ecf20Sopenharmony_ci	task->tk_status = 0;
20208c2ecf20Sopenharmony_ci	task->tk_action = call_bind;
20218c2ecf20Sopenharmony_ci	rpc_check_timeout(task);
20228c2ecf20Sopenharmony_ci}
20238c2ecf20Sopenharmony_ci
20248c2ecf20Sopenharmony_ci/*
20258c2ecf20Sopenharmony_ci * 4b.	Connect to the RPC server
20268c2ecf20Sopenharmony_ci */
20278c2ecf20Sopenharmony_cistatic void
20288c2ecf20Sopenharmony_cicall_connect(struct rpc_task *task)
20298c2ecf20Sopenharmony_ci{
20308c2ecf20Sopenharmony_ci	struct rpc_xprt *xprt = task->tk_rqstp->rq_xprt;
20318c2ecf20Sopenharmony_ci
20328c2ecf20Sopenharmony_ci	if (rpc_task_transmitted(task)) {
20338c2ecf20Sopenharmony_ci		rpc_task_handle_transmitted(task);
20348c2ecf20Sopenharmony_ci		return;
20358c2ecf20Sopenharmony_ci	}
20368c2ecf20Sopenharmony_ci
20378c2ecf20Sopenharmony_ci	if (xprt_connected(xprt)) {
20388c2ecf20Sopenharmony_ci		task->tk_action = call_transmit;
20398c2ecf20Sopenharmony_ci		return;
20408c2ecf20Sopenharmony_ci	}
20418c2ecf20Sopenharmony_ci
20428c2ecf20Sopenharmony_ci	task->tk_action = call_connect_status;
20438c2ecf20Sopenharmony_ci	if (task->tk_status < 0)
20448c2ecf20Sopenharmony_ci		return;
20458c2ecf20Sopenharmony_ci	if (task->tk_flags & RPC_TASK_NOCONNECT) {
20468c2ecf20Sopenharmony_ci		rpc_call_rpcerror(task, -ENOTCONN);
20478c2ecf20Sopenharmony_ci		return;
20488c2ecf20Sopenharmony_ci	}
20498c2ecf20Sopenharmony_ci	if (!xprt_prepare_transmit(task))
20508c2ecf20Sopenharmony_ci		return;
20518c2ecf20Sopenharmony_ci	xprt_connect(task);
20528c2ecf20Sopenharmony_ci}
20538c2ecf20Sopenharmony_ci
20548c2ecf20Sopenharmony_ci/*
20558c2ecf20Sopenharmony_ci * 4c.	Sort out connect result
20568c2ecf20Sopenharmony_ci */
20578c2ecf20Sopenharmony_cistatic void
20588c2ecf20Sopenharmony_cicall_connect_status(struct rpc_task *task)
20598c2ecf20Sopenharmony_ci{
20608c2ecf20Sopenharmony_ci	struct rpc_xprt *xprt = task->tk_rqstp->rq_xprt;
20618c2ecf20Sopenharmony_ci	struct rpc_clnt *clnt = task->tk_client;
20628c2ecf20Sopenharmony_ci	int status = task->tk_status;
20638c2ecf20Sopenharmony_ci
20648c2ecf20Sopenharmony_ci	if (rpc_task_transmitted(task)) {
20658c2ecf20Sopenharmony_ci		rpc_task_handle_transmitted(task);
20668c2ecf20Sopenharmony_ci		return;
20678c2ecf20Sopenharmony_ci	}
20688c2ecf20Sopenharmony_ci
20698c2ecf20Sopenharmony_ci	trace_rpc_connect_status(task);
20708c2ecf20Sopenharmony_ci
20718c2ecf20Sopenharmony_ci	if (task->tk_status == 0) {
20728c2ecf20Sopenharmony_ci		clnt->cl_stats->netreconn++;
20738c2ecf20Sopenharmony_ci		goto out_next;
20748c2ecf20Sopenharmony_ci	}
20758c2ecf20Sopenharmony_ci	if (xprt_connected(xprt)) {
20768c2ecf20Sopenharmony_ci		task->tk_status = 0;
20778c2ecf20Sopenharmony_ci		goto out_next;
20788c2ecf20Sopenharmony_ci	}
20798c2ecf20Sopenharmony_ci
20808c2ecf20Sopenharmony_ci	task->tk_status = 0;
20818c2ecf20Sopenharmony_ci	switch (status) {
20828c2ecf20Sopenharmony_ci	case -ECONNREFUSED:
20838c2ecf20Sopenharmony_ci	case -ECONNRESET:
20848c2ecf20Sopenharmony_ci		/* A positive refusal suggests a rebind is needed. */
20858c2ecf20Sopenharmony_ci		if (RPC_IS_SOFTCONN(task))
20868c2ecf20Sopenharmony_ci			break;
20878c2ecf20Sopenharmony_ci		if (clnt->cl_autobind) {
20888c2ecf20Sopenharmony_ci			rpc_force_rebind(clnt);
20898c2ecf20Sopenharmony_ci			goto out_retry;
20908c2ecf20Sopenharmony_ci		}
20918c2ecf20Sopenharmony_ci		fallthrough;
20928c2ecf20Sopenharmony_ci	case -ECONNABORTED:
20938c2ecf20Sopenharmony_ci	case -ENETDOWN:
20948c2ecf20Sopenharmony_ci	case -ENETUNREACH:
20958c2ecf20Sopenharmony_ci	case -EHOSTUNREACH:
20968c2ecf20Sopenharmony_ci	case -EPIPE:
20978c2ecf20Sopenharmony_ci	case -EPROTO:
20988c2ecf20Sopenharmony_ci		xprt_conditional_disconnect(task->tk_rqstp->rq_xprt,
20998c2ecf20Sopenharmony_ci					    task->tk_rqstp->rq_connect_cookie);
21008c2ecf20Sopenharmony_ci		if (RPC_IS_SOFTCONN(task))
21018c2ecf20Sopenharmony_ci			break;
21028c2ecf20Sopenharmony_ci		/* retry with existing socket, after a delay */
21038c2ecf20Sopenharmony_ci		rpc_delay(task, 3*HZ);
21048c2ecf20Sopenharmony_ci		fallthrough;
21058c2ecf20Sopenharmony_ci	case -EADDRINUSE:
21068c2ecf20Sopenharmony_ci	case -ENOTCONN:
21078c2ecf20Sopenharmony_ci	case -EAGAIN:
21088c2ecf20Sopenharmony_ci	case -ETIMEDOUT:
21098c2ecf20Sopenharmony_ci		goto out_retry;
21108c2ecf20Sopenharmony_ci	case -ENOBUFS:
21118c2ecf20Sopenharmony_ci		rpc_delay(task, HZ >> 2);
21128c2ecf20Sopenharmony_ci		goto out_retry;
21138c2ecf20Sopenharmony_ci	}
21148c2ecf20Sopenharmony_ci	rpc_call_rpcerror(task, status);
21158c2ecf20Sopenharmony_ci	return;
21168c2ecf20Sopenharmony_ciout_next:
21178c2ecf20Sopenharmony_ci	task->tk_action = call_transmit;
21188c2ecf20Sopenharmony_ci	return;
21198c2ecf20Sopenharmony_ciout_retry:
21208c2ecf20Sopenharmony_ci	/* Check for timeouts before looping back to call_bind */
21218c2ecf20Sopenharmony_ci	task->tk_action = call_bind;
21228c2ecf20Sopenharmony_ci	rpc_check_timeout(task);
21238c2ecf20Sopenharmony_ci}
21248c2ecf20Sopenharmony_ci
21258c2ecf20Sopenharmony_ci/*
21268c2ecf20Sopenharmony_ci * 5.	Transmit the RPC request, and wait for reply
21278c2ecf20Sopenharmony_ci */
21288c2ecf20Sopenharmony_cistatic void
21298c2ecf20Sopenharmony_cicall_transmit(struct rpc_task *task)
21308c2ecf20Sopenharmony_ci{
21318c2ecf20Sopenharmony_ci	if (rpc_task_transmitted(task)) {
21328c2ecf20Sopenharmony_ci		rpc_task_handle_transmitted(task);
21338c2ecf20Sopenharmony_ci		return;
21348c2ecf20Sopenharmony_ci	}
21358c2ecf20Sopenharmony_ci
21368c2ecf20Sopenharmony_ci	task->tk_action = call_transmit_status;
21378c2ecf20Sopenharmony_ci	if (!xprt_prepare_transmit(task))
21388c2ecf20Sopenharmony_ci		return;
21398c2ecf20Sopenharmony_ci	task->tk_status = 0;
21408c2ecf20Sopenharmony_ci	if (test_bit(RPC_TASK_NEED_XMIT, &task->tk_runstate)) {
21418c2ecf20Sopenharmony_ci		if (!xprt_connected(task->tk_xprt)) {
21428c2ecf20Sopenharmony_ci			task->tk_status = -ENOTCONN;
21438c2ecf20Sopenharmony_ci			return;
21448c2ecf20Sopenharmony_ci		}
21458c2ecf20Sopenharmony_ci		xprt_transmit(task);
21468c2ecf20Sopenharmony_ci	}
21478c2ecf20Sopenharmony_ci	xprt_end_transmit(task);
21488c2ecf20Sopenharmony_ci}
21498c2ecf20Sopenharmony_ci
21508c2ecf20Sopenharmony_ci/*
21518c2ecf20Sopenharmony_ci * 5a.	Handle cleanup after a transmission
21528c2ecf20Sopenharmony_ci */
21538c2ecf20Sopenharmony_cistatic void
21548c2ecf20Sopenharmony_cicall_transmit_status(struct rpc_task *task)
21558c2ecf20Sopenharmony_ci{
21568c2ecf20Sopenharmony_ci	task->tk_action = call_status;
21578c2ecf20Sopenharmony_ci
21588c2ecf20Sopenharmony_ci	/*
21598c2ecf20Sopenharmony_ci	 * Common case: success.  Force the compiler to put this
21608c2ecf20Sopenharmony_ci	 * test first.
21618c2ecf20Sopenharmony_ci	 */
21628c2ecf20Sopenharmony_ci	if (rpc_task_transmitted(task)) {
21638c2ecf20Sopenharmony_ci		task->tk_status = 0;
21648c2ecf20Sopenharmony_ci		xprt_request_wait_receive(task);
21658c2ecf20Sopenharmony_ci		return;
21668c2ecf20Sopenharmony_ci	}
21678c2ecf20Sopenharmony_ci
21688c2ecf20Sopenharmony_ci	switch (task->tk_status) {
21698c2ecf20Sopenharmony_ci	default:
21708c2ecf20Sopenharmony_ci		break;
21718c2ecf20Sopenharmony_ci	case -EBADMSG:
21728c2ecf20Sopenharmony_ci		task->tk_status = 0;
21738c2ecf20Sopenharmony_ci		task->tk_action = call_encode;
21748c2ecf20Sopenharmony_ci		break;
21758c2ecf20Sopenharmony_ci		/*
21768c2ecf20Sopenharmony_ci		 * Special cases: if we've been waiting on the
21778c2ecf20Sopenharmony_ci		 * socket's write_space() callback, or if the
21788c2ecf20Sopenharmony_ci		 * socket just returned a connection error,
21798c2ecf20Sopenharmony_ci		 * then hold onto the transport lock.
21808c2ecf20Sopenharmony_ci		 */
21818c2ecf20Sopenharmony_ci	case -ENOMEM:
21828c2ecf20Sopenharmony_ci	case -ENOBUFS:
21838c2ecf20Sopenharmony_ci		rpc_delay(task, HZ>>2);
21848c2ecf20Sopenharmony_ci		fallthrough;
21858c2ecf20Sopenharmony_ci	case -EBADSLT:
21868c2ecf20Sopenharmony_ci	case -EAGAIN:
21878c2ecf20Sopenharmony_ci		task->tk_action = call_transmit;
21888c2ecf20Sopenharmony_ci		task->tk_status = 0;
21898c2ecf20Sopenharmony_ci		break;
21908c2ecf20Sopenharmony_ci	case -ECONNREFUSED:
21918c2ecf20Sopenharmony_ci	case -EHOSTDOWN:
21928c2ecf20Sopenharmony_ci	case -ENETDOWN:
21938c2ecf20Sopenharmony_ci	case -EHOSTUNREACH:
21948c2ecf20Sopenharmony_ci	case -ENETUNREACH:
21958c2ecf20Sopenharmony_ci	case -EPERM:
21968c2ecf20Sopenharmony_ci		if (RPC_IS_SOFTCONN(task)) {
21978c2ecf20Sopenharmony_ci			if (!task->tk_msg.rpc_proc->p_proc)
21988c2ecf20Sopenharmony_ci				trace_xprt_ping(task->tk_xprt,
21998c2ecf20Sopenharmony_ci						task->tk_status);
22008c2ecf20Sopenharmony_ci			rpc_call_rpcerror(task, task->tk_status);
22018c2ecf20Sopenharmony_ci			return;
22028c2ecf20Sopenharmony_ci		}
22038c2ecf20Sopenharmony_ci		fallthrough;
22048c2ecf20Sopenharmony_ci	case -ECONNRESET:
22058c2ecf20Sopenharmony_ci	case -ECONNABORTED:
22068c2ecf20Sopenharmony_ci	case -EADDRINUSE:
22078c2ecf20Sopenharmony_ci	case -ENOTCONN:
22088c2ecf20Sopenharmony_ci	case -EPIPE:
22098c2ecf20Sopenharmony_ci		task->tk_action = call_bind;
22108c2ecf20Sopenharmony_ci		task->tk_status = 0;
22118c2ecf20Sopenharmony_ci		break;
22128c2ecf20Sopenharmony_ci	}
22138c2ecf20Sopenharmony_ci	rpc_check_timeout(task);
22148c2ecf20Sopenharmony_ci}
22158c2ecf20Sopenharmony_ci
22168c2ecf20Sopenharmony_ci#if defined(CONFIG_SUNRPC_BACKCHANNEL)
22178c2ecf20Sopenharmony_cistatic void call_bc_transmit(struct rpc_task *task);
22188c2ecf20Sopenharmony_cistatic void call_bc_transmit_status(struct rpc_task *task);
22198c2ecf20Sopenharmony_ci
22208c2ecf20Sopenharmony_cistatic void
22218c2ecf20Sopenharmony_cicall_bc_encode(struct rpc_task *task)
22228c2ecf20Sopenharmony_ci{
22238c2ecf20Sopenharmony_ci	xprt_request_enqueue_transmit(task);
22248c2ecf20Sopenharmony_ci	task->tk_action = call_bc_transmit;
22258c2ecf20Sopenharmony_ci}
22268c2ecf20Sopenharmony_ci
22278c2ecf20Sopenharmony_ci/*
22288c2ecf20Sopenharmony_ci * 5b.	Send the backchannel RPC reply.  On error, drop the reply.  In
22298c2ecf20Sopenharmony_ci * addition, disconnect on connectivity errors.
22308c2ecf20Sopenharmony_ci */
22318c2ecf20Sopenharmony_cistatic void
22328c2ecf20Sopenharmony_cicall_bc_transmit(struct rpc_task *task)
22338c2ecf20Sopenharmony_ci{
22348c2ecf20Sopenharmony_ci	task->tk_action = call_bc_transmit_status;
22358c2ecf20Sopenharmony_ci	if (test_bit(RPC_TASK_NEED_XMIT, &task->tk_runstate)) {
22368c2ecf20Sopenharmony_ci		if (!xprt_prepare_transmit(task))
22378c2ecf20Sopenharmony_ci			return;
22388c2ecf20Sopenharmony_ci		task->tk_status = 0;
22398c2ecf20Sopenharmony_ci		xprt_transmit(task);
22408c2ecf20Sopenharmony_ci	}
22418c2ecf20Sopenharmony_ci	xprt_end_transmit(task);
22428c2ecf20Sopenharmony_ci}
22438c2ecf20Sopenharmony_ci
22448c2ecf20Sopenharmony_cistatic void
22458c2ecf20Sopenharmony_cicall_bc_transmit_status(struct rpc_task *task)
22468c2ecf20Sopenharmony_ci{
22478c2ecf20Sopenharmony_ci	struct rpc_rqst *req = task->tk_rqstp;
22488c2ecf20Sopenharmony_ci
22498c2ecf20Sopenharmony_ci	if (rpc_task_transmitted(task))
22508c2ecf20Sopenharmony_ci		task->tk_status = 0;
22518c2ecf20Sopenharmony_ci
22528c2ecf20Sopenharmony_ci	switch (task->tk_status) {
22538c2ecf20Sopenharmony_ci	case 0:
22548c2ecf20Sopenharmony_ci		/* Success */
22558c2ecf20Sopenharmony_ci	case -ENETDOWN:
22568c2ecf20Sopenharmony_ci	case -EHOSTDOWN:
22578c2ecf20Sopenharmony_ci	case -EHOSTUNREACH:
22588c2ecf20Sopenharmony_ci	case -ENETUNREACH:
22598c2ecf20Sopenharmony_ci	case -ECONNRESET:
22608c2ecf20Sopenharmony_ci	case -ECONNREFUSED:
22618c2ecf20Sopenharmony_ci	case -EADDRINUSE:
22628c2ecf20Sopenharmony_ci	case -ENOTCONN:
22638c2ecf20Sopenharmony_ci	case -EPIPE:
22648c2ecf20Sopenharmony_ci		break;
22658c2ecf20Sopenharmony_ci	case -ENOMEM:
22668c2ecf20Sopenharmony_ci	case -ENOBUFS:
22678c2ecf20Sopenharmony_ci		rpc_delay(task, HZ>>2);
22688c2ecf20Sopenharmony_ci		fallthrough;
22698c2ecf20Sopenharmony_ci	case -EBADSLT:
22708c2ecf20Sopenharmony_ci	case -EAGAIN:
22718c2ecf20Sopenharmony_ci		task->tk_status = 0;
22728c2ecf20Sopenharmony_ci		task->tk_action = call_bc_transmit;
22738c2ecf20Sopenharmony_ci		return;
22748c2ecf20Sopenharmony_ci	case -ETIMEDOUT:
22758c2ecf20Sopenharmony_ci		/*
22768c2ecf20Sopenharmony_ci		 * Problem reaching the server.  Disconnect and let the
22778c2ecf20Sopenharmony_ci		 * forechannel reestablish the connection.  The server will
22788c2ecf20Sopenharmony_ci		 * have to retransmit the backchannel request and we'll
22798c2ecf20Sopenharmony_ci		 * reprocess it.  Since these ops are idempotent, there's no
22808c2ecf20Sopenharmony_ci		 * need to cache our reply at this time.
22818c2ecf20Sopenharmony_ci		 */
22828c2ecf20Sopenharmony_ci		printk(KERN_NOTICE "RPC: Could not send backchannel reply "
22838c2ecf20Sopenharmony_ci			"error: %d\n", task->tk_status);
22848c2ecf20Sopenharmony_ci		xprt_conditional_disconnect(req->rq_xprt,
22858c2ecf20Sopenharmony_ci			req->rq_connect_cookie);
22868c2ecf20Sopenharmony_ci		break;
22878c2ecf20Sopenharmony_ci	default:
22888c2ecf20Sopenharmony_ci		/*
22898c2ecf20Sopenharmony_ci		 * We were unable to reply and will have to drop the
22908c2ecf20Sopenharmony_ci		 * request.  The server should reconnect and retransmit.
22918c2ecf20Sopenharmony_ci		 */
22928c2ecf20Sopenharmony_ci		printk(KERN_NOTICE "RPC: Could not send backchannel reply "
22938c2ecf20Sopenharmony_ci			"error: %d\n", task->tk_status);
22948c2ecf20Sopenharmony_ci		break;
22958c2ecf20Sopenharmony_ci	}
22968c2ecf20Sopenharmony_ci	task->tk_action = rpc_exit_task;
22978c2ecf20Sopenharmony_ci}
22988c2ecf20Sopenharmony_ci#endif /* CONFIG_SUNRPC_BACKCHANNEL */
22998c2ecf20Sopenharmony_ci
23008c2ecf20Sopenharmony_ci/*
23018c2ecf20Sopenharmony_ci * 6.	Sort out the RPC call status
23028c2ecf20Sopenharmony_ci */
23038c2ecf20Sopenharmony_cistatic void
23048c2ecf20Sopenharmony_cicall_status(struct rpc_task *task)
23058c2ecf20Sopenharmony_ci{
23068c2ecf20Sopenharmony_ci	struct rpc_clnt	*clnt = task->tk_client;
23078c2ecf20Sopenharmony_ci	int		status;
23088c2ecf20Sopenharmony_ci
23098c2ecf20Sopenharmony_ci	if (!task->tk_msg.rpc_proc->p_proc)
23108c2ecf20Sopenharmony_ci		trace_xprt_ping(task->tk_xprt, task->tk_status);
23118c2ecf20Sopenharmony_ci
23128c2ecf20Sopenharmony_ci	status = task->tk_status;
23138c2ecf20Sopenharmony_ci	if (status >= 0) {
23148c2ecf20Sopenharmony_ci		task->tk_action = call_decode;
23158c2ecf20Sopenharmony_ci		return;
23168c2ecf20Sopenharmony_ci	}
23178c2ecf20Sopenharmony_ci
23188c2ecf20Sopenharmony_ci	trace_rpc_call_status(task);
23198c2ecf20Sopenharmony_ci	task->tk_status = 0;
23208c2ecf20Sopenharmony_ci	switch(status) {
23218c2ecf20Sopenharmony_ci	case -EHOSTDOWN:
23228c2ecf20Sopenharmony_ci	case -ENETDOWN:
23238c2ecf20Sopenharmony_ci	case -EHOSTUNREACH:
23248c2ecf20Sopenharmony_ci	case -ENETUNREACH:
23258c2ecf20Sopenharmony_ci	case -EPERM:
23268c2ecf20Sopenharmony_ci		if (RPC_IS_SOFTCONN(task))
23278c2ecf20Sopenharmony_ci			goto out_exit;
23288c2ecf20Sopenharmony_ci		/*
23298c2ecf20Sopenharmony_ci		 * Delay any retries for 3 seconds, then handle as if it
23308c2ecf20Sopenharmony_ci		 * were a timeout.
23318c2ecf20Sopenharmony_ci		 */
23328c2ecf20Sopenharmony_ci		rpc_delay(task, 3*HZ);
23338c2ecf20Sopenharmony_ci		fallthrough;
23348c2ecf20Sopenharmony_ci	case -ETIMEDOUT:
23358c2ecf20Sopenharmony_ci		break;
23368c2ecf20Sopenharmony_ci	case -ECONNREFUSED:
23378c2ecf20Sopenharmony_ci	case -ECONNRESET:
23388c2ecf20Sopenharmony_ci	case -ECONNABORTED:
23398c2ecf20Sopenharmony_ci	case -ENOTCONN:
23408c2ecf20Sopenharmony_ci		rpc_force_rebind(clnt);
23418c2ecf20Sopenharmony_ci		break;
23428c2ecf20Sopenharmony_ci	case -EADDRINUSE:
23438c2ecf20Sopenharmony_ci		rpc_delay(task, 3*HZ);
23448c2ecf20Sopenharmony_ci		fallthrough;
23458c2ecf20Sopenharmony_ci	case -EPIPE:
23468c2ecf20Sopenharmony_ci	case -EAGAIN:
23478c2ecf20Sopenharmony_ci		break;
23488c2ecf20Sopenharmony_ci	case -ENFILE:
23498c2ecf20Sopenharmony_ci	case -ENOBUFS:
23508c2ecf20Sopenharmony_ci	case -ENOMEM:
23518c2ecf20Sopenharmony_ci		rpc_delay(task, HZ>>2);
23528c2ecf20Sopenharmony_ci		break;
23538c2ecf20Sopenharmony_ci	case -EIO:
23548c2ecf20Sopenharmony_ci		/* shutdown or soft timeout */
23558c2ecf20Sopenharmony_ci		goto out_exit;
23568c2ecf20Sopenharmony_ci	default:
23578c2ecf20Sopenharmony_ci		if (clnt->cl_chatty)
23588c2ecf20Sopenharmony_ci			printk("%s: RPC call returned error %d\n",
23598c2ecf20Sopenharmony_ci			       clnt->cl_program->name, -status);
23608c2ecf20Sopenharmony_ci		goto out_exit;
23618c2ecf20Sopenharmony_ci	}
23628c2ecf20Sopenharmony_ci	task->tk_action = call_encode;
23638c2ecf20Sopenharmony_ci	rpc_check_timeout(task);
23648c2ecf20Sopenharmony_ci	return;
23658c2ecf20Sopenharmony_ciout_exit:
23668c2ecf20Sopenharmony_ci	rpc_call_rpcerror(task, status);
23678c2ecf20Sopenharmony_ci}
23688c2ecf20Sopenharmony_ci
23698c2ecf20Sopenharmony_cistatic bool
23708c2ecf20Sopenharmony_cirpc_check_connected(const struct rpc_rqst *req)
23718c2ecf20Sopenharmony_ci{
23728c2ecf20Sopenharmony_ci	/* No allocated request or transport? return true */
23738c2ecf20Sopenharmony_ci	if (!req || !req->rq_xprt)
23748c2ecf20Sopenharmony_ci		return true;
23758c2ecf20Sopenharmony_ci	return xprt_connected(req->rq_xprt);
23768c2ecf20Sopenharmony_ci}
23778c2ecf20Sopenharmony_ci
23788c2ecf20Sopenharmony_cistatic void
23798c2ecf20Sopenharmony_cirpc_check_timeout(struct rpc_task *task)
23808c2ecf20Sopenharmony_ci{
23818c2ecf20Sopenharmony_ci	struct rpc_clnt	*clnt = task->tk_client;
23828c2ecf20Sopenharmony_ci
23838c2ecf20Sopenharmony_ci	if (RPC_SIGNALLED(task)) {
23848c2ecf20Sopenharmony_ci		rpc_call_rpcerror(task, -ERESTARTSYS);
23858c2ecf20Sopenharmony_ci		return;
23868c2ecf20Sopenharmony_ci	}
23878c2ecf20Sopenharmony_ci
23888c2ecf20Sopenharmony_ci	if (xprt_adjust_timeout(task->tk_rqstp) == 0)
23898c2ecf20Sopenharmony_ci		return;
23908c2ecf20Sopenharmony_ci
23918c2ecf20Sopenharmony_ci	trace_rpc_timeout_status(task);
23928c2ecf20Sopenharmony_ci	task->tk_timeouts++;
23938c2ecf20Sopenharmony_ci
23948c2ecf20Sopenharmony_ci	if (RPC_IS_SOFTCONN(task) && !rpc_check_connected(task->tk_rqstp)) {
23958c2ecf20Sopenharmony_ci		rpc_call_rpcerror(task, -ETIMEDOUT);
23968c2ecf20Sopenharmony_ci		return;
23978c2ecf20Sopenharmony_ci	}
23988c2ecf20Sopenharmony_ci
23998c2ecf20Sopenharmony_ci	if (RPC_IS_SOFT(task)) {
24008c2ecf20Sopenharmony_ci		/*
24018c2ecf20Sopenharmony_ci		 * Once a "no retrans timeout" soft tasks (a.k.a NFSv4) has
24028c2ecf20Sopenharmony_ci		 * been sent, it should time out only if the transport
24038c2ecf20Sopenharmony_ci		 * connection gets terminally broken.
24048c2ecf20Sopenharmony_ci		 */
24058c2ecf20Sopenharmony_ci		if ((task->tk_flags & RPC_TASK_NO_RETRANS_TIMEOUT) &&
24068c2ecf20Sopenharmony_ci		    rpc_check_connected(task->tk_rqstp))
24078c2ecf20Sopenharmony_ci			return;
24088c2ecf20Sopenharmony_ci
24098c2ecf20Sopenharmony_ci		if (clnt->cl_chatty) {
24108c2ecf20Sopenharmony_ci			pr_notice_ratelimited(
24118c2ecf20Sopenharmony_ci				"%s: server %s not responding, timed out\n",
24128c2ecf20Sopenharmony_ci				clnt->cl_program->name,
24138c2ecf20Sopenharmony_ci				task->tk_xprt->servername);
24148c2ecf20Sopenharmony_ci		}
24158c2ecf20Sopenharmony_ci		if (task->tk_flags & RPC_TASK_TIMEOUT)
24168c2ecf20Sopenharmony_ci			rpc_call_rpcerror(task, -ETIMEDOUT);
24178c2ecf20Sopenharmony_ci		else
24188c2ecf20Sopenharmony_ci			__rpc_call_rpcerror(task, -EIO, -ETIMEDOUT);
24198c2ecf20Sopenharmony_ci		return;
24208c2ecf20Sopenharmony_ci	}
24218c2ecf20Sopenharmony_ci
24228c2ecf20Sopenharmony_ci	if (!(task->tk_flags & RPC_CALL_MAJORSEEN)) {
24238c2ecf20Sopenharmony_ci		task->tk_flags |= RPC_CALL_MAJORSEEN;
24248c2ecf20Sopenharmony_ci		if (clnt->cl_chatty) {
24258c2ecf20Sopenharmony_ci			pr_notice_ratelimited(
24268c2ecf20Sopenharmony_ci				"%s: server %s not responding, still trying\n",
24278c2ecf20Sopenharmony_ci				clnt->cl_program->name,
24288c2ecf20Sopenharmony_ci				task->tk_xprt->servername);
24298c2ecf20Sopenharmony_ci		}
24308c2ecf20Sopenharmony_ci	}
24318c2ecf20Sopenharmony_ci	rpc_force_rebind(clnt);
24328c2ecf20Sopenharmony_ci	/*
24338c2ecf20Sopenharmony_ci	 * Did our request time out due to an RPCSEC_GSS out-of-sequence
24348c2ecf20Sopenharmony_ci	 * event? RFC2203 requires the server to drop all such requests.
24358c2ecf20Sopenharmony_ci	 */
24368c2ecf20Sopenharmony_ci	rpcauth_invalcred(task);
24378c2ecf20Sopenharmony_ci}
24388c2ecf20Sopenharmony_ci
24398c2ecf20Sopenharmony_ci/*
24408c2ecf20Sopenharmony_ci * 7.	Decode the RPC reply
24418c2ecf20Sopenharmony_ci */
24428c2ecf20Sopenharmony_cistatic void
24438c2ecf20Sopenharmony_cicall_decode(struct rpc_task *task)
24448c2ecf20Sopenharmony_ci{
24458c2ecf20Sopenharmony_ci	struct rpc_clnt	*clnt = task->tk_client;
24468c2ecf20Sopenharmony_ci	struct rpc_rqst	*req = task->tk_rqstp;
24478c2ecf20Sopenharmony_ci	struct xdr_stream xdr;
24488c2ecf20Sopenharmony_ci	int err;
24498c2ecf20Sopenharmony_ci
24508c2ecf20Sopenharmony_ci	if (!task->tk_msg.rpc_proc->p_decode) {
24518c2ecf20Sopenharmony_ci		task->tk_action = rpc_exit_task;
24528c2ecf20Sopenharmony_ci		return;
24538c2ecf20Sopenharmony_ci	}
24548c2ecf20Sopenharmony_ci
24558c2ecf20Sopenharmony_ci	if (task->tk_flags & RPC_CALL_MAJORSEEN) {
24568c2ecf20Sopenharmony_ci		if (clnt->cl_chatty) {
24578c2ecf20Sopenharmony_ci			pr_notice_ratelimited("%s: server %s OK\n",
24588c2ecf20Sopenharmony_ci				clnt->cl_program->name,
24598c2ecf20Sopenharmony_ci				task->tk_xprt->servername);
24608c2ecf20Sopenharmony_ci		}
24618c2ecf20Sopenharmony_ci		task->tk_flags &= ~RPC_CALL_MAJORSEEN;
24628c2ecf20Sopenharmony_ci	}
24638c2ecf20Sopenharmony_ci
24648c2ecf20Sopenharmony_ci	/*
24658c2ecf20Sopenharmony_ci	 * Did we ever call xprt_complete_rqst()? If not, we should assume
24668c2ecf20Sopenharmony_ci	 * the message is incomplete.
24678c2ecf20Sopenharmony_ci	 */
24688c2ecf20Sopenharmony_ci	err = -EAGAIN;
24698c2ecf20Sopenharmony_ci	if (!req->rq_reply_bytes_recvd)
24708c2ecf20Sopenharmony_ci		goto out;
24718c2ecf20Sopenharmony_ci
24728c2ecf20Sopenharmony_ci	/* Ensure that we see all writes made by xprt_complete_rqst()
24738c2ecf20Sopenharmony_ci	 * before it changed req->rq_reply_bytes_recvd.
24748c2ecf20Sopenharmony_ci	 */
24758c2ecf20Sopenharmony_ci	smp_rmb();
24768c2ecf20Sopenharmony_ci
24778c2ecf20Sopenharmony_ci	req->rq_rcv_buf.len = req->rq_private_buf.len;
24788c2ecf20Sopenharmony_ci	trace_rpc_xdr_recvfrom(task, &req->rq_rcv_buf);
24798c2ecf20Sopenharmony_ci
24808c2ecf20Sopenharmony_ci	/* Check that the softirq receive buffer is valid */
24818c2ecf20Sopenharmony_ci	WARN_ON(memcmp(&req->rq_rcv_buf, &req->rq_private_buf,
24828c2ecf20Sopenharmony_ci				sizeof(req->rq_rcv_buf)) != 0);
24838c2ecf20Sopenharmony_ci
24848c2ecf20Sopenharmony_ci	xdr_init_decode(&xdr, &req->rq_rcv_buf,
24858c2ecf20Sopenharmony_ci			req->rq_rcv_buf.head[0].iov_base, req);
24868c2ecf20Sopenharmony_ci	err = rpc_decode_header(task, &xdr);
24878c2ecf20Sopenharmony_ciout:
24888c2ecf20Sopenharmony_ci	switch (err) {
24898c2ecf20Sopenharmony_ci	case 0:
24908c2ecf20Sopenharmony_ci		task->tk_action = rpc_exit_task;
24918c2ecf20Sopenharmony_ci		task->tk_status = rpcauth_unwrap_resp(task, &xdr);
24928c2ecf20Sopenharmony_ci		return;
24938c2ecf20Sopenharmony_ci	case -EAGAIN:
24948c2ecf20Sopenharmony_ci		task->tk_status = 0;
24958c2ecf20Sopenharmony_ci		if (task->tk_client->cl_discrtry)
24968c2ecf20Sopenharmony_ci			xprt_conditional_disconnect(req->rq_xprt,
24978c2ecf20Sopenharmony_ci						    req->rq_connect_cookie);
24988c2ecf20Sopenharmony_ci		task->tk_action = call_encode;
24998c2ecf20Sopenharmony_ci		rpc_check_timeout(task);
25008c2ecf20Sopenharmony_ci		break;
25018c2ecf20Sopenharmony_ci	case -EKEYREJECTED:
25028c2ecf20Sopenharmony_ci		task->tk_action = call_reserve;
25038c2ecf20Sopenharmony_ci		rpc_check_timeout(task);
25048c2ecf20Sopenharmony_ci		rpcauth_invalcred(task);
25058c2ecf20Sopenharmony_ci		/* Ensure we obtain a new XID if we retry! */
25068c2ecf20Sopenharmony_ci		xprt_release(task);
25078c2ecf20Sopenharmony_ci	}
25088c2ecf20Sopenharmony_ci}
25098c2ecf20Sopenharmony_ci
25108c2ecf20Sopenharmony_cistatic int
25118c2ecf20Sopenharmony_cirpc_encode_header(struct rpc_task *task, struct xdr_stream *xdr)
25128c2ecf20Sopenharmony_ci{
25138c2ecf20Sopenharmony_ci	struct rpc_clnt *clnt = task->tk_client;
25148c2ecf20Sopenharmony_ci	struct rpc_rqst	*req = task->tk_rqstp;
25158c2ecf20Sopenharmony_ci	__be32 *p;
25168c2ecf20Sopenharmony_ci	int error;
25178c2ecf20Sopenharmony_ci
25188c2ecf20Sopenharmony_ci	error = -EMSGSIZE;
25198c2ecf20Sopenharmony_ci	p = xdr_reserve_space(xdr, RPC_CALLHDRSIZE << 2);
25208c2ecf20Sopenharmony_ci	if (!p)
25218c2ecf20Sopenharmony_ci		goto out_fail;
25228c2ecf20Sopenharmony_ci	*p++ = req->rq_xid;
25238c2ecf20Sopenharmony_ci	*p++ = rpc_call;
25248c2ecf20Sopenharmony_ci	*p++ = cpu_to_be32(RPC_VERSION);
25258c2ecf20Sopenharmony_ci	*p++ = cpu_to_be32(clnt->cl_prog);
25268c2ecf20Sopenharmony_ci	*p++ = cpu_to_be32(clnt->cl_vers);
25278c2ecf20Sopenharmony_ci	*p   = cpu_to_be32(task->tk_msg.rpc_proc->p_proc);
25288c2ecf20Sopenharmony_ci
25298c2ecf20Sopenharmony_ci	error = rpcauth_marshcred(task, xdr);
25308c2ecf20Sopenharmony_ci	if (error < 0)
25318c2ecf20Sopenharmony_ci		goto out_fail;
25328c2ecf20Sopenharmony_ci	return 0;
25338c2ecf20Sopenharmony_ciout_fail:
25348c2ecf20Sopenharmony_ci	trace_rpc_bad_callhdr(task);
25358c2ecf20Sopenharmony_ci	rpc_call_rpcerror(task, error);
25368c2ecf20Sopenharmony_ci	return error;
25378c2ecf20Sopenharmony_ci}
25388c2ecf20Sopenharmony_ci
25398c2ecf20Sopenharmony_cistatic noinline int
25408c2ecf20Sopenharmony_cirpc_decode_header(struct rpc_task *task, struct xdr_stream *xdr)
25418c2ecf20Sopenharmony_ci{
25428c2ecf20Sopenharmony_ci	struct rpc_clnt *clnt = task->tk_client;
25438c2ecf20Sopenharmony_ci	int error;
25448c2ecf20Sopenharmony_ci	__be32 *p;
25458c2ecf20Sopenharmony_ci
25468c2ecf20Sopenharmony_ci	/* RFC-1014 says that the representation of XDR data must be a
25478c2ecf20Sopenharmony_ci	 * multiple of four bytes
25488c2ecf20Sopenharmony_ci	 * - if it isn't pointer subtraction in the NFS client may give
25498c2ecf20Sopenharmony_ci	 *   undefined results
25508c2ecf20Sopenharmony_ci	 */
25518c2ecf20Sopenharmony_ci	if (task->tk_rqstp->rq_rcv_buf.len & 3)
25528c2ecf20Sopenharmony_ci		goto out_unparsable;
25538c2ecf20Sopenharmony_ci
25548c2ecf20Sopenharmony_ci	p = xdr_inline_decode(xdr, 3 * sizeof(*p));
25558c2ecf20Sopenharmony_ci	if (!p)
25568c2ecf20Sopenharmony_ci		goto out_unparsable;
25578c2ecf20Sopenharmony_ci	p++;	/* skip XID */
25588c2ecf20Sopenharmony_ci	if (*p++ != rpc_reply)
25598c2ecf20Sopenharmony_ci		goto out_unparsable;
25608c2ecf20Sopenharmony_ci	if (*p++ != rpc_msg_accepted)
25618c2ecf20Sopenharmony_ci		goto out_msg_denied;
25628c2ecf20Sopenharmony_ci
25638c2ecf20Sopenharmony_ci	error = rpcauth_checkverf(task, xdr);
25648c2ecf20Sopenharmony_ci	if (error)
25658c2ecf20Sopenharmony_ci		goto out_verifier;
25668c2ecf20Sopenharmony_ci
25678c2ecf20Sopenharmony_ci	p = xdr_inline_decode(xdr, sizeof(*p));
25688c2ecf20Sopenharmony_ci	if (!p)
25698c2ecf20Sopenharmony_ci		goto out_unparsable;
25708c2ecf20Sopenharmony_ci	switch (*p) {
25718c2ecf20Sopenharmony_ci	case rpc_success:
25728c2ecf20Sopenharmony_ci		return 0;
25738c2ecf20Sopenharmony_ci	case rpc_prog_unavail:
25748c2ecf20Sopenharmony_ci		trace_rpc__prog_unavail(task);
25758c2ecf20Sopenharmony_ci		error = -EPFNOSUPPORT;
25768c2ecf20Sopenharmony_ci		goto out_err;
25778c2ecf20Sopenharmony_ci	case rpc_prog_mismatch:
25788c2ecf20Sopenharmony_ci		trace_rpc__prog_mismatch(task);
25798c2ecf20Sopenharmony_ci		error = -EPROTONOSUPPORT;
25808c2ecf20Sopenharmony_ci		goto out_err;
25818c2ecf20Sopenharmony_ci	case rpc_proc_unavail:
25828c2ecf20Sopenharmony_ci		trace_rpc__proc_unavail(task);
25838c2ecf20Sopenharmony_ci		error = -EOPNOTSUPP;
25848c2ecf20Sopenharmony_ci		goto out_err;
25858c2ecf20Sopenharmony_ci	case rpc_garbage_args:
25868c2ecf20Sopenharmony_ci	case rpc_system_err:
25878c2ecf20Sopenharmony_ci		trace_rpc__garbage_args(task);
25888c2ecf20Sopenharmony_ci		error = -EIO;
25898c2ecf20Sopenharmony_ci		break;
25908c2ecf20Sopenharmony_ci	default:
25918c2ecf20Sopenharmony_ci		goto out_unparsable;
25928c2ecf20Sopenharmony_ci	}
25938c2ecf20Sopenharmony_ci
25948c2ecf20Sopenharmony_ciout_garbage:
25958c2ecf20Sopenharmony_ci	clnt->cl_stats->rpcgarbage++;
25968c2ecf20Sopenharmony_ci	if (task->tk_garb_retry) {
25978c2ecf20Sopenharmony_ci		task->tk_garb_retry--;
25988c2ecf20Sopenharmony_ci		task->tk_action = call_encode;
25998c2ecf20Sopenharmony_ci		return -EAGAIN;
26008c2ecf20Sopenharmony_ci	}
26018c2ecf20Sopenharmony_ciout_err:
26028c2ecf20Sopenharmony_ci	rpc_call_rpcerror(task, error);
26038c2ecf20Sopenharmony_ci	return error;
26048c2ecf20Sopenharmony_ci
26058c2ecf20Sopenharmony_ciout_unparsable:
26068c2ecf20Sopenharmony_ci	trace_rpc__unparsable(task);
26078c2ecf20Sopenharmony_ci	error = -EIO;
26088c2ecf20Sopenharmony_ci	goto out_garbage;
26098c2ecf20Sopenharmony_ci
26108c2ecf20Sopenharmony_ciout_verifier:
26118c2ecf20Sopenharmony_ci	trace_rpc_bad_verifier(task);
26128c2ecf20Sopenharmony_ci	goto out_garbage;
26138c2ecf20Sopenharmony_ci
26148c2ecf20Sopenharmony_ciout_msg_denied:
26158c2ecf20Sopenharmony_ci	error = -EACCES;
26168c2ecf20Sopenharmony_ci	p = xdr_inline_decode(xdr, sizeof(*p));
26178c2ecf20Sopenharmony_ci	if (!p)
26188c2ecf20Sopenharmony_ci		goto out_unparsable;
26198c2ecf20Sopenharmony_ci	switch (*p++) {
26208c2ecf20Sopenharmony_ci	case rpc_auth_error:
26218c2ecf20Sopenharmony_ci		break;
26228c2ecf20Sopenharmony_ci	case rpc_mismatch:
26238c2ecf20Sopenharmony_ci		trace_rpc__mismatch(task);
26248c2ecf20Sopenharmony_ci		error = -EPROTONOSUPPORT;
26258c2ecf20Sopenharmony_ci		goto out_err;
26268c2ecf20Sopenharmony_ci	default:
26278c2ecf20Sopenharmony_ci		goto out_unparsable;
26288c2ecf20Sopenharmony_ci	}
26298c2ecf20Sopenharmony_ci
26308c2ecf20Sopenharmony_ci	p = xdr_inline_decode(xdr, sizeof(*p));
26318c2ecf20Sopenharmony_ci	if (!p)
26328c2ecf20Sopenharmony_ci		goto out_unparsable;
26338c2ecf20Sopenharmony_ci	switch (*p++) {
26348c2ecf20Sopenharmony_ci	case rpc_autherr_rejectedcred:
26358c2ecf20Sopenharmony_ci	case rpc_autherr_rejectedverf:
26368c2ecf20Sopenharmony_ci	case rpcsec_gsserr_credproblem:
26378c2ecf20Sopenharmony_ci	case rpcsec_gsserr_ctxproblem:
26388c2ecf20Sopenharmony_ci		rpcauth_invalcred(task);
26398c2ecf20Sopenharmony_ci		if (!task->tk_cred_retry)
26408c2ecf20Sopenharmony_ci			break;
26418c2ecf20Sopenharmony_ci		task->tk_cred_retry--;
26428c2ecf20Sopenharmony_ci		trace_rpc__stale_creds(task);
26438c2ecf20Sopenharmony_ci		return -EKEYREJECTED;
26448c2ecf20Sopenharmony_ci	case rpc_autherr_badcred:
26458c2ecf20Sopenharmony_ci	case rpc_autherr_badverf:
26468c2ecf20Sopenharmony_ci		/* possibly garbled cred/verf? */
26478c2ecf20Sopenharmony_ci		if (!task->tk_garb_retry)
26488c2ecf20Sopenharmony_ci			break;
26498c2ecf20Sopenharmony_ci		task->tk_garb_retry--;
26508c2ecf20Sopenharmony_ci		trace_rpc__bad_creds(task);
26518c2ecf20Sopenharmony_ci		task->tk_action = call_encode;
26528c2ecf20Sopenharmony_ci		return -EAGAIN;
26538c2ecf20Sopenharmony_ci	case rpc_autherr_tooweak:
26548c2ecf20Sopenharmony_ci		trace_rpc__auth_tooweak(task);
26558c2ecf20Sopenharmony_ci		pr_warn("RPC: server %s requires stronger authentication.\n",
26568c2ecf20Sopenharmony_ci			task->tk_xprt->servername);
26578c2ecf20Sopenharmony_ci		break;
26588c2ecf20Sopenharmony_ci	default:
26598c2ecf20Sopenharmony_ci		goto out_unparsable;
26608c2ecf20Sopenharmony_ci	}
26618c2ecf20Sopenharmony_ci	goto out_err;
26628c2ecf20Sopenharmony_ci}
26638c2ecf20Sopenharmony_ci
26648c2ecf20Sopenharmony_cistatic void rpcproc_encode_null(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
26658c2ecf20Sopenharmony_ci		const void *obj)
26668c2ecf20Sopenharmony_ci{
26678c2ecf20Sopenharmony_ci}
26688c2ecf20Sopenharmony_ci
26698c2ecf20Sopenharmony_cistatic int rpcproc_decode_null(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
26708c2ecf20Sopenharmony_ci		void *obj)
26718c2ecf20Sopenharmony_ci{
26728c2ecf20Sopenharmony_ci	return 0;
26738c2ecf20Sopenharmony_ci}
26748c2ecf20Sopenharmony_ci
26758c2ecf20Sopenharmony_cistatic const struct rpc_procinfo rpcproc_null = {
26768c2ecf20Sopenharmony_ci	.p_encode = rpcproc_encode_null,
26778c2ecf20Sopenharmony_ci	.p_decode = rpcproc_decode_null,
26788c2ecf20Sopenharmony_ci};
26798c2ecf20Sopenharmony_ci
26808c2ecf20Sopenharmony_cistatic int rpc_ping(struct rpc_clnt *clnt)
26818c2ecf20Sopenharmony_ci{
26828c2ecf20Sopenharmony_ci	struct rpc_message msg = {
26838c2ecf20Sopenharmony_ci		.rpc_proc = &rpcproc_null,
26848c2ecf20Sopenharmony_ci	};
26858c2ecf20Sopenharmony_ci	int err;
26868c2ecf20Sopenharmony_ci	err = rpc_call_sync(clnt, &msg, RPC_TASK_SOFT | RPC_TASK_SOFTCONN |
26878c2ecf20Sopenharmony_ci			    RPC_TASK_NULLCREDS);
26888c2ecf20Sopenharmony_ci	return err;
26898c2ecf20Sopenharmony_ci}
26908c2ecf20Sopenharmony_ci
26918c2ecf20Sopenharmony_cistatic
26928c2ecf20Sopenharmony_cistruct rpc_task *rpc_call_null_helper(struct rpc_clnt *clnt,
26938c2ecf20Sopenharmony_ci		struct rpc_xprt *xprt, struct rpc_cred *cred, int flags,
26948c2ecf20Sopenharmony_ci		const struct rpc_call_ops *ops, void *data)
26958c2ecf20Sopenharmony_ci{
26968c2ecf20Sopenharmony_ci	struct rpc_message msg = {
26978c2ecf20Sopenharmony_ci		.rpc_proc = &rpcproc_null,
26988c2ecf20Sopenharmony_ci	};
26998c2ecf20Sopenharmony_ci	struct rpc_task_setup task_setup_data = {
27008c2ecf20Sopenharmony_ci		.rpc_client = clnt,
27018c2ecf20Sopenharmony_ci		.rpc_xprt = xprt,
27028c2ecf20Sopenharmony_ci		.rpc_message = &msg,
27038c2ecf20Sopenharmony_ci		.rpc_op_cred = cred,
27048c2ecf20Sopenharmony_ci		.callback_ops = (ops != NULL) ? ops : &rpc_default_ops,
27058c2ecf20Sopenharmony_ci		.callback_data = data,
27068c2ecf20Sopenharmony_ci		.flags = flags | RPC_TASK_SOFT | RPC_TASK_SOFTCONN |
27078c2ecf20Sopenharmony_ci			 RPC_TASK_NULLCREDS,
27088c2ecf20Sopenharmony_ci	};
27098c2ecf20Sopenharmony_ci
27108c2ecf20Sopenharmony_ci	return rpc_run_task(&task_setup_data);
27118c2ecf20Sopenharmony_ci}
27128c2ecf20Sopenharmony_ci
27138c2ecf20Sopenharmony_cistruct rpc_task *rpc_call_null(struct rpc_clnt *clnt, struct rpc_cred *cred, int flags)
27148c2ecf20Sopenharmony_ci{
27158c2ecf20Sopenharmony_ci	return rpc_call_null_helper(clnt, NULL, cred, flags, NULL, NULL);
27168c2ecf20Sopenharmony_ci}
27178c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_call_null);
27188c2ecf20Sopenharmony_ci
27198c2ecf20Sopenharmony_cistruct rpc_cb_add_xprt_calldata {
27208c2ecf20Sopenharmony_ci	struct rpc_xprt_switch *xps;
27218c2ecf20Sopenharmony_ci	struct rpc_xprt *xprt;
27228c2ecf20Sopenharmony_ci};
27238c2ecf20Sopenharmony_ci
27248c2ecf20Sopenharmony_cistatic void rpc_cb_add_xprt_done(struct rpc_task *task, void *calldata)
27258c2ecf20Sopenharmony_ci{
27268c2ecf20Sopenharmony_ci	struct rpc_cb_add_xprt_calldata *data = calldata;
27278c2ecf20Sopenharmony_ci
27288c2ecf20Sopenharmony_ci	if (task->tk_status == 0)
27298c2ecf20Sopenharmony_ci		rpc_xprt_switch_add_xprt(data->xps, data->xprt);
27308c2ecf20Sopenharmony_ci}
27318c2ecf20Sopenharmony_ci
27328c2ecf20Sopenharmony_cistatic void rpc_cb_add_xprt_release(void *calldata)
27338c2ecf20Sopenharmony_ci{
27348c2ecf20Sopenharmony_ci	struct rpc_cb_add_xprt_calldata *data = calldata;
27358c2ecf20Sopenharmony_ci
27368c2ecf20Sopenharmony_ci	xprt_put(data->xprt);
27378c2ecf20Sopenharmony_ci	xprt_switch_put(data->xps);
27388c2ecf20Sopenharmony_ci	kfree(data);
27398c2ecf20Sopenharmony_ci}
27408c2ecf20Sopenharmony_ci
27418c2ecf20Sopenharmony_cistatic const struct rpc_call_ops rpc_cb_add_xprt_call_ops = {
27428c2ecf20Sopenharmony_ci	.rpc_call_done = rpc_cb_add_xprt_done,
27438c2ecf20Sopenharmony_ci	.rpc_release = rpc_cb_add_xprt_release,
27448c2ecf20Sopenharmony_ci};
27458c2ecf20Sopenharmony_ci
27468c2ecf20Sopenharmony_ci/**
27478c2ecf20Sopenharmony_ci * rpc_clnt_test_and_add_xprt - Test and add a new transport to a rpc_clnt
27488c2ecf20Sopenharmony_ci * @clnt: pointer to struct rpc_clnt
27498c2ecf20Sopenharmony_ci * @xps: pointer to struct rpc_xprt_switch,
27508c2ecf20Sopenharmony_ci * @xprt: pointer struct rpc_xprt
27518c2ecf20Sopenharmony_ci * @dummy: unused
27528c2ecf20Sopenharmony_ci */
27538c2ecf20Sopenharmony_ciint rpc_clnt_test_and_add_xprt(struct rpc_clnt *clnt,
27548c2ecf20Sopenharmony_ci		struct rpc_xprt_switch *xps, struct rpc_xprt *xprt,
27558c2ecf20Sopenharmony_ci		void *dummy)
27568c2ecf20Sopenharmony_ci{
27578c2ecf20Sopenharmony_ci	struct rpc_cb_add_xprt_calldata *data;
27588c2ecf20Sopenharmony_ci	struct rpc_task *task;
27598c2ecf20Sopenharmony_ci
27608c2ecf20Sopenharmony_ci	data = kmalloc(sizeof(*data), GFP_NOFS);
27618c2ecf20Sopenharmony_ci	if (!data)
27628c2ecf20Sopenharmony_ci		return -ENOMEM;
27638c2ecf20Sopenharmony_ci	data->xps = xprt_switch_get(xps);
27648c2ecf20Sopenharmony_ci	data->xprt = xprt_get(xprt);
27658c2ecf20Sopenharmony_ci	if (rpc_xprt_switch_has_addr(data->xps, (struct sockaddr *)&xprt->addr)) {
27668c2ecf20Sopenharmony_ci		rpc_cb_add_xprt_release(data);
27678c2ecf20Sopenharmony_ci		goto success;
27688c2ecf20Sopenharmony_ci	}
27698c2ecf20Sopenharmony_ci
27708c2ecf20Sopenharmony_ci	task = rpc_call_null_helper(clnt, xprt, NULL, RPC_TASK_ASYNC,
27718c2ecf20Sopenharmony_ci			&rpc_cb_add_xprt_call_ops, data);
27728c2ecf20Sopenharmony_ci
27738c2ecf20Sopenharmony_ci	rpc_put_task(task);
27748c2ecf20Sopenharmony_cisuccess:
27758c2ecf20Sopenharmony_ci	return 1;
27768c2ecf20Sopenharmony_ci}
27778c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_clnt_test_and_add_xprt);
27788c2ecf20Sopenharmony_ci
27798c2ecf20Sopenharmony_ci/**
27808c2ecf20Sopenharmony_ci * rpc_clnt_setup_test_and_add_xprt()
27818c2ecf20Sopenharmony_ci *
27828c2ecf20Sopenharmony_ci * This is an rpc_clnt_add_xprt setup() function which returns 1 so:
27838c2ecf20Sopenharmony_ci *   1) caller of the test function must dereference the rpc_xprt_switch
27848c2ecf20Sopenharmony_ci *   and the rpc_xprt.
27858c2ecf20Sopenharmony_ci *   2) test function must call rpc_xprt_switch_add_xprt, usually in
27868c2ecf20Sopenharmony_ci *   the rpc_call_done routine.
27878c2ecf20Sopenharmony_ci *
27888c2ecf20Sopenharmony_ci * Upon success (return of 1), the test function adds the new
27898c2ecf20Sopenharmony_ci * transport to the rpc_clnt xprt switch
27908c2ecf20Sopenharmony_ci *
27918c2ecf20Sopenharmony_ci * @clnt: struct rpc_clnt to get the new transport
27928c2ecf20Sopenharmony_ci * @xps:  the rpc_xprt_switch to hold the new transport
27938c2ecf20Sopenharmony_ci * @xprt: the rpc_xprt to test
27948c2ecf20Sopenharmony_ci * @data: a struct rpc_add_xprt_test pointer that holds the test function
27958c2ecf20Sopenharmony_ci *        and test function call data
27968c2ecf20Sopenharmony_ci */
27978c2ecf20Sopenharmony_ciint rpc_clnt_setup_test_and_add_xprt(struct rpc_clnt *clnt,
27988c2ecf20Sopenharmony_ci				     struct rpc_xprt_switch *xps,
27998c2ecf20Sopenharmony_ci				     struct rpc_xprt *xprt,
28008c2ecf20Sopenharmony_ci				     void *data)
28018c2ecf20Sopenharmony_ci{
28028c2ecf20Sopenharmony_ci	struct rpc_task *task;
28038c2ecf20Sopenharmony_ci	struct rpc_add_xprt_test *xtest = (struct rpc_add_xprt_test *)data;
28048c2ecf20Sopenharmony_ci	int status = -EADDRINUSE;
28058c2ecf20Sopenharmony_ci
28068c2ecf20Sopenharmony_ci	xprt = xprt_get(xprt);
28078c2ecf20Sopenharmony_ci	xprt_switch_get(xps);
28088c2ecf20Sopenharmony_ci
28098c2ecf20Sopenharmony_ci	if (rpc_xprt_switch_has_addr(xps, (struct sockaddr *)&xprt->addr))
28108c2ecf20Sopenharmony_ci		goto out_err;
28118c2ecf20Sopenharmony_ci
28128c2ecf20Sopenharmony_ci	/* Test the connection */
28138c2ecf20Sopenharmony_ci	task = rpc_call_null_helper(clnt, xprt, NULL, 0, NULL, NULL);
28148c2ecf20Sopenharmony_ci	if (IS_ERR(task)) {
28158c2ecf20Sopenharmony_ci		status = PTR_ERR(task);
28168c2ecf20Sopenharmony_ci		goto out_err;
28178c2ecf20Sopenharmony_ci	}
28188c2ecf20Sopenharmony_ci	status = task->tk_status;
28198c2ecf20Sopenharmony_ci	rpc_put_task(task);
28208c2ecf20Sopenharmony_ci
28218c2ecf20Sopenharmony_ci	if (status < 0)
28228c2ecf20Sopenharmony_ci		goto out_err;
28238c2ecf20Sopenharmony_ci
28248c2ecf20Sopenharmony_ci	/* rpc_xprt_switch and rpc_xprt are deferrenced by add_xprt_test() */
28258c2ecf20Sopenharmony_ci	xtest->add_xprt_test(clnt, xprt, xtest->data);
28268c2ecf20Sopenharmony_ci
28278c2ecf20Sopenharmony_ci	xprt_put(xprt);
28288c2ecf20Sopenharmony_ci	xprt_switch_put(xps);
28298c2ecf20Sopenharmony_ci
28308c2ecf20Sopenharmony_ci	/* so that rpc_clnt_add_xprt does not call rpc_xprt_switch_add_xprt */
28318c2ecf20Sopenharmony_ci	return 1;
28328c2ecf20Sopenharmony_ciout_err:
28338c2ecf20Sopenharmony_ci	xprt_put(xprt);
28348c2ecf20Sopenharmony_ci	xprt_switch_put(xps);
28358c2ecf20Sopenharmony_ci	pr_info("RPC:   rpc_clnt_test_xprt failed: %d addr %s not added\n",
28368c2ecf20Sopenharmony_ci		status, xprt->address_strings[RPC_DISPLAY_ADDR]);
28378c2ecf20Sopenharmony_ci	return status;
28388c2ecf20Sopenharmony_ci}
28398c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_clnt_setup_test_and_add_xprt);
28408c2ecf20Sopenharmony_ci
28418c2ecf20Sopenharmony_ci/**
28428c2ecf20Sopenharmony_ci * rpc_clnt_add_xprt - Add a new transport to a rpc_clnt
28438c2ecf20Sopenharmony_ci * @clnt: pointer to struct rpc_clnt
28448c2ecf20Sopenharmony_ci * @xprtargs: pointer to struct xprt_create
28458c2ecf20Sopenharmony_ci * @setup: callback to test and/or set up the connection
28468c2ecf20Sopenharmony_ci * @data: pointer to setup function data
28478c2ecf20Sopenharmony_ci *
28488c2ecf20Sopenharmony_ci * Creates a new transport using the parameters set in args and
28498c2ecf20Sopenharmony_ci * adds it to clnt.
28508c2ecf20Sopenharmony_ci * If ping is set, then test that connectivity succeeds before
28518c2ecf20Sopenharmony_ci * adding the new transport.
28528c2ecf20Sopenharmony_ci *
28538c2ecf20Sopenharmony_ci */
28548c2ecf20Sopenharmony_ciint rpc_clnt_add_xprt(struct rpc_clnt *clnt,
28558c2ecf20Sopenharmony_ci		struct xprt_create *xprtargs,
28568c2ecf20Sopenharmony_ci		int (*setup)(struct rpc_clnt *,
28578c2ecf20Sopenharmony_ci			struct rpc_xprt_switch *,
28588c2ecf20Sopenharmony_ci			struct rpc_xprt *,
28598c2ecf20Sopenharmony_ci			void *),
28608c2ecf20Sopenharmony_ci		void *data)
28618c2ecf20Sopenharmony_ci{
28628c2ecf20Sopenharmony_ci	struct rpc_xprt_switch *xps;
28638c2ecf20Sopenharmony_ci	struct rpc_xprt *xprt;
28648c2ecf20Sopenharmony_ci	unsigned long connect_timeout;
28658c2ecf20Sopenharmony_ci	unsigned long reconnect_timeout;
28668c2ecf20Sopenharmony_ci	unsigned char resvport, reuseport;
28678c2ecf20Sopenharmony_ci	int ret = 0;
28688c2ecf20Sopenharmony_ci
28698c2ecf20Sopenharmony_ci	rcu_read_lock();
28708c2ecf20Sopenharmony_ci	xps = xprt_switch_get(rcu_dereference(clnt->cl_xpi.xpi_xpswitch));
28718c2ecf20Sopenharmony_ci	xprt = xprt_iter_xprt(&clnt->cl_xpi);
28728c2ecf20Sopenharmony_ci	if (xps == NULL || xprt == NULL) {
28738c2ecf20Sopenharmony_ci		rcu_read_unlock();
28748c2ecf20Sopenharmony_ci		xprt_switch_put(xps);
28758c2ecf20Sopenharmony_ci		return -EAGAIN;
28768c2ecf20Sopenharmony_ci	}
28778c2ecf20Sopenharmony_ci	resvport = xprt->resvport;
28788c2ecf20Sopenharmony_ci	reuseport = xprt->reuseport;
28798c2ecf20Sopenharmony_ci	connect_timeout = xprt->connect_timeout;
28808c2ecf20Sopenharmony_ci	reconnect_timeout = xprt->max_reconnect_timeout;
28818c2ecf20Sopenharmony_ci	rcu_read_unlock();
28828c2ecf20Sopenharmony_ci
28838c2ecf20Sopenharmony_ci	xprt = xprt_create_transport(xprtargs);
28848c2ecf20Sopenharmony_ci	if (IS_ERR(xprt)) {
28858c2ecf20Sopenharmony_ci		ret = PTR_ERR(xprt);
28868c2ecf20Sopenharmony_ci		goto out_put_switch;
28878c2ecf20Sopenharmony_ci	}
28888c2ecf20Sopenharmony_ci	xprt->resvport = resvport;
28898c2ecf20Sopenharmony_ci	xprt->reuseport = reuseport;
28908c2ecf20Sopenharmony_ci	if (xprt->ops->set_connect_timeout != NULL)
28918c2ecf20Sopenharmony_ci		xprt->ops->set_connect_timeout(xprt,
28928c2ecf20Sopenharmony_ci				connect_timeout,
28938c2ecf20Sopenharmony_ci				reconnect_timeout);
28948c2ecf20Sopenharmony_ci
28958c2ecf20Sopenharmony_ci	rpc_xprt_switch_set_roundrobin(xps);
28968c2ecf20Sopenharmony_ci	if (setup) {
28978c2ecf20Sopenharmony_ci		ret = setup(clnt, xps, xprt, data);
28988c2ecf20Sopenharmony_ci		if (ret != 0)
28998c2ecf20Sopenharmony_ci			goto out_put_xprt;
29008c2ecf20Sopenharmony_ci	}
29018c2ecf20Sopenharmony_ci	rpc_xprt_switch_add_xprt(xps, xprt);
29028c2ecf20Sopenharmony_ciout_put_xprt:
29038c2ecf20Sopenharmony_ci	xprt_put(xprt);
29048c2ecf20Sopenharmony_ciout_put_switch:
29058c2ecf20Sopenharmony_ci	xprt_switch_put(xps);
29068c2ecf20Sopenharmony_ci	return ret;
29078c2ecf20Sopenharmony_ci}
29088c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_clnt_add_xprt);
29098c2ecf20Sopenharmony_ci
29108c2ecf20Sopenharmony_cistruct connect_timeout_data {
29118c2ecf20Sopenharmony_ci	unsigned long connect_timeout;
29128c2ecf20Sopenharmony_ci	unsigned long reconnect_timeout;
29138c2ecf20Sopenharmony_ci};
29148c2ecf20Sopenharmony_ci
29158c2ecf20Sopenharmony_cistatic int
29168c2ecf20Sopenharmony_cirpc_xprt_set_connect_timeout(struct rpc_clnt *clnt,
29178c2ecf20Sopenharmony_ci		struct rpc_xprt *xprt,
29188c2ecf20Sopenharmony_ci		void *data)
29198c2ecf20Sopenharmony_ci{
29208c2ecf20Sopenharmony_ci	struct connect_timeout_data *timeo = data;
29218c2ecf20Sopenharmony_ci
29228c2ecf20Sopenharmony_ci	if (xprt->ops->set_connect_timeout)
29238c2ecf20Sopenharmony_ci		xprt->ops->set_connect_timeout(xprt,
29248c2ecf20Sopenharmony_ci				timeo->connect_timeout,
29258c2ecf20Sopenharmony_ci				timeo->reconnect_timeout);
29268c2ecf20Sopenharmony_ci	return 0;
29278c2ecf20Sopenharmony_ci}
29288c2ecf20Sopenharmony_ci
29298c2ecf20Sopenharmony_civoid
29308c2ecf20Sopenharmony_cirpc_set_connect_timeout(struct rpc_clnt *clnt,
29318c2ecf20Sopenharmony_ci		unsigned long connect_timeout,
29328c2ecf20Sopenharmony_ci		unsigned long reconnect_timeout)
29338c2ecf20Sopenharmony_ci{
29348c2ecf20Sopenharmony_ci	struct connect_timeout_data timeout = {
29358c2ecf20Sopenharmony_ci		.connect_timeout = connect_timeout,
29368c2ecf20Sopenharmony_ci		.reconnect_timeout = reconnect_timeout,
29378c2ecf20Sopenharmony_ci	};
29388c2ecf20Sopenharmony_ci	rpc_clnt_iterate_for_each_xprt(clnt,
29398c2ecf20Sopenharmony_ci			rpc_xprt_set_connect_timeout,
29408c2ecf20Sopenharmony_ci			&timeout);
29418c2ecf20Sopenharmony_ci}
29428c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_set_connect_timeout);
29438c2ecf20Sopenharmony_ci
29448c2ecf20Sopenharmony_civoid rpc_clnt_xprt_switch_put(struct rpc_clnt *clnt)
29458c2ecf20Sopenharmony_ci{
29468c2ecf20Sopenharmony_ci	rcu_read_lock();
29478c2ecf20Sopenharmony_ci	xprt_switch_put(rcu_dereference(clnt->cl_xpi.xpi_xpswitch));
29488c2ecf20Sopenharmony_ci	rcu_read_unlock();
29498c2ecf20Sopenharmony_ci}
29508c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_clnt_xprt_switch_put);
29518c2ecf20Sopenharmony_ci
29528c2ecf20Sopenharmony_civoid rpc_clnt_xprt_switch_add_xprt(struct rpc_clnt *clnt, struct rpc_xprt *xprt)
29538c2ecf20Sopenharmony_ci{
29548c2ecf20Sopenharmony_ci	rcu_read_lock();
29558c2ecf20Sopenharmony_ci	rpc_xprt_switch_add_xprt(rcu_dereference(clnt->cl_xpi.xpi_xpswitch),
29568c2ecf20Sopenharmony_ci				 xprt);
29578c2ecf20Sopenharmony_ci	rcu_read_unlock();
29588c2ecf20Sopenharmony_ci}
29598c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_clnt_xprt_switch_add_xprt);
29608c2ecf20Sopenharmony_ci
29618c2ecf20Sopenharmony_cibool rpc_clnt_xprt_switch_has_addr(struct rpc_clnt *clnt,
29628c2ecf20Sopenharmony_ci				   const struct sockaddr *sap)
29638c2ecf20Sopenharmony_ci{
29648c2ecf20Sopenharmony_ci	struct rpc_xprt_switch *xps;
29658c2ecf20Sopenharmony_ci	bool ret;
29668c2ecf20Sopenharmony_ci
29678c2ecf20Sopenharmony_ci	rcu_read_lock();
29688c2ecf20Sopenharmony_ci	xps = rcu_dereference(clnt->cl_xpi.xpi_xpswitch);
29698c2ecf20Sopenharmony_ci	ret = rpc_xprt_switch_has_addr(xps, sap);
29708c2ecf20Sopenharmony_ci	rcu_read_unlock();
29718c2ecf20Sopenharmony_ci	return ret;
29728c2ecf20Sopenharmony_ci}
29738c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_clnt_xprt_switch_has_addr);
29748c2ecf20Sopenharmony_ci
29758c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
29768c2ecf20Sopenharmony_cistatic void rpc_show_header(void)
29778c2ecf20Sopenharmony_ci{
29788c2ecf20Sopenharmony_ci	printk(KERN_INFO "-pid- flgs status -client- --rqstp- "
29798c2ecf20Sopenharmony_ci		"-timeout ---ops--\n");
29808c2ecf20Sopenharmony_ci}
29818c2ecf20Sopenharmony_ci
29828c2ecf20Sopenharmony_cistatic void rpc_show_task(const struct rpc_clnt *clnt,
29838c2ecf20Sopenharmony_ci			  const struct rpc_task *task)
29848c2ecf20Sopenharmony_ci{
29858c2ecf20Sopenharmony_ci	const char *rpc_waitq = "none";
29868c2ecf20Sopenharmony_ci
29878c2ecf20Sopenharmony_ci	if (RPC_IS_QUEUED(task))
29888c2ecf20Sopenharmony_ci		rpc_waitq = rpc_qname(task->tk_waitqueue);
29898c2ecf20Sopenharmony_ci
29908c2ecf20Sopenharmony_ci	printk(KERN_INFO "%5u %04x %6d %8p %8p %8ld %8p %sv%u %s a:%ps q:%s\n",
29918c2ecf20Sopenharmony_ci		task->tk_pid, task->tk_flags, task->tk_status,
29928c2ecf20Sopenharmony_ci		clnt, task->tk_rqstp, rpc_task_timeout(task), task->tk_ops,
29938c2ecf20Sopenharmony_ci		clnt->cl_program->name, clnt->cl_vers, rpc_proc_name(task),
29948c2ecf20Sopenharmony_ci		task->tk_action, rpc_waitq);
29958c2ecf20Sopenharmony_ci}
29968c2ecf20Sopenharmony_ci
29978c2ecf20Sopenharmony_civoid rpc_show_tasks(struct net *net)
29988c2ecf20Sopenharmony_ci{
29998c2ecf20Sopenharmony_ci	struct rpc_clnt *clnt;
30008c2ecf20Sopenharmony_ci	struct rpc_task *task;
30018c2ecf20Sopenharmony_ci	int header = 0;
30028c2ecf20Sopenharmony_ci	struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
30038c2ecf20Sopenharmony_ci
30048c2ecf20Sopenharmony_ci	spin_lock(&sn->rpc_client_lock);
30058c2ecf20Sopenharmony_ci	list_for_each_entry(clnt, &sn->all_clients, cl_clients) {
30068c2ecf20Sopenharmony_ci		spin_lock(&clnt->cl_lock);
30078c2ecf20Sopenharmony_ci		list_for_each_entry(task, &clnt->cl_tasks, tk_task) {
30088c2ecf20Sopenharmony_ci			if (!header) {
30098c2ecf20Sopenharmony_ci				rpc_show_header();
30108c2ecf20Sopenharmony_ci				header++;
30118c2ecf20Sopenharmony_ci			}
30128c2ecf20Sopenharmony_ci			rpc_show_task(clnt, task);
30138c2ecf20Sopenharmony_ci		}
30148c2ecf20Sopenharmony_ci		spin_unlock(&clnt->cl_lock);
30158c2ecf20Sopenharmony_ci	}
30168c2ecf20Sopenharmony_ci	spin_unlock(&sn->rpc_client_lock);
30178c2ecf20Sopenharmony_ci}
30188c2ecf20Sopenharmony_ci#endif
30198c2ecf20Sopenharmony_ci
30208c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_SUNRPC_SWAP)
30218c2ecf20Sopenharmony_cistatic int
30228c2ecf20Sopenharmony_cirpc_clnt_swap_activate_callback(struct rpc_clnt *clnt,
30238c2ecf20Sopenharmony_ci		struct rpc_xprt *xprt,
30248c2ecf20Sopenharmony_ci		void *dummy)
30258c2ecf20Sopenharmony_ci{
30268c2ecf20Sopenharmony_ci	return xprt_enable_swap(xprt);
30278c2ecf20Sopenharmony_ci}
30288c2ecf20Sopenharmony_ci
30298c2ecf20Sopenharmony_ciint
30308c2ecf20Sopenharmony_cirpc_clnt_swap_activate(struct rpc_clnt *clnt)
30318c2ecf20Sopenharmony_ci{
30328c2ecf20Sopenharmony_ci	while (clnt != clnt->cl_parent)
30338c2ecf20Sopenharmony_ci		clnt = clnt->cl_parent;
30348c2ecf20Sopenharmony_ci	if (atomic_inc_return(&clnt->cl_swapper) == 1)
30358c2ecf20Sopenharmony_ci		return rpc_clnt_iterate_for_each_xprt(clnt,
30368c2ecf20Sopenharmony_ci				rpc_clnt_swap_activate_callback, NULL);
30378c2ecf20Sopenharmony_ci	return 0;
30388c2ecf20Sopenharmony_ci}
30398c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_clnt_swap_activate);
30408c2ecf20Sopenharmony_ci
30418c2ecf20Sopenharmony_cistatic int
30428c2ecf20Sopenharmony_cirpc_clnt_swap_deactivate_callback(struct rpc_clnt *clnt,
30438c2ecf20Sopenharmony_ci		struct rpc_xprt *xprt,
30448c2ecf20Sopenharmony_ci		void *dummy)
30458c2ecf20Sopenharmony_ci{
30468c2ecf20Sopenharmony_ci	xprt_disable_swap(xprt);
30478c2ecf20Sopenharmony_ci	return 0;
30488c2ecf20Sopenharmony_ci}
30498c2ecf20Sopenharmony_ci
30508c2ecf20Sopenharmony_civoid
30518c2ecf20Sopenharmony_cirpc_clnt_swap_deactivate(struct rpc_clnt *clnt)
30528c2ecf20Sopenharmony_ci{
30538c2ecf20Sopenharmony_ci	while (clnt != clnt->cl_parent)
30548c2ecf20Sopenharmony_ci		clnt = clnt->cl_parent;
30558c2ecf20Sopenharmony_ci	if (atomic_dec_if_positive(&clnt->cl_swapper) == 0)
30568c2ecf20Sopenharmony_ci		rpc_clnt_iterate_for_each_xprt(clnt,
30578c2ecf20Sopenharmony_ci				rpc_clnt_swap_deactivate_callback, NULL);
30588c2ecf20Sopenharmony_ci}
30598c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_clnt_swap_deactivate);
30608c2ecf20Sopenharmony_ci#endif /* CONFIG_SUNRPC_SWAP */
3061