xref: /openbmc/linux/net/sunrpc/clnt.c (revision 7e24a55b2122746c2eef192296fc84624354f895)
1457c8996SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
21da177e4SLinus Torvalds /*
355aa4f58SChuck Lever  *  linux/net/sunrpc/clnt.c
41da177e4SLinus Torvalds  *
51da177e4SLinus Torvalds  *  This file contains the high-level RPC interface.
61da177e4SLinus Torvalds  *  It is modeled as a finite state machine to support both synchronous
71da177e4SLinus Torvalds  *  and asynchronous requests.
81da177e4SLinus Torvalds  *
91da177e4SLinus Torvalds  *  -	RPC header generation and argument serialization.
101da177e4SLinus Torvalds  *  -	Credential refresh.
111da177e4SLinus Torvalds  *  -	TCP connect handling.
121da177e4SLinus Torvalds  *  -	Retry of operation when it is suspected the operation failed because
131da177e4SLinus Torvalds  *	of uid squashing on the server, or when the credentials were stale
141da177e4SLinus Torvalds  *	and need to be refreshed, or when a packet was damaged in transit.
151da177e4SLinus Torvalds  *	This may be have to be moved to the VFS layer.
161da177e4SLinus Torvalds  *
171da177e4SLinus Torvalds  *  Copyright (C) 1992,1993 Rick Sladkey <jrs@world.std.com>
181da177e4SLinus Torvalds  *  Copyright (C) 1995,1996 Olaf Kirch <okir@monad.swb.de>
191da177e4SLinus Torvalds  */
201da177e4SLinus Torvalds 
211da177e4SLinus Torvalds 
221da177e4SLinus Torvalds #include <linux/module.h>
231da177e4SLinus Torvalds #include <linux/types.h>
24cb3997b5SChuck Lever #include <linux/kallsyms.h>
251da177e4SLinus Torvalds #include <linux/mm.h>
2623ac6581STrond Myklebust #include <linux/namei.h>
2723ac6581STrond Myklebust #include <linux/mount.h>
281da177e4SLinus Torvalds #include <linux/slab.h>
2940b00b6bSTrond Myklebust #include <linux/rcupdate.h>
301da177e4SLinus Torvalds #include <linux/utsname.h>
3111c556b3SChuck Lever #include <linux/workqueue.h>
32176e21eeSChuck Lever #include <linux/in.h>
33510deb0dSChuck Lever #include <linux/in6.h>
34176e21eeSChuck Lever #include <linux/un.h>
351da177e4SLinus Torvalds 
361da177e4SLinus Torvalds #include <linux/sunrpc/clnt.h>
375976687aSJeff Layton #include <linux/sunrpc/addr.h>
381da177e4SLinus Torvalds #include <linux/sunrpc/rpc_pipe_fs.h>
3911c556b3SChuck Lever #include <linux/sunrpc/metrics.h>
4055ae1aabSRicardo Labiaga #include <linux/sunrpc/bc_xprt.h>
415753cba1SSteve Dickson #include <trace/events/sunrpc.h>
421da177e4SLinus Torvalds 
4355ae1aabSRicardo Labiaga #include "sunrpc.h"
44c5a382ebSOlga Kornievskaia #include "sysfs.h"
4570abc49bSStanislav Kinsbursky #include "netns.h"
461da177e4SLinus Torvalds 
47f895b252SJeff Layton #if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
481da177e4SLinus Torvalds # define RPCDBG_FACILITY	RPCDBG_CALL
491da177e4SLinus Torvalds #endif
501da177e4SLinus Torvalds 
51188fef11STrond Myklebust /*
52188fef11STrond Myklebust  * All RPC clients are linked into this list
53188fef11STrond Myklebust  */
54188fef11STrond Myklebust 
551da177e4SLinus Torvalds static DECLARE_WAIT_QUEUE_HEAD(destroy_wait);
561da177e4SLinus Torvalds 
571da177e4SLinus Torvalds 
581da177e4SLinus Torvalds static void	call_start(struct rpc_task *task);
591da177e4SLinus Torvalds static void	call_reserve(struct rpc_task *task);
601da177e4SLinus Torvalds static void	call_reserveresult(struct rpc_task *task);
611da177e4SLinus Torvalds static void	call_allocate(struct rpc_task *task);
62762e4e67STrond Myklebust static void	call_encode(struct rpc_task *task);
631da177e4SLinus Torvalds static void	call_decode(struct rpc_task *task);
641da177e4SLinus Torvalds static void	call_bind(struct rpc_task *task);
65da351878SChuck Lever static void	call_bind_status(struct rpc_task *task);
661da177e4SLinus Torvalds static void	call_transmit(struct rpc_task *task);
671da177e4SLinus Torvalds static void	call_status(struct rpc_task *task);
68940e3318STrond Myklebust static void	call_transmit_status(struct rpc_task *task);
691da177e4SLinus Torvalds static void	call_refresh(struct rpc_task *task);
701da177e4SLinus Torvalds static void	call_refreshresult(struct rpc_task *task);
711da177e4SLinus Torvalds static void	call_connect(struct rpc_task *task);
721da177e4SLinus Torvalds static void	call_connect_status(struct rpc_task *task);
731da177e4SLinus Torvalds 
74e8680a24SChuck Lever static int	rpc_encode_header(struct rpc_task *task,
75e8680a24SChuck Lever 				  struct xdr_stream *xdr);
76a0584ee9SChuck Lever static int	rpc_decode_header(struct rpc_task *task,
77a0584ee9SChuck Lever 				  struct xdr_stream *xdr);
78caabea8aSChuck Lever static int	rpc_ping(struct rpc_clnt *clnt);
79fd13359fSTrond Myklebust static int	rpc_ping_noreply(struct rpc_clnt *clnt);
807b3fef8eSTrond Myklebust static void	rpc_check_timeout(struct rpc_task *task);
8164c91a1fSTrond Myklebust 
rpc_register_client(struct rpc_clnt * clnt)82188fef11STrond Myklebust static void rpc_register_client(struct rpc_clnt *clnt)
83188fef11STrond Myklebust {
842446ab60STrond Myklebust 	struct net *net = rpc_net_ns(clnt);
852446ab60STrond Myklebust 	struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
8670abc49bSStanislav Kinsbursky 
8770abc49bSStanislav Kinsbursky 	spin_lock(&sn->rpc_client_lock);
8870abc49bSStanislav Kinsbursky 	list_add(&clnt->cl_clients, &sn->all_clients);
8970abc49bSStanislav Kinsbursky 	spin_unlock(&sn->rpc_client_lock);
90188fef11STrond Myklebust }
91188fef11STrond Myklebust 
rpc_unregister_client(struct rpc_clnt * clnt)92188fef11STrond Myklebust static void rpc_unregister_client(struct rpc_clnt *clnt)
93188fef11STrond Myklebust {
942446ab60STrond Myklebust 	struct net *net = rpc_net_ns(clnt);
952446ab60STrond Myklebust 	struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
9670abc49bSStanislav Kinsbursky 
9770abc49bSStanislav Kinsbursky 	spin_lock(&sn->rpc_client_lock);
98188fef11STrond Myklebust 	list_del(&clnt->cl_clients);
9970abc49bSStanislav Kinsbursky 	spin_unlock(&sn->rpc_client_lock);
100188fef11STrond Myklebust }
1011da177e4SLinus Torvalds 
__rpc_clnt_remove_pipedir(struct rpc_clnt * clnt)1020157d021SStanislav Kinsbursky static void __rpc_clnt_remove_pipedir(struct rpc_clnt *clnt)
1030157d021SStanislav Kinsbursky {
104c36dcfe1STrond Myklebust 	rpc_remove_client_dir(clnt);
1050157d021SStanislav Kinsbursky }
1060157d021SStanislav Kinsbursky 
rpc_clnt_remove_pipedir(struct rpc_clnt * clnt)1070157d021SStanislav Kinsbursky static void rpc_clnt_remove_pipedir(struct rpc_clnt *clnt)
1080157d021SStanislav Kinsbursky {
1092446ab60STrond Myklebust 	struct net *net = rpc_net_ns(clnt);
1100157d021SStanislav Kinsbursky 	struct super_block *pipefs_sb;
1110157d021SStanislav Kinsbursky 
1122446ab60STrond Myklebust 	pipefs_sb = rpc_get_sb_net(net);
1130157d021SStanislav Kinsbursky 	if (pipefs_sb) {
114cc2e7ebbSfelix 		if (pipefs_sb == clnt->pipefs_sb)
1150157d021SStanislav Kinsbursky 			__rpc_clnt_remove_pipedir(clnt);
1162446ab60STrond Myklebust 		rpc_put_sb_net(net);
1170157d021SStanislav Kinsbursky 	}
1180157d021SStanislav Kinsbursky }
1190157d021SStanislav Kinsbursky 
rpc_setup_pipedir_sb(struct super_block * sb,struct rpc_clnt * clnt)1200157d021SStanislav Kinsbursky static struct dentry *rpc_setup_pipedir_sb(struct super_block *sb,
12141b6b4d0STrond Myklebust 				    struct rpc_clnt *clnt)
1221da177e4SLinus Torvalds {
123f134585aSTrond Myklebust 	static uint32_t clntid;
12441b6b4d0STrond Myklebust 	const char *dir_name = clnt->cl_program->pipe_dir_name;
12523ac6581STrond Myklebust 	char name[15];
1260157d021SStanislav Kinsbursky 	struct dentry *dir, *dentry;
1271da177e4SLinus Torvalds 
1280157d021SStanislav Kinsbursky 	dir = rpc_d_lookup_sb(sb, dir_name);
129922eeac3SWeston Andros Adamson 	if (dir == NULL) {
130922eeac3SWeston Andros Adamson 		pr_info("RPC: pipefs directory doesn't exist: %s\n", dir_name);
1310157d021SStanislav Kinsbursky 		return dir;
132922eeac3SWeston Andros Adamson 	}
1330157d021SStanislav Kinsbursky 	for (;;) {
134a95e691fSAl Viro 		snprintf(name, sizeof(name), "clnt%x", (unsigned int)clntid++);
1350157d021SStanislav Kinsbursky 		name[sizeof(name) - 1] = '\0';
136a95e691fSAl Viro 		dentry = rpc_create_client_dir(dir, name, clnt);
1370157d021SStanislav Kinsbursky 		if (!IS_ERR(dentry))
1380157d021SStanislav Kinsbursky 			break;
139a95e691fSAl Viro 		if (dentry == ERR_PTR(-EEXIST))
140a95e691fSAl Viro 			continue;
1410157d021SStanislav Kinsbursky 		printk(KERN_INFO "RPC: Couldn't create pipefs entry"
142a95e691fSAl Viro 				" %s/%s, error %ld\n",
143a95e691fSAl Viro 				dir_name, name, PTR_ERR(dentry));
1440157d021SStanislav Kinsbursky 		break;
1450157d021SStanislav Kinsbursky 	}
1460157d021SStanislav Kinsbursky 	dput(dir);
1470157d021SStanislav Kinsbursky 	return dentry;
1480157d021SStanislav Kinsbursky }
1490157d021SStanislav Kinsbursky 
1500157d021SStanislav Kinsbursky static int
rpc_setup_pipedir(struct super_block * pipefs_sb,struct rpc_clnt * clnt)15141b6b4d0STrond Myklebust rpc_setup_pipedir(struct super_block *pipefs_sb, struct rpc_clnt *clnt)
1520157d021SStanislav Kinsbursky {
15330507f58SStanislav Kinsbursky 	struct dentry *dentry;
1540157d021SStanislav Kinsbursky 
155cc2e7ebbSfelix 	clnt->pipefs_sb = pipefs_sb;
156cc2e7ebbSfelix 
157c36dcfe1STrond Myklebust 	if (clnt->cl_program->pipe_dir_name != NULL) {
15841b6b4d0STrond Myklebust 		dentry = rpc_setup_pipedir_sb(pipefs_sb, clnt);
15930507f58SStanislav Kinsbursky 		if (IS_ERR(dentry))
16030507f58SStanislav Kinsbursky 			return PTR_ERR(dentry);
161c36dcfe1STrond Myklebust 	}
16223ac6581STrond Myklebust 	return 0;
163f134585aSTrond Myklebust }
1641da177e4SLinus Torvalds 
rpc_clnt_skip_event(struct rpc_clnt * clnt,unsigned long event)16541b6b4d0STrond Myklebust static int rpc_clnt_skip_event(struct rpc_clnt *clnt, unsigned long event)
166ea8cfa06SStanislav Kinsbursky {
16741b6b4d0STrond Myklebust 	if (clnt->cl_program->pipe_dir_name == NULL)
168ea8cfa06SStanislav Kinsbursky 		return 1;
16941b6b4d0STrond Myklebust 
170c36dcfe1STrond Myklebust 	switch (event) {
171c36dcfe1STrond Myklebust 	case RPC_PIPEFS_MOUNT:
172c36dcfe1STrond Myklebust 		if (clnt->cl_pipedir_objects.pdh_dentry != NULL)
1734f6bb246SStanislav Kinsbursky 			return 1;
17471d3d0ebSTrond Myklebust 		if (refcount_read(&clnt->cl_count) == 0)
175ea8cfa06SStanislav Kinsbursky 			return 1;
176c36dcfe1STrond Myklebust 		break;
177c36dcfe1STrond Myklebust 	case RPC_PIPEFS_UMOUNT:
178c36dcfe1STrond Myklebust 		if (clnt->cl_pipedir_objects.pdh_dentry == NULL)
179c36dcfe1STrond Myklebust 			return 1;
180c36dcfe1STrond Myklebust 		break;
181c36dcfe1STrond Myklebust 	}
182ea8cfa06SStanislav Kinsbursky 	return 0;
183ea8cfa06SStanislav Kinsbursky }
184ea8cfa06SStanislav Kinsbursky 
__rpc_clnt_handle_event(struct rpc_clnt * clnt,unsigned long event,struct super_block * sb)185ea8cfa06SStanislav Kinsbursky static int __rpc_clnt_handle_event(struct rpc_clnt *clnt, unsigned long event,
18680df9d20SStanislav Kinsbursky 				   struct super_block *sb)
18780df9d20SStanislav Kinsbursky {
18880df9d20SStanislav Kinsbursky 	struct dentry *dentry;
18980df9d20SStanislav Kinsbursky 
19080df9d20SStanislav Kinsbursky 	switch (event) {
19180df9d20SStanislav Kinsbursky 	case RPC_PIPEFS_MOUNT:
19241b6b4d0STrond Myklebust 		dentry = rpc_setup_pipedir_sb(sb, clnt);
193922eeac3SWeston Andros Adamson 		if (!dentry)
194922eeac3SWeston Andros Adamson 			return -ENOENT;
19580df9d20SStanislav Kinsbursky 		if (IS_ERR(dentry))
19680df9d20SStanislav Kinsbursky 			return PTR_ERR(dentry);
19780df9d20SStanislav Kinsbursky 		break;
19880df9d20SStanislav Kinsbursky 	case RPC_PIPEFS_UMOUNT:
19980df9d20SStanislav Kinsbursky 		__rpc_clnt_remove_pipedir(clnt);
20080df9d20SStanislav Kinsbursky 		break;
20180df9d20SStanislav Kinsbursky 	default:
20280df9d20SStanislav Kinsbursky 		printk(KERN_ERR "%s: unknown event: %ld\n", __func__, event);
20380df9d20SStanislav Kinsbursky 		return -ENOTSUPP;
20480df9d20SStanislav Kinsbursky 	}
2052813b626SAmitoj Kaur Chawla 	return 0;
20680df9d20SStanislav Kinsbursky }
20780df9d20SStanislav Kinsbursky 
__rpc_pipefs_event(struct rpc_clnt * clnt,unsigned long event,struct super_block * sb)208ea8cfa06SStanislav Kinsbursky static int __rpc_pipefs_event(struct rpc_clnt *clnt, unsigned long event,
209ea8cfa06SStanislav Kinsbursky 				struct super_block *sb)
210ea8cfa06SStanislav Kinsbursky {
211ea8cfa06SStanislav Kinsbursky 	int error = 0;
212ea8cfa06SStanislav Kinsbursky 
213ea8cfa06SStanislav Kinsbursky 	for (;; clnt = clnt->cl_parent) {
214ea8cfa06SStanislav Kinsbursky 		if (!rpc_clnt_skip_event(clnt, event))
215ea8cfa06SStanislav Kinsbursky 			error = __rpc_clnt_handle_event(clnt, event, sb);
216ea8cfa06SStanislav Kinsbursky 		if (error || clnt == clnt->cl_parent)
217ea8cfa06SStanislav Kinsbursky 			break;
218ea8cfa06SStanislav Kinsbursky 	}
219ea8cfa06SStanislav Kinsbursky 	return error;
220ea8cfa06SStanislav Kinsbursky }
221ea8cfa06SStanislav Kinsbursky 
rpc_get_client_for_event(struct net * net,int event)222da3b4622SStanislav Kinsbursky static struct rpc_clnt *rpc_get_client_for_event(struct net *net, int event)
223da3b4622SStanislav Kinsbursky {
224da3b4622SStanislav Kinsbursky 	struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
225da3b4622SStanislav Kinsbursky 	struct rpc_clnt *clnt;
226da3b4622SStanislav Kinsbursky 
227da3b4622SStanislav Kinsbursky 	spin_lock(&sn->rpc_client_lock);
228da3b4622SStanislav Kinsbursky 	list_for_each_entry(clnt, &sn->all_clients, cl_clients) {
229ea8cfa06SStanislav Kinsbursky 		if (rpc_clnt_skip_event(clnt, event))
230da3b4622SStanislav Kinsbursky 			continue;
231da3b4622SStanislav Kinsbursky 		spin_unlock(&sn->rpc_client_lock);
232da3b4622SStanislav Kinsbursky 		return clnt;
233da3b4622SStanislav Kinsbursky 	}
234da3b4622SStanislav Kinsbursky 	spin_unlock(&sn->rpc_client_lock);
235da3b4622SStanislav Kinsbursky 	return NULL;
236da3b4622SStanislav Kinsbursky }
237da3b4622SStanislav Kinsbursky 
rpc_pipefs_event(struct notifier_block * nb,unsigned long event,void * ptr)23880df9d20SStanislav Kinsbursky static int rpc_pipefs_event(struct notifier_block *nb, unsigned long event,
23980df9d20SStanislav Kinsbursky 			    void *ptr)
24080df9d20SStanislav Kinsbursky {
24180df9d20SStanislav Kinsbursky 	struct super_block *sb = ptr;
24280df9d20SStanislav Kinsbursky 	struct rpc_clnt *clnt;
24380df9d20SStanislav Kinsbursky 	int error = 0;
24480df9d20SStanislav Kinsbursky 
245da3b4622SStanislav Kinsbursky 	while ((clnt = rpc_get_client_for_event(sb->s_fs_info, event))) {
24680df9d20SStanislav Kinsbursky 		error = __rpc_pipefs_event(clnt, event, sb);
24780df9d20SStanislav Kinsbursky 		if (error)
24880df9d20SStanislav Kinsbursky 			break;
24980df9d20SStanislav Kinsbursky 	}
25080df9d20SStanislav Kinsbursky 	return error;
25180df9d20SStanislav Kinsbursky }
25280df9d20SStanislav Kinsbursky 
25380df9d20SStanislav Kinsbursky static struct notifier_block rpc_clients_block = {
25480df9d20SStanislav Kinsbursky 	.notifier_call	= rpc_pipefs_event,
255eee17325SStanislav Kinsbursky 	.priority	= SUNRPC_PIPEFS_RPC_PRIO,
25680df9d20SStanislav Kinsbursky };
25780df9d20SStanislav Kinsbursky 
rpc_clients_notifier_register(void)25880df9d20SStanislav Kinsbursky int rpc_clients_notifier_register(void)
25980df9d20SStanislav Kinsbursky {
26080df9d20SStanislav Kinsbursky 	return rpc_pipefs_notifier_register(&rpc_clients_block);
26180df9d20SStanislav Kinsbursky }
26280df9d20SStanislav Kinsbursky 
rpc_clients_notifier_unregister(void)26380df9d20SStanislav Kinsbursky void rpc_clients_notifier_unregister(void)
26480df9d20SStanislav Kinsbursky {
26580df9d20SStanislav Kinsbursky 	return rpc_pipefs_notifier_unregister(&rpc_clients_block);
26680df9d20SStanislav Kinsbursky }
26780df9d20SStanislav Kinsbursky 
rpc_clnt_set_transport(struct rpc_clnt * clnt,struct rpc_xprt * xprt,const struct rpc_timeout * timeout)26840b00b6bSTrond Myklebust static struct rpc_xprt *rpc_clnt_set_transport(struct rpc_clnt *clnt,
26940b00b6bSTrond Myklebust 		struct rpc_xprt *xprt,
27040b00b6bSTrond Myklebust 		const struct rpc_timeout *timeout)
27140b00b6bSTrond Myklebust {
27240b00b6bSTrond Myklebust 	struct rpc_xprt *old;
27340b00b6bSTrond Myklebust 
27440b00b6bSTrond Myklebust 	spin_lock(&clnt->cl_lock);
27534751b9dSTrond Myklebust 	old = rcu_dereference_protected(clnt->cl_xprt,
27634751b9dSTrond Myklebust 			lockdep_is_held(&clnt->cl_lock));
27740b00b6bSTrond Myklebust 
27840b00b6bSTrond Myklebust 	if (!xprt_bound(xprt))
27940b00b6bSTrond Myklebust 		clnt->cl_autobind = 1;
28040b00b6bSTrond Myklebust 
28140b00b6bSTrond Myklebust 	clnt->cl_timeout = timeout;
28240b00b6bSTrond Myklebust 	rcu_assign_pointer(clnt->cl_xprt, xprt);
28340b00b6bSTrond Myklebust 	spin_unlock(&clnt->cl_lock);
28440b00b6bSTrond Myklebust 
28540b00b6bSTrond Myklebust 	return old;
28640b00b6bSTrond Myklebust }
28740b00b6bSTrond Myklebust 
rpc_clnt_set_nodename(struct rpc_clnt * clnt,const char * nodename)288cbbb3449STrond Myklebust static void rpc_clnt_set_nodename(struct rpc_clnt *clnt, const char *nodename)
289cbbb3449STrond Myklebust {
29003a9a42aSTrond Myklebust 	clnt->cl_nodelen = strlcpy(clnt->cl_nodename,
29103a9a42aSTrond Myklebust 			nodename, sizeof(clnt->cl_nodename));
292cbbb3449STrond Myklebust }
293cbbb3449STrond Myklebust 
rpc_client_register(struct rpc_clnt * clnt,rpc_authflavor_t pseudoflavor,const char * client_name)294d746e545SChuck Lever static int rpc_client_register(struct rpc_clnt *clnt,
295d746e545SChuck Lever 			       rpc_authflavor_t pseudoflavor,
296d746e545SChuck Lever 			       const char *client_name)
297e73f4cc0SStanislav Kinsbursky {
298c2190661STrond Myklebust 	struct rpc_auth_create_args auth_args = {
299d746e545SChuck Lever 		.pseudoflavor = pseudoflavor,
300d746e545SChuck Lever 		.target_name = client_name,
301c2190661STrond Myklebust 	};
302e73f4cc0SStanislav Kinsbursky 	struct rpc_auth *auth;
303e73f4cc0SStanislav Kinsbursky 	struct net *net = rpc_net_ns(clnt);
304e73f4cc0SStanislav Kinsbursky 	struct super_block *pipefs_sb;
305eeee2452STrond Myklebust 	int err;
306e73f4cc0SStanislav Kinsbursky 
307f9c72d10SJeff Layton 	rpc_clnt_debugfs_register(clnt);
308b4b9d2ccSJeff Layton 
309e73f4cc0SStanislav Kinsbursky 	pipefs_sb = rpc_get_sb_net(net);
310e73f4cc0SStanislav Kinsbursky 	if (pipefs_sb) {
31141b6b4d0STrond Myklebust 		err = rpc_setup_pipedir(pipefs_sb, clnt);
312e73f4cc0SStanislav Kinsbursky 		if (err)
313e73f4cc0SStanislav Kinsbursky 			goto out;
314e73f4cc0SStanislav Kinsbursky 	}
315e73f4cc0SStanislav Kinsbursky 
316eeee2452STrond Myklebust 	rpc_register_client(clnt);
317eeee2452STrond Myklebust 	if (pipefs_sb)
318eeee2452STrond Myklebust 		rpc_put_sb_net(net);
319eeee2452STrond Myklebust 
320c2190661STrond Myklebust 	auth = rpcauth_create(&auth_args, clnt);
321e73f4cc0SStanislav Kinsbursky 	if (IS_ERR(auth)) {
322e73f4cc0SStanislav Kinsbursky 		dprintk("RPC:       Couldn't create auth handle (flavor %u)\n",
323d746e545SChuck Lever 				pseudoflavor);
324e73f4cc0SStanislav Kinsbursky 		err = PTR_ERR(auth);
325e73f4cc0SStanislav Kinsbursky 		goto err_auth;
326e73f4cc0SStanislav Kinsbursky 	}
327eeee2452STrond Myklebust 	return 0;
328eeee2452STrond Myklebust err_auth:
329eeee2452STrond Myklebust 	pipefs_sb = rpc_get_sb_net(net);
3301540c5d3STrond Myklebust 	rpc_unregister_client(clnt);
331eeee2452STrond Myklebust 	__rpc_clnt_remove_pipedir(clnt);
332e73f4cc0SStanislav Kinsbursky out:
333e73f4cc0SStanislav Kinsbursky 	if (pipefs_sb)
334e73f4cc0SStanislav Kinsbursky 		rpc_put_sb_net(net);
335c5a382ebSOlga Kornievskaia 	rpc_sysfs_client_destroy(clnt);
336b4b9d2ccSJeff Layton 	rpc_clnt_debugfs_unregister(clnt);
337e73f4cc0SStanislav Kinsbursky 	return err;
338e73f4cc0SStanislav Kinsbursky }
339e73f4cc0SStanislav Kinsbursky 
3402f048db4STrond Myklebust static DEFINE_IDA(rpc_clids);
3412f048db4STrond Myklebust 
rpc_cleanup_clids(void)342c929ea0bSKinglong Mee void rpc_cleanup_clids(void)
343c929ea0bSKinglong Mee {
344c929ea0bSKinglong Mee 	ida_destroy(&rpc_clids);
345c929ea0bSKinglong Mee }
346c929ea0bSKinglong Mee 
rpc_alloc_clid(struct rpc_clnt * clnt)3472f048db4STrond Myklebust static int rpc_alloc_clid(struct rpc_clnt *clnt)
3482f048db4STrond Myklebust {
3492f048db4STrond Myklebust 	int clid;
3502f048db4STrond Myklebust 
3519947e57bSBo Liu 	clid = ida_alloc(&rpc_clids, GFP_KERNEL);
3522f048db4STrond Myklebust 	if (clid < 0)
3532f048db4STrond Myklebust 		return clid;
3542f048db4STrond Myklebust 	clnt->cl_clid = clid;
3552f048db4STrond Myklebust 	return 0;
3562f048db4STrond Myklebust }
3572f048db4STrond Myklebust 
rpc_free_clid(struct rpc_clnt * clnt)3582f048db4STrond Myklebust static void rpc_free_clid(struct rpc_clnt *clnt)
3592f048db4STrond Myklebust {
3609947e57bSBo Liu 	ida_free(&rpc_clids, clnt->cl_clid);
3612f048db4STrond Myklebust }
3622f048db4STrond Myklebust 
rpc_new_client(const struct rpc_create_args * args,struct rpc_xprt_switch * xps,struct rpc_xprt * xprt,struct rpc_clnt * parent)363280ebcf9STrond Myklebust static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args,
364ad01b2c6STrond Myklebust 		struct rpc_xprt_switch *xps,
365280ebcf9STrond Myklebust 		struct rpc_xprt *xprt,
366280ebcf9STrond Myklebust 		struct rpc_clnt *parent)
3671da177e4SLinus Torvalds {
368a613fa16STrond Myklebust 	const struct rpc_program *program = args->program;
369a613fa16STrond Myklebust 	const struct rpc_version *version;
3701da177e4SLinus Torvalds 	struct rpc_clnt *clnt = NULL;
37140b00b6bSTrond Myklebust 	const struct rpc_timeout *timeout;
37203a9a42aSTrond Myklebust 	const char *nodename = args->nodename;
3731da177e4SLinus Torvalds 	int err;
37406b8d255SChuck Lever 
3754ada539eSTrond Myklebust 	err = rpciod_up();
3764ada539eSTrond Myklebust 	if (err)
3774ada539eSTrond Myklebust 		goto out_no_rpciod;
378698b6d08STrond Myklebust 
379f05c124aSTrond Myklebust 	err = -EINVAL;
380698b6d08STrond Myklebust 	if (args->version >= program->nrvers)
381698b6d08STrond Myklebust 		goto out_err;
382698b6d08STrond Myklebust 	version = program->version[args->version];
383698b6d08STrond Myklebust 	if (version == NULL)
3841da177e4SLinus Torvalds 		goto out_err;
3851da177e4SLinus Torvalds 
3861da177e4SLinus Torvalds 	err = -ENOMEM;
3870da974f4SPanagiotis Issaris 	clnt = kzalloc(sizeof(*clnt), GFP_KERNEL);
3881da177e4SLinus Torvalds 	if (!clnt)
3891da177e4SLinus Torvalds 		goto out_err;
390280ebcf9STrond Myklebust 	clnt->cl_parent = parent ? : clnt;
39150005319SChuck Lever 	clnt->cl_xprtsec = args->xprtsec;
3921da177e4SLinus Torvalds 
3932f048db4STrond Myklebust 	err = rpc_alloc_clid(clnt);
3942f048db4STrond Myklebust 	if (err)
3952f048db4STrond Myklebust 		goto out_no_clid;
3961da177e4SLinus Torvalds 
39779caa5faSTrond Myklebust 	clnt->cl_cred	  = get_cred(args->cred);
3981da177e4SLinus Torvalds 	clnt->cl_procinfo = version->procs;
3991da177e4SLinus Torvalds 	clnt->cl_maxproc  = version->nrprocs;
400d5b337b4SBenny Halevy 	clnt->cl_prog     = args->prognumber ? : program->number;
4011da177e4SLinus Torvalds 	clnt->cl_vers     = version->number;
402c4d324c4SJosef Bacik 	clnt->cl_stats    = args->stats ? : program->stats;
40311c556b3SChuck Lever 	clnt->cl_metrics  = rpc_alloc_iostats(clnt);
4046739ffb7STrond Myklebust 	rpc_init_pipe_dir_head(&clnt->cl_pipedir_objects);
40523bf85baSTrond Myklebust 	err = -ENOMEM;
40623bf85baSTrond Myklebust 	if (clnt->cl_metrics == NULL)
40723bf85baSTrond Myklebust 		goto out_no_stats;
4083e32a5d9STrond Myklebust 	clnt->cl_program  = program;
4096529eba0STrond Myklebust 	INIT_LIST_HEAD(&clnt->cl_tasks);
4104bef61ffSTrond Myklebust 	spin_lock_init(&clnt->cl_lock);
4111da177e4SLinus Torvalds 
41240b00b6bSTrond Myklebust 	timeout = xprt->timeout;
413ba7392bbSTrond Myklebust 	if (args->timeout != NULL) {
414ba7392bbSTrond Myklebust 		memcpy(&clnt->cl_timeout_default, args->timeout,
415ba7392bbSTrond Myklebust 				sizeof(clnt->cl_timeout_default));
41640b00b6bSTrond Myklebust 		timeout = &clnt->cl_timeout_default;
417ba7392bbSTrond Myklebust 	}
418ba7392bbSTrond Myklebust 
41940b00b6bSTrond Myklebust 	rpc_clnt_set_transport(clnt, xprt, timeout);
420e091853eSOlga Kornievskaia 	xprt->main = true;
421ad01b2c6STrond Myklebust 	xprt_iter_init(&clnt->cl_xpi, xps);
422ad01b2c6STrond Myklebust 	xprt_switch_put(xps);
42340b00b6bSTrond Myklebust 
4241da177e4SLinus Torvalds 	clnt->cl_rtt = &clnt->cl_rtt_default;
425ba7392bbSTrond Myklebust 	rpc_init_rtt(&clnt->cl_rtt_default, clnt->cl_timeout->to_initval);
4261da177e4SLinus Torvalds 
42771d3d0ebSTrond Myklebust 	refcount_set(&clnt->cl_count, 1);
42834f52e35STrond Myklebust 
42903a9a42aSTrond Myklebust 	if (nodename == NULL)
43003a9a42aSTrond Myklebust 		nodename = utsname()->nodename;
4311da177e4SLinus Torvalds 	/* save the nodename */
43203a9a42aSTrond Myklebust 	rpc_clnt_set_nodename(clnt, nodename);
433e73f4cc0SStanislav Kinsbursky 
4342a338a54SOlga Kornievskaia 	rpc_sysfs_client_setup(clnt, xps, rpc_net_ns(clnt));
435d746e545SChuck Lever 	err = rpc_client_register(clnt, args->authflavor, args->client_name);
436e73f4cc0SStanislav Kinsbursky 	if (err)
437e73f4cc0SStanislav Kinsbursky 		goto out_no_path;
438280ebcf9STrond Myklebust 	if (parent)
43971d3d0ebSTrond Myklebust 		refcount_inc(&parent->cl_count);
44042aad0d7SChuck Lever 
44197d1c83cSChuck Lever 	trace_rpc_clnt_new(clnt, xprt, args);
4421da177e4SLinus Torvalds 	return clnt;
4431da177e4SLinus Torvalds 
4441da177e4SLinus Torvalds out_no_path:
44523bf85baSTrond Myklebust 	rpc_free_iostats(clnt->cl_metrics);
44623bf85baSTrond Myklebust out_no_stats:
44779caa5faSTrond Myklebust 	put_cred(clnt->cl_cred);
4482f048db4STrond Myklebust 	rpc_free_clid(clnt);
4492f048db4STrond Myklebust out_no_clid:
4501da177e4SLinus Torvalds 	kfree(clnt);
4511da177e4SLinus Torvalds out_err:
4524ada539eSTrond Myklebust 	rpciod_down();
4534ada539eSTrond Myklebust out_no_rpciod:
454ad01b2c6STrond Myklebust 	xprt_switch_put(xps);
455f05c124aSTrond Myklebust 	xprt_put(xprt);
45642aad0d7SChuck Lever 	trace_rpc_clnt_new_err(program->name, args->servername, err);
4571da177e4SLinus Torvalds 	return ERR_PTR(err);
4581da177e4SLinus Torvalds }
4591da177e4SLinus Torvalds 
rpc_create_xprt(struct rpc_create_args * args,struct rpc_xprt * xprt)460d50039eaSJ. Bruce Fields static struct rpc_clnt *rpc_create_xprt(struct rpc_create_args *args,
46183ddfebdSKinglong Mee 					struct rpc_xprt *xprt)
46283ddfebdSKinglong Mee {
46383ddfebdSKinglong Mee 	struct rpc_clnt *clnt = NULL;
464ad01b2c6STrond Myklebust 	struct rpc_xprt_switch *xps;
46583ddfebdSKinglong Mee 
46639a9beabSJ. Bruce Fields 	if (args->bc_xprt && args->bc_xprt->xpt_bc_xps) {
46716590a22SChuck Lever 		WARN_ON_ONCE(!(args->protocol & XPRT_TRANSPORT_BC));
46839a9beabSJ. Bruce Fields 		xps = args->bc_xprt->xpt_bc_xps;
46939a9beabSJ. Bruce Fields 		xprt_switch_get(xps);
47039a9beabSJ. Bruce Fields 	} else {
471ad01b2c6STrond Myklebust 		xps = xprt_switch_alloc(xprt, GFP_KERNEL);
4721208fd56SJ. Bruce Fields 		if (xps == NULL) {
4731208fd56SJ. Bruce Fields 			xprt_put(xprt);
474ad01b2c6STrond Myklebust 			return ERR_PTR(-ENOMEM);
4751208fd56SJ. Bruce Fields 		}
47639a9beabSJ. Bruce Fields 		if (xprt->bc_xprt) {
47739a9beabSJ. Bruce Fields 			xprt_switch_get(xps);
47839a9beabSJ. Bruce Fields 			xprt->bc_xprt->xpt_bc_xps = xps;
47939a9beabSJ. Bruce Fields 		}
48039a9beabSJ. Bruce Fields 	}
481ad01b2c6STrond Myklebust 	clnt = rpc_new_client(args, xps, xprt, NULL);
48283ddfebdSKinglong Mee 	if (IS_ERR(clnt))
48383ddfebdSKinglong Mee 		return clnt;
48483ddfebdSKinglong Mee 
48583ddfebdSKinglong Mee 	if (!(args->flags & RPC_CLNT_CREATE_NOPING)) {
48683ddfebdSKinglong Mee 		int err = rpc_ping(clnt);
48783ddfebdSKinglong Mee 		if (err != 0) {
48883ddfebdSKinglong Mee 			rpc_shutdown_client(clnt);
48983ddfebdSKinglong Mee 			return ERR_PTR(err);
49083ddfebdSKinglong Mee 		}
491fd13359fSTrond Myklebust 	} else if (args->flags & RPC_CLNT_CREATE_CONNECTED) {
492fd13359fSTrond Myklebust 		int err = rpc_ping_noreply(clnt);
493fd13359fSTrond Myklebust 		if (err != 0) {
494fd13359fSTrond Myklebust 			rpc_shutdown_client(clnt);
495fd13359fSTrond Myklebust 			return ERR_PTR(err);
496fd13359fSTrond Myklebust 		}
49783ddfebdSKinglong Mee 	}
49883ddfebdSKinglong Mee 
49983ddfebdSKinglong Mee 	clnt->cl_softrtry = 1;
500ae6ec918STrond Myklebust 	if (args->flags & (RPC_CLNT_CREATE_HARDRTRY|RPC_CLNT_CREATE_SOFTERR)) {
50183ddfebdSKinglong Mee 		clnt->cl_softrtry = 0;
502ae6ec918STrond Myklebust 		if (args->flags & RPC_CLNT_CREATE_SOFTERR)
503ae6ec918STrond Myklebust 			clnt->cl_softerr = 1;
504ae6ec918STrond Myklebust 	}
50583ddfebdSKinglong Mee 
50683ddfebdSKinglong Mee 	if (args->flags & RPC_CLNT_CREATE_AUTOBIND)
50783ddfebdSKinglong Mee 		clnt->cl_autobind = 1;
5082aca5b86STrond Myklebust 	if (args->flags & RPC_CLNT_CREATE_NO_RETRANS_TIMEOUT)
5092aca5b86STrond Myklebust 		clnt->cl_noretranstimeo = 1;
51083ddfebdSKinglong Mee 	if (args->flags & RPC_CLNT_CREATE_DISCRTRY)
51183ddfebdSKinglong Mee 		clnt->cl_discrtry = 1;
51283ddfebdSKinglong Mee 	if (!(args->flags & RPC_CLNT_CREATE_QUIET))
51383ddfebdSKinglong Mee 		clnt->cl_chatty = 1;
51483ddfebdSKinglong Mee 
51583ddfebdSKinglong Mee 	return clnt;
51683ddfebdSKinglong Mee }
51783ddfebdSKinglong Mee 
5182c53040fSBen Hutchings /**
519c2866763SChuck Lever  * rpc_create - create an RPC client and transport with one call
520c2866763SChuck Lever  * @args: rpc_clnt create argument structure
521c2866763SChuck Lever  *
522c2866763SChuck Lever  * Creates and initializes an RPC transport and an RPC client.
523c2866763SChuck Lever  *
524c2866763SChuck Lever  * It can ping the server in order to determine if it is up, and to see if
525c2866763SChuck Lever  * it supports this program and version.  RPC_CLNT_CREATE_NOPING disables
526c2866763SChuck Lever  * this behavior so asynchronous tasks can also use rpc_create.
527c2866763SChuck Lever  */
rpc_create(struct rpc_create_args * args)528c2866763SChuck Lever struct rpc_clnt *rpc_create(struct rpc_create_args *args)
529c2866763SChuck Lever {
530c2866763SChuck Lever 	struct rpc_xprt *xprt;
5313c341b0bS\"Talpey, Thomas\ 	struct xprt_create xprtargs = {
5329a23e332SPavel Emelyanov 		.net = args->net,
5334fa016ebS\"Talpey, Thomas\ 		.ident = args->protocol,
534d3bc9a1dSFrank van Maarseveen 		.srcaddr = args->saddress,
53596802a09SFrank van Maarseveen 		.dstaddr = args->address,
53696802a09SFrank van Maarseveen 		.addrlen = args->addrsize,
5374e0038b6STrond Myklebust 		.servername = args->servername,
538f300babaSAlexandros Batsakis 		.bc_xprt = args->bc_xprt,
53950005319SChuck Lever 		.xprtsec = args->xprtsec,
540d2ee4138STrond Myklebust 		.connect_timeout = args->connect_timeout,
541d2ee4138STrond Myklebust 		.reconnect_timeout = args->reconnect_timeout,
54296802a09SFrank van Maarseveen 	};
543510deb0dSChuck Lever 	char servername[48];
544612b41f8STrond Myklebust 	struct rpc_clnt *clnt;
545612b41f8STrond Myklebust 	int i;
546c2866763SChuck Lever 
547d50039eaSJ. Bruce Fields 	if (args->bc_xprt) {
54816590a22SChuck Lever 		WARN_ON_ONCE(!(args->protocol & XPRT_TRANSPORT_BC));
549d50039eaSJ. Bruce Fields 		xprt = args->bc_xprt->xpt_bc_xprt;
550d50039eaSJ. Bruce Fields 		if (xprt) {
551d50039eaSJ. Bruce Fields 			xprt_get(xprt);
552d50039eaSJ. Bruce Fields 			return rpc_create_xprt(args, xprt);
553d50039eaSJ. Bruce Fields 		}
554d50039eaSJ. Bruce Fields 	}
555d50039eaSJ. Bruce Fields 
556b7993cebSTrond Myklebust 	if (args->flags & RPC_CLNT_CREATE_INFINITE_SLOTS)
557b7993cebSTrond Myklebust 		xprtargs.flags |= XPRT_CREATE_INFINITE_SLOTS;
55833d90ac0SJ. Bruce Fields 	if (args->flags & RPC_CLNT_CREATE_NO_IDLE_TIMEOUT)
55933d90ac0SJ. Bruce Fields 		xprtargs.flags |= XPRT_CREATE_NO_IDLE_TIMEOUT;
560c2866763SChuck Lever 	/*
56143780b87SChuck Lever 	 * If the caller chooses not to specify a hostname, whip
56243780b87SChuck Lever 	 * up a string representation of the passed-in address.
56343780b87SChuck Lever 	 */
5644e0038b6STrond Myklebust 	if (xprtargs.servername == NULL) {
565176e21eeSChuck Lever 		struct sockaddr_un *sun =
566176e21eeSChuck Lever 				(struct sockaddr_un *)args->address;
567510deb0dSChuck Lever 		struct sockaddr_in *sin =
568afde94f3SJ. Bruce Fields 				(struct sockaddr_in *)args->address;
569da09eb93SChuck Lever 		struct sockaddr_in6 *sin6 =
570da09eb93SChuck Lever 				(struct sockaddr_in6 *)args->address;
571da09eb93SChuck Lever 
572da09eb93SChuck Lever 		servername[0] = '\0';
573da09eb93SChuck Lever 		switch (args->address->sa_family) {
574176e21eeSChuck Lever 		case AF_LOCAL:
5754388ce05SNeilBrown 			if (sun->sun_path[0])
576176e21eeSChuck Lever 				snprintf(servername, sizeof(servername), "%s",
577176e21eeSChuck Lever 					 sun->sun_path);
5784388ce05SNeilBrown 			else
5794388ce05SNeilBrown 				snprintf(servername, sizeof(servername), "@%s",
5804388ce05SNeilBrown 					 sun->sun_path+1);
581176e21eeSChuck Lever 			break;
582da09eb93SChuck Lever 		case AF_INET:
58321454aaaSHarvey Harrison 			snprintf(servername, sizeof(servername), "%pI4",
58421454aaaSHarvey Harrison 				 &sin->sin_addr.s_addr);
585510deb0dSChuck Lever 			break;
586da09eb93SChuck Lever 		case AF_INET6:
5875b095d98SHarvey Harrison 			snprintf(servername, sizeof(servername), "%pI6",
588da09eb93SChuck Lever 				 &sin6->sin6_addr);
589510deb0dSChuck Lever 			break;
590510deb0dSChuck Lever 		default:
591510deb0dSChuck Lever 			/* caller wants default server name, but
592510deb0dSChuck Lever 			 * address family isn't recognized. */
593510deb0dSChuck Lever 			return ERR_PTR(-EINVAL);
594510deb0dSChuck Lever 		}
5954e0038b6STrond Myklebust 		xprtargs.servername = servername;
59643780b87SChuck Lever 	}
59743780b87SChuck Lever 
598510deb0dSChuck Lever 	xprt = xprt_create_transport(&xprtargs);
599510deb0dSChuck Lever 	if (IS_ERR(xprt))
600510deb0dSChuck Lever 		return (struct rpc_clnt *)xprt;
601510deb0dSChuck Lever 
60243780b87SChuck Lever 	/*
603c2866763SChuck Lever 	 * By default, kernel RPC client connects from a reserved port.
604c2866763SChuck Lever 	 * CAP_NET_BIND_SERVICE will not be set for unprivileged requesters,
605c2866763SChuck Lever 	 * but it is always enabled for rpciod, which handles the connect
606c2866763SChuck Lever 	 * operation.
607c2866763SChuck Lever 	 */
608c2866763SChuck Lever 	xprt->resvport = 1;
609c2866763SChuck Lever 	if (args->flags & RPC_CLNT_CREATE_NONPRIVPORT)
610c2866763SChuck Lever 		xprt->resvport = 0;
611e6237b6fSTrond Myklebust 	xprt->reuseport = 0;
612e6237b6fSTrond Myklebust 	if (args->flags & RPC_CLNT_CREATE_REUSEPORT)
613e6237b6fSTrond Myklebust 		xprt->reuseport = 1;
614c2866763SChuck Lever 
615612b41f8STrond Myklebust 	clnt = rpc_create_xprt(args, xprt);
616612b41f8STrond Myklebust 	if (IS_ERR(clnt) || args->nconnect <= 1)
617612b41f8STrond Myklebust 		return clnt;
618612b41f8STrond Myklebust 
619612b41f8STrond Myklebust 	for (i = 0; i < args->nconnect - 1; i++) {
620612b41f8STrond Myklebust 		if (rpc_clnt_add_xprt(clnt, &xprtargs, NULL, NULL) < 0)
621612b41f8STrond Myklebust 			break;
622612b41f8STrond Myklebust 	}
623612b41f8STrond Myklebust 	return clnt;
624c2866763SChuck Lever }
625b86acd50SChuck Lever EXPORT_SYMBOL_GPL(rpc_create);
626c2866763SChuck Lever 
6271da177e4SLinus Torvalds /*
6281da177e4SLinus Torvalds  * This function clones the RPC client structure. It allows us to share the
6291da177e4SLinus Torvalds  * same transport while varying parameters such as the authentication
6301da177e4SLinus Torvalds  * flavour.
6311da177e4SLinus Torvalds  */
__rpc_clone_client(struct rpc_create_args * args,struct rpc_clnt * clnt)6321b63a751SChuck Lever static struct rpc_clnt *__rpc_clone_client(struct rpc_create_args *args,
6331b63a751SChuck Lever 					   struct rpc_clnt *clnt)
6341da177e4SLinus Torvalds {
635ad01b2c6STrond Myklebust 	struct rpc_xprt_switch *xps;
6362446ab60STrond Myklebust 	struct rpc_xprt *xprt;
6371b63a751SChuck Lever 	struct rpc_clnt *new;
6381b63a751SChuck Lever 	int err;
6391da177e4SLinus Torvalds 
6401b63a751SChuck Lever 	err = -ENOMEM;
6412446ab60STrond Myklebust 	rcu_read_lock();
6422446ab60STrond Myklebust 	xprt = xprt_get(rcu_dereference(clnt->cl_xprt));
643ad01b2c6STrond Myklebust 	xps = xprt_switch_get(rcu_dereference(clnt->cl_xpi.xpi_xpswitch));
6442446ab60STrond Myklebust 	rcu_read_unlock();
645ad01b2c6STrond Myklebust 	if (xprt == NULL || xps == NULL) {
646ad01b2c6STrond Myklebust 		xprt_put(xprt);
647ad01b2c6STrond Myklebust 		xprt_switch_put(xps);
6481b63a751SChuck Lever 		goto out_err;
649ad01b2c6STrond Myklebust 	}
6501b63a751SChuck Lever 	args->servername = xprt->servername;
65103a9a42aSTrond Myklebust 	args->nodename = clnt->cl_nodename;
6521b63a751SChuck Lever 
653ad01b2c6STrond Myklebust 	new = rpc_new_client(args, xps, xprt, clnt);
65442aad0d7SChuck Lever 	if (IS_ERR(new))
65542aad0d7SChuck Lever 		return new;
6561b63a751SChuck Lever 
6571b63a751SChuck Lever 	/* Turn off autobind on clones */
6581b63a751SChuck Lever 	new->cl_autobind = 0;
6591b63a751SChuck Lever 	new->cl_softrtry = clnt->cl_softrtry;
660ae6ec918STrond Myklebust 	new->cl_softerr = clnt->cl_softerr;
6612aca5b86STrond Myklebust 	new->cl_noretranstimeo = clnt->cl_noretranstimeo;
6621b63a751SChuck Lever 	new->cl_discrtry = clnt->cl_discrtry;
6631b63a751SChuck Lever 	new->cl_chatty = clnt->cl_chatty;
6645e16923bSNeilBrown 	new->cl_principal = clnt->cl_principal;
66530479125SScott Mayhew 	new->cl_max_connect = clnt->cl_max_connect;
6661da177e4SLinus Torvalds 	return new;
6671b63a751SChuck Lever 
6681b63a751SChuck Lever out_err:
66942aad0d7SChuck Lever 	trace_rpc_clnt_clone_err(clnt, err);
6703e32a5d9STrond Myklebust 	return ERR_PTR(err);
6711da177e4SLinus Torvalds }
6721b63a751SChuck Lever 
6731b63a751SChuck Lever /**
6741b63a751SChuck Lever  * rpc_clone_client - Clone an RPC client structure
6751b63a751SChuck Lever  *
6761b63a751SChuck Lever  * @clnt: RPC client whose parameters are copied
6771b63a751SChuck Lever  *
6781b63a751SChuck Lever  * Returns a fresh RPC client or an ERR_PTR.
6791b63a751SChuck Lever  */
rpc_clone_client(struct rpc_clnt * clnt)6801b63a751SChuck Lever struct rpc_clnt *rpc_clone_client(struct rpc_clnt *clnt)
6811b63a751SChuck Lever {
6821b63a751SChuck Lever 	struct rpc_create_args args = {
6831b63a751SChuck Lever 		.program	= clnt->cl_program,
6841b63a751SChuck Lever 		.prognumber	= clnt->cl_prog,
6851b63a751SChuck Lever 		.version	= clnt->cl_vers,
6861b63a751SChuck Lever 		.authflavor	= clnt->cl_auth->au_flavor,
68779caa5faSTrond Myklebust 		.cred		= clnt->cl_cred,
688c4d324c4SJosef Bacik 		.stats		= clnt->cl_stats,
6891b63a751SChuck Lever 	};
6901b63a751SChuck Lever 	return __rpc_clone_client(&args, clnt);
6911b63a751SChuck Lever }
692e8914c65STrond Myklebust EXPORT_SYMBOL_GPL(rpc_clone_client);
6931da177e4SLinus Torvalds 
694ba9b584cSChuck Lever /**
695ba9b584cSChuck Lever  * rpc_clone_client_set_auth - Clone an RPC client structure and set its auth
696ba9b584cSChuck Lever  *
697ba9b584cSChuck Lever  * @clnt: RPC client whose parameters are copied
6987144bca6SRandy Dunlap  * @flavor: security flavor for new client
699ba9b584cSChuck Lever  *
700ba9b584cSChuck Lever  * Returns a fresh RPC client or an ERR_PTR.
701ba9b584cSChuck Lever  */
702ba9b584cSChuck Lever struct rpc_clnt *
rpc_clone_client_set_auth(struct rpc_clnt * clnt,rpc_authflavor_t flavor)703ba9b584cSChuck Lever rpc_clone_client_set_auth(struct rpc_clnt *clnt, rpc_authflavor_t flavor)
704ba9b584cSChuck Lever {
705ba9b584cSChuck Lever 	struct rpc_create_args args = {
706ba9b584cSChuck Lever 		.program	= clnt->cl_program,
707ba9b584cSChuck Lever 		.prognumber	= clnt->cl_prog,
708ba9b584cSChuck Lever 		.version	= clnt->cl_vers,
709ba9b584cSChuck Lever 		.authflavor	= flavor,
71079caa5faSTrond Myklebust 		.cred		= clnt->cl_cred,
711c4d324c4SJosef Bacik 		.stats		= clnt->cl_stats,
712ba9b584cSChuck Lever 	};
713ba9b584cSChuck Lever 	return __rpc_clone_client(&args, clnt);
714ba9b584cSChuck Lever }
715ba9b584cSChuck Lever EXPORT_SYMBOL_GPL(rpc_clone_client_set_auth);
716ba9b584cSChuck Lever 
71740b00b6bSTrond Myklebust /**
71840b00b6bSTrond Myklebust  * rpc_switch_client_transport: switch the RPC transport on the fly
71940b00b6bSTrond Myklebust  * @clnt: pointer to a struct rpc_clnt
72040b00b6bSTrond Myklebust  * @args: pointer to the new transport arguments
72140b00b6bSTrond Myklebust  * @timeout: pointer to the new timeout parameters
72240b00b6bSTrond Myklebust  *
72340b00b6bSTrond Myklebust  * This function allows the caller to switch the RPC transport for the
72440b00b6bSTrond Myklebust  * rpc_clnt structure 'clnt' to allow it to connect to a mirrored NFS
72540b00b6bSTrond Myklebust  * server, for instance.  It assumes that the caller has ensured that
72640b00b6bSTrond Myklebust  * there are no active RPC tasks by using some form of locking.
72740b00b6bSTrond Myklebust  *
72840b00b6bSTrond Myklebust  * Returns zero if "clnt" is now using the new xprt.  Otherwise a
72940b00b6bSTrond Myklebust  * negative errno is returned, and "clnt" continues to use the old
73040b00b6bSTrond Myklebust  * xprt.
73140b00b6bSTrond Myklebust  */
rpc_switch_client_transport(struct rpc_clnt * clnt,struct xprt_create * args,const struct rpc_timeout * timeout)73240b00b6bSTrond Myklebust int rpc_switch_client_transport(struct rpc_clnt *clnt,
73340b00b6bSTrond Myklebust 		struct xprt_create *args,
73440b00b6bSTrond Myklebust 		const struct rpc_timeout *timeout)
73540b00b6bSTrond Myklebust {
73640b00b6bSTrond Myklebust 	const struct rpc_timeout *old_timeo;
73740b00b6bSTrond Myklebust 	rpc_authflavor_t pseudoflavor;
738ad01b2c6STrond Myklebust 	struct rpc_xprt_switch *xps, *oldxps;
73940b00b6bSTrond Myklebust 	struct rpc_xprt *xprt, *old;
74040b00b6bSTrond Myklebust 	struct rpc_clnt *parent;
74140b00b6bSTrond Myklebust 	int err;
74240b00b6bSTrond Myklebust 
74350005319SChuck Lever 	args->xprtsec = clnt->cl_xprtsec;
74440b00b6bSTrond Myklebust 	xprt = xprt_create_transport(args);
74542aad0d7SChuck Lever 	if (IS_ERR(xprt))
74640b00b6bSTrond Myklebust 		return PTR_ERR(xprt);
74740b00b6bSTrond Myklebust 
748ad01b2c6STrond Myklebust 	xps = xprt_switch_alloc(xprt, GFP_KERNEL);
749ad01b2c6STrond Myklebust 	if (xps == NULL) {
750ad01b2c6STrond Myklebust 		xprt_put(xprt);
751ad01b2c6STrond Myklebust 		return -ENOMEM;
752ad01b2c6STrond Myklebust 	}
753ad01b2c6STrond Myklebust 
75440b00b6bSTrond Myklebust 	pseudoflavor = clnt->cl_auth->au_flavor;
75540b00b6bSTrond Myklebust 
75640b00b6bSTrond Myklebust 	old_timeo = clnt->cl_timeout;
75740b00b6bSTrond Myklebust 	old = rpc_clnt_set_transport(clnt, xprt, timeout);
758ad01b2c6STrond Myklebust 	oldxps = xprt_iter_xchg_switch(&clnt->cl_xpi, xps);
75940b00b6bSTrond Myklebust 
76040b00b6bSTrond Myklebust 	rpc_unregister_client(clnt);
76140b00b6bSTrond Myklebust 	__rpc_clnt_remove_pipedir(clnt);
762c5a382ebSOlga Kornievskaia 	rpc_sysfs_client_destroy(clnt);
763b4b9d2ccSJeff Layton 	rpc_clnt_debugfs_unregister(clnt);
76440b00b6bSTrond Myklebust 
76540b00b6bSTrond Myklebust 	/*
76640b00b6bSTrond Myklebust 	 * A new transport was created.  "clnt" therefore
76740b00b6bSTrond Myklebust 	 * becomes the root of a new cl_parent tree.  clnt's
76840b00b6bSTrond Myklebust 	 * children, if it has any, still point to the old xprt.
76940b00b6bSTrond Myklebust 	 */
77040b00b6bSTrond Myklebust 	parent = clnt->cl_parent;
77140b00b6bSTrond Myklebust 	clnt->cl_parent = clnt;
77240b00b6bSTrond Myklebust 
77340b00b6bSTrond Myklebust 	/*
77440b00b6bSTrond Myklebust 	 * The old rpc_auth cache cannot be re-used.  GSS
77540b00b6bSTrond Myklebust 	 * contexts in particular are between a single
77640b00b6bSTrond Myklebust 	 * client and server.
77740b00b6bSTrond Myklebust 	 */
77840b00b6bSTrond Myklebust 	err = rpc_client_register(clnt, pseudoflavor, NULL);
77940b00b6bSTrond Myklebust 	if (err)
78040b00b6bSTrond Myklebust 		goto out_revert;
78140b00b6bSTrond Myklebust 
78240b00b6bSTrond Myklebust 	synchronize_rcu();
78340b00b6bSTrond Myklebust 	if (parent != clnt)
78440b00b6bSTrond Myklebust 		rpc_release_client(parent);
785ad01b2c6STrond Myklebust 	xprt_switch_put(oldxps);
78640b00b6bSTrond Myklebust 	xprt_put(old);
78742aad0d7SChuck Lever 	trace_rpc_clnt_replace_xprt(clnt);
78840b00b6bSTrond Myklebust 	return 0;
78940b00b6bSTrond Myklebust 
79040b00b6bSTrond Myklebust out_revert:
791ad01b2c6STrond Myklebust 	xps = xprt_iter_xchg_switch(&clnt->cl_xpi, oldxps);
79240b00b6bSTrond Myklebust 	rpc_clnt_set_transport(clnt, old, old_timeo);
79340b00b6bSTrond Myklebust 	clnt->cl_parent = parent;
79440b00b6bSTrond Myklebust 	rpc_client_register(clnt, pseudoflavor, NULL);
795ad01b2c6STrond Myklebust 	xprt_switch_put(xps);
79640b00b6bSTrond Myklebust 	xprt_put(xprt);
79742aad0d7SChuck Lever 	trace_rpc_clnt_replace_xprt_err(clnt);
79840b00b6bSTrond Myklebust 	return err;
79940b00b6bSTrond Myklebust }
80040b00b6bSTrond Myklebust EXPORT_SYMBOL_GPL(rpc_switch_client_transport);
80140b00b6bSTrond Myklebust 
8023227886cSTrond Myklebust static
_rpc_clnt_xprt_iter_init(struct rpc_clnt * clnt,struct rpc_xprt_iter * xpi,void func (struct rpc_xprt_iter * xpi,struct rpc_xprt_switch * xps))80395d0d30cSOlga Kornievskaia int _rpc_clnt_xprt_iter_init(struct rpc_clnt *clnt, struct rpc_xprt_iter *xpi,
80495d0d30cSOlga Kornievskaia 			     void func(struct rpc_xprt_iter *xpi, struct rpc_xprt_switch *xps))
8053227886cSTrond Myklebust {
8063227886cSTrond Myklebust 	struct rpc_xprt_switch *xps;
8073227886cSTrond Myklebust 
8083227886cSTrond Myklebust 	rcu_read_lock();
8093227886cSTrond Myklebust 	xps = xprt_switch_get(rcu_dereference(clnt->cl_xpi.xpi_xpswitch));
8103227886cSTrond Myklebust 	rcu_read_unlock();
8113227886cSTrond Myklebust 	if (xps == NULL)
8123227886cSTrond Myklebust 		return -EAGAIN;
81395d0d30cSOlga Kornievskaia 	func(xpi, xps);
8143227886cSTrond Myklebust 	xprt_switch_put(xps);
8153227886cSTrond Myklebust 	return 0;
8163227886cSTrond Myklebust }
8173227886cSTrond Myklebust 
81895d0d30cSOlga Kornievskaia static
rpc_clnt_xprt_iter_init(struct rpc_clnt * clnt,struct rpc_xprt_iter * xpi)81995d0d30cSOlga Kornievskaia int rpc_clnt_xprt_iter_init(struct rpc_clnt *clnt, struct rpc_xprt_iter *xpi)
82095d0d30cSOlga Kornievskaia {
82195d0d30cSOlga Kornievskaia 	return _rpc_clnt_xprt_iter_init(clnt, xpi, xprt_iter_init_listall);
82295d0d30cSOlga Kornievskaia }
82395d0d30cSOlga Kornievskaia 
82492cc04f6SOlga Kornievskaia static
rpc_clnt_xprt_iter_offline_init(struct rpc_clnt * clnt,struct rpc_xprt_iter * xpi)82592cc04f6SOlga Kornievskaia int rpc_clnt_xprt_iter_offline_init(struct rpc_clnt *clnt,
82692cc04f6SOlga Kornievskaia 				    struct rpc_xprt_iter *xpi)
82792cc04f6SOlga Kornievskaia {
82892cc04f6SOlga Kornievskaia 	return _rpc_clnt_xprt_iter_init(clnt, xpi, xprt_iter_init_listoffline);
82992cc04f6SOlga Kornievskaia }
83092cc04f6SOlga Kornievskaia 
8313227886cSTrond Myklebust /**
8323227886cSTrond Myklebust  * rpc_clnt_iterate_for_each_xprt - Apply a function to all transports
8333227886cSTrond Myklebust  * @clnt: pointer to client
8343227886cSTrond Myklebust  * @fn: function to apply
8353227886cSTrond Myklebust  * @data: void pointer to function data
8363227886cSTrond Myklebust  *
8373227886cSTrond Myklebust  * Iterates through the list of RPC transports currently attached to the
8383227886cSTrond Myklebust  * client and applies the function fn(clnt, xprt, data).
8393227886cSTrond Myklebust  *
8403227886cSTrond Myklebust  * On error, the iteration stops, and the function returns the error value.
8413227886cSTrond Myklebust  */
rpc_clnt_iterate_for_each_xprt(struct rpc_clnt * clnt,int (* fn)(struct rpc_clnt *,struct rpc_xprt *,void *),void * data)8423227886cSTrond Myklebust int rpc_clnt_iterate_for_each_xprt(struct rpc_clnt *clnt,
8433227886cSTrond Myklebust 		int (*fn)(struct rpc_clnt *, struct rpc_xprt *, void *),
8443227886cSTrond Myklebust 		void *data)
8453227886cSTrond Myklebust {
8463227886cSTrond Myklebust 	struct rpc_xprt_iter xpi;
8473227886cSTrond Myklebust 	int ret;
8483227886cSTrond Myklebust 
8493227886cSTrond Myklebust 	ret = rpc_clnt_xprt_iter_init(clnt, &xpi);
8503227886cSTrond Myklebust 	if (ret)
8513227886cSTrond Myklebust 		return ret;
8523227886cSTrond Myklebust 	for (;;) {
8533227886cSTrond Myklebust 		struct rpc_xprt *xprt = xprt_iter_get_next(&xpi);
8543227886cSTrond Myklebust 
8553227886cSTrond Myklebust 		if (!xprt)
8563227886cSTrond Myklebust 			break;
8573227886cSTrond Myklebust 		ret = fn(clnt, xprt, data);
8583227886cSTrond Myklebust 		xprt_put(xprt);
8593227886cSTrond Myklebust 		if (ret < 0)
8603227886cSTrond Myklebust 			break;
8613227886cSTrond Myklebust 	}
8623227886cSTrond Myklebust 	xprt_iter_destroy(&xpi);
8633227886cSTrond Myklebust 	return ret;
8643227886cSTrond Myklebust }
8653227886cSTrond Myklebust EXPORT_SYMBOL_GPL(rpc_clnt_iterate_for_each_xprt);
8663227886cSTrond Myklebust 
8671da177e4SLinus Torvalds /*
86858f9612cSTrond Myklebust  * Kill all tasks for the given client.
86958f9612cSTrond Myklebust  * XXX: kill their descendants as well?
87058f9612cSTrond Myklebust  */
rpc_killall_tasks(struct rpc_clnt * clnt)87158f9612cSTrond Myklebust void rpc_killall_tasks(struct rpc_clnt *clnt)
87258f9612cSTrond Myklebust {
87358f9612cSTrond Myklebust 	struct rpc_task	*rovr;
87458f9612cSTrond Myklebust 
87558f9612cSTrond Myklebust 
87658f9612cSTrond Myklebust 	if (list_empty(&clnt->cl_tasks))
87758f9612cSTrond Myklebust 		return;
87842aad0d7SChuck Lever 
87958f9612cSTrond Myklebust 	/*
88058f9612cSTrond Myklebust 	 * Spin lock all_tasks to prevent changes...
88158f9612cSTrond Myklebust 	 */
88242aad0d7SChuck Lever 	trace_rpc_clnt_killall(clnt);
88358f9612cSTrond Myklebust 	spin_lock(&clnt->cl_lock);
884ae67bd38STrond Myklebust 	list_for_each_entry(rovr, &clnt->cl_tasks, tk_task)
885ae67bd38STrond Myklebust 		rpc_signal_task(rovr);
88658f9612cSTrond Myklebust 	spin_unlock(&clnt->cl_lock);
88758f9612cSTrond Myklebust }
88858f9612cSTrond Myklebust EXPORT_SYMBOL_GPL(rpc_killall_tasks);
88958f9612cSTrond Myklebust 
890f8423909STrond Myklebust /**
891f8423909STrond Myklebust  * rpc_cancel_tasks - try to cancel a set of RPC tasks
892f8423909STrond Myklebust  * @clnt: Pointer to RPC client
893f8423909STrond Myklebust  * @error: RPC task error value to set
894f8423909STrond Myklebust  * @fnmatch: Pointer to selector function
895f8423909STrond Myklebust  * @data: User data
896f8423909STrond Myklebust  *
897f8423909STrond Myklebust  * Uses @fnmatch to define a set of RPC tasks that are to be cancelled.
898f8423909STrond Myklebust  * The argument @error must be a negative error value.
899f8423909STrond Myklebust  */
rpc_cancel_tasks(struct rpc_clnt * clnt,int error,bool (* fnmatch)(const struct rpc_task *,const void *),const void * data)900f8423909STrond Myklebust unsigned long rpc_cancel_tasks(struct rpc_clnt *clnt, int error,
901f8423909STrond Myklebust 			       bool (*fnmatch)(const struct rpc_task *,
902f8423909STrond Myklebust 					       const void *),
903f8423909STrond Myklebust 			       const void *data)
904f8423909STrond Myklebust {
905f8423909STrond Myklebust 	struct rpc_task *task;
906f8423909STrond Myklebust 	unsigned long count = 0;
907f8423909STrond Myklebust 
908f8423909STrond Myklebust 	if (list_empty(&clnt->cl_tasks))
909f8423909STrond Myklebust 		return 0;
910f8423909STrond Myklebust 	/*
911f8423909STrond Myklebust 	 * Spin lock all_tasks to prevent changes...
912f8423909STrond Myklebust 	 */
913f8423909STrond Myklebust 	spin_lock(&clnt->cl_lock);
914f8423909STrond Myklebust 	list_for_each_entry(task, &clnt->cl_tasks, tk_task) {
915f8423909STrond Myklebust 		if (!RPC_IS_ACTIVATED(task))
916f8423909STrond Myklebust 			continue;
917f8423909STrond Myklebust 		if (!fnmatch(task, data))
918f8423909STrond Myklebust 			continue;
919f8423909STrond Myklebust 		rpc_task_try_cancel(task, error);
920f8423909STrond Myklebust 		count++;
921f8423909STrond Myklebust 	}
922f8423909STrond Myklebust 	spin_unlock(&clnt->cl_lock);
923f8423909STrond Myklebust 	return count;
924f8423909STrond Myklebust }
925f8423909STrond Myklebust EXPORT_SYMBOL_GPL(rpc_cancel_tasks);
926f8423909STrond Myklebust 
rpc_clnt_disconnect_xprt(struct rpc_clnt * clnt,struct rpc_xprt * xprt,void * dummy)927dc4c4304STrond Myklebust static int rpc_clnt_disconnect_xprt(struct rpc_clnt *clnt,
928dc4c4304STrond Myklebust 				    struct rpc_xprt *xprt, void *dummy)
929dc4c4304STrond Myklebust {
930dc4c4304STrond Myklebust 	if (xprt_connected(xprt))
931dc4c4304STrond Myklebust 		xprt_force_disconnect(xprt);
932dc4c4304STrond Myklebust 	return 0;
933dc4c4304STrond Myklebust }
934dc4c4304STrond Myklebust 
rpc_clnt_disconnect(struct rpc_clnt * clnt)935dc4c4304STrond Myklebust void rpc_clnt_disconnect(struct rpc_clnt *clnt)
936dc4c4304STrond Myklebust {
937dc4c4304STrond Myklebust 	rpc_clnt_iterate_for_each_xprt(clnt, rpc_clnt_disconnect_xprt, NULL);
938dc4c4304STrond Myklebust }
939dc4c4304STrond Myklebust EXPORT_SYMBOL_GPL(rpc_clnt_disconnect);
940dc4c4304STrond Myklebust 
94158f9612cSTrond Myklebust /*
9421da177e4SLinus Torvalds  * Properly shut down an RPC client, terminating all outstanding
94390c5755fSTrond Myklebust  * requests.
9441da177e4SLinus Torvalds  */
rpc_shutdown_client(struct rpc_clnt * clnt)9454c402b40STrond Myklebust void rpc_shutdown_client(struct rpc_clnt *clnt)
9461da177e4SLinus Torvalds {
947168e4b39SWeston Andros Adamson 	might_sleep();
948168e4b39SWeston Andros Adamson 
94942aad0d7SChuck Lever 	trace_rpc_clnt_shutdown(clnt);
9501da177e4SLinus Torvalds 
95134f52e35STrond Myklebust 	while (!list_empty(&clnt->cl_tasks)) {
9521da177e4SLinus Torvalds 		rpc_killall_tasks(clnt);
953532347e2SIngo Molnar 		wait_event_timeout(destroy_wait,
95434f52e35STrond Myklebust 			list_empty(&clnt->cl_tasks), 1*HZ);
9551da177e4SLinus Torvalds 	}
9561da177e4SLinus Torvalds 
9574c402b40STrond Myklebust 	rpc_release_client(clnt);
9581da177e4SLinus Torvalds }
959e8914c65STrond Myklebust EXPORT_SYMBOL_GPL(rpc_shutdown_client);
9601da177e4SLinus Torvalds 
9611da177e4SLinus Torvalds /*
96234f52e35STrond Myklebust  * Free an RPC client
9631da177e4SLinus Torvalds  */
rpc_free_client_work(struct work_struct * work)9647c4310ffSNeilBrown static void rpc_free_client_work(struct work_struct *work)
9657c4310ffSNeilBrown {
9667c4310ffSNeilBrown 	struct rpc_clnt *clnt = container_of(work, struct rpc_clnt, cl_work);
9677c4310ffSNeilBrown 
96842aad0d7SChuck Lever 	trace_rpc_clnt_free(clnt);
96942aad0d7SChuck Lever 
9707c4310ffSNeilBrown 	/* These might block on processes that might allocate memory,
9717c4310ffSNeilBrown 	 * so they cannot be called in rpciod, so they are handled separately
9727c4310ffSNeilBrown 	 * here.
9737c4310ffSNeilBrown 	 */
974c5a382ebSOlga Kornievskaia 	rpc_sysfs_client_destroy(clnt);
9757c4310ffSNeilBrown 	rpc_clnt_debugfs_unregister(clnt);
976933496e9SJ. Bruce Fields 	rpc_free_clid(clnt);
9777c4310ffSNeilBrown 	rpc_clnt_remove_pipedir(clnt);
97831e9a7f3SNeilBrown 	xprt_put(rcu_dereference_raw(clnt->cl_xprt));
9797c4310ffSNeilBrown 
9807c4310ffSNeilBrown 	kfree(clnt);
9817c4310ffSNeilBrown 	rpciod_down();
9827c4310ffSNeilBrown }
983d07ba842STrond Myklebust static struct rpc_clnt *
rpc_free_client(struct rpc_clnt * clnt)984006abe88STrond Myklebust rpc_free_client(struct rpc_clnt *clnt)
9851da177e4SLinus Torvalds {
986d07ba842STrond Myklebust 	struct rpc_clnt *parent = NULL;
987d07ba842STrond Myklebust 
98842aad0d7SChuck Lever 	trace_rpc_clnt_release(clnt);
9896eac7d3fSTrond Myklebust 	if (clnt->cl_parent != clnt)
990d07ba842STrond Myklebust 		parent = clnt->cl_parent;
991adb6fa7fSStanislav Kinsbursky 	rpc_unregister_client(clnt);
99211c556b3SChuck Lever 	rpc_free_iostats(clnt->cl_metrics);
99311c556b3SChuck Lever 	clnt->cl_metrics = NULL;
994ad01b2c6STrond Myklebust 	xprt_iter_destroy(&clnt->cl_xpi);
99579caa5faSTrond Myklebust 	put_cred(clnt->cl_cred);
9967c4310ffSNeilBrown 
9977c4310ffSNeilBrown 	INIT_WORK(&clnt->cl_work, rpc_free_client_work);
9987c4310ffSNeilBrown 	schedule_work(&clnt->cl_work);
999d07ba842STrond Myklebust 	return parent;
10001da177e4SLinus Torvalds }
10011da177e4SLinus Torvalds 
10021da177e4SLinus Torvalds /*
10031dd17ec6STrond Myklebust  * Free an RPC client
10041dd17ec6STrond Myklebust  */
1005d07ba842STrond Myklebust static struct rpc_clnt *
rpc_free_auth(struct rpc_clnt * clnt)1006006abe88STrond Myklebust rpc_free_auth(struct rpc_clnt *clnt)
10071dd17ec6STrond Myklebust {
10081dd17ec6STrond Myklebust 	/*
10091dd17ec6STrond Myklebust 	 * Note: RPCSEC_GSS may need to send NULL RPC calls in order to
10101dd17ec6STrond Myklebust 	 *       release remaining GSS contexts. This mechanism ensures
10111dd17ec6STrond Myklebust 	 *       that it can do so safely.
10121dd17ec6STrond Myklebust 	 */
101371d3d0ebSTrond Myklebust 	if (clnt->cl_auth != NULL) {
10141dd17ec6STrond Myklebust 		rpcauth_release(clnt->cl_auth);
10151dd17ec6STrond Myklebust 		clnt->cl_auth = NULL;
101671d3d0ebSTrond Myklebust 	}
101771d3d0ebSTrond Myklebust 	if (refcount_dec_and_test(&clnt->cl_count))
1018d07ba842STrond Myklebust 		return rpc_free_client(clnt);
1019d07ba842STrond Myklebust 	return NULL;
10201dd17ec6STrond Myklebust }
10211dd17ec6STrond Myklebust 
10221dd17ec6STrond Myklebust /*
102334f52e35STrond Myklebust  * Release reference to the RPC client
10241da177e4SLinus Torvalds  */
10251da177e4SLinus Torvalds void
rpc_release_client(struct rpc_clnt * clnt)10261da177e4SLinus Torvalds rpc_release_client(struct rpc_clnt *clnt)
10271da177e4SLinus Torvalds {
1028d07ba842STrond Myklebust 	do {
102934f52e35STrond Myklebust 		if (list_empty(&clnt->cl_tasks))
10301da177e4SLinus Torvalds 			wake_up(&destroy_wait);
103171d3d0ebSTrond Myklebust 		if (refcount_dec_not_one(&clnt->cl_count))
1032d07ba842STrond Myklebust 			break;
1033d07ba842STrond Myklebust 		clnt = rpc_free_auth(clnt);
1034d07ba842STrond Myklebust 	} while (clnt != NULL);
103534f52e35STrond Myklebust }
10361d658336SSimo Sorce EXPORT_SYMBOL_GPL(rpc_release_client);
103734f52e35STrond Myklebust 
1038007e251fSAndreas Gruenbacher /**
1039007e251fSAndreas Gruenbacher  * rpc_bind_new_program - bind a new RPC program to an existing client
104065b6e42cSRandy Dunlap  * @old: old rpc_client
104165b6e42cSRandy Dunlap  * @program: rpc program to set
104265b6e42cSRandy Dunlap  * @vers: rpc program version
1043007e251fSAndreas Gruenbacher  *
1044007e251fSAndreas Gruenbacher  * Clones the rpc client and sets up a new RPC program. This is mainly
1045007e251fSAndreas Gruenbacher  * of use for enabling different RPC programs to share the same transport.
1046007e251fSAndreas Gruenbacher  * The Sun NFSv2/v3 ACL protocol can do this.
1047007e251fSAndreas Gruenbacher  */
rpc_bind_new_program(struct rpc_clnt * old,const struct rpc_program * program,u32 vers)1048007e251fSAndreas Gruenbacher struct rpc_clnt *rpc_bind_new_program(struct rpc_clnt *old,
1049a613fa16STrond Myklebust 				      const struct rpc_program *program,
105089eb21c3SChuck Lever 				      u32 vers)
1051007e251fSAndreas Gruenbacher {
1052f994c43dSTrond Myklebust 	struct rpc_create_args args = {
1053f994c43dSTrond Myklebust 		.program	= program,
1054f994c43dSTrond Myklebust 		.prognumber	= program->number,
1055f994c43dSTrond Myklebust 		.version	= vers,
1056f994c43dSTrond Myklebust 		.authflavor	= old->cl_auth->au_flavor,
105779caa5faSTrond Myklebust 		.cred		= old->cl_cred,
1058c4d324c4SJosef Bacik 		.stats		= old->cl_stats,
1059f3a8f867SDan Aloni 		.timeout	= old->cl_timeout,
1060f994c43dSTrond Myklebust 	};
1061007e251fSAndreas Gruenbacher 	struct rpc_clnt *clnt;
1062007e251fSAndreas Gruenbacher 	int err;
1063007e251fSAndreas Gruenbacher 
1064f994c43dSTrond Myklebust 	clnt = __rpc_clone_client(&args, old);
1065007e251fSAndreas Gruenbacher 	if (IS_ERR(clnt))
1066007e251fSAndreas Gruenbacher 		goto out;
1067caabea8aSChuck Lever 	err = rpc_ping(clnt);
1068007e251fSAndreas Gruenbacher 	if (err != 0) {
1069007e251fSAndreas Gruenbacher 		rpc_shutdown_client(clnt);
1070007e251fSAndreas Gruenbacher 		clnt = ERR_PTR(err);
1071007e251fSAndreas Gruenbacher 	}
1072007e251fSAndreas Gruenbacher out:
1073007e251fSAndreas Gruenbacher 	return clnt;
1074007e251fSAndreas Gruenbacher }
1075e8914c65STrond Myklebust EXPORT_SYMBOL_GPL(rpc_bind_new_program);
1076007e251fSAndreas Gruenbacher 
1077a101b043STrond Myklebust struct rpc_xprt *
rpc_task_get_xprt(struct rpc_clnt * clnt,struct rpc_xprt * xprt)1078a101b043STrond Myklebust rpc_task_get_xprt(struct rpc_clnt *clnt, struct rpc_xprt *xprt)
107921f0ffafSTrond Myklebust {
108021f0ffafSTrond Myklebust 	struct rpc_xprt_switch *xps;
108121f0ffafSTrond Myklebust 
108221f0ffafSTrond Myklebust 	if (!xprt)
108321f0ffafSTrond Myklebust 		return NULL;
108421f0ffafSTrond Myklebust 	rcu_read_lock();
108521f0ffafSTrond Myklebust 	xps = rcu_dereference(clnt->cl_xpi.xpi_xpswitch);
108621f0ffafSTrond Myklebust 	atomic_long_inc(&xps->xps_queuelen);
108721f0ffafSTrond Myklebust 	rcu_read_unlock();
108821f0ffafSTrond Myklebust 	atomic_long_inc(&xprt->queuelen);
108921f0ffafSTrond Myklebust 
109021f0ffafSTrond Myklebust 	return xprt;
109121f0ffafSTrond Myklebust }
109221f0ffafSTrond Myklebust 
109321f0ffafSTrond Myklebust static void
rpc_task_release_xprt(struct rpc_clnt * clnt,struct rpc_xprt * xprt)109421f0ffafSTrond Myklebust rpc_task_release_xprt(struct rpc_clnt *clnt, struct rpc_xprt *xprt)
109521f0ffafSTrond Myklebust {
109621f0ffafSTrond Myklebust 	struct rpc_xprt_switch *xps;
109721f0ffafSTrond Myklebust 
109821f0ffafSTrond Myklebust 	atomic_long_dec(&xprt->queuelen);
109921f0ffafSTrond Myklebust 	rcu_read_lock();
110021f0ffafSTrond Myklebust 	xps = rcu_dereference(clnt->cl_xpi.xpi_xpswitch);
110121f0ffafSTrond Myklebust 	atomic_long_dec(&xps->xps_queuelen);
110221f0ffafSTrond Myklebust 	rcu_read_unlock();
110321f0ffafSTrond Myklebust 
110421f0ffafSTrond Myklebust 	xprt_put(xprt);
110521f0ffafSTrond Myklebust }
110621f0ffafSTrond Myklebust 
rpc_task_release_transport(struct rpc_task * task)11070f90be13SBill Baker void rpc_task_release_transport(struct rpc_task *task)
11080f90be13SBill Baker {
11090f90be13SBill Baker 	struct rpc_xprt *xprt = task->tk_xprt;
11100f90be13SBill Baker 
11110f90be13SBill Baker 	if (xprt) {
11120f90be13SBill Baker 		task->tk_xprt = NULL;
111321f0ffafSTrond Myklebust 		if (task->tk_client)
111421f0ffafSTrond Myklebust 			rpc_task_release_xprt(task->tk_client, xprt);
111521f0ffafSTrond Myklebust 		else
11160f90be13SBill Baker 			xprt_put(xprt);
11170f90be13SBill Baker 	}
11180f90be13SBill Baker }
11190f90be13SBill Baker EXPORT_SYMBOL_GPL(rpc_task_release_transport);
11200f90be13SBill Baker 
rpc_task_release_client(struct rpc_task * task)112158f9612cSTrond Myklebust void rpc_task_release_client(struct rpc_task *task)
112258f9612cSTrond Myklebust {
112358f9612cSTrond Myklebust 	struct rpc_clnt *clnt = task->tk_client;
112458f9612cSTrond Myklebust 
112521f0ffafSTrond Myklebust 	rpc_task_release_transport(task);
112658f9612cSTrond Myklebust 	if (clnt != NULL) {
112758f9612cSTrond Myklebust 		/* Remove from client task list */
112858f9612cSTrond Myklebust 		spin_lock(&clnt->cl_lock);
112958f9612cSTrond Myklebust 		list_del(&task->tk_task);
113058f9612cSTrond Myklebust 		spin_unlock(&clnt->cl_lock);
113158f9612cSTrond Myklebust 		task->tk_client = NULL;
113258f9612cSTrond Myklebust 
113358f9612cSTrond Myklebust 		rpc_release_client(clnt);
113458f9612cSTrond Myklebust 	}
1135fb43d172STrond Myklebust }
11360f90be13SBill Baker 
1137a101b043STrond Myklebust static struct rpc_xprt *
rpc_task_get_first_xprt(struct rpc_clnt * clnt)1138a101b043STrond Myklebust rpc_task_get_first_xprt(struct rpc_clnt *clnt)
1139a101b043STrond Myklebust {
1140a101b043STrond Myklebust 	struct rpc_xprt *xprt;
1141a101b043STrond Myklebust 
1142a101b043STrond Myklebust 	rcu_read_lock();
1143a101b043STrond Myklebust 	xprt = xprt_get(rcu_dereference(clnt->cl_xprt));
1144a101b043STrond Myklebust 	rcu_read_unlock();
1145a101b043STrond Myklebust 	return rpc_task_get_xprt(clnt, xprt);
1146a101b043STrond Myklebust }
1147a101b043STrond Myklebust 
1148a101b043STrond Myklebust static struct rpc_xprt *
rpc_task_get_next_xprt(struct rpc_clnt * clnt)1149a101b043STrond Myklebust rpc_task_get_next_xprt(struct rpc_clnt *clnt)
1150a101b043STrond Myklebust {
1151a101b043STrond Myklebust 	return rpc_task_get_xprt(clnt, xprt_iter_get_next(&clnt->cl_xpi));
1152a101b043STrond Myklebust }
1153a101b043STrond Myklebust 
11540f90be13SBill Baker static
rpc_task_set_transport(struct rpc_task * task,struct rpc_clnt * clnt)11550f90be13SBill Baker void rpc_task_set_transport(struct rpc_task *task, struct rpc_clnt *clnt)
11560f90be13SBill Baker {
1157e13433b4SOlga Kornievskaia 	if (task->tk_xprt) {
1158e13433b4SOlga Kornievskaia 		if (!(test_bit(XPRT_OFFLINE, &task->tk_xprt->state) &&
115982ee41b8SOlga Kornievskaia 		      (task->tk_flags & RPC_TASK_MOVEABLE)))
11605a0c257fSNeilBrown 			return;
1161e13433b4SOlga Kornievskaia 		xprt_release(task);
1162e13433b4SOlga Kornievskaia 		xprt_put(task->tk_xprt);
1163e13433b4SOlga Kornievskaia 	}
11645a0c257fSNeilBrown 	if (task->tk_flags & RPC_TASK_NO_ROUND_ROBIN)
11655a0c257fSNeilBrown 		task->tk_xprt = rpc_task_get_first_xprt(clnt);
11665a0c257fSNeilBrown 	else
1167a101b043STrond Myklebust 		task->tk_xprt = rpc_task_get_next_xprt(clnt);
116858f9612cSTrond Myklebust }
116958f9612cSTrond Myklebust 
117058f9612cSTrond Myklebust static
rpc_task_set_client(struct rpc_task * task,struct rpc_clnt * clnt)117158f9612cSTrond Myklebust void rpc_task_set_client(struct rpc_task *task, struct rpc_clnt *clnt)
117258f9612cSTrond Myklebust {
11730f90be13SBill Baker 	rpc_task_set_transport(task, clnt);
117458f9612cSTrond Myklebust 	task->tk_client = clnt;
117571d3d0ebSTrond Myklebust 	refcount_inc(&clnt->cl_count);
117658f9612cSTrond Myklebust 	if (clnt->cl_softrtry)
117758f9612cSTrond Myklebust 		task->tk_flags |= RPC_TASK_SOFT;
1178ae6ec918STrond Myklebust 	if (clnt->cl_softerr)
1179ae6ec918STrond Myklebust 		task->tk_flags |= RPC_TASK_TIMEOUT;
11808a19a0b6STrond Myklebust 	if (clnt->cl_noretranstimeo)
11818a19a0b6STrond Myklebust 		task->tk_flags |= RPC_TASK_NO_RETRANS_TIMEOUT;
118258f9612cSTrond Myklebust 	/* Add to the client's list of all tasks */
118358f9612cSTrond Myklebust 	spin_lock(&clnt->cl_lock);
118458f9612cSTrond Myklebust 	list_add_tail(&task->tk_task, &clnt->cl_tasks);
118558f9612cSTrond Myklebust 	spin_unlock(&clnt->cl_lock);
118658f9612cSTrond Myklebust }
118758f9612cSTrond Myklebust 
118858f9612cSTrond Myklebust static void
rpc_task_set_rpc_message(struct rpc_task * task,const struct rpc_message * msg)118958f9612cSTrond Myklebust rpc_task_set_rpc_message(struct rpc_task *task, const struct rpc_message *msg)
119058f9612cSTrond Myklebust {
119158f9612cSTrond Myklebust 	if (msg != NULL) {
119258f9612cSTrond Myklebust 		task->tk_msg.rpc_proc = msg->rpc_proc;
119358f9612cSTrond Myklebust 		task->tk_msg.rpc_argp = msg->rpc_argp;
119458f9612cSTrond Myklebust 		task->tk_msg.rpc_resp = msg->rpc_resp;
11957eac5264STrond Myklebust 		task->tk_msg.rpc_cred = msg->rpc_cred;
11967eac5264STrond Myklebust 		if (!(task->tk_flags & RPC_TASK_CRED_NOREF))
11977eac5264STrond Myklebust 			get_cred(task->tk_msg.rpc_cred);
119858f9612cSTrond Myklebust 	}
119958f9612cSTrond Myklebust }
120058f9612cSTrond Myklebust 
12011da177e4SLinus Torvalds /*
12021da177e4SLinus Torvalds  * Default callback for async RPC calls
12031da177e4SLinus Torvalds  */
12041da177e4SLinus Torvalds static void
rpc_default_callback(struct rpc_task * task,void * data)1205963d8fe5STrond Myklebust rpc_default_callback(struct rpc_task *task, void *data)
12061da177e4SLinus Torvalds {
12071da177e4SLinus Torvalds }
12081da177e4SLinus Torvalds 
1209963d8fe5STrond Myklebust static const struct rpc_call_ops rpc_default_ops = {
1210963d8fe5STrond Myklebust 	.rpc_call_done = rpc_default_callback,
1211963d8fe5STrond Myklebust };
1212963d8fe5STrond Myklebust 
1213c970aa85STrond Myklebust /**
1214c970aa85STrond Myklebust  * rpc_run_task - Allocate a new RPC task, then run rpc_execute against it
1215c970aa85STrond Myklebust  * @task_setup_data: pointer to task initialisation data
1216c970aa85STrond Myklebust  */
rpc_run_task(const struct rpc_task_setup * task_setup_data)1217c970aa85STrond Myklebust struct rpc_task *rpc_run_task(const struct rpc_task_setup *task_setup_data)
12186e5b70e9STrond Myklebust {
121919445b99STrond Myklebust 	struct rpc_task *task;
12206e5b70e9STrond Myklebust 
122184115e1cSTrond Myklebust 	task = rpc_new_task(task_setup_data);
122225cf32adSTrond Myklebust 	if (IS_ERR(task))
122325cf32adSTrond Myklebust 		return task;
12246e5b70e9STrond Myklebust 
1225263fb9c2STrond Myklebust 	if (!RPC_IS_ASYNC(task))
1226263fb9c2STrond Myklebust 		task->tk_flags |= RPC_TASK_CRED_NOREF;
1227263fb9c2STrond Myklebust 
122858f9612cSTrond Myklebust 	rpc_task_set_client(task, task_setup_data->rpc_client);
122958f9612cSTrond Myklebust 	rpc_task_set_rpc_message(task, task_setup_data->rpc_message);
123058f9612cSTrond Myklebust 
123158f9612cSTrond Myklebust 	if (task->tk_action == NULL)
123258f9612cSTrond Myklebust 		rpc_call_start(task);
123358f9612cSTrond Myklebust 
12346e5b70e9STrond Myklebust 	atomic_inc(&task->tk_count);
123534f5b466STrond Myklebust 	rpc_execute(task);
123619445b99STrond Myklebust 	return task;
12376e5b70e9STrond Myklebust }
1238c970aa85STrond Myklebust EXPORT_SYMBOL_GPL(rpc_run_task);
12396e5b70e9STrond Myklebust 
12406e5b70e9STrond Myklebust /**
12416e5b70e9STrond Myklebust  * rpc_call_sync - Perform a synchronous RPC call
12426e5b70e9STrond Myklebust  * @clnt: pointer to RPC client
12436e5b70e9STrond Myklebust  * @msg: RPC call parameters
12446e5b70e9STrond Myklebust  * @flags: RPC call flags
12451da177e4SLinus Torvalds  */
rpc_call_sync(struct rpc_clnt * clnt,const struct rpc_message * msg,int flags)1246cbc20059STrond Myklebust int rpc_call_sync(struct rpc_clnt *clnt, const struct rpc_message *msg, int flags)
12471da177e4SLinus Torvalds {
12481da177e4SLinus Torvalds 	struct rpc_task	*task;
124984115e1cSTrond Myklebust 	struct rpc_task_setup task_setup_data = {
125084115e1cSTrond Myklebust 		.rpc_client = clnt,
125184115e1cSTrond Myklebust 		.rpc_message = msg,
125284115e1cSTrond Myklebust 		.callback_ops = &rpc_default_ops,
125384115e1cSTrond Myklebust 		.flags = flags,
125484115e1cSTrond Myklebust 	};
12551da177e4SLinus Torvalds 	int status;
12561da177e4SLinus Torvalds 
125750d2bdb1SWeston Andros Adamson 	WARN_ON_ONCE(flags & RPC_TASK_ASYNC);
125850d2bdb1SWeston Andros Adamson 	if (flags & RPC_TASK_ASYNC) {
125950d2bdb1SWeston Andros Adamson 		rpc_release_calldata(task_setup_data.callback_ops,
126050d2bdb1SWeston Andros Adamson 			task_setup_data.callback_data);
126150d2bdb1SWeston Andros Adamson 		return -EINVAL;
126250d2bdb1SWeston Andros Adamson 	}
12631da177e4SLinus Torvalds 
1264c970aa85STrond Myklebust 	task = rpc_run_task(&task_setup_data);
12656e5b70e9STrond Myklebust 	if (IS_ERR(task))
12666e5b70e9STrond Myklebust 		return PTR_ERR(task);
1267e60859acSTrond Myklebust 	status = task->tk_status;
1268bde8f00cSTrond Myklebust 	rpc_put_task(task);
12691da177e4SLinus Torvalds 	return status;
12701da177e4SLinus Torvalds }
1271e8914c65STrond Myklebust EXPORT_SYMBOL_GPL(rpc_call_sync);
12721da177e4SLinus Torvalds 
12736e5b70e9STrond Myklebust /**
12746e5b70e9STrond Myklebust  * rpc_call_async - Perform an asynchronous RPC call
12756e5b70e9STrond Myklebust  * @clnt: pointer to RPC client
12766e5b70e9STrond Myklebust  * @msg: RPC call parameters
12776e5b70e9STrond Myklebust  * @flags: RPC call flags
127865b6e42cSRandy Dunlap  * @tk_ops: RPC call ops
12796e5b70e9STrond Myklebust  * @data: user call data
12801da177e4SLinus Torvalds  */
12811da177e4SLinus Torvalds int
rpc_call_async(struct rpc_clnt * clnt,const struct rpc_message * msg,int flags,const struct rpc_call_ops * tk_ops,void * data)1282cbc20059STrond Myklebust rpc_call_async(struct rpc_clnt *clnt, const struct rpc_message *msg, int flags,
1283963d8fe5STrond Myklebust 	       const struct rpc_call_ops *tk_ops, void *data)
12841da177e4SLinus Torvalds {
12851da177e4SLinus Torvalds 	struct rpc_task	*task;
128684115e1cSTrond Myklebust 	struct rpc_task_setup task_setup_data = {
128784115e1cSTrond Myklebust 		.rpc_client = clnt,
128884115e1cSTrond Myklebust 		.rpc_message = msg,
128984115e1cSTrond Myklebust 		.callback_ops = tk_ops,
129084115e1cSTrond Myklebust 		.callback_data = data,
129184115e1cSTrond Myklebust 		.flags = flags|RPC_TASK_ASYNC,
129284115e1cSTrond Myklebust 	};
12931da177e4SLinus Torvalds 
1294c970aa85STrond Myklebust 	task = rpc_run_task(&task_setup_data);
12956e5b70e9STrond Myklebust 	if (IS_ERR(task))
12966e5b70e9STrond Myklebust 		return PTR_ERR(task);
1297bde8f00cSTrond Myklebust 	rpc_put_task(task);
12986e5b70e9STrond Myklebust 	return 0;
12991da177e4SLinus Torvalds }
1300e8914c65STrond Myklebust EXPORT_SYMBOL_GPL(rpc_call_async);
13011da177e4SLinus Torvalds 
13029e00abc3STrond Myklebust #if defined(CONFIG_SUNRPC_BACKCHANNEL)
1303477687e1STrond Myklebust static void call_bc_encode(struct rpc_task *task);
1304477687e1STrond Myklebust 
130555ae1aabSRicardo Labiaga /**
130655ae1aabSRicardo Labiaga  * rpc_run_bc_task - Allocate a new RPC task for backchannel use, then run
130755ae1aabSRicardo Labiaga  * rpc_execute against it
13087a73fddeSJaswinder Singh Rajput  * @req: RPC request
130955ae1aabSRicardo Labiaga  */
rpc_run_bc_task(struct rpc_rqst * req)13100f419791STrond Myklebust struct rpc_task *rpc_run_bc_task(struct rpc_rqst *req)
131155ae1aabSRicardo Labiaga {
131255ae1aabSRicardo Labiaga 	struct rpc_task *task;
131355ae1aabSRicardo Labiaga 	struct rpc_task_setup task_setup_data = {
13140f419791STrond Myklebust 		.callback_ops = &rpc_default_ops,
1315762e4e67STrond Myklebust 		.flags = RPC_TASK_SOFTCONN |
1316762e4e67STrond Myklebust 			RPC_TASK_NO_RETRANS_TIMEOUT,
131755ae1aabSRicardo Labiaga 	};
131855ae1aabSRicardo Labiaga 
131955ae1aabSRicardo Labiaga 	dprintk("RPC: rpc_run_bc_task req= %p\n", req);
132055ae1aabSRicardo Labiaga 	/*
132155ae1aabSRicardo Labiaga 	 * Create an rpc_task to send the data
132255ae1aabSRicardo Labiaga 	 */
132355ae1aabSRicardo Labiaga 	task = rpc_new_task(&task_setup_data);
132425cf32adSTrond Myklebust 	if (IS_ERR(task)) {
132525cf32adSTrond Myklebust 		xprt_free_bc_request(req);
132625cf32adSTrond Myklebust 		return task;
132725cf32adSTrond Myklebust 	}
132825cf32adSTrond Myklebust 
1329902c5887STrond Myklebust 	xprt_init_bc_request(req, task);
133055ae1aabSRicardo Labiaga 
1331477687e1STrond Myklebust 	task->tk_action = call_bc_encode;
133255ae1aabSRicardo Labiaga 	atomic_inc(&task->tk_count);
13339a6478f6SWeston Andros Adamson 	WARN_ON_ONCE(atomic_read(&task->tk_count) != 2);
133455ae1aabSRicardo Labiaga 	rpc_execute(task);
133555ae1aabSRicardo Labiaga 
133655ae1aabSRicardo Labiaga 	dprintk("RPC: rpc_run_bc_task: task= %p\n", task);
133755ae1aabSRicardo Labiaga 	return task;
133855ae1aabSRicardo Labiaga }
13399e00abc3STrond Myklebust #endif /* CONFIG_SUNRPC_BACKCHANNEL */
134055ae1aabSRicardo Labiaga 
1341cf500bacSChuck Lever /**
1342cf500bacSChuck Lever  * rpc_prepare_reply_pages - Prepare to receive a reply data payload into pages
1343cf500bacSChuck Lever  * @req: RPC request to prepare
1344cf500bacSChuck Lever  * @pages: vector of struct page pointers
1345cf500bacSChuck Lever  * @base: offset in first page where receive should start, in bytes
1346cf500bacSChuck Lever  * @len: expected size of the upper layer data payload, in bytes
1347cf500bacSChuck Lever  * @hdrsize: expected size of upper layer reply header, in XDR words
1348cf500bacSChuck Lever  *
1349cf500bacSChuck Lever  */
rpc_prepare_reply_pages(struct rpc_rqst * req,struct page ** pages,unsigned int base,unsigned int len,unsigned int hdrsize)1350cf500bacSChuck Lever void rpc_prepare_reply_pages(struct rpc_rqst *req, struct page **pages,
1351cf500bacSChuck Lever 			     unsigned int base, unsigned int len,
1352cf500bacSChuck Lever 			     unsigned int hdrsize)
1353cf500bacSChuck Lever {
13549ed5af26STrond Myklebust 	hdrsize += RPC_REPHDRSIZE + req->rq_cred->cr_auth->au_ralign;
135502ef04e4SChuck Lever 
1356cf500bacSChuck Lever 	xdr_inline_pages(&req->rq_rcv_buf, hdrsize << 2, pages, base, len);
1357c509f15aSChuck Lever 	trace_rpc_xdr_reply_pages(req->rq_task, &req->rq_rcv_buf);
1358cf500bacSChuck Lever }
1359cf500bacSChuck Lever EXPORT_SYMBOL_GPL(rpc_prepare_reply_pages);
1360cf500bacSChuck Lever 
13611da177e4SLinus Torvalds void
rpc_call_start(struct rpc_task * task)136277de2c59STrond Myklebust rpc_call_start(struct rpc_task *task)
136377de2c59STrond Myklebust {
136477de2c59STrond Myklebust 	task->tk_action = call_start;
136577de2c59STrond Myklebust }
136677de2c59STrond Myklebust EXPORT_SYMBOL_GPL(rpc_call_start);
136777de2c59STrond Myklebust 
1368ed39440aSChuck Lever /**
1369ed39440aSChuck Lever  * rpc_peeraddr - extract remote peer address from clnt's xprt
1370ed39440aSChuck Lever  * @clnt: RPC client structure
1371ed39440aSChuck Lever  * @buf: target buffer
137265b6e42cSRandy Dunlap  * @bufsize: length of target buffer
1373ed39440aSChuck Lever  *
1374ed39440aSChuck Lever  * Returns the number of bytes that are actually in the stored address.
1375ed39440aSChuck Lever  */
rpc_peeraddr(struct rpc_clnt * clnt,struct sockaddr * buf,size_t bufsize)1376ed39440aSChuck Lever size_t rpc_peeraddr(struct rpc_clnt *clnt, struct sockaddr *buf, size_t bufsize)
1377ed39440aSChuck Lever {
1378ed39440aSChuck Lever 	size_t bytes;
13792446ab60STrond Myklebust 	struct rpc_xprt *xprt;
1380ed39440aSChuck Lever 
13812446ab60STrond Myklebust 	rcu_read_lock();
13822446ab60STrond Myklebust 	xprt = rcu_dereference(clnt->cl_xprt);
13832446ab60STrond Myklebust 
13842446ab60STrond Myklebust 	bytes = xprt->addrlen;
1385ed39440aSChuck Lever 	if (bytes > bufsize)
1386ed39440aSChuck Lever 		bytes = bufsize;
13872446ab60STrond Myklebust 	memcpy(buf, &xprt->addr, bytes);
13882446ab60STrond Myklebust 	rcu_read_unlock();
13892446ab60STrond Myklebust 
13902446ab60STrond Myklebust 	return bytes;
1391ed39440aSChuck Lever }
1392b86acd50SChuck Lever EXPORT_SYMBOL_GPL(rpc_peeraddr);
1393ed39440aSChuck Lever 
1394f425eba4SChuck Lever /**
1395f425eba4SChuck Lever  * rpc_peeraddr2str - return remote peer address in printable format
1396f425eba4SChuck Lever  * @clnt: RPC client structure
1397f425eba4SChuck Lever  * @format: address format
1398f425eba4SChuck Lever  *
13992446ab60STrond Myklebust  * NB: the lifetime of the memory referenced by the returned pointer is
14002446ab60STrond Myklebust  * the same as the rpc_xprt itself.  As long as the caller uses this
14012446ab60STrond Myklebust  * pointer, it must hold the RCU read lock.
1402f425eba4SChuck Lever  */
rpc_peeraddr2str(struct rpc_clnt * clnt,enum rpc_display_format_t format)1403b454ae90SChuck Lever const char *rpc_peeraddr2str(struct rpc_clnt *clnt,
1404b454ae90SChuck Lever 			     enum rpc_display_format_t format)
1405f425eba4SChuck Lever {
14062446ab60STrond Myklebust 	struct rpc_xprt *xprt;
14072446ab60STrond Myklebust 
14082446ab60STrond Myklebust 	xprt = rcu_dereference(clnt->cl_xprt);
14097559c7a2SChuck Lever 
14107559c7a2SChuck Lever 	if (xprt->address_strings[format] != NULL)
14117559c7a2SChuck Lever 		return xprt->address_strings[format];
14127559c7a2SChuck Lever 	else
14137559c7a2SChuck Lever 		return "unprintable";
1414f425eba4SChuck Lever }
1415b86acd50SChuck Lever EXPORT_SYMBOL_GPL(rpc_peeraddr2str);
1416f425eba4SChuck Lever 
14172e738fdcSChuck Lever static const struct sockaddr_in rpc_inaddr_loopback = {
14182e738fdcSChuck Lever 	.sin_family		= AF_INET,
14192e738fdcSChuck Lever 	.sin_addr.s_addr	= htonl(INADDR_ANY),
14202e738fdcSChuck Lever };
14212e738fdcSChuck Lever 
14222e738fdcSChuck Lever static const struct sockaddr_in6 rpc_in6addr_loopback = {
14232e738fdcSChuck Lever 	.sin6_family		= AF_INET6,
14242e738fdcSChuck Lever 	.sin6_addr		= IN6ADDR_ANY_INIT,
14252e738fdcSChuck Lever };
14262e738fdcSChuck Lever 
14272e738fdcSChuck Lever /*
14282e738fdcSChuck Lever  * Try a getsockname() on a connected datagram socket.  Using a
14292e738fdcSChuck Lever  * connected datagram socket prevents leaving a socket in TIME_WAIT.
14302e738fdcSChuck Lever  * This conserves the ephemeral port number space.
14312e738fdcSChuck Lever  *
14322e738fdcSChuck Lever  * Returns zero and fills in "buf" if successful; otherwise, a
14332e738fdcSChuck Lever  * negative errno is returned.
14342e738fdcSChuck Lever  */
rpc_sockname(struct net * net,struct sockaddr * sap,size_t salen,struct sockaddr * buf)14352e738fdcSChuck Lever static int rpc_sockname(struct net *net, struct sockaddr *sap, size_t salen,
14369b2c45d4SDenys Vlasenko 			struct sockaddr *buf)
14372e738fdcSChuck Lever {
14382e738fdcSChuck Lever 	struct socket *sock;
14392e738fdcSChuck Lever 	int err;
14402e738fdcSChuck Lever 
14412e738fdcSChuck Lever 	err = __sock_create(net, sap->sa_family,
14422e738fdcSChuck Lever 				SOCK_DGRAM, IPPROTO_UDP, &sock, 1);
14432e738fdcSChuck Lever 	if (err < 0) {
14442e738fdcSChuck Lever 		dprintk("RPC:       can't create UDP socket (%d)\n", err);
14452e738fdcSChuck Lever 		goto out;
14462e738fdcSChuck Lever 	}
14472e738fdcSChuck Lever 
14482e738fdcSChuck Lever 	switch (sap->sa_family) {
14492e738fdcSChuck Lever 	case AF_INET:
14502e738fdcSChuck Lever 		err = kernel_bind(sock,
14512e738fdcSChuck Lever 				(struct sockaddr *)&rpc_inaddr_loopback,
14522e738fdcSChuck Lever 				sizeof(rpc_inaddr_loopback));
14532e738fdcSChuck Lever 		break;
14542e738fdcSChuck Lever 	case AF_INET6:
14552e738fdcSChuck Lever 		err = kernel_bind(sock,
14562e738fdcSChuck Lever 				(struct sockaddr *)&rpc_in6addr_loopback,
14572e738fdcSChuck Lever 				sizeof(rpc_in6addr_loopback));
14582e738fdcSChuck Lever 		break;
14592e738fdcSChuck Lever 	default:
14602e738fdcSChuck Lever 		err = -EAFNOSUPPORT;
146150fa355bSWang ShaoBo 		goto out_release;
14622e738fdcSChuck Lever 	}
14632e738fdcSChuck Lever 	if (err < 0) {
14642e738fdcSChuck Lever 		dprintk("RPC:       can't bind UDP socket (%d)\n", err);
14652e738fdcSChuck Lever 		goto out_release;
14662e738fdcSChuck Lever 	}
14672e738fdcSChuck Lever 
14682e738fdcSChuck Lever 	err = kernel_connect(sock, sap, salen, 0);
14692e738fdcSChuck Lever 	if (err < 0) {
14702e738fdcSChuck Lever 		dprintk("RPC:       can't connect UDP socket (%d)\n", err);
14712e738fdcSChuck Lever 		goto out_release;
14722e738fdcSChuck Lever 	}
14732e738fdcSChuck Lever 
14749b2c45d4SDenys Vlasenko 	err = kernel_getsockname(sock, buf);
14752e738fdcSChuck Lever 	if (err < 0) {
14762e738fdcSChuck Lever 		dprintk("RPC:       getsockname failed (%d)\n", err);
14772e738fdcSChuck Lever 		goto out_release;
14782e738fdcSChuck Lever 	}
14792e738fdcSChuck Lever 
14802e738fdcSChuck Lever 	err = 0;
14812e738fdcSChuck Lever 	if (buf->sa_family == AF_INET6) {
14822e738fdcSChuck Lever 		struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)buf;
14832e738fdcSChuck Lever 		sin6->sin6_scope_id = 0;
14842e738fdcSChuck Lever 	}
14852e738fdcSChuck Lever 	dprintk("RPC:       %s succeeded\n", __func__);
14862e738fdcSChuck Lever 
14872e738fdcSChuck Lever out_release:
14882e738fdcSChuck Lever 	sock_release(sock);
14892e738fdcSChuck Lever out:
14902e738fdcSChuck Lever 	return err;
14912e738fdcSChuck Lever }
14922e738fdcSChuck Lever 
14932e738fdcSChuck Lever /*
14942e738fdcSChuck Lever  * Scraping a connected socket failed, so we don't have a useable
14952e738fdcSChuck Lever  * local address.  Fallback: generate an address that will prevent
14962e738fdcSChuck Lever  * the server from calling us back.
14972e738fdcSChuck Lever  *
14982e738fdcSChuck Lever  * Returns zero and fills in "buf" if successful; otherwise, a
14992e738fdcSChuck Lever  * negative errno is returned.
15002e738fdcSChuck Lever  */
rpc_anyaddr(int family,struct sockaddr * buf,size_t buflen)15012e738fdcSChuck Lever static int rpc_anyaddr(int family, struct sockaddr *buf, size_t buflen)
15022e738fdcSChuck Lever {
15032e738fdcSChuck Lever 	switch (family) {
15042e738fdcSChuck Lever 	case AF_INET:
15052e738fdcSChuck Lever 		if (buflen < sizeof(rpc_inaddr_loopback))
15062e738fdcSChuck Lever 			return -EINVAL;
15072e738fdcSChuck Lever 		memcpy(buf, &rpc_inaddr_loopback,
15082e738fdcSChuck Lever 				sizeof(rpc_inaddr_loopback));
15092e738fdcSChuck Lever 		break;
15102e738fdcSChuck Lever 	case AF_INET6:
15112e738fdcSChuck Lever 		if (buflen < sizeof(rpc_in6addr_loopback))
15122e738fdcSChuck Lever 			return -EINVAL;
15132e738fdcSChuck Lever 		memcpy(buf, &rpc_in6addr_loopback,
15142e738fdcSChuck Lever 				sizeof(rpc_in6addr_loopback));
15150b161e63STrond Myklebust 		break;
15162e738fdcSChuck Lever 	default:
15172e738fdcSChuck Lever 		dprintk("RPC:       %s: address family not supported\n",
15182e738fdcSChuck Lever 			__func__);
15192e738fdcSChuck Lever 		return -EAFNOSUPPORT;
15202e738fdcSChuck Lever 	}
15212e738fdcSChuck Lever 	dprintk("RPC:       %s: succeeded\n", __func__);
15222e738fdcSChuck Lever 	return 0;
15232e738fdcSChuck Lever }
15242e738fdcSChuck Lever 
15252e738fdcSChuck Lever /**
15262e738fdcSChuck Lever  * rpc_localaddr - discover local endpoint address for an RPC client
15272e738fdcSChuck Lever  * @clnt: RPC client structure
15282e738fdcSChuck Lever  * @buf: target buffer
15292e738fdcSChuck Lever  * @buflen: size of target buffer, in bytes
15302e738fdcSChuck Lever  *
15312e738fdcSChuck Lever  * Returns zero and fills in "buf" and "buflen" if successful;
15322e738fdcSChuck Lever  * otherwise, a negative errno is returned.
15332e738fdcSChuck Lever  *
15342e738fdcSChuck Lever  * This works even if the underlying transport is not currently connected,
15352e738fdcSChuck Lever  * or if the upper layer never previously provided a source address.
15362e738fdcSChuck Lever  *
15372e738fdcSChuck Lever  * The result of this function call is transient: multiple calls in
15382e738fdcSChuck Lever  * succession may give different results, depending on how local
15392e738fdcSChuck Lever  * networking configuration changes over time.
15402e738fdcSChuck Lever  */
rpc_localaddr(struct rpc_clnt * clnt,struct sockaddr * buf,size_t buflen)15412e738fdcSChuck Lever int rpc_localaddr(struct rpc_clnt *clnt, struct sockaddr *buf, size_t buflen)
15422e738fdcSChuck Lever {
15432e738fdcSChuck Lever 	struct sockaddr_storage address;
15442e738fdcSChuck Lever 	struct sockaddr *sap = (struct sockaddr *)&address;
15452e738fdcSChuck Lever 	struct rpc_xprt *xprt;
15462e738fdcSChuck Lever 	struct net *net;
15472e738fdcSChuck Lever 	size_t salen;
15482e738fdcSChuck Lever 	int err;
15492e738fdcSChuck Lever 
15502e738fdcSChuck Lever 	rcu_read_lock();
15512e738fdcSChuck Lever 	xprt = rcu_dereference(clnt->cl_xprt);
15522e738fdcSChuck Lever 	salen = xprt->addrlen;
15532e738fdcSChuck Lever 	memcpy(sap, &xprt->addr, salen);
15542e738fdcSChuck Lever 	net = get_net(xprt->xprt_net);
15552e738fdcSChuck Lever 	rcu_read_unlock();
15562e738fdcSChuck Lever 
15572e738fdcSChuck Lever 	rpc_set_port(sap, 0);
15589b2c45d4SDenys Vlasenko 	err = rpc_sockname(net, sap, salen, buf);
15592e738fdcSChuck Lever 	put_net(net);
15602e738fdcSChuck Lever 	if (err != 0)
15612e738fdcSChuck Lever 		/* Couldn't discover local address, return ANYADDR */
15622e738fdcSChuck Lever 		return rpc_anyaddr(sap->sa_family, buf, buflen);
15632e738fdcSChuck Lever 	return 0;
15642e738fdcSChuck Lever }
15652e738fdcSChuck Lever EXPORT_SYMBOL_GPL(rpc_localaddr);
15662e738fdcSChuck Lever 
15671da177e4SLinus Torvalds void
rpc_setbufsize(struct rpc_clnt * clnt,unsigned int sndsize,unsigned int rcvsize)15681da177e4SLinus Torvalds rpc_setbufsize(struct rpc_clnt *clnt, unsigned int sndsize, unsigned int rcvsize)
15691da177e4SLinus Torvalds {
15702446ab60STrond Myklebust 	struct rpc_xprt *xprt;
15712446ab60STrond Myklebust 
15722446ab60STrond Myklebust 	rcu_read_lock();
15732446ab60STrond Myklebust 	xprt = rcu_dereference(clnt->cl_xprt);
1574470056c2SChuck Lever 	if (xprt->ops->set_buffer_size)
1575470056c2SChuck Lever 		xprt->ops->set_buffer_size(xprt, sndsize, rcvsize);
15762446ab60STrond Myklebust 	rcu_read_unlock();
15771da177e4SLinus Torvalds }
1578e8914c65STrond Myklebust EXPORT_SYMBOL_GPL(rpc_setbufsize);
15791da177e4SLinus Torvalds 
15802446ab60STrond Myklebust /**
15812446ab60STrond Myklebust  * rpc_net_ns - Get the network namespace for this RPC client
15822446ab60STrond Myklebust  * @clnt: RPC client to query
15832446ab60STrond Myklebust  *
15842446ab60STrond Myklebust  */
rpc_net_ns(struct rpc_clnt * clnt)15852446ab60STrond Myklebust struct net *rpc_net_ns(struct rpc_clnt *clnt)
15862446ab60STrond Myklebust {
15872446ab60STrond Myklebust 	struct net *ret;
15882446ab60STrond Myklebust 
15892446ab60STrond Myklebust 	rcu_read_lock();
15902446ab60STrond Myklebust 	ret = rcu_dereference(clnt->cl_xprt)->xprt_net;
15912446ab60STrond Myklebust 	rcu_read_unlock();
15922446ab60STrond Myklebust 	return ret;
15932446ab60STrond Myklebust }
15942446ab60STrond Myklebust EXPORT_SYMBOL_GPL(rpc_net_ns);
15952446ab60STrond Myklebust 
15962446ab60STrond Myklebust /**
15972446ab60STrond Myklebust  * rpc_max_payload - Get maximum payload size for a transport, in bytes
15982446ab60STrond Myklebust  * @clnt: RPC client to query
15991da177e4SLinus Torvalds  *
16001da177e4SLinus Torvalds  * For stream transports, this is one RPC record fragment (see RFC
16011da177e4SLinus Torvalds  * 1831), as we don't support multi-record requests yet.  For datagram
16021da177e4SLinus Torvalds  * transports, this is the size of an IP packet minus the IP, UDP, and
16031da177e4SLinus Torvalds  * RPC header sizes.
16041da177e4SLinus Torvalds  */
rpc_max_payload(struct rpc_clnt * clnt)16051da177e4SLinus Torvalds size_t rpc_max_payload(struct rpc_clnt *clnt)
16061da177e4SLinus Torvalds {
16072446ab60STrond Myklebust 	size_t ret;
16082446ab60STrond Myklebust 
16092446ab60STrond Myklebust 	rcu_read_lock();
16102446ab60STrond Myklebust 	ret = rcu_dereference(clnt->cl_xprt)->max_payload;
16112446ab60STrond Myklebust 	rcu_read_unlock();
16122446ab60STrond Myklebust 	return ret;
16131da177e4SLinus Torvalds }
1614b86acd50SChuck Lever EXPORT_SYMBOL_GPL(rpc_max_payload);
16151da177e4SLinus Torvalds 
161635f5a422SChuck Lever /**
16176b26cc8cSChuck Lever  * rpc_max_bc_payload - Get maximum backchannel payload size, in bytes
16186b26cc8cSChuck Lever  * @clnt: RPC client to query
16196b26cc8cSChuck Lever  */
rpc_max_bc_payload(struct rpc_clnt * clnt)16206b26cc8cSChuck Lever size_t rpc_max_bc_payload(struct rpc_clnt *clnt)
16216b26cc8cSChuck Lever {
16226b26cc8cSChuck Lever 	struct rpc_xprt *xprt;
16236b26cc8cSChuck Lever 	size_t ret;
16246b26cc8cSChuck Lever 
16256b26cc8cSChuck Lever 	rcu_read_lock();
16266b26cc8cSChuck Lever 	xprt = rcu_dereference(clnt->cl_xprt);
16276b26cc8cSChuck Lever 	ret = xprt->ops->bc_maxpayload(xprt);
16286b26cc8cSChuck Lever 	rcu_read_unlock();
16296b26cc8cSChuck Lever 	return ret;
16306b26cc8cSChuck Lever }
16316b26cc8cSChuck Lever EXPORT_SYMBOL_GPL(rpc_max_bc_payload);
16326b26cc8cSChuck Lever 
rpc_num_bc_slots(struct rpc_clnt * clnt)16337402a4feSTrond Myklebust unsigned int rpc_num_bc_slots(struct rpc_clnt *clnt)
16347402a4feSTrond Myklebust {
16357402a4feSTrond Myklebust 	struct rpc_xprt *xprt;
16367402a4feSTrond Myklebust 	unsigned int ret;
16377402a4feSTrond Myklebust 
16387402a4feSTrond Myklebust 	rcu_read_lock();
16397402a4feSTrond Myklebust 	xprt = rcu_dereference(clnt->cl_xprt);
16407402a4feSTrond Myklebust 	ret = xprt->ops->bc_num_slots(xprt);
16417402a4feSTrond Myklebust 	rcu_read_unlock();
16427402a4feSTrond Myklebust 	return ret;
16437402a4feSTrond Myklebust }
16447402a4feSTrond Myklebust EXPORT_SYMBOL_GPL(rpc_num_bc_slots);
16457402a4feSTrond Myklebust 
16466b26cc8cSChuck Lever /**
164735f5a422SChuck Lever  * rpc_force_rebind - force transport to check that remote port is unchanged
164835f5a422SChuck Lever  * @clnt: client to rebind
164935f5a422SChuck Lever  *
165035f5a422SChuck Lever  */
rpc_force_rebind(struct rpc_clnt * clnt)165135f5a422SChuck Lever void rpc_force_rebind(struct rpc_clnt *clnt)
165235f5a422SChuck Lever {
16532446ab60STrond Myklebust 	if (clnt->cl_autobind) {
16542446ab60STrond Myklebust 		rcu_read_lock();
16552446ab60STrond Myklebust 		xprt_clear_bound(rcu_dereference(clnt->cl_xprt));
16562446ab60STrond Myklebust 		rcu_read_unlock();
16572446ab60STrond Myklebust 	}
165835f5a422SChuck Lever }
1659b86acd50SChuck Lever EXPORT_SYMBOL_GPL(rpc_force_rebind);
166035f5a422SChuck Lever 
16619e6fa0bbSTrond Myklebust static int
__rpc_restart_call(struct rpc_task * task,void (* action)(struct rpc_task *))16629e6fa0bbSTrond Myklebust __rpc_restart_call(struct rpc_task *task, void (*action)(struct rpc_task *))
1663aae2006eSAndy Adamson {
1664494314c4STrond Myklebust 	task->tk_status = 0;
16655ad64b36STrond Myklebust 	task->tk_rpc_status = 0;
16669e6fa0bbSTrond Myklebust 	task->tk_action = action;
1667f1f88fc7STrond Myklebust 	return 1;
1668aae2006eSAndy Adamson }
1669aae2006eSAndy Adamson 
1670aae2006eSAndy Adamson /*
16711da177e4SLinus Torvalds  * Restart an (async) RPC call. Usually called from within the
16721da177e4SLinus Torvalds  * exit handler.
16731da177e4SLinus Torvalds  */
1674f1f88fc7STrond Myklebust int
rpc_restart_call(struct rpc_task * task)16751da177e4SLinus Torvalds rpc_restart_call(struct rpc_task *task)
16761da177e4SLinus Torvalds {
16779e6fa0bbSTrond Myklebust 	return __rpc_restart_call(task, call_start);
16781da177e4SLinus Torvalds }
1679e8914c65STrond Myklebust EXPORT_SYMBOL_GPL(rpc_restart_call);
16801da177e4SLinus Torvalds 
16819e6fa0bbSTrond Myklebust /*
16829e6fa0bbSTrond Myklebust  * Restart an (async) RPC call from the call_prepare state.
16839e6fa0bbSTrond Myklebust  * Usually called from within the exit handler.
16849e6fa0bbSTrond Myklebust  */
16859e6fa0bbSTrond Myklebust int
rpc_restart_call_prepare(struct rpc_task * task)16869e6fa0bbSTrond Myklebust rpc_restart_call_prepare(struct rpc_task *task)
16879e6fa0bbSTrond Myklebust {
16889e6fa0bbSTrond Myklebust 	if (task->tk_ops->rpc_call_prepare != NULL)
16899e6fa0bbSTrond Myklebust 		return __rpc_restart_call(task, rpc_prepare_task);
16909e6fa0bbSTrond Myklebust 	return rpc_restart_call(task);
16919e6fa0bbSTrond Myklebust }
16929e6fa0bbSTrond Myklebust EXPORT_SYMBOL_GPL(rpc_restart_call_prepare);
16939e6fa0bbSTrond Myklebust 
1694b4b9d2ccSJeff Layton const char
rpc_proc_name(const struct rpc_task * task)1695b4b9d2ccSJeff Layton *rpc_proc_name(const struct rpc_task *task)
16963748f1e4SChuck Lever {
16973748f1e4SChuck Lever 	const struct rpc_procinfo *proc = task->tk_msg.rpc_proc;
16983748f1e4SChuck Lever 
16993748f1e4SChuck Lever 	if (proc) {
17003748f1e4SChuck Lever 		if (proc->p_name)
17013748f1e4SChuck Lever 			return proc->p_name;
17023748f1e4SChuck Lever 		else
17033748f1e4SChuck Lever 			return "NULL";
17043748f1e4SChuck Lever 	} else
17053748f1e4SChuck Lever 		return "no proc";
17063748f1e4SChuck Lever }
17073748f1e4SChuck Lever 
17085ad64b36STrond Myklebust static void
__rpc_call_rpcerror(struct rpc_task * task,int tk_status,int rpc_status)17095ad64b36STrond Myklebust __rpc_call_rpcerror(struct rpc_task *task, int tk_status, int rpc_status)
17105ad64b36STrond Myklebust {
17110125ecbbSChuck Lever 	trace_rpc_call_rpcerror(task, tk_status, rpc_status);
171239494194STrond Myklebust 	rpc_task_set_rpc_status(task, rpc_status);
17135ad64b36STrond Myklebust 	rpc_exit(task, tk_status);
17145ad64b36STrond Myklebust }
17155ad64b36STrond Myklebust 
17165ad64b36STrond Myklebust static void
rpc_call_rpcerror(struct rpc_task * task,int status)17175ad64b36STrond Myklebust rpc_call_rpcerror(struct rpc_task *task, int status)
17185ad64b36STrond Myklebust {
17195ad64b36STrond Myklebust 	__rpc_call_rpcerror(task, status, status);
17205ad64b36STrond Myklebust }
17215ad64b36STrond Myklebust 
17221da177e4SLinus Torvalds /*
17231da177e4SLinus Torvalds  * 0.  Initial state
17241da177e4SLinus Torvalds  *
17251da177e4SLinus Torvalds  *     Other FSM states can be visited zero or more times, but
17261da177e4SLinus Torvalds  *     this state is visited exactly once for each RPC.
17271da177e4SLinus Torvalds  */
17281da177e4SLinus Torvalds static void
call_start(struct rpc_task * task)17291da177e4SLinus Torvalds call_start(struct rpc_task *task)
17301da177e4SLinus Torvalds {
17311da177e4SLinus Torvalds 	struct rpc_clnt	*clnt = task->tk_client;
17321c5876ddSChristoph Hellwig 	int idx = task->tk_msg.rpc_proc->p_statidx;
17331da177e4SLinus Torvalds 
1734c435da68SChuck Lever 	trace_rpc_request(task);
17351da177e4SLinus Torvalds 
1736d9615d16SBenjamin Coddington 	if (task->tk_client->cl_shutdown) {
1737d9615d16SBenjamin Coddington 		rpc_call_rpcerror(task, -EIO);
1738d9615d16SBenjamin Coddington 		return;
1739d9615d16SBenjamin Coddington 	}
1740d9615d16SBenjamin Coddington 
17411c5876ddSChristoph Hellwig 	/* Increment call count (version might not be valid for ping) */
17421c5876ddSChristoph Hellwig 	if (clnt->cl_program->version[clnt->cl_vers])
17431c5876ddSChristoph Hellwig 		clnt->cl_program->version[clnt->cl_vers]->counts[idx]++;
17441da177e4SLinus Torvalds 	clnt->cl_stats->rpccnt++;
17451da177e4SLinus Torvalds 	task->tk_action = call_reserve;
17460f90be13SBill Baker 	rpc_task_set_transport(task, clnt);
17471da177e4SLinus Torvalds }
17481da177e4SLinus Torvalds 
17491da177e4SLinus Torvalds /*
17501da177e4SLinus Torvalds  * 1.	Reserve an RPC call slot
17511da177e4SLinus Torvalds  */
17521da177e4SLinus Torvalds static void
call_reserve(struct rpc_task * task)17531da177e4SLinus Torvalds call_reserve(struct rpc_task *task)
17541da177e4SLinus Torvalds {
17551da177e4SLinus Torvalds 	task->tk_status  = 0;
17561da177e4SLinus Torvalds 	task->tk_action  = call_reserveresult;
17571da177e4SLinus Torvalds 	xprt_reserve(task);
17581da177e4SLinus Torvalds }
17591da177e4SLinus Torvalds 
1760ba60eb25STrond Myklebust static void call_retry_reserve(struct rpc_task *task);
1761ba60eb25STrond Myklebust 
17621da177e4SLinus Torvalds /*
17631da177e4SLinus Torvalds  * 1b.	Grok the result of xprt_reserve()
17641da177e4SLinus Torvalds  */
17651da177e4SLinus Torvalds static void
call_reserveresult(struct rpc_task * task)17661da177e4SLinus Torvalds call_reserveresult(struct rpc_task *task)
17671da177e4SLinus Torvalds {
17681da177e4SLinus Torvalds 	int status = task->tk_status;
17691da177e4SLinus Torvalds 
17701da177e4SLinus Torvalds 	/*
17711da177e4SLinus Torvalds 	 * After a call to xprt_reserve(), we must have either
17721da177e4SLinus Torvalds 	 * a request slot or else an error status.
17731da177e4SLinus Torvalds 	 */
17741da177e4SLinus Torvalds 	task->tk_status = 0;
17751da177e4SLinus Torvalds 	if (status >= 0) {
17761da177e4SLinus Torvalds 		if (task->tk_rqstp) {
1777f2d47d02SJ. Bruce Fields 			task->tk_action = call_refresh;
17781da177e4SLinus Torvalds 			return;
17791da177e4SLinus Torvalds 		}
17801da177e4SLinus Torvalds 
17815ad64b36STrond Myklebust 		rpc_call_rpcerror(task, -EIO);
17821da177e4SLinus Torvalds 		return;
17831da177e4SLinus Torvalds 	}
17841da177e4SLinus Torvalds 
17851da177e4SLinus Torvalds 	switch (status) {
17861afeaf5cSTrond Myklebust 	case -ENOMEM:
17871afeaf5cSTrond Myklebust 		rpc_delay(task, HZ >> 2);
1788df561f66SGustavo A. R. Silva 		fallthrough;
17891da177e4SLinus Torvalds 	case -EAGAIN:	/* woken up; retry */
1790ba60eb25STrond Myklebust 		task->tk_action = call_retry_reserve;
17911da177e4SLinus Torvalds 		return;
17921da177e4SLinus Torvalds 	default:
17935ad64b36STrond Myklebust 		rpc_call_rpcerror(task, status);
17941da177e4SLinus Torvalds 	}
17955cd8b0d4SChuck Lever }
17961da177e4SLinus Torvalds 
17971da177e4SLinus Torvalds /*
1798ba60eb25STrond Myklebust  * 1c.	Retry reserving an RPC call slot
1799ba60eb25STrond Myklebust  */
1800ba60eb25STrond Myklebust static void
call_retry_reserve(struct rpc_task * task)1801ba60eb25STrond Myklebust call_retry_reserve(struct rpc_task *task)
1802ba60eb25STrond Myklebust {
1803ba60eb25STrond Myklebust 	task->tk_status  = 0;
1804ba60eb25STrond Myklebust 	task->tk_action  = call_reserveresult;
1805ba60eb25STrond Myklebust 	xprt_retry_reserve(task);
1806ba60eb25STrond Myklebust }
1807ba60eb25STrond Myklebust 
1808ba60eb25STrond Myklebust /*
180955576244SJ. Bruce Fields  * 2.	Bind and/or refresh the credentials
181055576244SJ. Bruce Fields  */
181155576244SJ. Bruce Fields static void
call_refresh(struct rpc_task * task)181255576244SJ. Bruce Fields call_refresh(struct rpc_task *task)
181355576244SJ. Bruce Fields {
181455576244SJ. Bruce Fields 	task->tk_action = call_refreshresult;
181555576244SJ. Bruce Fields 	task->tk_status = 0;
181655576244SJ. Bruce Fields 	task->tk_client->cl_stats->rpcauthrefresh++;
181755576244SJ. Bruce Fields 	rpcauth_refreshcred(task);
181855576244SJ. Bruce Fields }
181955576244SJ. Bruce Fields 
182055576244SJ. Bruce Fields /*
182155576244SJ. Bruce Fields  * 2a.	Process the results of a credential refresh
182255576244SJ. Bruce Fields  */
182355576244SJ. Bruce Fields static void
call_refreshresult(struct rpc_task * task)182455576244SJ. Bruce Fields call_refreshresult(struct rpc_task *task)
182555576244SJ. Bruce Fields {
182655576244SJ. Bruce Fields 	int status = task->tk_status;
182755576244SJ. Bruce Fields 
182855576244SJ. Bruce Fields 	task->tk_status = 0;
18295fc43978STrond Myklebust 	task->tk_action = call_refresh;
183055576244SJ. Bruce Fields 	switch (status) {
18315fc43978STrond Myklebust 	case 0:
18326ff33b7dSWeston Andros Adamson 		if (rpcauth_uptodatecred(task)) {
18335fc43978STrond Myklebust 			task->tk_action = call_allocate;
183455576244SJ. Bruce Fields 			return;
18356ff33b7dSWeston Andros Adamson 		}
18366ff33b7dSWeston Andros Adamson 		/* Use rate-limiting and a max number of retries if refresh
18376ff33b7dSWeston Andros Adamson 		 * had status 0 but failed to update the cred.
18386ff33b7dSWeston Andros Adamson 		 */
1839df561f66SGustavo A. R. Silva 		fallthrough;
184055576244SJ. Bruce Fields 	case -ETIMEDOUT:
184155576244SJ. Bruce Fields 		rpc_delay(task, 3*HZ);
1842df561f66SGustavo A. R. Silva 		fallthrough;
18435fc43978STrond Myklebust 	case -EAGAIN:
18445fc43978STrond Myklebust 		status = -EACCES;
1845df561f66SGustavo A. R. Silva 		fallthrough;
1846f1ff0c27SAndy Adamson 	case -EKEYEXPIRED:
18475fc43978STrond Myklebust 		if (!task->tk_cred_retry)
18485fc43978STrond Myklebust 			break;
18495fc43978STrond Myklebust 		task->tk_cred_retry--;
18507c8099f6SChuck Lever 		trace_rpc_retry_refresh_status(task);
18515fc43978STrond Myklebust 		return;
1852a41b05edSNeilBrown 	case -ENOMEM:
1853a41b05edSNeilBrown 		rpc_delay(task, HZ >> 4);
1854a41b05edSNeilBrown 		return;
185555576244SJ. Bruce Fields 	}
18567c8099f6SChuck Lever 	trace_rpc_refresh_status(task);
18575ad64b36STrond Myklebust 	rpc_call_rpcerror(task, status);
185855576244SJ. Bruce Fields }
185955576244SJ. Bruce Fields 
186055576244SJ. Bruce Fields /*
186155576244SJ. Bruce Fields  * 2b.	Allocate the buffer. For details, see sched.c:rpc_malloc.
186202107148SChuck Lever  *	(Note: buffer memory is freed in xprt_release).
18631da177e4SLinus Torvalds  */
18641da177e4SLinus Torvalds static void
call_allocate(struct rpc_task * task)18651da177e4SLinus Torvalds call_allocate(struct rpc_task *task)
18661da177e4SLinus Torvalds {
18672c94b8ecSChuck Lever 	const struct rpc_auth *auth = task->tk_rqstp->rq_cred->cr_auth;
186802107148SChuck Lever 	struct rpc_rqst *req = task->tk_rqstp;
1869a4f0835cSTrond Myklebust 	struct rpc_xprt *xprt = req->rq_xprt;
1870499b4988SChristoph Hellwig 	const struct rpc_procinfo *proc = task->tk_msg.rpc_proc;
18715fe6eaa1SChuck Lever 	int status;
18721da177e4SLinus Torvalds 
18732bea90d4SChuck Lever 	task->tk_status = 0;
1874762e4e67STrond Myklebust 	task->tk_action = call_encode;
18752bea90d4SChuck Lever 
1876af6b61d7STrond Myklebust 	if (req->rq_buffer)
18771da177e4SLinus Torvalds 		return;
18781da177e4SLinus Torvalds 
18792bea90d4SChuck Lever 	if (proc->p_proc != 0) {
18802bea90d4SChuck Lever 		BUG_ON(proc->p_arglen == 0);
18812bea90d4SChuck Lever 		if (proc->p_decode != NULL)
18822bea90d4SChuck Lever 			BUG_ON(proc->p_replen == 0);
18832bea90d4SChuck Lever 	}
18841da177e4SLinus Torvalds 
18852bea90d4SChuck Lever 	/*
18862bea90d4SChuck Lever 	 * Calculate the size (in quads) of the RPC call
18872bea90d4SChuck Lever 	 * and reply headers, and convert both values
18882bea90d4SChuck Lever 	 * to byte sizes.
18892bea90d4SChuck Lever 	 */
18902c94b8ecSChuck Lever 	req->rq_callsize = RPC_CALLHDRSIZE + (auth->au_cslack << 1) +
18912c94b8ecSChuck Lever 			   proc->p_arglen;
18922bea90d4SChuck Lever 	req->rq_callsize <<= 2;
189351314960STrond Myklebust 	/*
189451314960STrond Myklebust 	 * Note: the reply buffer must at minimum allocate enough space
189551314960STrond Myklebust 	 * for the 'struct accepted_reply' from RFC5531.
189651314960STrond Myklebust 	 */
189751314960STrond Myklebust 	req->rq_rcvsize = RPC_REPHDRSIZE + auth->au_rslack + \
189851314960STrond Myklebust 			max_t(size_t, proc->p_replen, 2);
18992bea90d4SChuck Lever 	req->rq_rcvsize <<= 2;
19002bea90d4SChuck Lever 
19015fe6eaa1SChuck Lever 	status = xprt->ops->buf_alloc(task);
190206e234c6SChuck Lever 	trace_rpc_buf_alloc(task, status);
1903af6b61d7STrond Myklebust 	if (status == 0)
19045fe6eaa1SChuck Lever 		return;
19055fe6eaa1SChuck Lever 	if (status != -ENOMEM) {
19065ad64b36STrond Myklebust 		rpc_call_rpcerror(task, status);
19075fe6eaa1SChuck Lever 		return;
19085fe6eaa1SChuck Lever 	}
190946121cf7SChuck Lever 
19105afa9133STrond Myklebust 	if (RPC_IS_ASYNC(task) || !fatal_signal_pending(current)) {
1911b6e9c713STrond Myklebust 		task->tk_action = call_allocate;
19121da177e4SLinus Torvalds 		rpc_delay(task, HZ>>4);
19131da177e4SLinus Torvalds 		return;
19141da177e4SLinus Torvalds 	}
19151da177e4SLinus Torvalds 
1916714fbc73STrond Myklebust 	rpc_call_rpcerror(task, -ERESTARTSYS);
19171da177e4SLinus Torvalds }
19181da177e4SLinus Torvalds 
19197ebbbc6eSTrond Myklebust static int
rpc_task_need_encode(struct rpc_task * task)1920940e3318STrond Myklebust rpc_task_need_encode(struct rpc_task *task)
1921940e3318STrond Myklebust {
1922762e4e67STrond Myklebust 	return test_bit(RPC_TASK_NEED_XMIT, &task->tk_runstate) == 0 &&
1923762e4e67STrond Myklebust 		(!(task->tk_flags & RPC_TASK_SENT) ||
1924762e4e67STrond Myklebust 		 !(task->tk_flags & RPC_TASK_NO_RETRANS_TIMEOUT) ||
1925762e4e67STrond Myklebust 		 xprt_request_need_retransmit(task));
1926940e3318STrond Myklebust }
1927940e3318STrond Myklebust 
19281da177e4SLinus Torvalds static void
rpc_xdr_encode(struct rpc_task * task)1929b0e1c57eSChuck Lever rpc_xdr_encode(struct rpc_task *task)
19301da177e4SLinus Torvalds {
19311da177e4SLinus Torvalds 	struct rpc_rqst	*req = task->tk_rqstp;
1932e8680a24SChuck Lever 	struct xdr_stream xdr;
19331da177e4SLinus Torvalds 
1934b9c5bc03SChuck Lever 	xdr_buf_init(&req->rq_snd_buf,
19352bea90d4SChuck Lever 		     req->rq_buffer,
19362bea90d4SChuck Lever 		     req->rq_callsize);
1937b9c5bc03SChuck Lever 	xdr_buf_init(&req->rq_rcv_buf,
193868778945SChuck Lever 		     req->rq_rbuffer,
19392bea90d4SChuck Lever 		     req->rq_rcvsize);
19401da177e4SLinus Torvalds 
1941cc204d01STrond Myklebust 	req->rq_reply_bytes_recvd = 0;
1942e8680a24SChuck Lever 	req->rq_snd_buf.head[0].iov_len = 0;
1943e8680a24SChuck Lever 	xdr_init_encode(&xdr, &req->rq_snd_buf,
1944e8680a24SChuck Lever 			req->rq_snd_buf.head[0].iov_base, req);
1945e8680a24SChuck Lever 	if (rpc_encode_header(task, &xdr))
19461da177e4SLinus Torvalds 		return;
1947b0e1c57eSChuck Lever 
1948e8680a24SChuck Lever 	task->tk_status = rpcauth_wrap_req(task, &xdr);
19491da177e4SLinus Torvalds }
19501da177e4SLinus Torvalds 
19511da177e4SLinus Torvalds /*
1952762e4e67STrond Myklebust  * 3.	Encode arguments of an RPC call
1953762e4e67STrond Myklebust  */
1954762e4e67STrond Myklebust static void
call_encode(struct rpc_task * task)1955762e4e67STrond Myklebust call_encode(struct rpc_task *task)
1956762e4e67STrond Myklebust {
1957762e4e67STrond Myklebust 	if (!rpc_task_need_encode(task))
1958762e4e67STrond Myklebust 		goto out;
19596387039dSChuck Lever 
1960cc204d01STrond Myklebust 	/* Dequeue task from the receive queue while we're encoding */
1961cc204d01STrond Myklebust 	xprt_request_dequeue_xprt(task);
1962762e4e67STrond Myklebust 	/* Encode here so that rpcsec_gss can use correct sequence number. */
1963762e4e67STrond Myklebust 	rpc_xdr_encode(task);
1964eb07d5a4SNeilBrown 	/* Add task to reply queue before transmission to avoid races */
1965eb07d5a4SNeilBrown 	if (task->tk_status == 0 && rpc_reply_expected(task))
1966eb07d5a4SNeilBrown 		task->tk_status = xprt_request_enqueue_receive(task);
1967762e4e67STrond Myklebust 	/* Did the encode result in an error condition? */
1968762e4e67STrond Myklebust 	if (task->tk_status != 0) {
1969762e4e67STrond Myklebust 		/* Was the error nonfatal? */
197097b78ae9STrond Myklebust 		switch (task->tk_status) {
197197b78ae9STrond Myklebust 		case -EAGAIN:
197297b78ae9STrond Myklebust 		case -ENOMEM:
1973762e4e67STrond Myklebust 			rpc_delay(task, HZ >> 4);
197497b78ae9STrond Myklebust 			break;
197597b78ae9STrond Myklebust 		case -EKEYEXPIRED:
19769c5948c2SZhangXiaoxu 			if (!task->tk_cred_retry) {
1977ed06fce0STrond Myklebust 				rpc_call_rpcerror(task, task->tk_status);
19789c5948c2SZhangXiaoxu 			} else {
197997b78ae9STrond Myklebust 				task->tk_action = call_refresh;
19809c5948c2SZhangXiaoxu 				task->tk_cred_retry--;
19817c8099f6SChuck Lever 				trace_rpc_retry_refresh_status(task);
19829c5948c2SZhangXiaoxu 			}
198397b78ae9STrond Myklebust 			break;
198497b78ae9STrond Myklebust 		default:
19855ad64b36STrond Myklebust 			rpc_call_rpcerror(task, task->tk_status);
198697b78ae9STrond Myklebust 		}
1987762e4e67STrond Myklebust 		return;
1988762e4e67STrond Myklebust 	}
1989762e4e67STrond Myklebust 
1990762e4e67STrond Myklebust 	xprt_request_enqueue_transmit(task);
1991762e4e67STrond Myklebust out:
1992af6b61d7STrond Myklebust 	task->tk_action = call_transmit;
1993af6b61d7STrond Myklebust 	/* Check that the connection is OK */
1994af6b61d7STrond Myklebust 	if (!xprt_bound(task->tk_xprt))
1995762e4e67STrond Myklebust 		task->tk_action = call_bind;
1996af6b61d7STrond Myklebust 	else if (!xprt_connected(task->tk_xprt))
1997af6b61d7STrond Myklebust 		task->tk_action = call_connect;
1998762e4e67STrond Myklebust }
1999762e4e67STrond Myklebust 
2000762e4e67STrond Myklebust /*
200103e51d32STrond Myklebust  * Helpers to check if the task was already transmitted, and
200203e51d32STrond Myklebust  * to take action when that is the case.
200303e51d32STrond Myklebust  */
200403e51d32STrond Myklebust static bool
rpc_task_transmitted(struct rpc_task * task)200503e51d32STrond Myklebust rpc_task_transmitted(struct rpc_task *task)
200603e51d32STrond Myklebust {
200703e51d32STrond Myklebust 	return !test_bit(RPC_TASK_NEED_XMIT, &task->tk_runstate);
200803e51d32STrond Myklebust }
200903e51d32STrond Myklebust 
201003e51d32STrond Myklebust static void
rpc_task_handle_transmitted(struct rpc_task * task)201103e51d32STrond Myklebust rpc_task_handle_transmitted(struct rpc_task *task)
201203e51d32STrond Myklebust {
201303e51d32STrond Myklebust 	xprt_end_transmit(task);
201403e51d32STrond Myklebust 	task->tk_action = call_transmit_status;
201503e51d32STrond Myklebust }
201603e51d32STrond Myklebust 
201703e51d32STrond Myklebust /*
20181da177e4SLinus Torvalds  * 4.	Get the server port number if not yet set
20191da177e4SLinus Torvalds  */
20201da177e4SLinus Torvalds static void
call_bind(struct rpc_task * task)20211da177e4SLinus Torvalds call_bind(struct rpc_task *task)
20221da177e4SLinus Torvalds {
2023ad2368d6STrond Myklebust 	struct rpc_xprt *xprt = task->tk_rqstp->rq_xprt;
20241da177e4SLinus Torvalds 
202503e51d32STrond Myklebust 	if (rpc_task_transmitted(task)) {
202603e51d32STrond Myklebust 		rpc_task_handle_transmitted(task);
202703e51d32STrond Myklebust 		return;
202803e51d32STrond Myklebust 	}
202903e51d32STrond Myklebust 
2030009a82f6STrond Myklebust 	if (xprt_bound(xprt)) {
2031009a82f6STrond Myklebust 		task->tk_action = call_connect;
2032009a82f6STrond Myklebust 		return;
2033009a82f6STrond Myklebust 	}
2034009a82f6STrond Myklebust 
2035da351878SChuck Lever 	task->tk_action = call_bind_status;
20364d6c671aSTrond Myklebust 	if (!xprt_prepare_transmit(task))
20374d6c671aSTrond Myklebust 		return;
20384d6c671aSTrond Myklebust 
2039bbf7c1ddSChuck Lever 	xprt->ops->rpcbind(task);
20401da177e4SLinus Torvalds }
20411da177e4SLinus Torvalds 
20421da177e4SLinus Torvalds /*
2043da351878SChuck Lever  * 4a.	Sort out bind result
2044da351878SChuck Lever  */
2045da351878SChuck Lever static void
call_bind_status(struct rpc_task * task)2046da351878SChuck Lever call_bind_status(struct rpc_task *task)
2047da351878SChuck Lever {
2048bd736ed3STrond Myklebust 	struct rpc_xprt *xprt = task->tk_rqstp->rq_xprt;
2049906462afSChuck Lever 	int status = -EIO;
2050da351878SChuck Lever 
205103e51d32STrond Myklebust 	if (rpc_task_transmitted(task)) {
205203e51d32STrond Myklebust 		rpc_task_handle_transmitted(task);
205303e51d32STrond Myklebust 		return;
205403e51d32STrond Myklebust 	}
205503e51d32STrond Myklebust 
2056bd736ed3STrond Myklebust 	if (task->tk_status >= 0)
2057bd736ed3STrond Myklebust 		goto out_next;
2058bd736ed3STrond Myklebust 	if (xprt_bound(xprt)) {
2059da351878SChuck Lever 		task->tk_status = 0;
2060bd736ed3STrond Myklebust 		goto out_next;
2061da351878SChuck Lever 	}
2062da351878SChuck Lever 
2063da351878SChuck Lever 	switch (task->tk_status) {
2064381ba74aSTrond Myklebust 	case -ENOMEM:
2065381ba74aSTrond Myklebust 		rpc_delay(task, HZ >> 2);
20662429cbf6SChuck Lever 		goto retry_timeout;
2067da351878SChuck Lever 	case -EACCES:
206842ebfc2cSChuck Lever 		trace_rpcb_prog_unavail_err(task);
2069b79dc8ceSChuck Lever 		/* fail immediately if this is an RPC ping */
2070b79dc8ceSChuck Lever 		if (task->tk_msg.rpc_proc->p_proc == 0) {
2071b79dc8ceSChuck Lever 			status = -EOPNOTSUPP;
2072b79dc8ceSChuck Lever 			break;
2073b79dc8ceSChuck Lever 		}
2074ea635a51SChuck Lever 		rpc_delay(task, 3*HZ);
2075da45828eSTrond Myklebust 		goto retry_timeout;
207680f455daSTrond Myklebust 	case -ENOBUFS:
207780f455daSTrond Myklebust 		rpc_delay(task, HZ >> 2);
207880f455daSTrond Myklebust 		goto retry_timeout;
20794d6c671aSTrond Myklebust 	case -EAGAIN:
20804d6c671aSTrond Myklebust 		goto retry_timeout;
2081da351878SChuck Lever 	case -ETIMEDOUT:
208242ebfc2cSChuck Lever 		trace_rpcb_timeout_err(task);
2083da45828eSTrond Myklebust 		goto retry_timeout;
2084da351878SChuck Lever 	case -EPFNOSUPPORT:
2085906462afSChuck Lever 		/* server doesn't support any rpcbind version we know of */
208642ebfc2cSChuck Lever 		trace_rpcb_bind_version_err(task);
2087da351878SChuck Lever 		break;
2088da351878SChuck Lever 	case -EPROTONOSUPPORT:
208942ebfc2cSChuck Lever 		trace_rpcb_bind_version_err(task);
2090fdb63dcdSTrond Myklebust 		goto retry_timeout;
2091012da158SChuck Lever 	case -ECONNREFUSED:		/* connection problems */
2092012da158SChuck Lever 	case -ECONNRESET:
2093df277270STrond Myklebust 	case -ECONNABORTED:
2094012da158SChuck Lever 	case -ENOTCONN:
2095012da158SChuck Lever 	case -EHOSTDOWN:
2096eb5b46faSTrond Myklebust 	case -ENETDOWN:
2097012da158SChuck Lever 	case -EHOSTUNREACH:
2098012da158SChuck Lever 	case -ENETUNREACH:
2099012da158SChuck Lever 	case -EPIPE:
210042ebfc2cSChuck Lever 		trace_rpcb_unreachable_err(task);
2101012da158SChuck Lever 		if (!RPC_IS_SOFTCONN(task)) {
2102012da158SChuck Lever 			rpc_delay(task, 5*HZ);
2103012da158SChuck Lever 			goto retry_timeout;
2104012da158SChuck Lever 		}
2105012da158SChuck Lever 		status = task->tk_status;
2106012da158SChuck Lever 		break;
2107da351878SChuck Lever 	default:
210842ebfc2cSChuck Lever 		trace_rpcb_unrecognized_err(task);
2109da351878SChuck Lever 	}
2110da351878SChuck Lever 
21115ad64b36STrond Myklebust 	rpc_call_rpcerror(task, status);
2112da351878SChuck Lever 	return;
2113bd736ed3STrond Myklebust out_next:
2114bd736ed3STrond Myklebust 	task->tk_action = call_connect;
2115bd736ed3STrond Myklebust 	return;
2116da45828eSTrond Myklebust retry_timeout:
2117fdb63dcdSTrond Myklebust 	task->tk_status = 0;
21184d6c671aSTrond Myklebust 	task->tk_action = call_bind;
2119cea57789STrond Myklebust 	rpc_check_timeout(task);
2120da351878SChuck Lever }
2121da351878SChuck Lever 
2122da351878SChuck Lever /*
2123da351878SChuck Lever  * 4b.	Connect to the RPC server
21241da177e4SLinus Torvalds  */
21251da177e4SLinus Torvalds static void
call_connect(struct rpc_task * task)21261da177e4SLinus Torvalds call_connect(struct rpc_task *task)
21271da177e4SLinus Torvalds {
2128ad2368d6STrond Myklebust 	struct rpc_xprt *xprt = task->tk_rqstp->rq_xprt;
21291da177e4SLinus Torvalds 
213003e51d32STrond Myklebust 	if (rpc_task_transmitted(task)) {
213103e51d32STrond Myklebust 		rpc_task_handle_transmitted(task);
213203e51d32STrond Myklebust 		return;
213303e51d32STrond Myklebust 	}
213403e51d32STrond Myklebust 
2135009a82f6STrond Myklebust 	if (xprt_connected(xprt)) {
2136009a82f6STrond Myklebust 		task->tk_action = call_transmit;
2137009a82f6STrond Myklebust 		return;
2138009a82f6STrond Myklebust 	}
2139009a82f6STrond Myklebust 
21401da177e4SLinus Torvalds 	task->tk_action = call_connect_status;
21411da177e4SLinus Torvalds 	if (task->tk_status < 0)
21421da177e4SLinus Torvalds 		return;
2143786615bcSTrond Myklebust 	if (task->tk_flags & RPC_TASK_NOCONNECT) {
21445ad64b36STrond Myklebust 		rpc_call_rpcerror(task, -ENOTCONN);
2145786615bcSTrond Myklebust 		return;
2146786615bcSTrond Myklebust 	}
21474d6c671aSTrond Myklebust 	if (!xprt_prepare_transmit(task))
21484d6c671aSTrond Myklebust 		return;
21491da177e4SLinus Torvalds 	xprt_connect(task);
21501da177e4SLinus Torvalds }
21511da177e4SLinus Torvalds 
21521da177e4SLinus Torvalds /*
2153da351878SChuck Lever  * 4c.	Sort out connect result
21541da177e4SLinus Torvalds  */
21551da177e4SLinus Torvalds static void
call_connect_status(struct rpc_task * task)21561da177e4SLinus Torvalds call_connect_status(struct rpc_task *task)
21571da177e4SLinus Torvalds {
2158bd736ed3STrond Myklebust 	struct rpc_xprt *xprt = task->tk_rqstp->rq_xprt;
21591da177e4SLinus Torvalds 	struct rpc_clnt *clnt = task->tk_client;
21601da177e4SLinus Torvalds 	int status = task->tk_status;
21611da177e4SLinus Torvalds 
216203e51d32STrond Myklebust 	if (rpc_task_transmitted(task)) {
216303e51d32STrond Myklebust 		rpc_task_handle_transmitted(task);
21649bd11523STrond Myklebust 		return;
21659bd11523STrond Myklebust 	}
21669bd11523STrond Myklebust 
2167e671edb9SChuck Lever 	trace_rpc_connect_status(task);
2168bd736ed3STrond Myklebust 
2169bd736ed3STrond Myklebust 	if (task->tk_status == 0) {
2170bd736ed3STrond Myklebust 		clnt->cl_stats->netreconn++;
2171bd736ed3STrond Myklebust 		goto out_next;
2172bd736ed3STrond Myklebust 	}
2173bd736ed3STrond Myklebust 	if (xprt_connected(xprt)) {
2174bd736ed3STrond Myklebust 		task->tk_status = 0;
2175bd736ed3STrond Myklebust 		goto out_next;
2176bd736ed3STrond Myklebust 	}
2177bd736ed3STrond Myklebust 
2178561ec160STrond Myklebust 	task->tk_status = 0;
21791da177e4SLinus Torvalds 	switch (status) {
21803ed5e2a2STrond Myklebust 	case -ECONNREFUSED:
2181d4f51690STrond Myklebust 	case -ECONNRESET:
2182fd01b259SNeilBrown 		/* A positive refusal suggests a rebind is needed. */
2183fd01b259SNeilBrown 		if (RPC_IS_SOFTCONN(task))
2184fd01b259SNeilBrown 			break;
2185fd01b259SNeilBrown 		if (clnt->cl_autobind) {
2186fd01b259SNeilBrown 			rpc_force_rebind(clnt);
21877b3fef8eSTrond Myklebust 			goto out_retry;
2188fd01b259SNeilBrown 		}
2189df561f66SGustavo A. R. Silva 		fallthrough;
2190df277270STrond Myklebust 	case -ECONNABORTED:
2191eb5b46faSTrond Myklebust 	case -ENETDOWN:
21923ed5e2a2STrond Myklebust 	case -ENETUNREACH:
2193df277270STrond Myklebust 	case -EHOSTUNREACH:
21942fc193cfSTrond Myklebust 	case -EPIPE:
2195b8457606SChuck Lever 	case -EPROTO:
21962c2ee6d2SNeilBrown 		xprt_conditional_disconnect(task->tk_rqstp->rq_xprt,
21972c2ee6d2SNeilBrown 					    task->tk_rqstp->rq_connect_cookie);
21983ed5e2a2STrond Myklebust 		if (RPC_IS_SOFTCONN(task))
21992a491991STrond Myklebust 			break;
22001fa3e2ebSSteve Dickson 		/* retry with existing socket, after a delay */
22011fa3e2ebSSteve Dickson 		rpc_delay(task, 3*HZ);
2202df561f66SGustavo A. R. Silva 		fallthrough;
220380f455daSTrond Myklebust 	case -EADDRINUSE:
22040445f92cSTrond Myklebust 	case -ENOTCONN:
22053ed5e2a2STrond Myklebust 	case -EAGAIN:
2206485f2251STrond Myklebust 	case -ETIMEDOUT:
22076f081693SOlga Kornievskaia 		if (!(task->tk_flags & RPC_TASK_NO_ROUND_ROBIN) &&
22086f081693SOlga Kornievskaia 		    (task->tk_flags & RPC_TASK_MOVEABLE) &&
22096f081693SOlga Kornievskaia 		    test_bit(XPRT_REMOVE, &xprt->state)) {
22106f081693SOlga Kornievskaia 			struct rpc_xprt *saved = task->tk_xprt;
22116f081693SOlga Kornievskaia 			struct rpc_xprt_switch *xps;
22126f081693SOlga Kornievskaia 
22136f081693SOlga Kornievskaia 			rcu_read_lock();
22146f081693SOlga Kornievskaia 			xps = xprt_switch_get(rcu_dereference(clnt->cl_xpi.xpi_xpswitch));
22156f081693SOlga Kornievskaia 			rcu_read_unlock();
22166f081693SOlga Kornievskaia 			if (xps->xps_nxprts > 1) {
22176f081693SOlga Kornievskaia 				long value;
22186f081693SOlga Kornievskaia 
22196f081693SOlga Kornievskaia 				xprt_release(task);
22206f081693SOlga Kornievskaia 				value = atomic_long_dec_return(&xprt->queuelen);
22216f081693SOlga Kornievskaia 				if (value == 0)
2222497e6464SOlga Kornievskaia 					rpc_xprt_switch_remove_xprt(xps, saved,
2223497e6464SOlga Kornievskaia 								    true);
22246f081693SOlga Kornievskaia 				xprt_put(saved);
22256f081693SOlga Kornievskaia 				task->tk_xprt = NULL;
22266f081693SOlga Kornievskaia 				task->tk_action = call_start;
22276f081693SOlga Kornievskaia 			}
22286f081693SOlga Kornievskaia 			xprt_switch_put(xps);
22296f081693SOlga Kornievskaia 			if (!task->tk_xprt)
22306f081693SOlga Kornievskaia 				return;
22316f081693SOlga Kornievskaia 		}
22327b3fef8eSTrond Myklebust 		goto out_retry;
223380f455daSTrond Myklebust 	case -ENOBUFS:
223480f455daSTrond Myklebust 		rpc_delay(task, HZ >> 2);
223580f455daSTrond Myklebust 		goto out_retry;
22361da177e4SLinus Torvalds 	}
22375ad64b36STrond Myklebust 	rpc_call_rpcerror(task, status);
22387b3fef8eSTrond Myklebust 	return;
2239bd736ed3STrond Myklebust out_next:
2240bd736ed3STrond Myklebust 	task->tk_action = call_transmit;
2241bd736ed3STrond Myklebust 	return;
22427b3fef8eSTrond Myklebust out_retry:
22437b3fef8eSTrond Myklebust 	/* Check for timeouts before looping back to call_bind */
22447b3fef8eSTrond Myklebust 	task->tk_action = call_bind;
22457b3fef8eSTrond Myklebust 	rpc_check_timeout(task);
22462a491991STrond Myklebust }
22471da177e4SLinus Torvalds 
22481da177e4SLinus Torvalds /*
22491da177e4SLinus Torvalds  * 5.	Transmit the RPC request, and wait for reply
22501da177e4SLinus Torvalds  */
22511da177e4SLinus Torvalds static void
call_transmit(struct rpc_task * task)22521da177e4SLinus Torvalds call_transmit(struct rpc_task *task)
22531da177e4SLinus Torvalds {
225403e51d32STrond Myklebust 	if (rpc_task_transmitted(task)) {
225503e51d32STrond Myklebust 		rpc_task_handle_transmitted(task);
225603e51d32STrond Myklebust 		return;
225703e51d32STrond Myklebust 	}
225803e51d32STrond Myklebust 
2259ed7dc973STrond Myklebust 	task->tk_action = call_transmit_status;
22603a03818fSTrond Myklebust 	if (!xprt_prepare_transmit(task))
22613a03818fSTrond Myklebust 		return;
2262ed7dc973STrond Myklebust 	task->tk_status = 0;
2263ed7dc973STrond Myklebust 	if (test_bit(RPC_TASK_NEED_XMIT, &task->tk_runstate)) {
2264ed7dc973STrond Myklebust 		if (!xprt_connected(task->tk_xprt)) {
2265ed7dc973STrond Myklebust 			task->tk_status = -ENOTCONN;
2266ed7dc973STrond Myklebust 			return;
2267ed7dc973STrond Myklebust 		}
22681da177e4SLinus Torvalds 		xprt_transmit(task);
22691da177e4SLinus Torvalds 	}
2270c544577dSTrond Myklebust 	xprt_end_transmit(task);
2271c544577dSTrond Myklebust }
2272e0ab53deSTrond Myklebust 
2273e0ab53deSTrond Myklebust /*
2274e0ab53deSTrond Myklebust  * 5a.	Handle cleanup after a transmission
2275e0ab53deSTrond Myklebust  */
2276e0ab53deSTrond Myklebust static void
call_transmit_status(struct rpc_task * task)2277e0ab53deSTrond Myklebust call_transmit_status(struct rpc_task *task)
2278e0ab53deSTrond Myklebust {
2279e0ab53deSTrond Myklebust 	task->tk_action = call_status;
2280206a134bSChuck Lever 
2281206a134bSChuck Lever 	/*
2282206a134bSChuck Lever 	 * Common case: success.  Force the compiler to put this
2283206a134bSChuck Lever 	 * test first.
2284206a134bSChuck Lever 	 */
2285009a82f6STrond Myklebust 	if (rpc_task_transmitted(task)) {
2286a7b1a483STrond Myklebust 		task->tk_status = 0;
22877f3a1d1eSTrond Myklebust 		xprt_request_wait_receive(task);
2288206a134bSChuck Lever 		return;
2289206a134bSChuck Lever 	}
2290206a134bSChuck Lever 
229115f081caSTrond Myklebust 	switch (task->tk_status) {
229215f081caSTrond Myklebust 	default:
229375891f50STrond Myklebust 		break;
229478b576ceSTrond Myklebust 	case -EBADMSG:
2295762e4e67STrond Myklebust 		task->tk_status = 0;
2296762e4e67STrond Myklebust 		task->tk_action = call_encode;
229778b576ceSTrond Myklebust 		break;
229815f081caSTrond Myklebust 		/*
229915f081caSTrond Myklebust 		 * Special cases: if we've been waiting on the
230015f081caSTrond Myklebust 		 * socket's write_space() callback, or if the
230115f081caSTrond Myklebust 		 * socket just returned a connection error,
230215f081caSTrond Myklebust 		 * then hold onto the transport lock.
230315f081caSTrond Myklebust 		 */
2304d3c15033STrond Myklebust 	case -ENOMEM:
230578b576ceSTrond Myklebust 	case -ENOBUFS:
230678b576ceSTrond Myklebust 		rpc_delay(task, HZ>>2);
2307df561f66SGustavo A. R. Silva 		fallthrough;
2308c544577dSTrond Myklebust 	case -EBADSLT:
230978b576ceSTrond Myklebust 	case -EAGAIN:
231078b576ceSTrond Myklebust 		task->tk_action = call_transmit;
231178b576ceSTrond Myklebust 		task->tk_status = 0;
231278b576ceSTrond Myklebust 		break;
231315f081caSTrond Myklebust 	case -EHOSTDOWN:
2314eb5b46faSTrond Myklebust 	case -ENETDOWN:
231515f081caSTrond Myklebust 	case -EHOSTUNREACH:
231615f081caSTrond Myklebust 	case -ENETUNREACH:
23173dedbb5cSJason Baron 	case -EPERM:
2318*3b45d190SNeilBrown 		break;
2319*3b45d190SNeilBrown 	case -ECONNREFUSED:
232009a21c41SChuck Lever 		if (RPC_IS_SOFTCONN(task)) {
2321a25a4cb3SChuck Lever 			if (!task->tk_msg.rpc_proc->p_proc)
2322a25a4cb3SChuck Lever 				trace_xprt_ping(task->tk_xprt,
2323a25a4cb3SChuck Lever 						task->tk_status);
23245ad64b36STrond Myklebust 			rpc_call_rpcerror(task, task->tk_status);
23257b3fef8eSTrond Myklebust 			return;
232609a21c41SChuck Lever 		}
2327df561f66SGustavo A. R. Silva 		fallthrough;
232809a21c41SChuck Lever 	case -ECONNRESET:
2329df277270STrond Myklebust 	case -ECONNABORTED:
23303913c78cSTrond Myklebust 	case -EADDRINUSE:
233109a21c41SChuck Lever 	case -ENOTCONN:
2332c8485e4dSTrond Myklebust 	case -EPIPE:
2333ed7dc973STrond Myklebust 		task->tk_action = call_bind;
2334ed7dc973STrond Myklebust 		task->tk_status = 0;
23357ebbbc6eSTrond Myklebust 		break;
23361da177e4SLinus Torvalds 	}
23377b3fef8eSTrond Myklebust 	rpc_check_timeout(task);
233815f081caSTrond Myklebust }
23391da177e4SLinus Torvalds 
23409e00abc3STrond Myklebust #if defined(CONFIG_SUNRPC_BACKCHANNEL)
2341477687e1STrond Myklebust static void call_bc_transmit(struct rpc_task *task);
2342477687e1STrond Myklebust static void call_bc_transmit_status(struct rpc_task *task);
2343477687e1STrond Myklebust 
2344477687e1STrond Myklebust static void
call_bc_encode(struct rpc_task * task)2345477687e1STrond Myklebust call_bc_encode(struct rpc_task *task)
2346477687e1STrond Myklebust {
2347477687e1STrond Myklebust 	xprt_request_enqueue_transmit(task);
2348477687e1STrond Myklebust 	task->tk_action = call_bc_transmit;
2349477687e1STrond Myklebust }
2350477687e1STrond Myklebust 
235155ae1aabSRicardo Labiaga /*
235255ae1aabSRicardo Labiaga  * 5b.	Send the backchannel RPC reply.  On error, drop the reply.  In
235355ae1aabSRicardo Labiaga  * addition, disconnect on connectivity errors.
235455ae1aabSRicardo Labiaga  */
235555ae1aabSRicardo Labiaga static void
call_bc_transmit(struct rpc_task * task)235655ae1aabSRicardo Labiaga call_bc_transmit(struct rpc_task *task)
235755ae1aabSRicardo Labiaga {
2358477687e1STrond Myklebust 	task->tk_action = call_bc_transmit_status;
2359477687e1STrond Myklebust 	if (test_bit(RPC_TASK_NEED_XMIT, &task->tk_runstate)) {
23601193d58fSTrond Myklebust 		if (!xprt_prepare_transmit(task))
2361477687e1STrond Myklebust 			return;
2362477687e1STrond Myklebust 		task->tk_status = 0;
2363477687e1STrond Myklebust 		xprt_transmit(task);
2364477687e1STrond Myklebust 	}
2365477687e1STrond Myklebust 	xprt_end_transmit(task);
236655ae1aabSRicardo Labiaga }
236755ae1aabSRicardo Labiaga 
2368477687e1STrond Myklebust static void
call_bc_transmit_status(struct rpc_task * task)2369477687e1STrond Myklebust call_bc_transmit_status(struct rpc_task *task)
2370477687e1STrond Myklebust {
2371477687e1STrond Myklebust 	struct rpc_rqst *req = task->tk_rqstp;
23721193d58fSTrond Myklebust 
2373a7b1a483STrond Myklebust 	if (rpc_task_transmitted(task))
2374a7b1a483STrond Myklebust 		task->tk_status = 0;
2375a7b1a483STrond Myklebust 
237655ae1aabSRicardo Labiaga 	switch (task->tk_status) {
237755ae1aabSRicardo Labiaga 	case 0:
237855ae1aabSRicardo Labiaga 		/* Success */
2379eb5b46faSTrond Myklebust 	case -ENETDOWN:
238055ae1aabSRicardo Labiaga 	case -EHOSTDOWN:
238155ae1aabSRicardo Labiaga 	case -EHOSTUNREACH:
238255ae1aabSRicardo Labiaga 	case -ENETUNREACH:
23833832591eSTrond Myklebust 	case -ECONNRESET:
23843832591eSTrond Myklebust 	case -ECONNREFUSED:
23853832591eSTrond Myklebust 	case -EADDRINUSE:
23863832591eSTrond Myklebust 	case -ENOTCONN:
23873832591eSTrond Myklebust 	case -EPIPE:
23883832591eSTrond Myklebust 		break;
2389d3c15033STrond Myklebust 	case -ENOMEM:
2390477687e1STrond Myklebust 	case -ENOBUFS:
2391477687e1STrond Myklebust 		rpc_delay(task, HZ>>2);
2392df561f66SGustavo A. R. Silva 		fallthrough;
2393477687e1STrond Myklebust 	case -EBADSLT:
2394c544577dSTrond Myklebust 	case -EAGAIN:
2395477687e1STrond Myklebust 		task->tk_status = 0;
2396477687e1STrond Myklebust 		task->tk_action = call_bc_transmit;
2397477687e1STrond Myklebust 		return;
239855ae1aabSRicardo Labiaga 	case -ETIMEDOUT:
239955ae1aabSRicardo Labiaga 		/*
240055ae1aabSRicardo Labiaga 		 * Problem reaching the server.  Disconnect and let the
240155ae1aabSRicardo Labiaga 		 * forechannel reestablish the connection.  The server will
240255ae1aabSRicardo Labiaga 		 * have to retransmit the backchannel request and we'll
240355ae1aabSRicardo Labiaga 		 * reprocess it.  Since these ops are idempotent, there's no
240455ae1aabSRicardo Labiaga 		 * need to cache our reply at this time.
240555ae1aabSRicardo Labiaga 		 */
240655ae1aabSRicardo Labiaga 		printk(KERN_NOTICE "RPC: Could not send backchannel reply "
240755ae1aabSRicardo Labiaga 			"error: %d\n", task->tk_status);
2408a4f0835cSTrond Myklebust 		xprt_conditional_disconnect(req->rq_xprt,
240955ae1aabSRicardo Labiaga 			req->rq_connect_cookie);
241055ae1aabSRicardo Labiaga 		break;
241155ae1aabSRicardo Labiaga 	default:
241255ae1aabSRicardo Labiaga 		/*
241355ae1aabSRicardo Labiaga 		 * We were unable to reply and will have to drop the
241455ae1aabSRicardo Labiaga 		 * request.  The server should reconnect and retransmit.
241555ae1aabSRicardo Labiaga 		 */
241655ae1aabSRicardo Labiaga 		printk(KERN_NOTICE "RPC: Could not send backchannel reply "
241755ae1aabSRicardo Labiaga 			"error: %d\n", task->tk_status);
241855ae1aabSRicardo Labiaga 		break;
241955ae1aabSRicardo Labiaga 	}
24201193d58fSTrond Myklebust 	task->tk_action = rpc_exit_task;
242155ae1aabSRicardo Labiaga }
24229e00abc3STrond Myklebust #endif /* CONFIG_SUNRPC_BACKCHANNEL */
242355ae1aabSRicardo Labiaga 
24241da177e4SLinus Torvalds /*
24251da177e4SLinus Torvalds  * 6.	Sort out the RPC call status
24261da177e4SLinus Torvalds  */
24271da177e4SLinus Torvalds static void
call_status(struct rpc_task * task)24281da177e4SLinus Torvalds call_status(struct rpc_task *task)
24291da177e4SLinus Torvalds {
24301da177e4SLinus Torvalds 	struct rpc_clnt	*clnt = task->tk_client;
24311da177e4SLinus Torvalds 	int		status;
24321da177e4SLinus Torvalds 
2433a25a4cb3SChuck Lever 	if (!task->tk_msg.rpc_proc->p_proc)
2434a25a4cb3SChuck Lever 		trace_xprt_ping(task->tk_xprt, task->tk_status);
2435a25a4cb3SChuck Lever 
24361da177e4SLinus Torvalds 	status = task->tk_status;
24371da177e4SLinus Torvalds 	if (status >= 0) {
24381da177e4SLinus Torvalds 		task->tk_action = call_decode;
24391da177e4SLinus Torvalds 		return;
24401da177e4SLinus Torvalds 	}
24411da177e4SLinus Torvalds 
24425753cba1SSteve Dickson 	trace_rpc_call_status(task);
24431da177e4SLinus Torvalds 	task->tk_status = 0;
24441da177e4SLinus Torvalds 	switch(status) {
244576303992STrond Myklebust 	case -EHOSTDOWN:
2446eb5b46faSTrond Myklebust 	case -ENETDOWN:
244776303992STrond Myklebust 	case -EHOSTUNREACH:
244876303992STrond Myklebust 	case -ENETUNREACH:
24493dedbb5cSJason Baron 	case -EPERM:
2450cea57789STrond Myklebust 		if (RPC_IS_SOFTCONN(task))
2451cea57789STrond Myklebust 			goto out_exit;
245276303992STrond Myklebust 		/*
245376303992STrond Myklebust 		 * Delay any retries for 3 seconds, then handle as if it
245476303992STrond Myklebust 		 * were a timeout.
245576303992STrond Myklebust 		 */
245676303992STrond Myklebust 		rpc_delay(task, 3*HZ);
2457df561f66SGustavo A. R. Silva 		fallthrough;
24581da177e4SLinus Torvalds 	case -ETIMEDOUT:
24591da177e4SLinus Torvalds 		break;
24601da177e4SLinus Torvalds 	case -ECONNREFUSED:
2461df277270STrond Myklebust 	case -ECONNRESET:
2462df277270STrond Myklebust 	case -ECONNABORTED:
2463ec6017d9SOlga Kornievskaia 	case -ENOTCONN:
246435f5a422SChuck Lever 		rpc_force_rebind(clnt);
2465c82e5472STrond Myklebust 		break;
24663913c78cSTrond Myklebust 	case -EADDRINUSE:
2467c8485e4dSTrond Myklebust 		rpc_delay(task, 3*HZ);
2468df561f66SGustavo A. R. Silva 		fallthrough;
2469c8485e4dSTrond Myklebust 	case -EPIPE:
24701da177e4SLinus Torvalds 	case -EAGAIN:
24711da177e4SLinus Torvalds 		break;
24729d82819dSTrond Myklebust 	case -ENFILE:
24739d82819dSTrond Myklebust 	case -ENOBUFS:
24749d82819dSTrond Myklebust 	case -ENOMEM:
24759d82819dSTrond Myklebust 		rpc_delay(task, HZ>>2);
24769d82819dSTrond Myklebust 		break;
24771da177e4SLinus Torvalds 	case -EIO:
24781da177e4SLinus Torvalds 		/* shutdown or soft timeout */
2479cea57789STrond Myklebust 		goto out_exit;
24801da177e4SLinus Torvalds 	default:
2481b6b6152cSOlga Kornievskaia 		if (clnt->cl_chatty)
24821da177e4SLinus Torvalds 			printk("%s: RPC call returned error %d\n",
248355909f21STrond Myklebust 			       clnt->cl_program->name, -status);
2484cea57789STrond Myklebust 		goto out_exit;
24851da177e4SLinus Torvalds 	}
2486cea57789STrond Myklebust 	task->tk_action = call_encode;
2487cea57789STrond Myklebust 	rpc_check_timeout(task);
2488cea57789STrond Myklebust 	return;
2489cea57789STrond Myklebust out_exit:
24905ad64b36STrond Myklebust 	rpc_call_rpcerror(task, status);
24911da177e4SLinus Torvalds }
24921da177e4SLinus Torvalds 
2493d84dd3fbSTrond Myklebust static bool
rpc_check_connected(const struct rpc_rqst * req)2494d84dd3fbSTrond Myklebust rpc_check_connected(const struct rpc_rqst *req)
2495d84dd3fbSTrond Myklebust {
2496d84dd3fbSTrond Myklebust 	/* No allocated request or transport? return true */
2497d84dd3fbSTrond Myklebust 	if (!req || !req->rq_xprt)
2498d84dd3fbSTrond Myklebust 		return true;
2499d84dd3fbSTrond Myklebust 	return xprt_connected(req->rq_xprt);
2500d84dd3fbSTrond Myklebust }
2501d84dd3fbSTrond Myklebust 
25021da177e4SLinus Torvalds static void
rpc_check_timeout(struct rpc_task * task)25037b3fef8eSTrond Myklebust rpc_check_timeout(struct rpc_task *task)
25041da177e4SLinus Torvalds {
25051da177e4SLinus Torvalds 	struct rpc_clnt	*clnt = task->tk_client;
25061da177e4SLinus Torvalds 
250739494194STrond Myklebust 	if (RPC_SIGNALLED(task))
2508ce99aa62SChuck Lever 		return;
2509ce99aa62SChuck Lever 
25107b3fef8eSTrond Myklebust 	if (xprt_adjust_timeout(task->tk_rqstp) == 0)
25117b3fef8eSTrond Myklebust 		return;
25121da177e4SLinus Torvalds 
2513914cdcc7SChuck Lever 	trace_rpc_timeout_status(task);
2514ef759a2eSChuck Lever 	task->tk_timeouts++;
2515ef759a2eSChuck Lever 
2516d84dd3fbSTrond Myklebust 	if (RPC_IS_SOFTCONN(task) && !rpc_check_connected(task->tk_rqstp)) {
25175ad64b36STrond Myklebust 		rpc_call_rpcerror(task, -ETIMEDOUT);
25183a28beccSChuck Lever 		return;
25193a28beccSChuck Lever 	}
2520d84dd3fbSTrond Myklebust 
25211da177e4SLinus Torvalds 	if (RPC_IS_SOFT(task)) {
2522e4ec48d3STrond Myklebust 		/*
2523e4ec48d3STrond Myklebust 		 * Once a "no retrans timeout" soft tasks (a.k.a NFSv4) has
2524e4ec48d3STrond Myklebust 		 * been sent, it should time out only if the transport
2525e4ec48d3STrond Myklebust 		 * connection gets terminally broken.
2526e4ec48d3STrond Myklebust 		 */
2527e4ec48d3STrond Myklebust 		if ((task->tk_flags & RPC_TASK_NO_RETRANS_TIMEOUT) &&
2528e4ec48d3STrond Myklebust 		    rpc_check_connected(task->tk_rqstp))
2529e4ec48d3STrond Myklebust 			return;
2530e4ec48d3STrond Myklebust 
2531cac5d07eSJoe Perches 		if (clnt->cl_chatty) {
25320729d995STrond Myklebust 			pr_notice_ratelimited(
25330729d995STrond Myklebust 				"%s: server %s not responding, timed out\n",
253455909f21STrond Myklebust 				clnt->cl_program->name,
2535fb43d172STrond Myklebust 				task->tk_xprt->servername);
2536cac5d07eSJoe Perches 		}
25377494d00cSTrond Myklebust 		if (task->tk_flags & RPC_TASK_TIMEOUT)
25385ad64b36STrond Myklebust 			rpc_call_rpcerror(task, -ETIMEDOUT);
25397494d00cSTrond Myklebust 		else
25405ad64b36STrond Myklebust 			__rpc_call_rpcerror(task, -EIO, -ETIMEDOUT);
25411da177e4SLinus Torvalds 		return;
25421da177e4SLinus Torvalds 	}
25431da177e4SLinus Torvalds 
2544f518e35aSChuck Lever 	if (!(task->tk_flags & RPC_CALL_MAJORSEEN)) {
25451da177e4SLinus Torvalds 		task->tk_flags |= RPC_CALL_MAJORSEEN;
25464e0038b6STrond Myklebust 		if (clnt->cl_chatty) {
25470729d995STrond Myklebust 			pr_notice_ratelimited(
25480729d995STrond Myklebust 				"%s: server %s not responding, still trying\n",
254955909f21STrond Myklebust 				clnt->cl_program->name,
2550fb43d172STrond Myklebust 				task->tk_xprt->servername);
25514e0038b6STrond Myklebust 		}
25521da177e4SLinus Torvalds 	}
255335f5a422SChuck Lever 	rpc_force_rebind(clnt);
2554b48633bdSTrond Myklebust 	/*
2555b48633bdSTrond Myklebust 	 * Did our request time out due to an RPCSEC_GSS out-of-sequence
2556b48633bdSTrond Myklebust 	 * event? RFC2203 requires the server to drop all such requests.
2557b48633bdSTrond Myklebust 	 */
2558b48633bdSTrond Myklebust 	rpcauth_invalcred(task);
25597b3fef8eSTrond Myklebust }
25601da177e4SLinus Torvalds 
25617b3fef8eSTrond Myklebust /*
25621da177e4SLinus Torvalds  * 7.	Decode the RPC reply
25631da177e4SLinus Torvalds  */
25641da177e4SLinus Torvalds static void
call_decode(struct rpc_task * task)25651da177e4SLinus Torvalds call_decode(struct rpc_task *task)
25661da177e4SLinus Torvalds {
25671da177e4SLinus Torvalds 	struct rpc_clnt	*clnt = task->tk_client;
25681da177e4SLinus Torvalds 	struct rpc_rqst	*req = task->tk_rqstp;
2569a0584ee9SChuck Lever 	struct xdr_stream xdr;
25709ba82886STrond Myklebust 	int err;
25711da177e4SLinus Torvalds 
2572a0584ee9SChuck Lever 	if (!task->tk_msg.rpc_proc->p_decode) {
25739ee94d3eSTrond Myklebust 		task->tk_action = rpc_exit_task;
25749ee94d3eSTrond Myklebust 		return;
25759ee94d3eSTrond Myklebust 	}
25769ee94d3eSTrond Myklebust 
2577f518e35aSChuck Lever 	if (task->tk_flags & RPC_CALL_MAJORSEEN) {
25784e0038b6STrond Myklebust 		if (clnt->cl_chatty) {
25790729d995STrond Myklebust 			pr_notice_ratelimited("%s: server %s OK\n",
258055909f21STrond Myklebust 				clnt->cl_program->name,
2581fb43d172STrond Myklebust 				task->tk_xprt->servername);
25824e0038b6STrond Myklebust 		}
25831da177e4SLinus Torvalds 		task->tk_flags &= ~RPC_CALL_MAJORSEEN;
25841da177e4SLinus Torvalds 	}
25851da177e4SLinus Torvalds 
258643ac3f29STrond Myklebust 	/*
25879ba82886STrond Myklebust 	 * Did we ever call xprt_complete_rqst()? If not, we should assume
25889ba82886STrond Myklebust 	 * the message is incomplete.
25899ba82886STrond Myklebust 	 */
25909ba82886STrond Myklebust 	err = -EAGAIN;
25919ba82886STrond Myklebust 	if (!req->rq_reply_bytes_recvd)
25929ba82886STrond Myklebust 		goto out;
25939ba82886STrond Myklebust 
2594f8f7e0fbSBaptiste Lepers 	/* Ensure that we see all writes made by xprt_complete_rqst()
2595f8f7e0fbSBaptiste Lepers 	 * before it changed req->rq_reply_bytes_recvd.
2596f8f7e0fbSBaptiste Lepers 	 */
2597f8f7e0fbSBaptiste Lepers 	smp_rmb();
2598f8f7e0fbSBaptiste Lepers 
25991da177e4SLinus Torvalds 	req->rq_rcv_buf.len = req->rq_private_buf.len;
2600c509f15aSChuck Lever 	trace_rpc_xdr_recvfrom(task, &req->rq_rcv_buf);
26011da177e4SLinus Torvalds 
26021da177e4SLinus Torvalds 	/* Check that the softirq receive buffer is valid */
26031da177e4SLinus Torvalds 	WARN_ON(memcmp(&req->rq_rcv_buf, &req->rq_private_buf,
26041da177e4SLinus Torvalds 				sizeof(req->rq_rcv_buf)) != 0);
26051da177e4SLinus Torvalds 
2606a0584ee9SChuck Lever 	xdr_init_decode(&xdr, &req->rq_rcv_buf,
2607a0584ee9SChuck Lever 			req->rq_rcv_buf.head[0].iov_base, req);
26089ba82886STrond Myklebust 	err = rpc_decode_header(task, &xdr);
26099ba82886STrond Myklebust out:
26109ba82886STrond Myklebust 	switch (err) {
2611a0584ee9SChuck Lever 	case 0:
2612abbcf28fSTrond Myklebust 		task->tk_action = rpc_exit_task;
2613a0584ee9SChuck Lever 		task->tk_status = rpcauth_unwrap_resp(task, &xdr);
261461182c79SAnna Schumaker 		xdr_finish_decode(&xdr);
26151da177e4SLinus Torvalds 		return;
2616a0584ee9SChuck Lever 	case -EAGAIN:
26171da177e4SLinus Torvalds 		task->tk_status = 0;
2618241c39b9STrond Myklebust 		if (task->tk_client->cl_discrtry)
2619a4f0835cSTrond Myklebust 			xprt_conditional_disconnect(req->rq_xprt,
26207c1d71cfSTrond Myklebust 						    req->rq_connect_cookie);
2621cea57789STrond Myklebust 		task->tk_action = call_encode;
2622cea57789STrond Myklebust 		rpc_check_timeout(task);
26237987b694STrond Myklebust 		break;
26247987b694STrond Myklebust 	case -EKEYREJECTED:
26257987b694STrond Myklebust 		task->tk_action = call_reserve;
26267987b694STrond Myklebust 		rpc_check_timeout(task);
26277987b694STrond Myklebust 		rpcauth_invalcred(task);
26287987b694STrond Myklebust 		/* Ensure we obtain a new XID if we retry! */
26297987b694STrond Myklebust 		xprt_release(task);
26301da177e4SLinus Torvalds 	}
2631a0584ee9SChuck Lever }
26321da177e4SLinus Torvalds 
2633e8680a24SChuck Lever static int
rpc_encode_header(struct rpc_task * task,struct xdr_stream * xdr)2634e8680a24SChuck Lever rpc_encode_header(struct rpc_task *task, struct xdr_stream *xdr)
26351da177e4SLinus Torvalds {
26361da177e4SLinus Torvalds 	struct rpc_clnt *clnt = task->tk_client;
26371da177e4SLinus Torvalds 	struct rpc_rqst	*req = task->tk_rqstp;
2638e8680a24SChuck Lever 	__be32 *p;
2639e8680a24SChuck Lever 	int error;
26401da177e4SLinus Torvalds 
2641e8680a24SChuck Lever 	error = -EMSGSIZE;
2642e8680a24SChuck Lever 	p = xdr_reserve_space(xdr, RPC_CALLHDRSIZE << 2);
2643e8680a24SChuck Lever 	if (!p)
2644e8680a24SChuck Lever 		goto out_fail;
2645e8680a24SChuck Lever 	*p++ = req->rq_xid;
2646e8680a24SChuck Lever 	*p++ = rpc_call;
2647e8680a24SChuck Lever 	*p++ = cpu_to_be32(RPC_VERSION);
2648e8680a24SChuck Lever 	*p++ = cpu_to_be32(clnt->cl_prog);
2649e8680a24SChuck Lever 	*p++ = cpu_to_be32(clnt->cl_vers);
2650e8680a24SChuck Lever 	*p   = cpu_to_be32(task->tk_msg.rpc_proc->p_proc);
2651808012fbSChuck Lever 
2652e8680a24SChuck Lever 	error = rpcauth_marshcred(task, xdr);
2653e8680a24SChuck Lever 	if (error < 0)
2654e8680a24SChuck Lever 		goto out_fail;
2655e8680a24SChuck Lever 	return 0;
2656e8680a24SChuck Lever out_fail:
2657e8680a24SChuck Lever 	trace_rpc_bad_callhdr(task);
2658714fbc73STrond Myklebust 	rpc_call_rpcerror(task, error);
2659e8680a24SChuck Lever 	return error;
26601da177e4SLinus Torvalds }
26611da177e4SLinus Torvalds 
2662a0584ee9SChuck Lever static noinline int
rpc_decode_header(struct rpc_task * task,struct xdr_stream * xdr)2663a0584ee9SChuck Lever rpc_decode_header(struct rpc_task *task, struct xdr_stream *xdr)
26641da177e4SLinus Torvalds {
26654e0038b6STrond Myklebust 	struct rpc_clnt *clnt = task->tk_client;
2666eb90a16eSTrond Myklebust 	int error;
2667a0584ee9SChuck Lever 	__be32 *p;
26681da177e4SLinus Torvalds 
2669e8896495SDavid Howells 	/* RFC-1014 says that the representation of XDR data must be a
2670e8896495SDavid Howells 	 * multiple of four bytes
2671e8896495SDavid Howells 	 * - if it isn't pointer subtraction in the NFS client may give
2672e8896495SDavid Howells 	 *   undefined results
2673e8896495SDavid Howells 	 */
26747f5667a5SChuck Lever 	if (task->tk_rqstp->rq_rcv_buf.len & 3)
2675eb90a16eSTrond Myklebust 		goto out_unparsable;
26761da177e4SLinus Torvalds 
2677a0584ee9SChuck Lever 	p = xdr_inline_decode(xdr, 3 * sizeof(*p));
2678a0584ee9SChuck Lever 	if (!p)
2679a0584ee9SChuck Lever 		goto out_unparsable;
26807f5667a5SChuck Lever 	p++;	/* skip XID */
26817f5667a5SChuck Lever 	if (*p++ != rpc_reply)
26827f5667a5SChuck Lever 		goto out_unparsable;
26837f5667a5SChuck Lever 	if (*p++ != rpc_msg_accepted)
26847f5667a5SChuck Lever 		goto out_msg_denied;
2685f4a2e418SRicardo Labiaga 
2686a0584ee9SChuck Lever 	error = rpcauth_checkverf(task, xdr);
2687a0584ee9SChuck Lever 	if (error)
26887f5667a5SChuck Lever 		goto out_verifier;
26897f5667a5SChuck Lever 
2690a0584ee9SChuck Lever 	p = xdr_inline_decode(xdr, sizeof(*p));
2691a0584ee9SChuck Lever 	if (!p)
26927f5667a5SChuck Lever 		goto out_unparsable;
2693a0584ee9SChuck Lever 	switch (*p) {
26947f5667a5SChuck Lever 	case rpc_success:
2695a0584ee9SChuck Lever 		return 0;
26967f5667a5SChuck Lever 	case rpc_prog_unavail:
26977f5667a5SChuck Lever 		trace_rpc__prog_unavail(task);
2698cdf47706SAndreas Gruenbacher 		error = -EPFNOSUPPORT;
2699cdf47706SAndreas Gruenbacher 		goto out_err;
27007f5667a5SChuck Lever 	case rpc_prog_mismatch:
27017f5667a5SChuck Lever 		trace_rpc__prog_mismatch(task);
2702cdf47706SAndreas Gruenbacher 		error = -EPROTONOSUPPORT;
2703cdf47706SAndreas Gruenbacher 		goto out_err;
27047f5667a5SChuck Lever 	case rpc_proc_unavail:
27057f5667a5SChuck Lever 		trace_rpc__proc_unavail(task);
2706cdf47706SAndreas Gruenbacher 		error = -EOPNOTSUPP;
2707cdf47706SAndreas Gruenbacher 		goto out_err;
27087f5667a5SChuck Lever 	case rpc_garbage_args:
2709928d42f7STrond Myklebust 	case rpc_system_err:
27107f5667a5SChuck Lever 		trace_rpc__garbage_args(task);
2711eb90a16eSTrond Myklebust 		error = -EIO;
27127f5667a5SChuck Lever 		break;
27131da177e4SLinus Torvalds 	default:
2714eb90a16eSTrond Myklebust 		goto out_unparsable;
27151da177e4SLinus Torvalds 	}
27161da177e4SLinus Torvalds 
2717abbcf28fSTrond Myklebust out_garbage:
27184e0038b6STrond Myklebust 	clnt->cl_stats->rpcgarbage++;
27191da177e4SLinus Torvalds 	if (task->tk_garb_retry) {
27201da177e4SLinus Torvalds 		task->tk_garb_retry--;
2721762e4e67STrond Myklebust 		task->tk_action = call_encode;
2722a0584ee9SChuck Lever 		return -EAGAIN;
27231da177e4SLinus Torvalds 	}
27241da177e4SLinus Torvalds out_err:
2725714fbc73STrond Myklebust 	rpc_call_rpcerror(task, error);
2726a0584ee9SChuck Lever 	return error;
27277f5667a5SChuck Lever 
27287f5667a5SChuck Lever out_unparsable:
27297f5667a5SChuck Lever 	trace_rpc__unparsable(task);
27307f5667a5SChuck Lever 	error = -EIO;
2731abbcf28fSTrond Myklebust 	goto out_garbage;
27327f5667a5SChuck Lever 
27337f5667a5SChuck Lever out_verifier:
27347f5667a5SChuck Lever 	trace_rpc_bad_verifier(task);
27355623ecfcSChuck Lever 	switch (error) {
27365623ecfcSChuck Lever 	case -EPROTONOSUPPORT:
27375623ecfcSChuck Lever 		goto out_err;
27385623ecfcSChuck Lever 	case -EACCES:
27395623ecfcSChuck Lever 		/* Re-encode with a fresh cred */
27405623ecfcSChuck Lever 		fallthrough;
27415623ecfcSChuck Lever 	default:
2742e86fcf08STrond Myklebust 		goto out_garbage;
27435623ecfcSChuck Lever 	}
27447f5667a5SChuck Lever 
27457f5667a5SChuck Lever out_msg_denied:
2746eb90a16eSTrond Myklebust 	error = -EACCES;
2747a0584ee9SChuck Lever 	p = xdr_inline_decode(xdr, sizeof(*p));
2748a0584ee9SChuck Lever 	if (!p)
2749a0584ee9SChuck Lever 		goto out_unparsable;
27507f5667a5SChuck Lever 	switch (*p++) {
27517f5667a5SChuck Lever 	case rpc_auth_error:
27527f5667a5SChuck Lever 		break;
27537f5667a5SChuck Lever 	case rpc_mismatch:
27547f5667a5SChuck Lever 		trace_rpc__mismatch(task);
27557f5667a5SChuck Lever 		error = -EPROTONOSUPPORT;
27567f5667a5SChuck Lever 		goto out_err;
27577f5667a5SChuck Lever 	default:
2758eb90a16eSTrond Myklebust 		goto out_unparsable;
27597f5667a5SChuck Lever 	}
27607f5667a5SChuck Lever 
2761a0584ee9SChuck Lever 	p = xdr_inline_decode(xdr, sizeof(*p));
2762a0584ee9SChuck Lever 	if (!p)
2763a0584ee9SChuck Lever 		goto out_unparsable;
27647f5667a5SChuck Lever 	switch (*p++) {
27657f5667a5SChuck Lever 	case rpc_autherr_rejectedcred:
27667f5667a5SChuck Lever 	case rpc_autherr_rejectedverf:
27677f5667a5SChuck Lever 	case rpcsec_gsserr_credproblem:
27687f5667a5SChuck Lever 	case rpcsec_gsserr_ctxproblem:
2769611fa42dSTrond Myklebust 		rpcauth_invalcred(task);
27707f5667a5SChuck Lever 		if (!task->tk_cred_retry)
27717f5667a5SChuck Lever 			break;
27727f5667a5SChuck Lever 		task->tk_cred_retry--;
27737f5667a5SChuck Lever 		trace_rpc__stale_creds(task);
27747987b694STrond Myklebust 		return -EKEYREJECTED;
27757f5667a5SChuck Lever 	case rpc_autherr_badcred:
27767f5667a5SChuck Lever 	case rpc_autherr_badverf:
27777f5667a5SChuck Lever 		/* possibly garbled cred/verf? */
27787f5667a5SChuck Lever 		if (!task->tk_garb_retry)
27797f5667a5SChuck Lever 			break;
27807f5667a5SChuck Lever 		task->tk_garb_retry--;
27817f5667a5SChuck Lever 		trace_rpc__bad_creds(task);
27827f5667a5SChuck Lever 		task->tk_action = call_encode;
2783a0584ee9SChuck Lever 		return -EAGAIN;
27847f5667a5SChuck Lever 	case rpc_autherr_tooweak:
27857f5667a5SChuck Lever 		trace_rpc__auth_tooweak(task);
27867f5667a5SChuck Lever 		pr_warn("RPC: server %s requires stronger authentication.\n",
27877f5667a5SChuck Lever 			task->tk_xprt->servername);
27887f5667a5SChuck Lever 		break;
27897f5667a5SChuck Lever 	default:
2790eb90a16eSTrond Myklebust 		goto out_unparsable;
27917f5667a5SChuck Lever 	}
27927f5667a5SChuck Lever 	goto out_err;
27931da177e4SLinus Torvalds }
27945ee0ed7dSTrond Myklebust 
rpcproc_encode_null(struct rpc_rqst * rqstp,struct xdr_stream * xdr,const void * obj)2795c512f36bSChristoph Hellwig static void rpcproc_encode_null(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
2796c512f36bSChristoph Hellwig 		const void *obj)
27975ee0ed7dSTrond Myklebust {
27985ee0ed7dSTrond Myklebust }
27995ee0ed7dSTrond Myklebust 
rpcproc_decode_null(struct rpc_rqst * rqstp,struct xdr_stream * xdr,void * obj)280073c8dc13SChristoph Hellwig static int rpcproc_decode_null(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
280173c8dc13SChristoph Hellwig 		void *obj)
28025ee0ed7dSTrond Myklebust {
28035ee0ed7dSTrond Myklebust 	return 0;
28045ee0ed7dSTrond Myklebust }
28055ee0ed7dSTrond Myklebust 
2806499b4988SChristoph Hellwig static const struct rpc_procinfo rpcproc_null = {
28075ee0ed7dSTrond Myklebust 	.p_encode = rpcproc_encode_null,
28085ee0ed7dSTrond Myklebust 	.p_decode = rpcproc_decode_null,
28095ee0ed7dSTrond Myklebust };
28105ee0ed7dSTrond Myklebust 
2811fd13359fSTrond Myklebust static const struct rpc_procinfo rpcproc_null_noreply = {
2812fd13359fSTrond Myklebust 	.p_encode = rpcproc_encode_null,
2813fd13359fSTrond Myklebust };
2814fd13359fSTrond Myklebust 
2815823c73d0SChuck Lever static void
rpc_null_call_prepare(struct rpc_task * task,void * data)2816823c73d0SChuck Lever rpc_null_call_prepare(struct rpc_task *task, void *data)
2817823c73d0SChuck Lever {
2818823c73d0SChuck Lever 	task->tk_flags &= ~RPC_TASK_NO_RETRANS_TIMEOUT;
2819823c73d0SChuck Lever 	rpc_call_start(task);
2820823c73d0SChuck Lever }
2821823c73d0SChuck Lever 
2822823c73d0SChuck Lever static const struct rpc_call_ops rpc_null_ops = {
2823823c73d0SChuck Lever 	.rpc_call_prepare = rpc_null_call_prepare,
2824823c73d0SChuck Lever 	.rpc_call_done = rpc_default_callback,
2825823c73d0SChuck Lever };
2826823c73d0SChuck Lever 
28277f554890STrond Myklebust static
rpc_call_null_helper(struct rpc_clnt * clnt,struct rpc_xprt * xprt,struct rpc_cred * cred,int flags,const struct rpc_call_ops * ops,void * data)28287f554890STrond Myklebust struct rpc_task *rpc_call_null_helper(struct rpc_clnt *clnt,
28297f554890STrond Myklebust 		struct rpc_xprt *xprt, struct rpc_cred *cred, int flags,
28307f554890STrond Myklebust 		const struct rpc_call_ops *ops, void *data)
28315e1550d6STrond Myklebust {
28325e1550d6STrond Myklebust 	struct rpc_message msg = {
28335e1550d6STrond Myklebust 		.rpc_proc = &rpcproc_null,
28345e1550d6STrond Myklebust 	};
283584115e1cSTrond Myklebust 	struct rpc_task_setup task_setup_data = {
283684115e1cSTrond Myklebust 		.rpc_client = clnt,
28377f554890STrond Myklebust 		.rpc_xprt = xprt,
283884115e1cSTrond Myklebust 		.rpc_message = &msg,
28391de7eea9SNeilBrown 		.rpc_op_cred = cred,
2840823c73d0SChuck Lever 		.callback_ops = ops ?: &rpc_null_ops,
28417f554890STrond Myklebust 		.callback_data = data,
2842841a2ed9SChuck Lever 		.flags = flags | RPC_TASK_SOFT | RPC_TASK_SOFTCONN |
2843841a2ed9SChuck Lever 			 RPC_TASK_NULLCREDS,
284484115e1cSTrond Myklebust 	};
28457f554890STrond Myklebust 
2846c970aa85STrond Myklebust 	return rpc_run_task(&task_setup_data);
28475e1550d6STrond Myklebust }
28487f554890STrond Myklebust 
rpc_call_null(struct rpc_clnt * clnt,struct rpc_cred * cred,int flags)28497f554890STrond Myklebust struct rpc_task *rpc_call_null(struct rpc_clnt *clnt, struct rpc_cred *cred, int flags)
28507f554890STrond Myklebust {
28517f554890STrond Myklebust 	return rpc_call_null_helper(clnt, NULL, cred, flags, NULL, NULL);
28527f554890STrond Myklebust }
2853e8914c65STrond Myklebust EXPORT_SYMBOL_GPL(rpc_call_null);
28545e1550d6STrond Myklebust 
rpc_ping(struct rpc_clnt * clnt)2855aede5172SChuck Lever static int rpc_ping(struct rpc_clnt *clnt)
2856aede5172SChuck Lever {
2857aede5172SChuck Lever 	struct rpc_task	*task;
2858aede5172SChuck Lever 	int status;
2859aede5172SChuck Lever 
286012072652SChuck Lever 	if (clnt->cl_auth->au_ops->ping)
286112072652SChuck Lever 		return clnt->cl_auth->au_ops->ping(clnt);
286212072652SChuck Lever 
2863aede5172SChuck Lever 	task = rpc_call_null_helper(clnt, NULL, NULL, 0, NULL, NULL);
2864aede5172SChuck Lever 	if (IS_ERR(task))
2865aede5172SChuck Lever 		return PTR_ERR(task);
2866aede5172SChuck Lever 	status = task->tk_status;
2867aede5172SChuck Lever 	rpc_put_task(task);
2868aede5172SChuck Lever 	return status;
2869aede5172SChuck Lever }
2870aede5172SChuck Lever 
rpc_ping_noreply(struct rpc_clnt * clnt)2871fd13359fSTrond Myklebust static int rpc_ping_noreply(struct rpc_clnt *clnt)
2872fd13359fSTrond Myklebust {
2873fd13359fSTrond Myklebust 	struct rpc_message msg = {
2874fd13359fSTrond Myklebust 		.rpc_proc = &rpcproc_null_noreply,
2875fd13359fSTrond Myklebust 	};
2876fd13359fSTrond Myklebust 	struct rpc_task_setup task_setup_data = {
2877fd13359fSTrond Myklebust 		.rpc_client = clnt,
2878fd13359fSTrond Myklebust 		.rpc_message = &msg,
2879fd13359fSTrond Myklebust 		.callback_ops = &rpc_null_ops,
2880fd13359fSTrond Myklebust 		.flags = RPC_TASK_SOFT | RPC_TASK_SOFTCONN | RPC_TASK_NULLCREDS,
2881fd13359fSTrond Myklebust 	};
2882fd13359fSTrond Myklebust 	struct rpc_task	*task;
2883fd13359fSTrond Myklebust 	int status;
2884fd13359fSTrond Myklebust 
2885fd13359fSTrond Myklebust 	task = rpc_run_task(&task_setup_data);
2886fd13359fSTrond Myklebust 	if (IS_ERR(task))
2887fd13359fSTrond Myklebust 		return PTR_ERR(task);
2888fd13359fSTrond Myklebust 	status = task->tk_status;
2889fd13359fSTrond Myklebust 	rpc_put_task(task);
2890fd13359fSTrond Myklebust 	return status;
2891fd13359fSTrond Myklebust }
2892fd13359fSTrond Myklebust 
28937f554890STrond Myklebust struct rpc_cb_add_xprt_calldata {
28947f554890STrond Myklebust 	struct rpc_xprt_switch *xps;
28957f554890STrond Myklebust 	struct rpc_xprt *xprt;
28967f554890STrond Myklebust };
28977f554890STrond Myklebust 
rpc_cb_add_xprt_done(struct rpc_task * task,void * calldata)28987f554890STrond Myklebust static void rpc_cb_add_xprt_done(struct rpc_task *task, void *calldata)
28997f554890STrond Myklebust {
29007f554890STrond Myklebust 	struct rpc_cb_add_xprt_calldata *data = calldata;
29017f554890STrond Myklebust 
29027f554890STrond Myklebust 	if (task->tk_status == 0)
29037f554890STrond Myklebust 		rpc_xprt_switch_add_xprt(data->xps, data->xprt);
29047f554890STrond Myklebust }
29057f554890STrond Myklebust 
rpc_cb_add_xprt_release(void * calldata)29067f554890STrond Myklebust static void rpc_cb_add_xprt_release(void *calldata)
29077f554890STrond Myklebust {
29087f554890STrond Myklebust 	struct rpc_cb_add_xprt_calldata *data = calldata;
29097f554890STrond Myklebust 
29107f554890STrond Myklebust 	xprt_put(data->xprt);
29117f554890STrond Myklebust 	xprt_switch_put(data->xps);
29127f554890STrond Myklebust 	kfree(data);
29137f554890STrond Myklebust }
29147f554890STrond Myklebust 
2915ce272302STrond Myklebust static const struct rpc_call_ops rpc_cb_add_xprt_call_ops = {
2916823c73d0SChuck Lever 	.rpc_call_prepare = rpc_null_call_prepare,
29177f554890STrond Myklebust 	.rpc_call_done = rpc_cb_add_xprt_done,
29187f554890STrond Myklebust 	.rpc_release = rpc_cb_add_xprt_release,
29197f554890STrond Myklebust };
29207f554890STrond Myklebust 
29217f554890STrond Myklebust /**
29227f554890STrond Myklebust  * rpc_clnt_test_and_add_xprt - Test and add a new transport to a rpc_clnt
29237f554890STrond Myklebust  * @clnt: pointer to struct rpc_clnt
29247f554890STrond Myklebust  * @xps: pointer to struct rpc_xprt_switch,
29257f554890STrond Myklebust  * @xprt: pointer struct rpc_xprt
2926806a3bc4SOlga Kornievskaia  * @in_max_connect: pointer to the max_connect value for the passed in xprt transport
29277f554890STrond Myklebust  */
rpc_clnt_test_and_add_xprt(struct rpc_clnt * clnt,struct rpc_xprt_switch * xps,struct rpc_xprt * xprt,void * in_max_connect)29287f554890STrond Myklebust int rpc_clnt_test_and_add_xprt(struct rpc_clnt *clnt,
29297f554890STrond Myklebust 		struct rpc_xprt_switch *xps, struct rpc_xprt *xprt,
2930806a3bc4SOlga Kornievskaia 		void *in_max_connect)
29317f554890STrond Myklebust {
29327f554890STrond Myklebust 	struct rpc_cb_add_xprt_calldata *data;
29337f554890STrond Myklebust 	struct rpc_task *task;
2934806a3bc4SOlga Kornievskaia 	int max_connect = clnt->cl_max_connect;
29357f554890STrond Myklebust 
2936806a3bc4SOlga Kornievskaia 	if (in_max_connect)
2937806a3bc4SOlga Kornievskaia 		max_connect = *(int *)in_max_connect;
2938806a3bc4SOlga Kornievskaia 	if (xps->xps_nunique_destaddr_xprts + 1 > max_connect) {
2939dc48e0abSOlga Kornievskaia 		rcu_read_lock();
2940dc48e0abSOlga Kornievskaia 		pr_warn("SUNRPC: reached max allowed number (%d) did not add "
2941806a3bc4SOlga Kornievskaia 			"transport to server: %s\n", max_connect,
2942dc48e0abSOlga Kornievskaia 			rpc_peeraddr2str(clnt, RPC_DISPLAY_ADDR));
2943dc48e0abSOlga Kornievskaia 		rcu_read_unlock();
2944dc48e0abSOlga Kornievskaia 		return -EINVAL;
2945dc48e0abSOlga Kornievskaia 	}
2946dc48e0abSOlga Kornievskaia 
29470adc8794STrond Myklebust 	data = kmalloc(sizeof(*data), GFP_KERNEL);
29487f554890STrond Myklebust 	if (!data)
29497f554890STrond Myklebust 		return -ENOMEM;
29507f554890STrond Myklebust 	data->xps = xprt_switch_get(xps);
29517f554890STrond Myklebust 	data->xprt = xprt_get(xprt);
2952612b41f8STrond Myklebust 	if (rpc_xprt_switch_has_addr(data->xps, (struct sockaddr *)&xprt->addr)) {
2953612b41f8STrond Myklebust 		rpc_cb_add_xprt_release(data);
2954612b41f8STrond Myklebust 		goto success;
2955612b41f8STrond Myklebust 	}
29567f554890STrond Myklebust 
2957841a2ed9SChuck Lever 	task = rpc_call_null_helper(clnt, xprt, NULL, RPC_TASK_ASYNC,
29587f554890STrond Myklebust 			&rpc_cb_add_xprt_call_ops, data);
295913bd9014SDan Aloni 	if (IS_ERR(task))
296013bd9014SDan Aloni 		return PTR_ERR(task);
296113bd9014SDan Aloni 
29623a3f9766SOlga Kornievskaia 	data->xps->xps_nunique_destaddr_xprts++;
29637f554890STrond Myklebust 	rpc_put_task(task);
2964612b41f8STrond Myklebust success:
29657f554890STrond Myklebust 	return 1;
29667f554890STrond Myklebust }
29677f554890STrond Myklebust EXPORT_SYMBOL_GPL(rpc_clnt_test_and_add_xprt);
29687f554890STrond Myklebust 
rpc_clnt_add_xprt_helper(struct rpc_clnt * clnt,struct rpc_xprt * xprt,struct rpc_add_xprt_test * data)29697960aa9eSOlga Kornievskaia static int rpc_clnt_add_xprt_helper(struct rpc_clnt *clnt,
29707960aa9eSOlga Kornievskaia 				    struct rpc_xprt *xprt,
29717960aa9eSOlga Kornievskaia 				    struct rpc_add_xprt_test *data)
29727960aa9eSOlga Kornievskaia {
29737960aa9eSOlga Kornievskaia 	struct rpc_task *task;
29747960aa9eSOlga Kornievskaia 	int status = -EADDRINUSE;
29757960aa9eSOlga Kornievskaia 
29767960aa9eSOlga Kornievskaia 	/* Test the connection */
29777960aa9eSOlga Kornievskaia 	task = rpc_call_null_helper(clnt, xprt, NULL, 0, NULL, NULL);
29787960aa9eSOlga Kornievskaia 	if (IS_ERR(task))
29797960aa9eSOlga Kornievskaia 		return PTR_ERR(task);
29807960aa9eSOlga Kornievskaia 
29817960aa9eSOlga Kornievskaia 	status = task->tk_status;
29827960aa9eSOlga Kornievskaia 	rpc_put_task(task);
29837960aa9eSOlga Kornievskaia 
29847960aa9eSOlga Kornievskaia 	if (status < 0)
29857960aa9eSOlga Kornievskaia 		return status;
29867960aa9eSOlga Kornievskaia 
29877960aa9eSOlga Kornievskaia 	/* rpc_xprt_switch and rpc_xprt are deferrenced by add_xprt_test() */
29887960aa9eSOlga Kornievskaia 	data->add_xprt_test(clnt, xprt, data->data);
29897960aa9eSOlga Kornievskaia 
29907960aa9eSOlga Kornievskaia 	return 0;
29917960aa9eSOlga Kornievskaia }
29927960aa9eSOlga Kornievskaia 
29937f554890STrond Myklebust /**
2994fda0ab41SAndy Adamson  * rpc_clnt_setup_test_and_add_xprt()
2995fda0ab41SAndy Adamson  *
2996fda0ab41SAndy Adamson  * This is an rpc_clnt_add_xprt setup() function which returns 1 so:
2997fda0ab41SAndy Adamson  *   1) caller of the test function must dereference the rpc_xprt_switch
2998fda0ab41SAndy Adamson  *   and the rpc_xprt.
2999fda0ab41SAndy Adamson  *   2) test function must call rpc_xprt_switch_add_xprt, usually in
3000fda0ab41SAndy Adamson  *   the rpc_call_done routine.
3001fda0ab41SAndy Adamson  *
3002fda0ab41SAndy Adamson  * Upon success (return of 1), the test function adds the new
3003fda0ab41SAndy Adamson  * transport to the rpc_clnt xprt switch
3004fda0ab41SAndy Adamson  *
3005fda0ab41SAndy Adamson  * @clnt: struct rpc_clnt to get the new transport
3006fda0ab41SAndy Adamson  * @xps:  the rpc_xprt_switch to hold the new transport
3007fda0ab41SAndy Adamson  * @xprt: the rpc_xprt to test
3008fda0ab41SAndy Adamson  * @data: a struct rpc_add_xprt_test pointer that holds the test function
3009fda0ab41SAndy Adamson  *        and test function call data
3010fda0ab41SAndy Adamson  */
rpc_clnt_setup_test_and_add_xprt(struct rpc_clnt * clnt,struct rpc_xprt_switch * xps,struct rpc_xprt * xprt,void * data)3011fda0ab41SAndy Adamson int rpc_clnt_setup_test_and_add_xprt(struct rpc_clnt *clnt,
3012fda0ab41SAndy Adamson 				     struct rpc_xprt_switch *xps,
3013fda0ab41SAndy Adamson 				     struct rpc_xprt *xprt,
3014fda0ab41SAndy Adamson 				     void *data)
3015fda0ab41SAndy Adamson {
3016fda0ab41SAndy Adamson 	int status = -EADDRINUSE;
3017fda0ab41SAndy Adamson 
3018fda0ab41SAndy Adamson 	xprt = xprt_get(xprt);
3019fda0ab41SAndy Adamson 	xprt_switch_get(xps);
3020fda0ab41SAndy Adamson 
3021fda0ab41SAndy Adamson 	if (rpc_xprt_switch_has_addr(xps, (struct sockaddr *)&xprt->addr))
3022fda0ab41SAndy Adamson 		goto out_err;
3023fda0ab41SAndy Adamson 
30247960aa9eSOlga Kornievskaia 	status = rpc_clnt_add_xprt_helper(clnt, xprt, data);
3025fda0ab41SAndy Adamson 	if (status < 0)
3026fda0ab41SAndy Adamson 		goto out_err;
3027fda0ab41SAndy Adamson 
30287960aa9eSOlga Kornievskaia 	status = 1;
3029fda0ab41SAndy Adamson out_err:
3030fda0ab41SAndy Adamson 	xprt_put(xprt);
3031fda0ab41SAndy Adamson 	xprt_switch_put(xps);
30327960aa9eSOlga Kornievskaia 	if (status < 0)
30337960aa9eSOlga Kornievskaia 		pr_info("RPC:   rpc_clnt_test_xprt failed: %d addr %s not "
30347960aa9eSOlga Kornievskaia 			"added\n", status,
30357960aa9eSOlga Kornievskaia 			xprt->address_strings[RPC_DISPLAY_ADDR]);
30367960aa9eSOlga Kornievskaia 	/* so that rpc_clnt_add_xprt does not call rpc_xprt_switch_add_xprt */
3037fda0ab41SAndy Adamson 	return status;
3038fda0ab41SAndy Adamson }
3039fda0ab41SAndy Adamson EXPORT_SYMBOL_GPL(rpc_clnt_setup_test_and_add_xprt);
3040fda0ab41SAndy Adamson 
3041fda0ab41SAndy Adamson /**
30427f554890STrond Myklebust  * rpc_clnt_add_xprt - Add a new transport to a rpc_clnt
30437f554890STrond Myklebust  * @clnt: pointer to struct rpc_clnt
30447f554890STrond Myklebust  * @xprtargs: pointer to struct xprt_create
30457f554890STrond Myklebust  * @setup: callback to test and/or set up the connection
30467f554890STrond Myklebust  * @data: pointer to setup function data
30477f554890STrond Myklebust  *
30487f554890STrond Myklebust  * Creates a new transport using the parameters set in args and
30497f554890STrond Myklebust  * adds it to clnt.
30507f554890STrond Myklebust  * If ping is set, then test that connectivity succeeds before
30517f554890STrond Myklebust  * adding the new transport.
30527f554890STrond Myklebust  *
30537f554890STrond Myklebust  */
rpc_clnt_add_xprt(struct rpc_clnt * clnt,struct xprt_create * xprtargs,int (* setup)(struct rpc_clnt *,struct rpc_xprt_switch *,struct rpc_xprt *,void *),void * data)30547f554890STrond Myklebust int rpc_clnt_add_xprt(struct rpc_clnt *clnt,
30557f554890STrond Myklebust 		struct xprt_create *xprtargs,
30567f554890STrond Myklebust 		int (*setup)(struct rpc_clnt *,
30577f554890STrond Myklebust 			struct rpc_xprt_switch *,
30587f554890STrond Myklebust 			struct rpc_xprt *,
30597f554890STrond Myklebust 			void *),
30607f554890STrond Myklebust 		void *data)
30617f554890STrond Myklebust {
30627f554890STrond Myklebust 	struct rpc_xprt_switch *xps;
30637f554890STrond Myklebust 	struct rpc_xprt *xprt;
30647196dbb0STrond Myklebust 	unsigned long connect_timeout;
30653851f1cdSTrond Myklebust 	unsigned long reconnect_timeout;
3066e6237b6fSTrond Myklebust 	unsigned char resvport, reuseport;
3067b8a09619SOlga Kornievskaia 	int ret = 0, ident;
30687f554890STrond Myklebust 
30697f554890STrond Myklebust 	rcu_read_lock();
30707f554890STrond Myklebust 	xps = xprt_switch_get(rcu_dereference(clnt->cl_xpi.xpi_xpswitch));
30717f554890STrond Myklebust 	xprt = xprt_iter_xprt(&clnt->cl_xpi);
30727f554890STrond Myklebust 	if (xps == NULL || xprt == NULL) {
30737f554890STrond Myklebust 		rcu_read_unlock();
3074b9622614SLin Yi 		xprt_switch_put(xps);
30757f554890STrond Myklebust 		return -EAGAIN;
30767f554890STrond Myklebust 	}
30777f554890STrond Myklebust 	resvport = xprt->resvport;
3078e6237b6fSTrond Myklebust 	reuseport = xprt->reuseport;
30797196dbb0STrond Myklebust 	connect_timeout = xprt->connect_timeout;
30803851f1cdSTrond Myklebust 	reconnect_timeout = xprt->max_reconnect_timeout;
3081b8a09619SOlga Kornievskaia 	ident = xprt->xprt_class->ident;
30827f554890STrond Myklebust 	rcu_read_unlock();
30837f554890STrond Myklebust 
3084b8a09619SOlga Kornievskaia 	if (!xprtargs->ident)
3085b8a09619SOlga Kornievskaia 		xprtargs->ident = ident;
308650005319SChuck Lever 	xprtargs->xprtsec = clnt->cl_xprtsec;
30877f554890STrond Myklebust 	xprt = xprt_create_transport(xprtargs);
30887f554890STrond Myklebust 	if (IS_ERR(xprt)) {
30897f554890STrond Myklebust 		ret = PTR_ERR(xprt);
30907f554890STrond Myklebust 		goto out_put_switch;
30917f554890STrond Myklebust 	}
30927f554890STrond Myklebust 	xprt->resvport = resvport;
3093e6237b6fSTrond Myklebust 	xprt->reuseport = reuseport;
3094cd18f240STrond Myklebust 
3095cd18f240STrond Myklebust 	if (xprtargs->connect_timeout)
3096cd18f240STrond Myklebust 		connect_timeout = xprtargs->connect_timeout;
3097cd18f240STrond Myklebust 	if (xprtargs->reconnect_timeout)
3098cd18f240STrond Myklebust 		reconnect_timeout = xprtargs->reconnect_timeout;
30997196dbb0STrond Myklebust 	if (xprt->ops->set_connect_timeout != NULL)
31007196dbb0STrond Myklebust 		xprt->ops->set_connect_timeout(xprt,
31017196dbb0STrond Myklebust 				connect_timeout,
31027196dbb0STrond Myklebust 				reconnect_timeout);
31037f554890STrond Myklebust 
31047f554890STrond Myklebust 	rpc_xprt_switch_set_roundrobin(xps);
31057f554890STrond Myklebust 	if (setup) {
31067f554890STrond Myklebust 		ret = setup(clnt, xps, xprt, data);
31077f554890STrond Myklebust 		if (ret != 0)
31087f554890STrond Myklebust 			goto out_put_xprt;
31097f554890STrond Myklebust 	}
31107f554890STrond Myklebust 	rpc_xprt_switch_add_xprt(xps, xprt);
31117f554890STrond Myklebust out_put_xprt:
31127f554890STrond Myklebust 	xprt_put(xprt);
31137f554890STrond Myklebust out_put_switch:
31147f554890STrond Myklebust 	xprt_switch_put(xps);
31157f554890STrond Myklebust 	return ret;
31167f554890STrond Myklebust }
31177f554890STrond Myklebust EXPORT_SYMBOL_GPL(rpc_clnt_add_xprt);
31187f554890STrond Myklebust 
rpc_xprt_probe_trunked(struct rpc_clnt * clnt,struct rpc_xprt * xprt,struct rpc_add_xprt_test * data)311992cc04f6SOlga Kornievskaia static int rpc_xprt_probe_trunked(struct rpc_clnt *clnt,
312092cc04f6SOlga Kornievskaia 				  struct rpc_xprt *xprt,
312192cc04f6SOlga Kornievskaia 				  struct rpc_add_xprt_test *data)
312292cc04f6SOlga Kornievskaia {
312392cc04f6SOlga Kornievskaia 	struct rpc_xprt_switch *xps;
312492cc04f6SOlga Kornievskaia 	struct rpc_xprt *main_xprt;
312592cc04f6SOlga Kornievskaia 	int status = 0;
312692cc04f6SOlga Kornievskaia 
312792cc04f6SOlga Kornievskaia 	xprt_get(xprt);
312892cc04f6SOlga Kornievskaia 
312992cc04f6SOlga Kornievskaia 	rcu_read_lock();
313092cc04f6SOlga Kornievskaia 	main_xprt = xprt_get(rcu_dereference(clnt->cl_xprt));
313192cc04f6SOlga Kornievskaia 	xps = xprt_switch_get(rcu_dereference(clnt->cl_xpi.xpi_xpswitch));
313292cc04f6SOlga Kornievskaia 	status = rpc_cmp_addr_port((struct sockaddr *)&xprt->addr,
313392cc04f6SOlga Kornievskaia 				   (struct sockaddr *)&main_xprt->addr);
313492cc04f6SOlga Kornievskaia 	rcu_read_unlock();
313592cc04f6SOlga Kornievskaia 	xprt_put(main_xprt);
313692cc04f6SOlga Kornievskaia 	if (status || !test_bit(XPRT_OFFLINE, &xprt->state))
313792cc04f6SOlga Kornievskaia 		goto out;
313892cc04f6SOlga Kornievskaia 
313992cc04f6SOlga Kornievskaia 	status = rpc_clnt_add_xprt_helper(clnt, xprt, data);
314092cc04f6SOlga Kornievskaia out:
314192cc04f6SOlga Kornievskaia 	xprt_put(xprt);
314292cc04f6SOlga Kornievskaia 	xprt_switch_put(xps);
314392cc04f6SOlga Kornievskaia 	return status;
314492cc04f6SOlga Kornievskaia }
314592cc04f6SOlga Kornievskaia 
314692cc04f6SOlga Kornievskaia /* rpc_clnt_probe_trunked_xprt -- probe offlined transport for session trunking
314792cc04f6SOlga Kornievskaia  * @clnt rpc_clnt structure
314892cc04f6SOlga Kornievskaia  *
314992cc04f6SOlga Kornievskaia  * For each offlined transport found in the rpc_clnt structure call
315092cc04f6SOlga Kornievskaia  * the function rpc_xprt_probe_trunked() which will determine if this
315192cc04f6SOlga Kornievskaia  * transport still belongs to the trunking group.
315292cc04f6SOlga Kornievskaia  */
rpc_clnt_probe_trunked_xprts(struct rpc_clnt * clnt,struct rpc_add_xprt_test * data)315392cc04f6SOlga Kornievskaia void rpc_clnt_probe_trunked_xprts(struct rpc_clnt *clnt,
315492cc04f6SOlga Kornievskaia 				  struct rpc_add_xprt_test *data)
315592cc04f6SOlga Kornievskaia {
315692cc04f6SOlga Kornievskaia 	struct rpc_xprt_iter xpi;
315792cc04f6SOlga Kornievskaia 	int ret;
315892cc04f6SOlga Kornievskaia 
315992cc04f6SOlga Kornievskaia 	ret = rpc_clnt_xprt_iter_offline_init(clnt, &xpi);
316092cc04f6SOlga Kornievskaia 	if (ret)
316192cc04f6SOlga Kornievskaia 		return;
316292cc04f6SOlga Kornievskaia 	for (;;) {
316392cc04f6SOlga Kornievskaia 		struct rpc_xprt *xprt = xprt_iter_get_next(&xpi);
316492cc04f6SOlga Kornievskaia 
316592cc04f6SOlga Kornievskaia 		if (!xprt)
316692cc04f6SOlga Kornievskaia 			break;
316792cc04f6SOlga Kornievskaia 		ret = rpc_xprt_probe_trunked(clnt, xprt, data);
316892cc04f6SOlga Kornievskaia 		xprt_put(xprt);
316992cc04f6SOlga Kornievskaia 		if (ret < 0)
317092cc04f6SOlga Kornievskaia 			break;
317192cc04f6SOlga Kornievskaia 		xprt_iter_rewind(&xpi);
317292cc04f6SOlga Kornievskaia 	}
317392cc04f6SOlga Kornievskaia 	xprt_iter_destroy(&xpi);
317492cc04f6SOlga Kornievskaia }
317592cc04f6SOlga Kornievskaia EXPORT_SYMBOL_GPL(rpc_clnt_probe_trunked_xprts);
317692cc04f6SOlga Kornievskaia 
rpc_xprt_offline(struct rpc_clnt * clnt,struct rpc_xprt * xprt,void * data)3177895245ccSOlga Kornievskaia static int rpc_xprt_offline(struct rpc_clnt *clnt,
3178895245ccSOlga Kornievskaia 			    struct rpc_xprt *xprt,
3179895245ccSOlga Kornievskaia 			    void *data)
3180895245ccSOlga Kornievskaia {
3181895245ccSOlga Kornievskaia 	struct rpc_xprt *main_xprt;
3182895245ccSOlga Kornievskaia 	struct rpc_xprt_switch *xps;
3183895245ccSOlga Kornievskaia 	int err = 0;
3184895245ccSOlga Kornievskaia 
3185895245ccSOlga Kornievskaia 	xprt_get(xprt);
3186895245ccSOlga Kornievskaia 
3187895245ccSOlga Kornievskaia 	rcu_read_lock();
3188895245ccSOlga Kornievskaia 	main_xprt = xprt_get(rcu_dereference(clnt->cl_xprt));
3189895245ccSOlga Kornievskaia 	xps = xprt_switch_get(rcu_dereference(clnt->cl_xpi.xpi_xpswitch));
3190895245ccSOlga Kornievskaia 	err = rpc_cmp_addr_port((struct sockaddr *)&xprt->addr,
3191895245ccSOlga Kornievskaia 				(struct sockaddr *)&main_xprt->addr);
3192895245ccSOlga Kornievskaia 	rcu_read_unlock();
3193895245ccSOlga Kornievskaia 	xprt_put(main_xprt);
3194895245ccSOlga Kornievskaia 	if (err)
3195895245ccSOlga Kornievskaia 		goto out;
3196895245ccSOlga Kornievskaia 
3197895245ccSOlga Kornievskaia 	if (wait_on_bit_lock(&xprt->state, XPRT_LOCKED, TASK_KILLABLE)) {
3198895245ccSOlga Kornievskaia 		err = -EINTR;
3199895245ccSOlga Kornievskaia 		goto out;
3200895245ccSOlga Kornievskaia 	}
3201895245ccSOlga Kornievskaia 	xprt_set_offline_locked(xprt, xps);
3202895245ccSOlga Kornievskaia 
3203895245ccSOlga Kornievskaia 	xprt_release_write(xprt, NULL);
3204895245ccSOlga Kornievskaia out:
3205895245ccSOlga Kornievskaia 	xprt_put(xprt);
3206895245ccSOlga Kornievskaia 	xprt_switch_put(xps);
3207895245ccSOlga Kornievskaia 	return err;
3208895245ccSOlga Kornievskaia }
3209895245ccSOlga Kornievskaia 
3210895245ccSOlga Kornievskaia /* rpc_clnt_manage_trunked_xprts -- offline trunked transports
3211895245ccSOlga Kornievskaia  * @clnt rpc_clnt structure
3212895245ccSOlga Kornievskaia  *
3213895245ccSOlga Kornievskaia  * For each active transport found in the rpc_clnt structure call
3214895245ccSOlga Kornievskaia  * the function rpc_xprt_offline() which will identify trunked transports
3215895245ccSOlga Kornievskaia  * and will mark them offline.
3216895245ccSOlga Kornievskaia  */
rpc_clnt_manage_trunked_xprts(struct rpc_clnt * clnt)3217895245ccSOlga Kornievskaia void rpc_clnt_manage_trunked_xprts(struct rpc_clnt *clnt)
3218895245ccSOlga Kornievskaia {
3219895245ccSOlga Kornievskaia 	rpc_clnt_iterate_for_each_xprt(clnt, rpc_xprt_offline, NULL);
3220895245ccSOlga Kornievskaia }
3221895245ccSOlga Kornievskaia EXPORT_SYMBOL_GPL(rpc_clnt_manage_trunked_xprts);
3222895245ccSOlga Kornievskaia 
32237196dbb0STrond Myklebust struct connect_timeout_data {
32247196dbb0STrond Myklebust 	unsigned long connect_timeout;
32257196dbb0STrond Myklebust 	unsigned long reconnect_timeout;
32267196dbb0STrond Myklebust };
32277196dbb0STrond Myklebust 
32288d480326STrond Myklebust static int
rpc_xprt_set_connect_timeout(struct rpc_clnt * clnt,struct rpc_xprt * xprt,void * data)32297196dbb0STrond Myklebust rpc_xprt_set_connect_timeout(struct rpc_clnt *clnt,
32308d480326STrond Myklebust 		struct rpc_xprt *xprt,
32318d480326STrond Myklebust 		void *data)
32328d480326STrond Myklebust {
32337196dbb0STrond Myklebust 	struct connect_timeout_data *timeo = data;
32348d480326STrond Myklebust 
32357196dbb0STrond Myklebust 	if (xprt->ops->set_connect_timeout)
32367196dbb0STrond Myklebust 		xprt->ops->set_connect_timeout(xprt,
32377196dbb0STrond Myklebust 				timeo->connect_timeout,
32387196dbb0STrond Myklebust 				timeo->reconnect_timeout);
32398d480326STrond Myklebust 	return 0;
32408d480326STrond Myklebust }
32418d480326STrond Myklebust 
32428d480326STrond Myklebust void
rpc_set_connect_timeout(struct rpc_clnt * clnt,unsigned long connect_timeout,unsigned long reconnect_timeout)324326ae102fSTrond Myklebust rpc_set_connect_timeout(struct rpc_clnt *clnt,
324426ae102fSTrond Myklebust 		unsigned long connect_timeout,
324526ae102fSTrond Myklebust 		unsigned long reconnect_timeout)
32468d480326STrond Myklebust {
32477196dbb0STrond Myklebust 	struct connect_timeout_data timeout = {
324826ae102fSTrond Myklebust 		.connect_timeout = connect_timeout,
324926ae102fSTrond Myklebust 		.reconnect_timeout = reconnect_timeout,
32507196dbb0STrond Myklebust 	};
32518d480326STrond Myklebust 	rpc_clnt_iterate_for_each_xprt(clnt,
32527196dbb0STrond Myklebust 			rpc_xprt_set_connect_timeout,
32537196dbb0STrond Myklebust 			&timeout);
32548d480326STrond Myklebust }
325526ae102fSTrond Myklebust EXPORT_SYMBOL_GPL(rpc_set_connect_timeout);
32568d480326STrond Myklebust 
rpc_clnt_xprt_switch_put(struct rpc_clnt * clnt)32573b58a8a9SAndy Adamson void rpc_clnt_xprt_switch_put(struct rpc_clnt *clnt)
32583b58a8a9SAndy Adamson {
3259bb29dd84SAnna Schumaker 	rcu_read_lock();
32603b58a8a9SAndy Adamson 	xprt_switch_put(rcu_dereference(clnt->cl_xpi.xpi_xpswitch));
3261bb29dd84SAnna Schumaker 	rcu_read_unlock();
32623b58a8a9SAndy Adamson }
32633b58a8a9SAndy Adamson EXPORT_SYMBOL_GPL(rpc_clnt_xprt_switch_put);
32643b58a8a9SAndy Adamson 
rpc_clnt_xprt_set_online(struct rpc_clnt * clnt,struct rpc_xprt * xprt)32659368fd6cSOlga Kornievskaia void rpc_clnt_xprt_set_online(struct rpc_clnt *clnt, struct rpc_xprt *xprt)
32669368fd6cSOlga Kornievskaia {
32679368fd6cSOlga Kornievskaia 	struct rpc_xprt_switch *xps;
32689368fd6cSOlga Kornievskaia 
32699368fd6cSOlga Kornievskaia 	rcu_read_lock();
32709368fd6cSOlga Kornievskaia 	xps = rcu_dereference(clnt->cl_xpi.xpi_xpswitch);
32719368fd6cSOlga Kornievskaia 	rcu_read_unlock();
32729368fd6cSOlga Kornievskaia 	xprt_set_online_locked(xprt, xps);
32739368fd6cSOlga Kornievskaia }
32749368fd6cSOlga Kornievskaia 
rpc_clnt_xprt_switch_add_xprt(struct rpc_clnt * clnt,struct rpc_xprt * xprt)3275dd691717SAndy Adamson void rpc_clnt_xprt_switch_add_xprt(struct rpc_clnt *clnt, struct rpc_xprt *xprt)
3276dd691717SAndy Adamson {
32779368fd6cSOlga Kornievskaia 	if (rpc_clnt_xprt_switch_has_addr(clnt,
32789368fd6cSOlga Kornievskaia 		(const struct sockaddr *)&xprt->addr)) {
32799368fd6cSOlga Kornievskaia 		return rpc_clnt_xprt_set_online(clnt, xprt);
32809368fd6cSOlga Kornievskaia 	}
3281bb29dd84SAnna Schumaker 	rcu_read_lock();
3282dd691717SAndy Adamson 	rpc_xprt_switch_add_xprt(rcu_dereference(clnt->cl_xpi.xpi_xpswitch),
3283dd691717SAndy Adamson 				 xprt);
3284bb29dd84SAnna Schumaker 	rcu_read_unlock();
3285dd691717SAndy Adamson }
3286dd691717SAndy Adamson EXPORT_SYMBOL_GPL(rpc_clnt_xprt_switch_add_xprt);
3287dd691717SAndy Adamson 
rpc_clnt_xprt_switch_remove_xprt(struct rpc_clnt * clnt,struct rpc_xprt * xprt)3288497e6464SOlga Kornievskaia void rpc_clnt_xprt_switch_remove_xprt(struct rpc_clnt *clnt, struct rpc_xprt *xprt)
3289497e6464SOlga Kornievskaia {
3290497e6464SOlga Kornievskaia 	struct rpc_xprt_switch *xps;
3291497e6464SOlga Kornievskaia 
3292497e6464SOlga Kornievskaia 	rcu_read_lock();
3293497e6464SOlga Kornievskaia 	xps = rcu_dereference(clnt->cl_xpi.xpi_xpswitch);
3294497e6464SOlga Kornievskaia 	rpc_xprt_switch_remove_xprt(rcu_dereference(clnt->cl_xpi.xpi_xpswitch),
3295497e6464SOlga Kornievskaia 				    xprt, 0);
3296497e6464SOlga Kornievskaia 	xps->xps_nunique_destaddr_xprts--;
3297497e6464SOlga Kornievskaia 	rcu_read_unlock();
3298497e6464SOlga Kornievskaia }
3299497e6464SOlga Kornievskaia EXPORT_SYMBOL_GPL(rpc_clnt_xprt_switch_remove_xprt);
3300497e6464SOlga Kornievskaia 
rpc_clnt_xprt_switch_has_addr(struct rpc_clnt * clnt,const struct sockaddr * sap)330139e5d2dfSAndy Adamson bool rpc_clnt_xprt_switch_has_addr(struct rpc_clnt *clnt,
330239e5d2dfSAndy Adamson 				   const struct sockaddr *sap)
330339e5d2dfSAndy Adamson {
330439e5d2dfSAndy Adamson 	struct rpc_xprt_switch *xps;
330539e5d2dfSAndy Adamson 	bool ret;
330639e5d2dfSAndy Adamson 
330739e5d2dfSAndy Adamson 	rcu_read_lock();
3308bb29dd84SAnna Schumaker 	xps = rcu_dereference(clnt->cl_xpi.xpi_xpswitch);
330939e5d2dfSAndy Adamson 	ret = rpc_xprt_switch_has_addr(xps, sap);
331039e5d2dfSAndy Adamson 	rcu_read_unlock();
331139e5d2dfSAndy Adamson 	return ret;
331239e5d2dfSAndy Adamson }
331339e5d2dfSAndy Adamson EXPORT_SYMBOL_GPL(rpc_clnt_xprt_switch_has_addr);
331439e5d2dfSAndy Adamson 
3315f895b252SJeff Layton #if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
rpc_show_header(void)331668a23ee9SChuck Lever static void rpc_show_header(void)
331768a23ee9SChuck Lever {
3318cb3997b5SChuck Lever 	printk(KERN_INFO "-pid- flgs status -client- --rqstp- "
3319cb3997b5SChuck Lever 		"-timeout ---ops--\n");
332068a23ee9SChuck Lever }
332168a23ee9SChuck Lever 
rpc_show_task(const struct rpc_clnt * clnt,const struct rpc_task * task)332238e886e0SChuck Lever static void rpc_show_task(const struct rpc_clnt *clnt,
332338e886e0SChuck Lever 			  const struct rpc_task *task)
332438e886e0SChuck Lever {
332538e886e0SChuck Lever 	const char *rpc_waitq = "none";
332638e886e0SChuck Lever 
332738e886e0SChuck Lever 	if (RPC_IS_QUEUED(task))
332838e886e0SChuck Lever 		rpc_waitq = rpc_qname(task->tk_waitqueue);
332938e886e0SChuck Lever 
3330b3bcedadSJoe Perches 	printk(KERN_INFO "%5u %04x %6d %8p %8p %8ld %8p %sv%u %s a:%ps q:%s\n",
3331cb3997b5SChuck Lever 		task->tk_pid, task->tk_flags, task->tk_status,
33325efd1876STrond Myklebust 		clnt, task->tk_rqstp, rpc_task_timeout(task), task->tk_ops,
333355909f21STrond Myklebust 		clnt->cl_program->name, clnt->cl_vers, rpc_proc_name(task),
3334b3bcedadSJoe Perches 		task->tk_action, rpc_waitq);
333538e886e0SChuck Lever }
333638e886e0SChuck Lever 
rpc_show_tasks(struct net * net)333770abc49bSStanislav Kinsbursky void rpc_show_tasks(struct net *net)
3338188fef11STrond Myklebust {
3339188fef11STrond Myklebust 	struct rpc_clnt *clnt;
334038e886e0SChuck Lever 	struct rpc_task *task;
334168a23ee9SChuck Lever 	int header = 0;
334270abc49bSStanislav Kinsbursky 	struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
3343188fef11STrond Myklebust 
334470abc49bSStanislav Kinsbursky 	spin_lock(&sn->rpc_client_lock);
334570abc49bSStanislav Kinsbursky 	list_for_each_entry(clnt, &sn->all_clients, cl_clients) {
3346188fef11STrond Myklebust 		spin_lock(&clnt->cl_lock);
334738e886e0SChuck Lever 		list_for_each_entry(task, &clnt->cl_tasks, tk_task) {
334868a23ee9SChuck Lever 			if (!header) {
334968a23ee9SChuck Lever 				rpc_show_header();
335068a23ee9SChuck Lever 				header++;
335168a23ee9SChuck Lever 			}
335238e886e0SChuck Lever 			rpc_show_task(clnt, task);
3353188fef11STrond Myklebust 		}
3354188fef11STrond Myklebust 		spin_unlock(&clnt->cl_lock);
3355188fef11STrond Myklebust 	}
335670abc49bSStanislav Kinsbursky 	spin_unlock(&sn->rpc_client_lock);
3357188fef11STrond Myklebust }
3358188fef11STrond Myklebust #endif
33593c87ef6eSJeff Layton 
33603c87ef6eSJeff Layton #if IS_ENABLED(CONFIG_SUNRPC_SWAP)
336115001e5aSTrond Myklebust static int
rpc_clnt_swap_activate_callback(struct rpc_clnt * clnt,struct rpc_xprt * xprt,void * dummy)336215001e5aSTrond Myklebust rpc_clnt_swap_activate_callback(struct rpc_clnt *clnt,
336315001e5aSTrond Myklebust 		struct rpc_xprt *xprt,
336415001e5aSTrond Myklebust 		void *dummy)
336515001e5aSTrond Myklebust {
336615001e5aSTrond Myklebust 	return xprt_enable_swap(xprt);
336715001e5aSTrond Myklebust }
336815001e5aSTrond Myklebust 
33693c87ef6eSJeff Layton int
rpc_clnt_swap_activate(struct rpc_clnt * clnt)33703c87ef6eSJeff Layton rpc_clnt_swap_activate(struct rpc_clnt *clnt)
33713c87ef6eSJeff Layton {
33724dc73c67SNeilBrown 	while (clnt != clnt->cl_parent)
33734dc73c67SNeilBrown 		clnt = clnt->cl_parent;
337415001e5aSTrond Myklebust 	if (atomic_inc_return(&clnt->cl_swapper) == 1)
337515001e5aSTrond Myklebust 		return rpc_clnt_iterate_for_each_xprt(clnt,
337615001e5aSTrond Myklebust 				rpc_clnt_swap_activate_callback, NULL);
337715001e5aSTrond Myklebust 	return 0;
33783c87ef6eSJeff Layton }
33793c87ef6eSJeff Layton EXPORT_SYMBOL_GPL(rpc_clnt_swap_activate);
33803c87ef6eSJeff Layton 
338115001e5aSTrond Myklebust static int
rpc_clnt_swap_deactivate_callback(struct rpc_clnt * clnt,struct rpc_xprt * xprt,void * dummy)338215001e5aSTrond Myklebust rpc_clnt_swap_deactivate_callback(struct rpc_clnt *clnt,
338315001e5aSTrond Myklebust 		struct rpc_xprt *xprt,
338415001e5aSTrond Myklebust 		void *dummy)
338515001e5aSTrond Myklebust {
338615001e5aSTrond Myklebust 	xprt_disable_swap(xprt);
338715001e5aSTrond Myklebust 	return 0;
338815001e5aSTrond Myklebust }
338915001e5aSTrond Myklebust 
33903c87ef6eSJeff Layton void
rpc_clnt_swap_deactivate(struct rpc_clnt * clnt)33913c87ef6eSJeff Layton rpc_clnt_swap_deactivate(struct rpc_clnt *clnt)
33923c87ef6eSJeff Layton {
33935bab56ffSNeilBrown 	while (clnt != clnt->cl_parent)
33945bab56ffSNeilBrown 		clnt = clnt->cl_parent;
339515001e5aSTrond Myklebust 	if (atomic_dec_if_positive(&clnt->cl_swapper) == 0)
339615001e5aSTrond Myklebust 		rpc_clnt_iterate_for_each_xprt(clnt,
339715001e5aSTrond Myklebust 				rpc_clnt_swap_deactivate_callback, NULL);
33983c87ef6eSJeff Layton }
33993c87ef6eSJeff Layton EXPORT_SYMBOL_GPL(rpc_clnt_swap_deactivate);
34003c87ef6eSJeff Layton #endif /* CONFIG_SUNRPC_SWAP */
3401