xref: /openbmc/linux/net/sunrpc/clnt.c (revision d3bc9a1deb8964d774af8535814cb91bf8f6def0)
11da177e4SLinus Torvalds /*
255aa4f58SChuck Lever  *  linux/net/sunrpc/clnt.c
31da177e4SLinus Torvalds  *
41da177e4SLinus Torvalds  *  This file contains the high-level RPC interface.
51da177e4SLinus Torvalds  *  It is modeled as a finite state machine to support both synchronous
61da177e4SLinus Torvalds  *  and asynchronous requests.
71da177e4SLinus Torvalds  *
81da177e4SLinus Torvalds  *  -	RPC header generation and argument serialization.
91da177e4SLinus Torvalds  *  -	Credential refresh.
101da177e4SLinus Torvalds  *  -	TCP connect handling.
111da177e4SLinus Torvalds  *  -	Retry of operation when it is suspected the operation failed because
121da177e4SLinus Torvalds  *	of uid squashing on the server, or when the credentials were stale
131da177e4SLinus Torvalds  *	and need to be refreshed, or when a packet was damaged in transit.
141da177e4SLinus Torvalds  *	This may be have to be moved to the VFS layer.
151da177e4SLinus Torvalds  *
161da177e4SLinus Torvalds  *  NB: BSD uses a more intelligent approach to guessing when a request
171da177e4SLinus Torvalds  *  or reply has been lost by keeping the RTO estimate for each procedure.
181da177e4SLinus Torvalds  *  We currently make do with a constant timeout value.
191da177e4SLinus Torvalds  *
201da177e4SLinus Torvalds  *  Copyright (C) 1992,1993 Rick Sladkey <jrs@world.std.com>
211da177e4SLinus Torvalds  *  Copyright (C) 1995,1996 Olaf Kirch <okir@monad.swb.de>
221da177e4SLinus Torvalds  */
231da177e4SLinus Torvalds 
241da177e4SLinus Torvalds #include <asm/system.h>
251da177e4SLinus Torvalds 
261da177e4SLinus Torvalds #include <linux/module.h>
271da177e4SLinus Torvalds #include <linux/types.h>
281da177e4SLinus Torvalds #include <linux/mm.h>
291da177e4SLinus Torvalds #include <linux/slab.h>
306d5fcb5aSTrond Myklebust #include <linux/smp_lock.h>
311da177e4SLinus Torvalds #include <linux/utsname.h>
3211c556b3SChuck Lever #include <linux/workqueue.h>
331da177e4SLinus Torvalds 
341da177e4SLinus Torvalds #include <linux/sunrpc/clnt.h>
351da177e4SLinus Torvalds #include <linux/sunrpc/rpc_pipe_fs.h>
3611c556b3SChuck Lever #include <linux/sunrpc/metrics.h>
371da177e4SLinus Torvalds 
381da177e4SLinus Torvalds 
391da177e4SLinus Torvalds #ifdef RPC_DEBUG
401da177e4SLinus Torvalds # define RPCDBG_FACILITY	RPCDBG_CALL
411da177e4SLinus Torvalds #endif
421da177e4SLinus Torvalds 
4346121cf7SChuck Lever #define dprint_status(t)					\
4446121cf7SChuck Lever 	dprintk("RPC: %5u %s (status %d)\n", t->tk_pid,		\
4546121cf7SChuck Lever 			__FUNCTION__, t->tk_status)
4646121cf7SChuck Lever 
47188fef11STrond Myklebust /*
48188fef11STrond Myklebust  * All RPC clients are linked into this list
49188fef11STrond Myklebust  */
50188fef11STrond Myklebust static LIST_HEAD(all_clients);
51188fef11STrond Myklebust static DEFINE_SPINLOCK(rpc_client_lock);
52188fef11STrond Myklebust 
531da177e4SLinus Torvalds static DECLARE_WAIT_QUEUE_HEAD(destroy_wait);
541da177e4SLinus Torvalds 
551da177e4SLinus Torvalds 
561da177e4SLinus Torvalds static void	call_start(struct rpc_task *task);
571da177e4SLinus Torvalds static void	call_reserve(struct rpc_task *task);
581da177e4SLinus Torvalds static void	call_reserveresult(struct rpc_task *task);
591da177e4SLinus Torvalds static void	call_allocate(struct rpc_task *task);
601da177e4SLinus Torvalds static void	call_encode(struct rpc_task *task);
611da177e4SLinus Torvalds static void	call_decode(struct rpc_task *task);
621da177e4SLinus Torvalds static void	call_bind(struct rpc_task *task);
63da351878SChuck Lever static void	call_bind_status(struct rpc_task *task);
641da177e4SLinus Torvalds static void	call_transmit(struct rpc_task *task);
651da177e4SLinus Torvalds static void	call_status(struct rpc_task *task);
66940e3318STrond Myklebust static void	call_transmit_status(struct rpc_task *task);
671da177e4SLinus Torvalds static void	call_refresh(struct rpc_task *task);
681da177e4SLinus Torvalds static void	call_refreshresult(struct rpc_task *task);
691da177e4SLinus Torvalds static void	call_timeout(struct rpc_task *task);
701da177e4SLinus Torvalds static void	call_connect(struct rpc_task *task);
711da177e4SLinus Torvalds static void	call_connect_status(struct rpc_task *task);
72d8ed029dSAlexey Dobriyan static __be32 *	call_header(struct rpc_task *task);
73d8ed029dSAlexey Dobriyan static __be32 *	call_verify(struct rpc_task *task);
741da177e4SLinus Torvalds 
7564c91a1fSTrond Myklebust static int	rpc_ping(struct rpc_clnt *clnt, int flags);
7664c91a1fSTrond Myklebust 
77188fef11STrond Myklebust static void rpc_register_client(struct rpc_clnt *clnt)
78188fef11STrond Myklebust {
79188fef11STrond Myklebust 	spin_lock(&rpc_client_lock);
80188fef11STrond Myklebust 	list_add(&clnt->cl_clients, &all_clients);
81188fef11STrond Myklebust 	spin_unlock(&rpc_client_lock);
82188fef11STrond Myklebust }
83188fef11STrond Myklebust 
84188fef11STrond Myklebust static void rpc_unregister_client(struct rpc_clnt *clnt)
85188fef11STrond Myklebust {
86188fef11STrond Myklebust 	spin_lock(&rpc_client_lock);
87188fef11STrond Myklebust 	list_del(&clnt->cl_clients);
88188fef11STrond Myklebust 	spin_unlock(&rpc_client_lock);
89188fef11STrond Myklebust }
901da177e4SLinus Torvalds 
911da177e4SLinus Torvalds static int
921da177e4SLinus Torvalds rpc_setup_pipedir(struct rpc_clnt *clnt, char *dir_name)
931da177e4SLinus Torvalds {
94f134585aSTrond Myklebust 	static uint32_t clntid;
951da177e4SLinus Torvalds 	int error;
961da177e4SLinus Torvalds 
9754281548STrond Myklebust 	clnt->cl_vfsmnt = ERR_PTR(-ENOENT);
9854281548STrond Myklebust 	clnt->cl_dentry = ERR_PTR(-ENOENT);
991da177e4SLinus Torvalds 	if (dir_name == NULL)
1001da177e4SLinus Torvalds 		return 0;
10154281548STrond Myklebust 
10254281548STrond Myklebust 	clnt->cl_vfsmnt = rpc_get_mount();
10354281548STrond Myklebust 	if (IS_ERR(clnt->cl_vfsmnt))
10454281548STrond Myklebust 		return PTR_ERR(clnt->cl_vfsmnt);
10554281548STrond Myklebust 
106f134585aSTrond Myklebust 	for (;;) {
107f134585aSTrond Myklebust 		snprintf(clnt->cl_pathname, sizeof(clnt->cl_pathname),
108f134585aSTrond Myklebust 				"%s/clnt%x", dir_name,
109f134585aSTrond Myklebust 				(unsigned int)clntid++);
110f134585aSTrond Myklebust 		clnt->cl_pathname[sizeof(clnt->cl_pathname) - 1] = '\0';
111f134585aSTrond Myklebust 		clnt->cl_dentry = rpc_mkdir(clnt->cl_pathname, clnt);
112f134585aSTrond Myklebust 		if (!IS_ERR(clnt->cl_dentry))
113278c995cSChristoph Hellwig 			return 0;
114f134585aSTrond Myklebust 		error = PTR_ERR(clnt->cl_dentry);
115f134585aSTrond Myklebust 		if (error != -EEXIST) {
116f134585aSTrond Myklebust 			printk(KERN_INFO "RPC: Couldn't create pipefs entry %s, error %d\n",
117f134585aSTrond Myklebust 					clnt->cl_pathname, error);
11854281548STrond Myklebust 			rpc_put_mount();
119f134585aSTrond Myklebust 			return error;
120f134585aSTrond Myklebust 		}
121f134585aSTrond Myklebust 	}
1221da177e4SLinus Torvalds }
1231da177e4SLinus Torvalds 
124ff9aa5e5SChuck Lever static struct rpc_clnt * rpc_new_client(struct rpc_xprt *xprt, char *servname, struct rpc_program *program, u32 vers, rpc_authflavor_t flavor)
1251da177e4SLinus Torvalds {
1261da177e4SLinus Torvalds 	struct rpc_version	*version;
1271da177e4SLinus Torvalds 	struct rpc_clnt		*clnt = NULL;
1286a19275aSJ. Bruce Fields 	struct rpc_auth		*auth;
1291da177e4SLinus Torvalds 	int err;
1301da177e4SLinus Torvalds 	int len;
1311da177e4SLinus Torvalds 
1321da177e4SLinus Torvalds 	dprintk("RPC:       creating %s client for %s (xprt %p)\n",
1331da177e4SLinus Torvalds 			program->name, servname, xprt);
1341da177e4SLinus Torvalds 
1354ada539eSTrond Myklebust 	err = rpciod_up();
1364ada539eSTrond Myklebust 	if (err)
1374ada539eSTrond Myklebust 		goto out_no_rpciod;
1381da177e4SLinus Torvalds 	err = -EINVAL;
1391da177e4SLinus Torvalds 	if (!xprt)
140712917d1SAdrian Bunk 		goto out_no_xprt;
1411da177e4SLinus Torvalds 	if (vers >= program->nrvers || !(version = program->version[vers]))
1421da177e4SLinus Torvalds 		goto out_err;
1431da177e4SLinus Torvalds 
1441da177e4SLinus Torvalds 	err = -ENOMEM;
1450da974f4SPanagiotis Issaris 	clnt = kzalloc(sizeof(*clnt), GFP_KERNEL);
1461da177e4SLinus Torvalds 	if (!clnt)
1471da177e4SLinus Torvalds 		goto out_err;
1481da177e4SLinus Torvalds 	clnt->cl_parent = clnt;
1491da177e4SLinus Torvalds 
1501da177e4SLinus Torvalds 	clnt->cl_server = clnt->cl_inline_name;
1511da177e4SLinus Torvalds 	len = strlen(servname) + 1;
1521da177e4SLinus Torvalds 	if (len > sizeof(clnt->cl_inline_name)) {
1531da177e4SLinus Torvalds 		char *buf = kmalloc(len, GFP_KERNEL);
1541da177e4SLinus Torvalds 		if (buf != 0)
1551da177e4SLinus Torvalds 			clnt->cl_server = buf;
1561da177e4SLinus Torvalds 		else
1571da177e4SLinus Torvalds 			len = sizeof(clnt->cl_inline_name);
1581da177e4SLinus Torvalds 	}
1591da177e4SLinus Torvalds 	strlcpy(clnt->cl_server, servname, len);
1601da177e4SLinus Torvalds 
1611da177e4SLinus Torvalds 	clnt->cl_xprt     = xprt;
1621da177e4SLinus Torvalds 	clnt->cl_procinfo = version->procs;
1631da177e4SLinus Torvalds 	clnt->cl_maxproc  = version->nrprocs;
1641da177e4SLinus Torvalds 	clnt->cl_protname = program->name;
1651da177e4SLinus Torvalds 	clnt->cl_prog     = program->number;
1661da177e4SLinus Torvalds 	clnt->cl_vers     = version->number;
1671da177e4SLinus Torvalds 	clnt->cl_stats    = program->stats;
16811c556b3SChuck Lever 	clnt->cl_metrics  = rpc_alloc_iostats(clnt);
16923bf85baSTrond Myklebust 	err = -ENOMEM;
17023bf85baSTrond Myklebust 	if (clnt->cl_metrics == NULL)
17123bf85baSTrond Myklebust 		goto out_no_stats;
1723e32a5d9STrond Myklebust 	clnt->cl_program  = program;
1736529eba0STrond Myklebust 	INIT_LIST_HEAD(&clnt->cl_tasks);
1744bef61ffSTrond Myklebust 	spin_lock_init(&clnt->cl_lock);
1751da177e4SLinus Torvalds 
176ec739ef0SChuck Lever 	if (!xprt_bound(clnt->cl_xprt))
1771da177e4SLinus Torvalds 		clnt->cl_autobind = 1;
1781da177e4SLinus Torvalds 
1791da177e4SLinus Torvalds 	clnt->cl_rtt = &clnt->cl_rtt_default;
1801da177e4SLinus Torvalds 	rpc_init_rtt(&clnt->cl_rtt_default, xprt->timeout.to_initval);
1811da177e4SLinus Torvalds 
18234f52e35STrond Myklebust 	kref_init(&clnt->cl_kref);
18334f52e35STrond Myklebust 
1841da177e4SLinus Torvalds 	err = rpc_setup_pipedir(clnt, program->pipe_dir_name);
1851da177e4SLinus Torvalds 	if (err < 0)
1861da177e4SLinus Torvalds 		goto out_no_path;
1871da177e4SLinus Torvalds 
1886a19275aSJ. Bruce Fields 	auth = rpcauth_create(flavor, clnt);
1896a19275aSJ. Bruce Fields 	if (IS_ERR(auth)) {
1901da177e4SLinus Torvalds 		printk(KERN_INFO "RPC: Couldn't create auth handle (flavor %u)\n",
1911da177e4SLinus Torvalds 				flavor);
1926a19275aSJ. Bruce Fields 		err = PTR_ERR(auth);
1931da177e4SLinus Torvalds 		goto out_no_auth;
1941da177e4SLinus Torvalds 	}
1951da177e4SLinus Torvalds 
1961da177e4SLinus Torvalds 	/* save the nodename */
197e9ff3990SSerge E. Hallyn 	clnt->cl_nodelen = strlen(utsname()->nodename);
1981da177e4SLinus Torvalds 	if (clnt->cl_nodelen > UNX_MAXNODENAME)
1991da177e4SLinus Torvalds 		clnt->cl_nodelen = UNX_MAXNODENAME;
200e9ff3990SSerge E. Hallyn 	memcpy(clnt->cl_nodename, utsname()->nodename, clnt->cl_nodelen);
2016529eba0STrond Myklebust 	rpc_register_client(clnt);
2021da177e4SLinus Torvalds 	return clnt;
2031da177e4SLinus Torvalds 
2041da177e4SLinus Torvalds out_no_auth:
20554281548STrond Myklebust 	if (!IS_ERR(clnt->cl_dentry)) {
206dff02cc1STrond Myklebust 		rpc_rmdir(clnt->cl_dentry);
20754281548STrond Myklebust 		rpc_put_mount();
20854281548STrond Myklebust 	}
2091da177e4SLinus Torvalds out_no_path:
21023bf85baSTrond Myklebust 	rpc_free_iostats(clnt->cl_metrics);
21123bf85baSTrond Myklebust out_no_stats:
2121da177e4SLinus Torvalds 	if (clnt->cl_server != clnt->cl_inline_name)
2131da177e4SLinus Torvalds 		kfree(clnt->cl_server);
2141da177e4SLinus Torvalds 	kfree(clnt);
2151da177e4SLinus Torvalds out_err:
2166b6ca86bSTrond Myklebust 	xprt_put(xprt);
217712917d1SAdrian Bunk out_no_xprt:
2184ada539eSTrond Myklebust 	rpciod_down();
2194ada539eSTrond Myklebust out_no_rpciod:
2201da177e4SLinus Torvalds 	return ERR_PTR(err);
2211da177e4SLinus Torvalds }
2221da177e4SLinus Torvalds 
223c2866763SChuck Lever /*
224c2866763SChuck Lever  * rpc_create - create an RPC client and transport with one call
225c2866763SChuck Lever  * @args: rpc_clnt create argument structure
226c2866763SChuck Lever  *
227c2866763SChuck Lever  * Creates and initializes an RPC transport and an RPC client.
228c2866763SChuck Lever  *
229c2866763SChuck Lever  * It can ping the server in order to determine if it is up, and to see if
230c2866763SChuck Lever  * it supports this program and version.  RPC_CLNT_CREATE_NOPING disables
231c2866763SChuck Lever  * this behavior so asynchronous tasks can also use rpc_create.
232c2866763SChuck Lever  */
233c2866763SChuck Lever struct rpc_clnt *rpc_create(struct rpc_create_args *args)
234c2866763SChuck Lever {
235c2866763SChuck Lever 	struct rpc_xprt *xprt;
236c2866763SChuck Lever 	struct rpc_clnt *clnt;
23796802a09SFrank van Maarseveen 	struct rpc_xprtsock_create xprtargs = {
23896802a09SFrank van Maarseveen 		.proto = args->protocol,
239*d3bc9a1dSFrank van Maarseveen 		.srcaddr = args->saddress,
24096802a09SFrank van Maarseveen 		.dstaddr = args->address,
24196802a09SFrank van Maarseveen 		.addrlen = args->addrsize,
24296802a09SFrank van Maarseveen 		.timeout = args->timeout
24396802a09SFrank van Maarseveen 	};
24443780b87SChuck Lever 	char servername[20];
245c2866763SChuck Lever 
24696802a09SFrank van Maarseveen 	xprt = xprt_create_transport(&xprtargs);
247c2866763SChuck Lever 	if (IS_ERR(xprt))
248c2866763SChuck Lever 		return (struct rpc_clnt *)xprt;
249c2866763SChuck Lever 
250c2866763SChuck Lever 	/*
25143780b87SChuck Lever 	 * If the caller chooses not to specify a hostname, whip
25243780b87SChuck Lever 	 * up a string representation of the passed-in address.
25343780b87SChuck Lever 	 */
25443780b87SChuck Lever 	if (args->servername == NULL) {
25543780b87SChuck Lever 		struct sockaddr_in *addr =
25643780b87SChuck Lever 					(struct sockaddr_in *) &args->address;
25743780b87SChuck Lever 		snprintf(servername, sizeof(servername), NIPQUAD_FMT,
25843780b87SChuck Lever 			NIPQUAD(addr->sin_addr.s_addr));
25943780b87SChuck Lever 		args->servername = servername;
26043780b87SChuck Lever 	}
26143780b87SChuck Lever 
26243780b87SChuck Lever 	/*
263c2866763SChuck Lever 	 * By default, kernel RPC client connects from a reserved port.
264c2866763SChuck Lever 	 * CAP_NET_BIND_SERVICE will not be set for unprivileged requesters,
265c2866763SChuck Lever 	 * but it is always enabled for rpciod, which handles the connect
266c2866763SChuck Lever 	 * operation.
267c2866763SChuck Lever 	 */
268c2866763SChuck Lever 	xprt->resvport = 1;
269c2866763SChuck Lever 	if (args->flags & RPC_CLNT_CREATE_NONPRIVPORT)
270c2866763SChuck Lever 		xprt->resvport = 0;
271c2866763SChuck Lever 
272c2866763SChuck Lever 	dprintk("RPC:       creating %s client for %s (xprt %p)\n",
273c2866763SChuck Lever 			args->program->name, args->servername, xprt);
274c2866763SChuck Lever 
275c2866763SChuck Lever 	clnt = rpc_new_client(xprt, args->servername, args->program,
276c2866763SChuck Lever 				args->version, args->authflavor);
277c2866763SChuck Lever 	if (IS_ERR(clnt))
278c2866763SChuck Lever 		return clnt;
279c2866763SChuck Lever 
280c2866763SChuck Lever 	if (!(args->flags & RPC_CLNT_CREATE_NOPING)) {
281c2866763SChuck Lever 		int err = rpc_ping(clnt, RPC_TASK_SOFT|RPC_TASK_NOINTR);
282c2866763SChuck Lever 		if (err != 0) {
283c2866763SChuck Lever 			rpc_shutdown_client(clnt);
284c2866763SChuck Lever 			return ERR_PTR(err);
285c2866763SChuck Lever 		}
286c2866763SChuck Lever 	}
287c2866763SChuck Lever 
288c2866763SChuck Lever 	clnt->cl_softrtry = 1;
289c2866763SChuck Lever 	if (args->flags & RPC_CLNT_CREATE_HARDRTRY)
290c2866763SChuck Lever 		clnt->cl_softrtry = 0;
291c2866763SChuck Lever 
292c2866763SChuck Lever 	if (args->flags & RPC_CLNT_CREATE_INTR)
293c2866763SChuck Lever 		clnt->cl_intr = 1;
294c2866763SChuck Lever 	if (args->flags & RPC_CLNT_CREATE_AUTOBIND)
295c2866763SChuck Lever 		clnt->cl_autobind = 1;
29643d78ef2SChuck Lever 	if (args->flags & RPC_CLNT_CREATE_DISCRTRY)
29743d78ef2SChuck Lever 		clnt->cl_discrtry = 1;
298c2866763SChuck Lever 
299c2866763SChuck Lever 	return clnt;
300c2866763SChuck Lever }
301b86acd50SChuck Lever EXPORT_SYMBOL_GPL(rpc_create);
302c2866763SChuck Lever 
3031da177e4SLinus Torvalds /*
3041da177e4SLinus Torvalds  * This function clones the RPC client structure. It allows us to share the
3051da177e4SLinus Torvalds  * same transport while varying parameters such as the authentication
3061da177e4SLinus Torvalds  * flavour.
3071da177e4SLinus Torvalds  */
3081da177e4SLinus Torvalds struct rpc_clnt *
3091da177e4SLinus Torvalds rpc_clone_client(struct rpc_clnt *clnt)
3101da177e4SLinus Torvalds {
3111da177e4SLinus Torvalds 	struct rpc_clnt *new;
3123e32a5d9STrond Myklebust 	int err = -ENOMEM;
3131da177e4SLinus Torvalds 
314e69062b4SArnaldo Carvalho de Melo 	new = kmemdup(clnt, sizeof(*new), GFP_KERNEL);
3151da177e4SLinus Torvalds 	if (!new)
3161da177e4SLinus Torvalds 		goto out_no_clnt;
317d431a555STrond Myklebust 	new->cl_parent = clnt;
318d431a555STrond Myklebust 	/* Turn off autobind on clones */
319d431a555STrond Myklebust 	new->cl_autobind = 0;
320d431a555STrond Myklebust 	INIT_LIST_HEAD(&new->cl_tasks);
321d431a555STrond Myklebust 	spin_lock_init(&new->cl_lock);
322d431a555STrond Myklebust 	rpc_init_rtt(&new->cl_rtt_default, clnt->cl_xprt->timeout.to_initval);
32323bf85baSTrond Myklebust 	new->cl_metrics = rpc_alloc_iostats(clnt);
32423bf85baSTrond Myklebust 	if (new->cl_metrics == NULL)
32523bf85baSTrond Myklebust 		goto out_no_stats;
32634f52e35STrond Myklebust 	kref_init(&new->cl_kref);
3273e32a5d9STrond Myklebust 	err = rpc_setup_pipedir(new, clnt->cl_program->pipe_dir_name);
3283e32a5d9STrond Myklebust 	if (err != 0)
3293e32a5d9STrond Myklebust 		goto out_no_path;
3301da177e4SLinus Torvalds 	if (new->cl_auth)
3311da177e4SLinus Torvalds 		atomic_inc(&new->cl_auth->au_count);
332d431a555STrond Myklebust 	xprt_get(clnt->cl_xprt);
333d431a555STrond Myklebust 	kref_get(&clnt->cl_kref);
3346529eba0STrond Myklebust 	rpc_register_client(new);
3354ada539eSTrond Myklebust 	rpciod_up();
3361da177e4SLinus Torvalds 	return new;
3373e32a5d9STrond Myklebust out_no_path:
3383e32a5d9STrond Myklebust 	rpc_free_iostats(new->cl_metrics);
33923bf85baSTrond Myklebust out_no_stats:
34023bf85baSTrond Myklebust 	kfree(new);
3411da177e4SLinus Torvalds out_no_clnt:
34246121cf7SChuck Lever 	dprintk("RPC:       %s: returned error %d\n", __FUNCTION__, err);
3433e32a5d9STrond Myklebust 	return ERR_PTR(err);
3441da177e4SLinus Torvalds }
3451da177e4SLinus Torvalds 
3461da177e4SLinus Torvalds /*
3471da177e4SLinus Torvalds  * Properly shut down an RPC client, terminating all outstanding
34890c5755fSTrond Myklebust  * requests.
3491da177e4SLinus Torvalds  */
3504c402b40STrond Myklebust void rpc_shutdown_client(struct rpc_clnt *clnt)
3511da177e4SLinus Torvalds {
35234f52e35STrond Myklebust 	dprintk("RPC:       shutting down %s client for %s\n",
35334f52e35STrond Myklebust 			clnt->cl_protname, clnt->cl_server);
3541da177e4SLinus Torvalds 
35534f52e35STrond Myklebust 	while (!list_empty(&clnt->cl_tasks)) {
3561da177e4SLinus Torvalds 		rpc_killall_tasks(clnt);
357532347e2SIngo Molnar 		wait_event_timeout(destroy_wait,
35834f52e35STrond Myklebust 			list_empty(&clnt->cl_tasks), 1*HZ);
3591da177e4SLinus Torvalds 	}
3601da177e4SLinus Torvalds 
3614c402b40STrond Myklebust 	rpc_release_client(clnt);
3621da177e4SLinus Torvalds }
3631da177e4SLinus Torvalds 
3641da177e4SLinus Torvalds /*
36534f52e35STrond Myklebust  * Free an RPC client
3661da177e4SLinus Torvalds  */
36734f52e35STrond Myklebust static void
36834f52e35STrond Myklebust rpc_free_client(struct kref *kref)
3691da177e4SLinus Torvalds {
37034f52e35STrond Myklebust 	struct rpc_clnt *clnt = container_of(kref, struct rpc_clnt, cl_kref);
3711da177e4SLinus Torvalds 
3721da177e4SLinus Torvalds 	dprintk("RPC:       destroying %s client for %s\n",
3731da177e4SLinus Torvalds 			clnt->cl_protname, clnt->cl_server);
3748f8e7a50STrond Myklebust 	if (!IS_ERR(clnt->cl_dentry)) {
375dff02cc1STrond Myklebust 		rpc_rmdir(clnt->cl_dentry);
3768f8e7a50STrond Myklebust 		rpc_put_mount();
3778f8e7a50STrond Myklebust 	}
3783e32a5d9STrond Myklebust 	if (clnt->cl_parent != clnt) {
3798ad7c892STrond Myklebust 		rpc_release_client(clnt->cl_parent);
3803e32a5d9STrond Myklebust 		goto out_free;
3813e32a5d9STrond Myklebust 	}
3821da177e4SLinus Torvalds 	if (clnt->cl_server != clnt->cl_inline_name)
3831da177e4SLinus Torvalds 		kfree(clnt->cl_server);
3841da177e4SLinus Torvalds out_free:
3856529eba0STrond Myklebust 	rpc_unregister_client(clnt);
38611c556b3SChuck Lever 	rpc_free_iostats(clnt->cl_metrics);
38711c556b3SChuck Lever 	clnt->cl_metrics = NULL;
3886b6ca86bSTrond Myklebust 	xprt_put(clnt->cl_xprt);
3894ada539eSTrond Myklebust 	rpciod_down();
3901da177e4SLinus Torvalds 	kfree(clnt);
3911da177e4SLinus Torvalds }
3921da177e4SLinus Torvalds 
3931da177e4SLinus Torvalds /*
3941dd17ec6STrond Myklebust  * Free an RPC client
3951dd17ec6STrond Myklebust  */
3961dd17ec6STrond Myklebust static void
3971dd17ec6STrond Myklebust rpc_free_auth(struct kref *kref)
3981dd17ec6STrond Myklebust {
3991dd17ec6STrond Myklebust 	struct rpc_clnt *clnt = container_of(kref, struct rpc_clnt, cl_kref);
4001dd17ec6STrond Myklebust 
4011dd17ec6STrond Myklebust 	if (clnt->cl_auth == NULL) {
4021dd17ec6STrond Myklebust 		rpc_free_client(kref);
4031dd17ec6STrond Myklebust 		return;
4041dd17ec6STrond Myklebust 	}
4051dd17ec6STrond Myklebust 
4061dd17ec6STrond Myklebust 	/*
4071dd17ec6STrond Myklebust 	 * Note: RPCSEC_GSS may need to send NULL RPC calls in order to
4081dd17ec6STrond Myklebust 	 *       release remaining GSS contexts. This mechanism ensures
4091dd17ec6STrond Myklebust 	 *       that it can do so safely.
4101dd17ec6STrond Myklebust 	 */
4111dd17ec6STrond Myklebust 	kref_init(kref);
4121dd17ec6STrond Myklebust 	rpcauth_release(clnt->cl_auth);
4131dd17ec6STrond Myklebust 	clnt->cl_auth = NULL;
4141dd17ec6STrond Myklebust 	kref_put(kref, rpc_free_client);
4151dd17ec6STrond Myklebust }
4161dd17ec6STrond Myklebust 
4171dd17ec6STrond Myklebust /*
41834f52e35STrond Myklebust  * Release reference to the RPC client
4191da177e4SLinus Torvalds  */
4201da177e4SLinus Torvalds void
4211da177e4SLinus Torvalds rpc_release_client(struct rpc_clnt *clnt)
4221da177e4SLinus Torvalds {
42334f52e35STrond Myklebust 	dprintk("RPC:       rpc_release_client(%p)\n", clnt);
4241da177e4SLinus Torvalds 
42534f52e35STrond Myklebust 	if (list_empty(&clnt->cl_tasks))
4261da177e4SLinus Torvalds 		wake_up(&destroy_wait);
4271dd17ec6STrond Myklebust 	kref_put(&clnt->cl_kref, rpc_free_auth);
42834f52e35STrond Myklebust }
42934f52e35STrond Myklebust 
430007e251fSAndreas Gruenbacher /**
431007e251fSAndreas Gruenbacher  * rpc_bind_new_program - bind a new RPC program to an existing client
432007e251fSAndreas Gruenbacher  * @old - old rpc_client
433007e251fSAndreas Gruenbacher  * @program - rpc program to set
434007e251fSAndreas Gruenbacher  * @vers - rpc program version
435007e251fSAndreas Gruenbacher  *
436007e251fSAndreas Gruenbacher  * Clones the rpc client and sets up a new RPC program. This is mainly
437007e251fSAndreas Gruenbacher  * of use for enabling different RPC programs to share the same transport.
438007e251fSAndreas Gruenbacher  * The Sun NFSv2/v3 ACL protocol can do this.
439007e251fSAndreas Gruenbacher  */
440007e251fSAndreas Gruenbacher struct rpc_clnt *rpc_bind_new_program(struct rpc_clnt *old,
441007e251fSAndreas Gruenbacher 				      struct rpc_program *program,
442007e251fSAndreas Gruenbacher 				      int vers)
443007e251fSAndreas Gruenbacher {
444007e251fSAndreas Gruenbacher 	struct rpc_clnt *clnt;
445007e251fSAndreas Gruenbacher 	struct rpc_version *version;
446007e251fSAndreas Gruenbacher 	int err;
447007e251fSAndreas Gruenbacher 
448007e251fSAndreas Gruenbacher 	BUG_ON(vers >= program->nrvers || !program->version[vers]);
449007e251fSAndreas Gruenbacher 	version = program->version[vers];
450007e251fSAndreas Gruenbacher 	clnt = rpc_clone_client(old);
451007e251fSAndreas Gruenbacher 	if (IS_ERR(clnt))
452007e251fSAndreas Gruenbacher 		goto out;
453007e251fSAndreas Gruenbacher 	clnt->cl_procinfo = version->procs;
454007e251fSAndreas Gruenbacher 	clnt->cl_maxproc  = version->nrprocs;
455007e251fSAndreas Gruenbacher 	clnt->cl_protname = program->name;
456007e251fSAndreas Gruenbacher 	clnt->cl_prog     = program->number;
457007e251fSAndreas Gruenbacher 	clnt->cl_vers     = version->number;
458007e251fSAndreas Gruenbacher 	clnt->cl_stats    = program->stats;
459007e251fSAndreas Gruenbacher 	err = rpc_ping(clnt, RPC_TASK_SOFT|RPC_TASK_NOINTR);
460007e251fSAndreas Gruenbacher 	if (err != 0) {
461007e251fSAndreas Gruenbacher 		rpc_shutdown_client(clnt);
462007e251fSAndreas Gruenbacher 		clnt = ERR_PTR(err);
463007e251fSAndreas Gruenbacher 	}
464007e251fSAndreas Gruenbacher out:
465007e251fSAndreas Gruenbacher 	return clnt;
466007e251fSAndreas Gruenbacher }
467007e251fSAndreas Gruenbacher 
4681da177e4SLinus Torvalds /*
4691da177e4SLinus Torvalds  * Default callback for async RPC calls
4701da177e4SLinus Torvalds  */
4711da177e4SLinus Torvalds static void
472963d8fe5STrond Myklebust rpc_default_callback(struct rpc_task *task, void *data)
4731da177e4SLinus Torvalds {
4741da177e4SLinus Torvalds }
4751da177e4SLinus Torvalds 
476963d8fe5STrond Myklebust static const struct rpc_call_ops rpc_default_ops = {
477963d8fe5STrond Myklebust 	.rpc_call_done = rpc_default_callback,
478963d8fe5STrond Myklebust };
479963d8fe5STrond Myklebust 
4801da177e4SLinus Torvalds /*
48114b218a8STrond Myklebust  *	Export the signal mask handling for synchronous code that
4821da177e4SLinus Torvalds  *	sleeps on RPC calls
4831da177e4SLinus Torvalds  */
4842bd61579STrond Myklebust #define RPC_INTR_SIGNALS (sigmask(SIGHUP) | sigmask(SIGINT) | sigmask(SIGQUIT) | sigmask(SIGTERM))
48514b218a8STrond Myklebust 
48614b218a8STrond Myklebust static void rpc_save_sigmask(sigset_t *oldset, int intr)
48714b218a8STrond Myklebust {
4882bd61579STrond Myklebust 	unsigned long	sigallow = sigmask(SIGKILL);
48914b218a8STrond Myklebust 	sigset_t sigmask;
49014b218a8STrond Myklebust 
49114b218a8STrond Myklebust 	/* Block all signals except those listed in sigallow */
49214b218a8STrond Myklebust 	if (intr)
49314b218a8STrond Myklebust 		sigallow |= RPC_INTR_SIGNALS;
49414b218a8STrond Myklebust 	siginitsetinv(&sigmask, sigallow);
49514b218a8STrond Myklebust 	sigprocmask(SIG_BLOCK, &sigmask, oldset);
49614b218a8STrond Myklebust }
49714b218a8STrond Myklebust 
49814b218a8STrond Myklebust static inline void rpc_task_sigmask(struct rpc_task *task, sigset_t *oldset)
49914b218a8STrond Myklebust {
50014b218a8STrond Myklebust 	rpc_save_sigmask(oldset, !RPC_TASK_UNINTERRUPTIBLE(task));
50114b218a8STrond Myklebust }
50214b218a8STrond Myklebust 
50314b218a8STrond Myklebust static inline void rpc_restore_sigmask(sigset_t *oldset)
50414b218a8STrond Myklebust {
50514b218a8STrond Myklebust 	sigprocmask(SIG_SETMASK, oldset, NULL);
50614b218a8STrond Myklebust }
5071da177e4SLinus Torvalds 
5081da177e4SLinus Torvalds void rpc_clnt_sigmask(struct rpc_clnt *clnt, sigset_t *oldset)
5091da177e4SLinus Torvalds {
51014b218a8STrond Myklebust 	rpc_save_sigmask(oldset, clnt->cl_intr);
5111da177e4SLinus Torvalds }
5121da177e4SLinus Torvalds 
5131da177e4SLinus Torvalds void rpc_clnt_sigunmask(struct rpc_clnt *clnt, sigset_t *oldset)
5141da177e4SLinus Torvalds {
51514b218a8STrond Myklebust 	rpc_restore_sigmask(oldset);
5161da177e4SLinus Torvalds }
5171da177e4SLinus Torvalds 
5186e5b70e9STrond Myklebust static
5196e5b70e9STrond Myklebust struct rpc_task *rpc_do_run_task(struct rpc_clnt *clnt,
5206e5b70e9STrond Myklebust 		struct rpc_message *msg,
5216e5b70e9STrond Myklebust 		int flags,
5226e5b70e9STrond Myklebust 		const struct rpc_call_ops *ops,
5236e5b70e9STrond Myklebust 		void *data)
5246e5b70e9STrond Myklebust {
5256e5b70e9STrond Myklebust 	struct rpc_task *task, *ret;
5266e5b70e9STrond Myklebust 	sigset_t oldset;
5276e5b70e9STrond Myklebust 
5286e5b70e9STrond Myklebust 	task = rpc_new_task(clnt, flags, ops, data);
5296e5b70e9STrond Myklebust 	if (task == NULL) {
5306e5b70e9STrond Myklebust 		rpc_release_calldata(ops, data);
5316e5b70e9STrond Myklebust 		return ERR_PTR(-ENOMEM);
5326e5b70e9STrond Myklebust 	}
5336e5b70e9STrond Myklebust 
5346e5b70e9STrond Myklebust 	/* Mask signals on synchronous RPC calls and RPCSEC_GSS upcalls */
5356e5b70e9STrond Myklebust 	rpc_task_sigmask(task, &oldset);
5366e5b70e9STrond Myklebust 	if (msg != NULL) {
5376e5b70e9STrond Myklebust 		rpc_call_setup(task, msg, 0);
5386e5b70e9STrond Myklebust 		if (task->tk_status != 0) {
5396e5b70e9STrond Myklebust 			ret = ERR_PTR(task->tk_status);
5406e5b70e9STrond Myklebust 			rpc_put_task(task);
5416e5b70e9STrond Myklebust 			goto out;
5426e5b70e9STrond Myklebust 		}
5436e5b70e9STrond Myklebust 	}
5446e5b70e9STrond Myklebust 	atomic_inc(&task->tk_count);
5456e5b70e9STrond Myklebust 	rpc_execute(task);
5466e5b70e9STrond Myklebust 	ret = task;
5476e5b70e9STrond Myklebust out:
5486e5b70e9STrond Myklebust 	rpc_restore_sigmask(&oldset);
5496e5b70e9STrond Myklebust 	return ret;
5506e5b70e9STrond Myklebust }
5516e5b70e9STrond Myklebust 
5526e5b70e9STrond Myklebust /**
5536e5b70e9STrond Myklebust  * rpc_call_sync - Perform a synchronous RPC call
5546e5b70e9STrond Myklebust  * @clnt: pointer to RPC client
5556e5b70e9STrond Myklebust  * @msg: RPC call parameters
5566e5b70e9STrond Myklebust  * @flags: RPC call flags
5571da177e4SLinus Torvalds  */
5581da177e4SLinus Torvalds int rpc_call_sync(struct rpc_clnt *clnt, struct rpc_message *msg, int flags)
5591da177e4SLinus Torvalds {
5601da177e4SLinus Torvalds 	struct rpc_task	*task;
5611da177e4SLinus Torvalds 	int status;
5621da177e4SLinus Torvalds 
5631da177e4SLinus Torvalds 	BUG_ON(flags & RPC_TASK_ASYNC);
5641da177e4SLinus Torvalds 
5656e5b70e9STrond Myklebust 	task = rpc_do_run_task(clnt, msg, flags, &rpc_default_ops, NULL);
5666e5b70e9STrond Myklebust 	if (IS_ERR(task))
5676e5b70e9STrond Myklebust 		return PTR_ERR(task);
568e60859acSTrond Myklebust 	status = task->tk_status;
569bde8f00cSTrond Myklebust 	rpc_put_task(task);
5701da177e4SLinus Torvalds 	return status;
5711da177e4SLinus Torvalds }
5721da177e4SLinus Torvalds 
5736e5b70e9STrond Myklebust /**
5746e5b70e9STrond Myklebust  * rpc_call_async - Perform an asynchronous RPC call
5756e5b70e9STrond Myklebust  * @clnt: pointer to RPC client
5766e5b70e9STrond Myklebust  * @msg: RPC call parameters
5776e5b70e9STrond Myklebust  * @flags: RPC call flags
5786e5b70e9STrond Myklebust  * @ops: RPC call ops
5796e5b70e9STrond Myklebust  * @data: user call data
5801da177e4SLinus Torvalds  */
5811da177e4SLinus Torvalds int
5821da177e4SLinus Torvalds rpc_call_async(struct rpc_clnt *clnt, struct rpc_message *msg, int flags,
583963d8fe5STrond Myklebust 	       const struct rpc_call_ops *tk_ops, void *data)
5841da177e4SLinus Torvalds {
5851da177e4SLinus Torvalds 	struct rpc_task	*task;
5861da177e4SLinus Torvalds 
5876e5b70e9STrond Myklebust 	task = rpc_do_run_task(clnt, msg, flags|RPC_TASK_ASYNC, tk_ops, data);
5886e5b70e9STrond Myklebust 	if (IS_ERR(task))
5896e5b70e9STrond Myklebust 		return PTR_ERR(task);
590bde8f00cSTrond Myklebust 	rpc_put_task(task);
5916e5b70e9STrond Myklebust 	return 0;
5921da177e4SLinus Torvalds }
5931da177e4SLinus Torvalds 
5946e5b70e9STrond Myklebust /**
5956e5b70e9STrond Myklebust  * rpc_run_task - Allocate a new RPC task, then run rpc_execute against it
5966e5b70e9STrond Myklebust  * @clnt: pointer to RPC client
5976e5b70e9STrond Myklebust  * @flags: RPC flags
5986e5b70e9STrond Myklebust  * @ops: RPC call ops
5996e5b70e9STrond Myklebust  * @data: user call data
6006e5b70e9STrond Myklebust  */
6016e5b70e9STrond Myklebust struct rpc_task *rpc_run_task(struct rpc_clnt *clnt, int flags,
6026e5b70e9STrond Myklebust 					const struct rpc_call_ops *tk_ops,
6036e5b70e9STrond Myklebust 					void *data)
6046e5b70e9STrond Myklebust {
6056e5b70e9STrond Myklebust 	return rpc_do_run_task(clnt, NULL, flags, tk_ops, data);
6066e5b70e9STrond Myklebust }
6076e5b70e9STrond Myklebust EXPORT_SYMBOL(rpc_run_task);
6081da177e4SLinus Torvalds 
6091da177e4SLinus Torvalds void
6101da177e4SLinus Torvalds rpc_call_setup(struct rpc_task *task, struct rpc_message *msg, int flags)
6111da177e4SLinus Torvalds {
6121da177e4SLinus Torvalds 	task->tk_msg   = *msg;
6131da177e4SLinus Torvalds 	task->tk_flags |= flags;
6141da177e4SLinus Torvalds 	/* Bind the user cred */
6151da177e4SLinus Torvalds 	if (task->tk_msg.rpc_cred != NULL)
6161da177e4SLinus Torvalds 		rpcauth_holdcred(task);
6171da177e4SLinus Torvalds 	else
6181da177e4SLinus Torvalds 		rpcauth_bindcred(task);
6191da177e4SLinus Torvalds 
6201da177e4SLinus Torvalds 	if (task->tk_status == 0)
6211da177e4SLinus Torvalds 		task->tk_action = call_start;
6221da177e4SLinus Torvalds 	else
623abbcf28fSTrond Myklebust 		task->tk_action = rpc_exit_task;
6241da177e4SLinus Torvalds }
6251da177e4SLinus Torvalds 
626ed39440aSChuck Lever /**
627ed39440aSChuck Lever  * rpc_peeraddr - extract remote peer address from clnt's xprt
628ed39440aSChuck Lever  * @clnt: RPC client structure
629ed39440aSChuck Lever  * @buf: target buffer
630ed39440aSChuck Lever  * @size: length of target buffer
631ed39440aSChuck Lever  *
632ed39440aSChuck Lever  * Returns the number of bytes that are actually in the stored address.
633ed39440aSChuck Lever  */
634ed39440aSChuck Lever size_t rpc_peeraddr(struct rpc_clnt *clnt, struct sockaddr *buf, size_t bufsize)
635ed39440aSChuck Lever {
636ed39440aSChuck Lever 	size_t bytes;
637ed39440aSChuck Lever 	struct rpc_xprt *xprt = clnt->cl_xprt;
638ed39440aSChuck Lever 
639ed39440aSChuck Lever 	bytes = sizeof(xprt->addr);
640ed39440aSChuck Lever 	if (bytes > bufsize)
641ed39440aSChuck Lever 		bytes = bufsize;
642ed39440aSChuck Lever 	memcpy(buf, &clnt->cl_xprt->addr, bytes);
643c4efcb1dSChuck Lever 	return xprt->addrlen;
644ed39440aSChuck Lever }
645b86acd50SChuck Lever EXPORT_SYMBOL_GPL(rpc_peeraddr);
646ed39440aSChuck Lever 
647f425eba4SChuck Lever /**
648f425eba4SChuck Lever  * rpc_peeraddr2str - return remote peer address in printable format
649f425eba4SChuck Lever  * @clnt: RPC client structure
650f425eba4SChuck Lever  * @format: address format
651f425eba4SChuck Lever  *
652f425eba4SChuck Lever  */
653f425eba4SChuck Lever char *rpc_peeraddr2str(struct rpc_clnt *clnt, enum rpc_display_format_t format)
654f425eba4SChuck Lever {
655f425eba4SChuck Lever 	struct rpc_xprt *xprt = clnt->cl_xprt;
6567559c7a2SChuck Lever 
6577559c7a2SChuck Lever 	if (xprt->address_strings[format] != NULL)
6587559c7a2SChuck Lever 		return xprt->address_strings[format];
6597559c7a2SChuck Lever 	else
6607559c7a2SChuck Lever 		return "unprintable";
661f425eba4SChuck Lever }
662b86acd50SChuck Lever EXPORT_SYMBOL_GPL(rpc_peeraddr2str);
663f425eba4SChuck Lever 
6641da177e4SLinus Torvalds void
6651da177e4SLinus Torvalds rpc_setbufsize(struct rpc_clnt *clnt, unsigned int sndsize, unsigned int rcvsize)
6661da177e4SLinus Torvalds {
6671da177e4SLinus Torvalds 	struct rpc_xprt *xprt = clnt->cl_xprt;
668470056c2SChuck Lever 	if (xprt->ops->set_buffer_size)
669470056c2SChuck Lever 		xprt->ops->set_buffer_size(xprt, sndsize, rcvsize);
6701da177e4SLinus Torvalds }
6711da177e4SLinus Torvalds 
6721da177e4SLinus Torvalds /*
6731da177e4SLinus Torvalds  * Return size of largest payload RPC client can support, in bytes
6741da177e4SLinus Torvalds  *
6751da177e4SLinus Torvalds  * For stream transports, this is one RPC record fragment (see RFC
6761da177e4SLinus Torvalds  * 1831), as we don't support multi-record requests yet.  For datagram
6771da177e4SLinus Torvalds  * transports, this is the size of an IP packet minus the IP, UDP, and
6781da177e4SLinus Torvalds  * RPC header sizes.
6791da177e4SLinus Torvalds  */
6801da177e4SLinus Torvalds size_t rpc_max_payload(struct rpc_clnt *clnt)
6811da177e4SLinus Torvalds {
6821da177e4SLinus Torvalds 	return clnt->cl_xprt->max_payload;
6831da177e4SLinus Torvalds }
684b86acd50SChuck Lever EXPORT_SYMBOL_GPL(rpc_max_payload);
6851da177e4SLinus Torvalds 
68635f5a422SChuck Lever /**
68735f5a422SChuck Lever  * rpc_force_rebind - force transport to check that remote port is unchanged
68835f5a422SChuck Lever  * @clnt: client to rebind
68935f5a422SChuck Lever  *
69035f5a422SChuck Lever  */
69135f5a422SChuck Lever void rpc_force_rebind(struct rpc_clnt *clnt)
69235f5a422SChuck Lever {
69335f5a422SChuck Lever 	if (clnt->cl_autobind)
694ec739ef0SChuck Lever 		xprt_clear_bound(clnt->cl_xprt);
69535f5a422SChuck Lever }
696b86acd50SChuck Lever EXPORT_SYMBOL_GPL(rpc_force_rebind);
69735f5a422SChuck Lever 
6981da177e4SLinus Torvalds /*
6991da177e4SLinus Torvalds  * Restart an (async) RPC call. Usually called from within the
7001da177e4SLinus Torvalds  * exit handler.
7011da177e4SLinus Torvalds  */
7021da177e4SLinus Torvalds void
7031da177e4SLinus Torvalds rpc_restart_call(struct rpc_task *task)
7041da177e4SLinus Torvalds {
7051da177e4SLinus Torvalds 	if (RPC_ASSASSINATED(task))
7061da177e4SLinus Torvalds 		return;
7071da177e4SLinus Torvalds 
7081da177e4SLinus Torvalds 	task->tk_action = call_start;
7091da177e4SLinus Torvalds }
7101da177e4SLinus Torvalds 
7111da177e4SLinus Torvalds /*
7121da177e4SLinus Torvalds  * 0.  Initial state
7131da177e4SLinus Torvalds  *
7141da177e4SLinus Torvalds  *     Other FSM states can be visited zero or more times, but
7151da177e4SLinus Torvalds  *     this state is visited exactly once for each RPC.
7161da177e4SLinus Torvalds  */
7171da177e4SLinus Torvalds static void
7181da177e4SLinus Torvalds call_start(struct rpc_task *task)
7191da177e4SLinus Torvalds {
7201da177e4SLinus Torvalds 	struct rpc_clnt	*clnt = task->tk_client;
7211da177e4SLinus Torvalds 
72246121cf7SChuck Lever 	dprintk("RPC: %5u call_start %s%d proc %d (%s)\n", task->tk_pid,
72346121cf7SChuck Lever 			clnt->cl_protname, clnt->cl_vers,
72446121cf7SChuck Lever 			task->tk_msg.rpc_proc->p_proc,
7251da177e4SLinus Torvalds 			(RPC_IS_ASYNC(task) ? "async" : "sync"));
7261da177e4SLinus Torvalds 
7271da177e4SLinus Torvalds 	/* Increment call count */
7281da177e4SLinus Torvalds 	task->tk_msg.rpc_proc->p_count++;
7291da177e4SLinus Torvalds 	clnt->cl_stats->rpccnt++;
7301da177e4SLinus Torvalds 	task->tk_action = call_reserve;
7311da177e4SLinus Torvalds }
7321da177e4SLinus Torvalds 
7331da177e4SLinus Torvalds /*
7341da177e4SLinus Torvalds  * 1.	Reserve an RPC call slot
7351da177e4SLinus Torvalds  */
7361da177e4SLinus Torvalds static void
7371da177e4SLinus Torvalds call_reserve(struct rpc_task *task)
7381da177e4SLinus Torvalds {
73946121cf7SChuck Lever 	dprint_status(task);
7401da177e4SLinus Torvalds 
7411da177e4SLinus Torvalds 	if (!rpcauth_uptodatecred(task)) {
7421da177e4SLinus Torvalds 		task->tk_action = call_refresh;
7431da177e4SLinus Torvalds 		return;
7441da177e4SLinus Torvalds 	}
7451da177e4SLinus Torvalds 
7461da177e4SLinus Torvalds 	task->tk_status  = 0;
7471da177e4SLinus Torvalds 	task->tk_action  = call_reserveresult;
7481da177e4SLinus Torvalds 	xprt_reserve(task);
7491da177e4SLinus Torvalds }
7501da177e4SLinus Torvalds 
7511da177e4SLinus Torvalds /*
7521da177e4SLinus Torvalds  * 1b.	Grok the result of xprt_reserve()
7531da177e4SLinus Torvalds  */
7541da177e4SLinus Torvalds static void
7551da177e4SLinus Torvalds call_reserveresult(struct rpc_task *task)
7561da177e4SLinus Torvalds {
7571da177e4SLinus Torvalds 	int status = task->tk_status;
7581da177e4SLinus Torvalds 
75946121cf7SChuck Lever 	dprint_status(task);
7601da177e4SLinus Torvalds 
7611da177e4SLinus Torvalds 	/*
7621da177e4SLinus Torvalds 	 * After a call to xprt_reserve(), we must have either
7631da177e4SLinus Torvalds 	 * a request slot or else an error status.
7641da177e4SLinus Torvalds 	 */
7651da177e4SLinus Torvalds 	task->tk_status = 0;
7661da177e4SLinus Torvalds 	if (status >= 0) {
7671da177e4SLinus Torvalds 		if (task->tk_rqstp) {
7681da177e4SLinus Torvalds 			task->tk_action = call_allocate;
7691da177e4SLinus Torvalds 			return;
7701da177e4SLinus Torvalds 		}
7711da177e4SLinus Torvalds 
7721da177e4SLinus Torvalds 		printk(KERN_ERR "%s: status=%d, but no request slot, exiting\n",
7731da177e4SLinus Torvalds 				__FUNCTION__, status);
7741da177e4SLinus Torvalds 		rpc_exit(task, -EIO);
7751da177e4SLinus Torvalds 		return;
7761da177e4SLinus Torvalds 	}
7771da177e4SLinus Torvalds 
7781da177e4SLinus Torvalds 	/*
7791da177e4SLinus Torvalds 	 * Even though there was an error, we may have acquired
7801da177e4SLinus Torvalds 	 * a request slot somehow.  Make sure not to leak it.
7811da177e4SLinus Torvalds 	 */
7821da177e4SLinus Torvalds 	if (task->tk_rqstp) {
7831da177e4SLinus Torvalds 		printk(KERN_ERR "%s: status=%d, request allocated anyway\n",
7841da177e4SLinus Torvalds 				__FUNCTION__, status);
7851da177e4SLinus Torvalds 		xprt_release(task);
7861da177e4SLinus Torvalds 	}
7871da177e4SLinus Torvalds 
7881da177e4SLinus Torvalds 	switch (status) {
7891da177e4SLinus Torvalds 	case -EAGAIN:	/* woken up; retry */
7901da177e4SLinus Torvalds 		task->tk_action = call_reserve;
7911da177e4SLinus Torvalds 		return;
7921da177e4SLinus Torvalds 	case -EIO:	/* probably a shutdown */
7931da177e4SLinus Torvalds 		break;
7941da177e4SLinus Torvalds 	default:
7951da177e4SLinus Torvalds 		printk(KERN_ERR "%s: unrecognized error %d, exiting\n",
7961da177e4SLinus Torvalds 				__FUNCTION__, status);
7971da177e4SLinus Torvalds 		break;
7981da177e4SLinus Torvalds 	}
7991da177e4SLinus Torvalds 	rpc_exit(task, status);
8001da177e4SLinus Torvalds }
8011da177e4SLinus Torvalds 
8021da177e4SLinus Torvalds /*
8031da177e4SLinus Torvalds  * 2.	Allocate the buffer. For details, see sched.c:rpc_malloc.
80402107148SChuck Lever  *	(Note: buffer memory is freed in xprt_release).
8051da177e4SLinus Torvalds  */
8061da177e4SLinus Torvalds static void
8071da177e4SLinus Torvalds call_allocate(struct rpc_task *task)
8081da177e4SLinus Torvalds {
8091be27f36STrond Myklebust 	unsigned int slack = task->tk_msg.rpc_cred->cr_auth->au_cslack;
81002107148SChuck Lever 	struct rpc_rqst *req = task->tk_rqstp;
81102107148SChuck Lever 	struct rpc_xprt *xprt = task->tk_xprt;
8122bea90d4SChuck Lever 	struct rpc_procinfo *proc = task->tk_msg.rpc_proc;
8131da177e4SLinus Torvalds 
81446121cf7SChuck Lever 	dprint_status(task);
81546121cf7SChuck Lever 
8162bea90d4SChuck Lever 	task->tk_status = 0;
8171da177e4SLinus Torvalds 	task->tk_action = call_bind;
8182bea90d4SChuck Lever 
81902107148SChuck Lever 	if (req->rq_buffer)
8201da177e4SLinus Torvalds 		return;
8211da177e4SLinus Torvalds 
8222bea90d4SChuck Lever 	if (proc->p_proc != 0) {
8232bea90d4SChuck Lever 		BUG_ON(proc->p_arglen == 0);
8242bea90d4SChuck Lever 		if (proc->p_decode != NULL)
8252bea90d4SChuck Lever 			BUG_ON(proc->p_replen == 0);
8262bea90d4SChuck Lever 	}
8271da177e4SLinus Torvalds 
8282bea90d4SChuck Lever 	/*
8292bea90d4SChuck Lever 	 * Calculate the size (in quads) of the RPC call
8302bea90d4SChuck Lever 	 * and reply headers, and convert both values
8312bea90d4SChuck Lever 	 * to byte sizes.
8322bea90d4SChuck Lever 	 */
8332bea90d4SChuck Lever 	req->rq_callsize = RPC_CALLHDRSIZE + (slack << 1) + proc->p_arglen;
8342bea90d4SChuck Lever 	req->rq_callsize <<= 2;
8352bea90d4SChuck Lever 	req->rq_rcvsize = RPC_REPHDRSIZE + slack + proc->p_replen;
8362bea90d4SChuck Lever 	req->rq_rcvsize <<= 2;
8372bea90d4SChuck Lever 
838c5a4dd8bSChuck Lever 	req->rq_buffer = xprt->ops->buf_alloc(task,
839c5a4dd8bSChuck Lever 					req->rq_callsize + req->rq_rcvsize);
8402bea90d4SChuck Lever 	if (req->rq_buffer != NULL)
8411da177e4SLinus Torvalds 		return;
84246121cf7SChuck Lever 
84346121cf7SChuck Lever 	dprintk("RPC: %5u rpc_buffer allocation failed\n", task->tk_pid);
8441da177e4SLinus Torvalds 
84514b218a8STrond Myklebust 	if (RPC_IS_ASYNC(task) || !signalled()) {
8461da177e4SLinus Torvalds 		xprt_release(task);
8471da177e4SLinus Torvalds 		task->tk_action = call_reserve;
8481da177e4SLinus Torvalds 		rpc_delay(task, HZ>>4);
8491da177e4SLinus Torvalds 		return;
8501da177e4SLinus Torvalds 	}
8511da177e4SLinus Torvalds 
8521da177e4SLinus Torvalds 	rpc_exit(task, -ERESTARTSYS);
8531da177e4SLinus Torvalds }
8541da177e4SLinus Torvalds 
855940e3318STrond Myklebust static inline int
856940e3318STrond Myklebust rpc_task_need_encode(struct rpc_task *task)
857940e3318STrond Myklebust {
858940e3318STrond Myklebust 	return task->tk_rqstp->rq_snd_buf.len == 0;
859940e3318STrond Myklebust }
860940e3318STrond Myklebust 
861940e3318STrond Myklebust static inline void
862940e3318STrond Myklebust rpc_task_force_reencode(struct rpc_task *task)
863940e3318STrond Myklebust {
864940e3318STrond Myklebust 	task->tk_rqstp->rq_snd_buf.len = 0;
865940e3318STrond Myklebust }
866940e3318STrond Myklebust 
8672bea90d4SChuck Lever static inline void
8682bea90d4SChuck Lever rpc_xdr_buf_init(struct xdr_buf *buf, void *start, size_t len)
8692bea90d4SChuck Lever {
8702bea90d4SChuck Lever 	buf->head[0].iov_base = start;
8712bea90d4SChuck Lever 	buf->head[0].iov_len = len;
8722bea90d4SChuck Lever 	buf->tail[0].iov_len = 0;
8732bea90d4SChuck Lever 	buf->page_len = 0;
8742bea90d4SChuck Lever 	buf->len = 0;
8752bea90d4SChuck Lever 	buf->buflen = len;
8762bea90d4SChuck Lever }
8772bea90d4SChuck Lever 
8781da177e4SLinus Torvalds /*
8791da177e4SLinus Torvalds  * 3.	Encode arguments of an RPC call
8801da177e4SLinus Torvalds  */
8811da177e4SLinus Torvalds static void
8821da177e4SLinus Torvalds call_encode(struct rpc_task *task)
8831da177e4SLinus Torvalds {
8841da177e4SLinus Torvalds 	struct rpc_rqst	*req = task->tk_rqstp;
8851da177e4SLinus Torvalds 	kxdrproc_t	encode;
886d8ed029dSAlexey Dobriyan 	__be32		*p;
8871da177e4SLinus Torvalds 
88846121cf7SChuck Lever 	dprint_status(task);
8891da177e4SLinus Torvalds 
8902bea90d4SChuck Lever 	rpc_xdr_buf_init(&req->rq_snd_buf,
8912bea90d4SChuck Lever 			 req->rq_buffer,
8922bea90d4SChuck Lever 			 req->rq_callsize);
8932bea90d4SChuck Lever 	rpc_xdr_buf_init(&req->rq_rcv_buf,
8942bea90d4SChuck Lever 			 (char *)req->rq_buffer + req->rq_callsize,
8952bea90d4SChuck Lever 			 req->rq_rcvsize);
8961da177e4SLinus Torvalds 
8971da177e4SLinus Torvalds 	/* Encode header and provided arguments */
8981da177e4SLinus Torvalds 	encode = task->tk_msg.rpc_proc->p_encode;
8991da177e4SLinus Torvalds 	if (!(p = call_header(task))) {
9001da177e4SLinus Torvalds 		printk(KERN_INFO "RPC: call_header failed, exit EIO\n");
9011da177e4SLinus Torvalds 		rpc_exit(task, -EIO);
9021da177e4SLinus Torvalds 		return;
9031da177e4SLinus Torvalds 	}
904f3680312SJ. Bruce Fields 	if (encode == NULL)
905f3680312SJ. Bruce Fields 		return;
906f3680312SJ. Bruce Fields 
9076d5fcb5aSTrond Myklebust 	lock_kernel();
9085e5ce5beSTrond Myklebust 	task->tk_status = rpcauth_wrap_req(task, encode, req, p,
9095e5ce5beSTrond Myklebust 			task->tk_msg.rpc_argp);
9106d5fcb5aSTrond Myklebust 	unlock_kernel();
911f3680312SJ. Bruce Fields 	if (task->tk_status == -ENOMEM) {
912f3680312SJ. Bruce Fields 		/* XXX: Is this sane? */
913f3680312SJ. Bruce Fields 		rpc_delay(task, 3*HZ);
914f3680312SJ. Bruce Fields 		task->tk_status = -EAGAIN;
915f3680312SJ. Bruce Fields 	}
9161da177e4SLinus Torvalds }
9171da177e4SLinus Torvalds 
9181da177e4SLinus Torvalds /*
9191da177e4SLinus Torvalds  * 4.	Get the server port number if not yet set
9201da177e4SLinus Torvalds  */
9211da177e4SLinus Torvalds static void
9221da177e4SLinus Torvalds call_bind(struct rpc_task *task)
9231da177e4SLinus Torvalds {
924ec739ef0SChuck Lever 	struct rpc_xprt *xprt = task->tk_xprt;
9251da177e4SLinus Torvalds 
92646121cf7SChuck Lever 	dprint_status(task);
9271da177e4SLinus Torvalds 
9281da177e4SLinus Torvalds 	task->tk_action = call_connect;
929ec739ef0SChuck Lever 	if (!xprt_bound(xprt)) {
930da351878SChuck Lever 		task->tk_action = call_bind_status;
931ec739ef0SChuck Lever 		task->tk_timeout = xprt->bind_timeout;
932bbf7c1ddSChuck Lever 		xprt->ops->rpcbind(task);
9331da177e4SLinus Torvalds 	}
9341da177e4SLinus Torvalds }
9351da177e4SLinus Torvalds 
9361da177e4SLinus Torvalds /*
937da351878SChuck Lever  * 4a.	Sort out bind result
938da351878SChuck Lever  */
939da351878SChuck Lever static void
940da351878SChuck Lever call_bind_status(struct rpc_task *task)
941da351878SChuck Lever {
942da351878SChuck Lever 	int status = -EACCES;
943da351878SChuck Lever 
944da351878SChuck Lever 	if (task->tk_status >= 0) {
94546121cf7SChuck Lever 		dprint_status(task);
946da351878SChuck Lever 		task->tk_status = 0;
947da351878SChuck Lever 		task->tk_action = call_connect;
948da351878SChuck Lever 		return;
949da351878SChuck Lever 	}
950da351878SChuck Lever 
951da351878SChuck Lever 	switch (task->tk_status) {
952da351878SChuck Lever 	case -EACCES:
95346121cf7SChuck Lever 		dprintk("RPC: %5u remote rpcbind: RPC program/version "
95446121cf7SChuck Lever 				"unavailable\n", task->tk_pid);
955ea635a51SChuck Lever 		rpc_delay(task, 3*HZ);
956da45828eSTrond Myklebust 		goto retry_timeout;
957da351878SChuck Lever 	case -ETIMEDOUT:
95846121cf7SChuck Lever 		dprintk("RPC: %5u rpcbind request timed out\n",
959da351878SChuck Lever 				task->tk_pid);
960da45828eSTrond Myklebust 		goto retry_timeout;
961da351878SChuck Lever 	case -EPFNOSUPPORT:
96246121cf7SChuck Lever 		dprintk("RPC: %5u remote rpcbind service unavailable\n",
963da351878SChuck Lever 				task->tk_pid);
964da351878SChuck Lever 		break;
965da351878SChuck Lever 	case -EPROTONOSUPPORT:
96600a6e7bbSChuck Lever 		dprintk("RPC: %5u remote rpcbind version unavailable, retrying\n",
967da351878SChuck Lever 				task->tk_pid);
96800a6e7bbSChuck Lever 		task->tk_status = 0;
96900a6e7bbSChuck Lever 		task->tk_action = call_bind;
97000a6e7bbSChuck Lever 		return;
971da351878SChuck Lever 	default:
97246121cf7SChuck Lever 		dprintk("RPC: %5u unrecognized rpcbind error (%d)\n",
973da351878SChuck Lever 				task->tk_pid, -task->tk_status);
974da351878SChuck Lever 		status = -EIO;
975da351878SChuck Lever 	}
976da351878SChuck Lever 
977da351878SChuck Lever 	rpc_exit(task, status);
978da351878SChuck Lever 	return;
979da351878SChuck Lever 
980da45828eSTrond Myklebust retry_timeout:
981da45828eSTrond Myklebust 	task->tk_action = call_timeout;
982da351878SChuck Lever }
983da351878SChuck Lever 
984da351878SChuck Lever /*
985da351878SChuck Lever  * 4b.	Connect to the RPC server
9861da177e4SLinus Torvalds  */
9871da177e4SLinus Torvalds static void
9881da177e4SLinus Torvalds call_connect(struct rpc_task *task)
9891da177e4SLinus Torvalds {
990da351878SChuck Lever 	struct rpc_xprt *xprt = task->tk_xprt;
9911da177e4SLinus Torvalds 
99246121cf7SChuck Lever 	dprintk("RPC: %5u call_connect xprt %p %s connected\n",
993da351878SChuck Lever 			task->tk_pid, xprt,
994da351878SChuck Lever 			(xprt_connected(xprt) ? "is" : "is not"));
9951da177e4SLinus Torvalds 
9961da177e4SLinus Torvalds 	task->tk_action = call_transmit;
997da351878SChuck Lever 	if (!xprt_connected(xprt)) {
9981da177e4SLinus Torvalds 		task->tk_action = call_connect_status;
9991da177e4SLinus Torvalds 		if (task->tk_status < 0)
10001da177e4SLinus Torvalds 			return;
10011da177e4SLinus Torvalds 		xprt_connect(task);
10021da177e4SLinus Torvalds 	}
1003da351878SChuck Lever }
10041da177e4SLinus Torvalds 
10051da177e4SLinus Torvalds /*
1006da351878SChuck Lever  * 4c.	Sort out connect result
10071da177e4SLinus Torvalds  */
10081da177e4SLinus Torvalds static void
10091da177e4SLinus Torvalds call_connect_status(struct rpc_task *task)
10101da177e4SLinus Torvalds {
10111da177e4SLinus Torvalds 	struct rpc_clnt *clnt = task->tk_client;
10121da177e4SLinus Torvalds 	int status = task->tk_status;
10131da177e4SLinus Torvalds 
101446121cf7SChuck Lever 	dprint_status(task);
1015da351878SChuck Lever 
10161da177e4SLinus Torvalds 	task->tk_status = 0;
10171da177e4SLinus Torvalds 	if (status >= 0) {
10181da177e4SLinus Torvalds 		clnt->cl_stats->netreconn++;
10191da177e4SLinus Torvalds 		task->tk_action = call_transmit;
10201da177e4SLinus Torvalds 		return;
10211da177e4SLinus Torvalds 	}
10221da177e4SLinus Torvalds 
1023da351878SChuck Lever 	/* Something failed: remote service port may have changed */
102435f5a422SChuck Lever 	rpc_force_rebind(clnt);
1025da351878SChuck Lever 
10261da177e4SLinus Torvalds 	switch (status) {
10271da177e4SLinus Torvalds 	case -ENOTCONN:
10281da177e4SLinus Torvalds 	case -EAGAIN:
1029da351878SChuck Lever 		task->tk_action = call_bind;
1030da45828eSTrond Myklebust 		if (!RPC_IS_SOFT(task))
1031da45828eSTrond Myklebust 			return;
1032da45828eSTrond Myklebust 		/* if soft mounted, test if we've timed out */
1033da45828eSTrond Myklebust 	case -ETIMEDOUT:
1034da45828eSTrond Myklebust 		task->tk_action = call_timeout;
1035da45828eSTrond Myklebust 		return;
10361da177e4SLinus Torvalds 	}
1037da45828eSTrond Myklebust 	rpc_exit(task, -EIO);
10381da177e4SLinus Torvalds }
10391da177e4SLinus Torvalds 
10401da177e4SLinus Torvalds /*
10411da177e4SLinus Torvalds  * 5.	Transmit the RPC request, and wait for reply
10421da177e4SLinus Torvalds  */
10431da177e4SLinus Torvalds static void
10441da177e4SLinus Torvalds call_transmit(struct rpc_task *task)
10451da177e4SLinus Torvalds {
104646121cf7SChuck Lever 	dprint_status(task);
10471da177e4SLinus Torvalds 
10481da177e4SLinus Torvalds 	task->tk_action = call_status;
10491da177e4SLinus Torvalds 	if (task->tk_status < 0)
10501da177e4SLinus Torvalds 		return;
10511da177e4SLinus Torvalds 	task->tk_status = xprt_prepare_transmit(task);
10521da177e4SLinus Torvalds 	if (task->tk_status != 0)
10531da177e4SLinus Torvalds 		return;
1054e0ab53deSTrond Myklebust 	task->tk_action = call_transmit_status;
10551da177e4SLinus Torvalds 	/* Encode here so that rpcsec_gss can use correct sequence number. */
1056940e3318STrond Myklebust 	if (rpc_task_need_encode(task)) {
1057e0ab53deSTrond Myklebust 		BUG_ON(task->tk_rqstp->rq_bytes_sent != 0);
10581da177e4SLinus Torvalds 		call_encode(task);
10595e5ce5beSTrond Myklebust 		/* Did the encode result in an error condition? */
10605e5ce5beSTrond Myklebust 		if (task->tk_status != 0)
1061e0ab53deSTrond Myklebust 			return;
10625e5ce5beSTrond Myklebust 	}
10631da177e4SLinus Torvalds 	xprt_transmit(task);
10641da177e4SLinus Torvalds 	if (task->tk_status < 0)
10651da177e4SLinus Torvalds 		return;
1066e0ab53deSTrond Myklebust 	/*
1067e0ab53deSTrond Myklebust 	 * On success, ensure that we call xprt_end_transmit() before sleeping
1068e0ab53deSTrond Myklebust 	 * in order to allow access to the socket to other RPC requests.
1069e0ab53deSTrond Myklebust 	 */
1070e0ab53deSTrond Myklebust 	call_transmit_status(task);
1071e0ab53deSTrond Myklebust 	if (task->tk_msg.rpc_proc->p_decode != NULL)
1072e0ab53deSTrond Myklebust 		return;
1073abbcf28fSTrond Myklebust 	task->tk_action = rpc_exit_task;
10741da177e4SLinus Torvalds 	rpc_wake_up_task(task);
10751da177e4SLinus Torvalds }
1076e0ab53deSTrond Myklebust 
1077e0ab53deSTrond Myklebust /*
1078e0ab53deSTrond Myklebust  * 5a.	Handle cleanup after a transmission
1079e0ab53deSTrond Myklebust  */
1080e0ab53deSTrond Myklebust static void
1081e0ab53deSTrond Myklebust call_transmit_status(struct rpc_task *task)
1082e0ab53deSTrond Myklebust {
1083e0ab53deSTrond Myklebust 	task->tk_action = call_status;
1084e0ab53deSTrond Myklebust 	/*
1085e0ab53deSTrond Myklebust 	 * Special case: if we've been waiting on the socket's write_space()
1086e0ab53deSTrond Myklebust 	 * callback, then don't call xprt_end_transmit().
1087e0ab53deSTrond Myklebust 	 */
1088e0ab53deSTrond Myklebust 	if (task->tk_status == -EAGAIN)
10895e5ce5beSTrond Myklebust 		return;
1090e0ab53deSTrond Myklebust 	xprt_end_transmit(task);
1091940e3318STrond Myklebust 	rpc_task_force_reencode(task);
10921da177e4SLinus Torvalds }
10931da177e4SLinus Torvalds 
10941da177e4SLinus Torvalds /*
10951da177e4SLinus Torvalds  * 6.	Sort out the RPC call status
10961da177e4SLinus Torvalds  */
10971da177e4SLinus Torvalds static void
10981da177e4SLinus Torvalds call_status(struct rpc_task *task)
10991da177e4SLinus Torvalds {
11001da177e4SLinus Torvalds 	struct rpc_clnt	*clnt = task->tk_client;
11011da177e4SLinus Torvalds 	struct rpc_rqst	*req = task->tk_rqstp;
11021da177e4SLinus Torvalds 	int		status;
11031da177e4SLinus Torvalds 
11041da177e4SLinus Torvalds 	if (req->rq_received > 0 && !req->rq_bytes_sent)
11051da177e4SLinus Torvalds 		task->tk_status = req->rq_received;
11061da177e4SLinus Torvalds 
110746121cf7SChuck Lever 	dprint_status(task);
11081da177e4SLinus Torvalds 
11091da177e4SLinus Torvalds 	status = task->tk_status;
11101da177e4SLinus Torvalds 	if (status >= 0) {
11111da177e4SLinus Torvalds 		task->tk_action = call_decode;
11121da177e4SLinus Torvalds 		return;
11131da177e4SLinus Torvalds 	}
11141da177e4SLinus Torvalds 
11151da177e4SLinus Torvalds 	task->tk_status = 0;
11161da177e4SLinus Torvalds 	switch(status) {
111776303992STrond Myklebust 	case -EHOSTDOWN:
111876303992STrond Myklebust 	case -EHOSTUNREACH:
111976303992STrond Myklebust 	case -ENETUNREACH:
112076303992STrond Myklebust 		/*
112176303992STrond Myklebust 		 * Delay any retries for 3 seconds, then handle as if it
112276303992STrond Myklebust 		 * were a timeout.
112376303992STrond Myklebust 		 */
112476303992STrond Myklebust 		rpc_delay(task, 3*HZ);
11251da177e4SLinus Torvalds 	case -ETIMEDOUT:
11261da177e4SLinus Torvalds 		task->tk_action = call_timeout;
1127241c39b9STrond Myklebust 		if (task->tk_client->cl_discrtry)
1128241c39b9STrond Myklebust 			xprt_disconnect(task->tk_xprt);
11291da177e4SLinus Torvalds 		break;
11301da177e4SLinus Torvalds 	case -ECONNREFUSED:
11311da177e4SLinus Torvalds 	case -ENOTCONN:
113235f5a422SChuck Lever 		rpc_force_rebind(clnt);
11331da177e4SLinus Torvalds 		task->tk_action = call_bind;
11341da177e4SLinus Torvalds 		break;
11351da177e4SLinus Torvalds 	case -EAGAIN:
11361da177e4SLinus Torvalds 		task->tk_action = call_transmit;
11371da177e4SLinus Torvalds 		break;
11381da177e4SLinus Torvalds 	case -EIO:
11391da177e4SLinus Torvalds 		/* shutdown or soft timeout */
11401da177e4SLinus Torvalds 		rpc_exit(task, status);
11411da177e4SLinus Torvalds 		break;
11421da177e4SLinus Torvalds 	default:
11431da177e4SLinus Torvalds 		printk("%s: RPC call returned error %d\n",
11441da177e4SLinus Torvalds 			       clnt->cl_protname, -status);
11451da177e4SLinus Torvalds 		rpc_exit(task, status);
11461da177e4SLinus Torvalds 	}
11471da177e4SLinus Torvalds }
11481da177e4SLinus Torvalds 
11491da177e4SLinus Torvalds /*
1150e0ab53deSTrond Myklebust  * 6a.	Handle RPC timeout
11511da177e4SLinus Torvalds  * 	We do not release the request slot, so we keep using the
11521da177e4SLinus Torvalds  *	same XID for all retransmits.
11531da177e4SLinus Torvalds  */
11541da177e4SLinus Torvalds static void
11551da177e4SLinus Torvalds call_timeout(struct rpc_task *task)
11561da177e4SLinus Torvalds {
11571da177e4SLinus Torvalds 	struct rpc_clnt	*clnt = task->tk_client;
11581da177e4SLinus Torvalds 
11591da177e4SLinus Torvalds 	if (xprt_adjust_timeout(task->tk_rqstp) == 0) {
116046121cf7SChuck Lever 		dprintk("RPC: %5u call_timeout (minor)\n", task->tk_pid);
11611da177e4SLinus Torvalds 		goto retry;
11621da177e4SLinus Torvalds 	}
11631da177e4SLinus Torvalds 
116446121cf7SChuck Lever 	dprintk("RPC: %5u call_timeout (major)\n", task->tk_pid);
1165ef759a2eSChuck Lever 	task->tk_timeouts++;
1166ef759a2eSChuck Lever 
11671da177e4SLinus Torvalds 	if (RPC_IS_SOFT(task)) {
11681da177e4SLinus Torvalds 		printk(KERN_NOTICE "%s: server %s not responding, timed out\n",
11691da177e4SLinus Torvalds 				clnt->cl_protname, clnt->cl_server);
11701da177e4SLinus Torvalds 		rpc_exit(task, -EIO);
11711da177e4SLinus Torvalds 		return;
11721da177e4SLinus Torvalds 	}
11731da177e4SLinus Torvalds 
1174f518e35aSChuck Lever 	if (!(task->tk_flags & RPC_CALL_MAJORSEEN)) {
11751da177e4SLinus Torvalds 		task->tk_flags |= RPC_CALL_MAJORSEEN;
11761da177e4SLinus Torvalds 		printk(KERN_NOTICE "%s: server %s not responding, still trying\n",
11771da177e4SLinus Torvalds 			clnt->cl_protname, clnt->cl_server);
11781da177e4SLinus Torvalds 	}
117935f5a422SChuck Lever 	rpc_force_rebind(clnt);
11801da177e4SLinus Torvalds 
11811da177e4SLinus Torvalds retry:
11821da177e4SLinus Torvalds 	clnt->cl_stats->rpcretrans++;
11831da177e4SLinus Torvalds 	task->tk_action = call_bind;
11841da177e4SLinus Torvalds 	task->tk_status = 0;
11851da177e4SLinus Torvalds }
11861da177e4SLinus Torvalds 
11871da177e4SLinus Torvalds /*
11881da177e4SLinus Torvalds  * 7.	Decode the RPC reply
11891da177e4SLinus Torvalds  */
11901da177e4SLinus Torvalds static void
11911da177e4SLinus Torvalds call_decode(struct rpc_task *task)
11921da177e4SLinus Torvalds {
11931da177e4SLinus Torvalds 	struct rpc_clnt	*clnt = task->tk_client;
11941da177e4SLinus Torvalds 	struct rpc_rqst	*req = task->tk_rqstp;
11951da177e4SLinus Torvalds 	kxdrproc_t	decode = task->tk_msg.rpc_proc->p_decode;
1196d8ed029dSAlexey Dobriyan 	__be32		*p;
11971da177e4SLinus Torvalds 
119846121cf7SChuck Lever 	dprintk("RPC: %5u call_decode (status %d)\n",
11991da177e4SLinus Torvalds 			task->tk_pid, task->tk_status);
12001da177e4SLinus Torvalds 
1201f518e35aSChuck Lever 	if (task->tk_flags & RPC_CALL_MAJORSEEN) {
12021da177e4SLinus Torvalds 		printk(KERN_NOTICE "%s: server %s OK\n",
12031da177e4SLinus Torvalds 			clnt->cl_protname, clnt->cl_server);
12041da177e4SLinus Torvalds 		task->tk_flags &= ~RPC_CALL_MAJORSEEN;
12051da177e4SLinus Torvalds 	}
12061da177e4SLinus Torvalds 
12071da177e4SLinus Torvalds 	if (task->tk_status < 12) {
12081da177e4SLinus Torvalds 		if (!RPC_IS_SOFT(task)) {
12091da177e4SLinus Torvalds 			task->tk_action = call_bind;
12101da177e4SLinus Torvalds 			clnt->cl_stats->rpcretrans++;
12111da177e4SLinus Torvalds 			goto out_retry;
12121da177e4SLinus Torvalds 		}
121346121cf7SChuck Lever 		dprintk("RPC:       %s: too small RPC reply size (%d bytes)\n",
12141da177e4SLinus Torvalds 				clnt->cl_protname, task->tk_status);
1215da45828eSTrond Myklebust 		task->tk_action = call_timeout;
1216da45828eSTrond Myklebust 		goto out_retry;
12171da177e4SLinus Torvalds 	}
12181da177e4SLinus Torvalds 
121943ac3f29STrond Myklebust 	/*
122043ac3f29STrond Myklebust 	 * Ensure that we see all writes made by xprt_complete_rqst()
122143ac3f29STrond Myklebust 	 * before it changed req->rq_received.
122243ac3f29STrond Myklebust 	 */
122343ac3f29STrond Myklebust 	smp_rmb();
12241da177e4SLinus Torvalds 	req->rq_rcv_buf.len = req->rq_private_buf.len;
12251da177e4SLinus Torvalds 
12261da177e4SLinus Torvalds 	/* Check that the softirq receive buffer is valid */
12271da177e4SLinus Torvalds 	WARN_ON(memcmp(&req->rq_rcv_buf, &req->rq_private_buf,
12281da177e4SLinus Torvalds 				sizeof(req->rq_rcv_buf)) != 0);
12291da177e4SLinus Torvalds 
12301da177e4SLinus Torvalds 	/* Verify the RPC header */
1231abbcf28fSTrond Myklebust 	p = call_verify(task);
1232abbcf28fSTrond Myklebust 	if (IS_ERR(p)) {
1233abbcf28fSTrond Myklebust 		if (p == ERR_PTR(-EAGAIN))
12341da177e4SLinus Torvalds 			goto out_retry;
1235abbcf28fSTrond Myklebust 		return;
12361da177e4SLinus Torvalds 	}
12371da177e4SLinus Torvalds 
1238abbcf28fSTrond Myklebust 	task->tk_action = rpc_exit_task;
12391da177e4SLinus Torvalds 
12406d5fcb5aSTrond Myklebust 	if (decode) {
12416d5fcb5aSTrond Myklebust 		lock_kernel();
12421da177e4SLinus Torvalds 		task->tk_status = rpcauth_unwrap_resp(task, decode, req, p,
12431da177e4SLinus Torvalds 						      task->tk_msg.rpc_resp);
12446d5fcb5aSTrond Myklebust 		unlock_kernel();
12456d5fcb5aSTrond Myklebust 	}
124646121cf7SChuck Lever 	dprintk("RPC: %5u call_decode result %d\n", task->tk_pid,
12471da177e4SLinus Torvalds 			task->tk_status);
12481da177e4SLinus Torvalds 	return;
12491da177e4SLinus Torvalds out_retry:
12501da177e4SLinus Torvalds 	req->rq_received = req->rq_private_buf.len = 0;
12511da177e4SLinus Torvalds 	task->tk_status = 0;
1252241c39b9STrond Myklebust 	if (task->tk_client->cl_discrtry)
1253241c39b9STrond Myklebust 		xprt_disconnect(task->tk_xprt);
12541da177e4SLinus Torvalds }
12551da177e4SLinus Torvalds 
12561da177e4SLinus Torvalds /*
12571da177e4SLinus Torvalds  * 8.	Refresh the credentials if rejected by the server
12581da177e4SLinus Torvalds  */
12591da177e4SLinus Torvalds static void
12601da177e4SLinus Torvalds call_refresh(struct rpc_task *task)
12611da177e4SLinus Torvalds {
126246121cf7SChuck Lever 	dprint_status(task);
12631da177e4SLinus Torvalds 
12641da177e4SLinus Torvalds 	xprt_release(task);	/* Must do to obtain new XID */
12651da177e4SLinus Torvalds 	task->tk_action = call_refreshresult;
12661da177e4SLinus Torvalds 	task->tk_status = 0;
12671da177e4SLinus Torvalds 	task->tk_client->cl_stats->rpcauthrefresh++;
12681da177e4SLinus Torvalds 	rpcauth_refreshcred(task);
12691da177e4SLinus Torvalds }
12701da177e4SLinus Torvalds 
12711da177e4SLinus Torvalds /*
12721da177e4SLinus Torvalds  * 8a.	Process the results of a credential refresh
12731da177e4SLinus Torvalds  */
12741da177e4SLinus Torvalds static void
12751da177e4SLinus Torvalds call_refreshresult(struct rpc_task *task)
12761da177e4SLinus Torvalds {
12771da177e4SLinus Torvalds 	int status = task->tk_status;
127846121cf7SChuck Lever 
127946121cf7SChuck Lever 	dprint_status(task);
12801da177e4SLinus Torvalds 
12811da177e4SLinus Torvalds 	task->tk_status = 0;
12821da177e4SLinus Torvalds 	task->tk_action = call_reserve;
12831da177e4SLinus Torvalds 	if (status >= 0 && rpcauth_uptodatecred(task))
12841da177e4SLinus Torvalds 		return;
12851da177e4SLinus Torvalds 	if (status == -EACCES) {
12861da177e4SLinus Torvalds 		rpc_exit(task, -EACCES);
12871da177e4SLinus Torvalds 		return;
12881da177e4SLinus Torvalds 	}
12891da177e4SLinus Torvalds 	task->tk_action = call_refresh;
12901da177e4SLinus Torvalds 	if (status != -ETIMEDOUT)
12911da177e4SLinus Torvalds 		rpc_delay(task, 3*HZ);
12921da177e4SLinus Torvalds 	return;
12931da177e4SLinus Torvalds }
12941da177e4SLinus Torvalds 
12951da177e4SLinus Torvalds /*
12961da177e4SLinus Torvalds  * Call header serialization
12971da177e4SLinus Torvalds  */
1298d8ed029dSAlexey Dobriyan static __be32 *
12991da177e4SLinus Torvalds call_header(struct rpc_task *task)
13001da177e4SLinus Torvalds {
13011da177e4SLinus Torvalds 	struct rpc_clnt *clnt = task->tk_client;
13021da177e4SLinus Torvalds 	struct rpc_rqst	*req = task->tk_rqstp;
1303d8ed029dSAlexey Dobriyan 	__be32		*p = req->rq_svec[0].iov_base;
13041da177e4SLinus Torvalds 
13051da177e4SLinus Torvalds 	/* FIXME: check buffer size? */
1306808012fbSChuck Lever 
1307808012fbSChuck Lever 	p = xprt_skip_transport_header(task->tk_xprt, p);
13081da177e4SLinus Torvalds 	*p++ = req->rq_xid;		/* XID */
13091da177e4SLinus Torvalds 	*p++ = htonl(RPC_CALL);		/* CALL */
13101da177e4SLinus Torvalds 	*p++ = htonl(RPC_VERSION);	/* RPC version */
13111da177e4SLinus Torvalds 	*p++ = htonl(clnt->cl_prog);	/* program number */
13121da177e4SLinus Torvalds 	*p++ = htonl(clnt->cl_vers);	/* program version */
13131da177e4SLinus Torvalds 	*p++ = htonl(task->tk_msg.rpc_proc->p_proc);	/* procedure */
1314334ccfd5STrond Myklebust 	p = rpcauth_marshcred(task, p);
1315334ccfd5STrond Myklebust 	req->rq_slen = xdr_adjust_iovec(&req->rq_svec[0], p);
1316334ccfd5STrond Myklebust 	return p;
13171da177e4SLinus Torvalds }
13181da177e4SLinus Torvalds 
13191da177e4SLinus Torvalds /*
13201da177e4SLinus Torvalds  * Reply header verification
13211da177e4SLinus Torvalds  */
1322d8ed029dSAlexey Dobriyan static __be32 *
13231da177e4SLinus Torvalds call_verify(struct rpc_task *task)
13241da177e4SLinus Torvalds {
13251da177e4SLinus Torvalds 	struct kvec *iov = &task->tk_rqstp->rq_rcv_buf.head[0];
13261da177e4SLinus Torvalds 	int len = task->tk_rqstp->rq_rcv_buf.len >> 2;
1327d8ed029dSAlexey Dobriyan 	__be32	*p = iov->iov_base;
1328d8ed029dSAlexey Dobriyan 	u32 n;
13291da177e4SLinus Torvalds 	int error = -EACCES;
13301da177e4SLinus Torvalds 
1331e8896495SDavid Howells 	if ((task->tk_rqstp->rq_rcv_buf.len & 3) != 0) {
1332e8896495SDavid Howells 		/* RFC-1014 says that the representation of XDR data must be a
1333e8896495SDavid Howells 		 * multiple of four bytes
1334e8896495SDavid Howells 		 * - if it isn't pointer subtraction in the NFS client may give
1335e8896495SDavid Howells 		 *   undefined results
1336e8896495SDavid Howells 		 */
13378a702bbbSTrond Myklebust 		dprintk("RPC: %5u %s: XDR representation not a multiple of"
13388a702bbbSTrond Myklebust 		       " 4 bytes: 0x%x\n", task->tk_pid, __FUNCTION__,
13398a702bbbSTrond Myklebust 		       task->tk_rqstp->rq_rcv_buf.len);
1340e8896495SDavid Howells 		goto out_eio;
1341e8896495SDavid Howells 	}
13421da177e4SLinus Torvalds 	if ((len -= 3) < 0)
13431da177e4SLinus Torvalds 		goto out_overflow;
13441da177e4SLinus Torvalds 	p += 1;	/* skip XID */
13451da177e4SLinus Torvalds 
13461da177e4SLinus Torvalds 	if ((n = ntohl(*p++)) != RPC_REPLY) {
13478a702bbbSTrond Myklebust 		dprintk("RPC: %5u %s: not an RPC reply: %x\n",
13488a702bbbSTrond Myklebust 				task->tk_pid, __FUNCTION__, n);
1349abbcf28fSTrond Myklebust 		goto out_garbage;
13501da177e4SLinus Torvalds 	}
13511da177e4SLinus Torvalds 	if ((n = ntohl(*p++)) != RPC_MSG_ACCEPTED) {
13521da177e4SLinus Torvalds 		if (--len < 0)
13531da177e4SLinus Torvalds 			goto out_overflow;
13541da177e4SLinus Torvalds 		switch ((n = ntohl(*p++))) {
13551da177e4SLinus Torvalds 			case RPC_AUTH_ERROR:
13561da177e4SLinus Torvalds 				break;
13571da177e4SLinus Torvalds 			case RPC_MISMATCH:
135846121cf7SChuck Lever 				dprintk("RPC: %5u %s: RPC call version "
135946121cf7SChuck Lever 						"mismatch!\n",
136046121cf7SChuck Lever 						task->tk_pid, __FUNCTION__);
1361cdf47706SAndreas Gruenbacher 				error = -EPROTONOSUPPORT;
1362cdf47706SAndreas Gruenbacher 				goto out_err;
13631da177e4SLinus Torvalds 			default:
136446121cf7SChuck Lever 				dprintk("RPC: %5u %s: RPC call rejected, "
136546121cf7SChuck Lever 						"unknown error: %x\n",
136646121cf7SChuck Lever 						task->tk_pid, __FUNCTION__, n);
13671da177e4SLinus Torvalds 				goto out_eio;
13681da177e4SLinus Torvalds 		}
13691da177e4SLinus Torvalds 		if (--len < 0)
13701da177e4SLinus Torvalds 			goto out_overflow;
13711da177e4SLinus Torvalds 		switch ((n = ntohl(*p++))) {
13721da177e4SLinus Torvalds 		case RPC_AUTH_REJECTEDCRED:
13731da177e4SLinus Torvalds 		case RPC_AUTH_REJECTEDVERF:
13741da177e4SLinus Torvalds 		case RPCSEC_GSS_CREDPROBLEM:
13751da177e4SLinus Torvalds 		case RPCSEC_GSS_CTXPROBLEM:
13761da177e4SLinus Torvalds 			if (!task->tk_cred_retry)
13771da177e4SLinus Torvalds 				break;
13781da177e4SLinus Torvalds 			task->tk_cred_retry--;
137946121cf7SChuck Lever 			dprintk("RPC: %5u %s: retry stale creds\n",
138046121cf7SChuck Lever 					task->tk_pid, __FUNCTION__);
13811da177e4SLinus Torvalds 			rpcauth_invalcred(task);
13821da177e4SLinus Torvalds 			task->tk_action = call_refresh;
1383abbcf28fSTrond Myklebust 			goto out_retry;
13841da177e4SLinus Torvalds 		case RPC_AUTH_BADCRED:
13851da177e4SLinus Torvalds 		case RPC_AUTH_BADVERF:
13861da177e4SLinus Torvalds 			/* possibly garbled cred/verf? */
13871da177e4SLinus Torvalds 			if (!task->tk_garb_retry)
13881da177e4SLinus Torvalds 				break;
13891da177e4SLinus Torvalds 			task->tk_garb_retry--;
139046121cf7SChuck Lever 			dprintk("RPC: %5u %s: retry garbled creds\n",
139146121cf7SChuck Lever 					task->tk_pid, __FUNCTION__);
13921da177e4SLinus Torvalds 			task->tk_action = call_bind;
1393abbcf28fSTrond Myklebust 			goto out_retry;
13941da177e4SLinus Torvalds 		case RPC_AUTH_TOOWEAK:
13951356b8c2SLevent Serinol 			printk(KERN_NOTICE "call_verify: server %s requires stronger "
13961356b8c2SLevent Serinol 			       "authentication.\n", task->tk_client->cl_server);
13971da177e4SLinus Torvalds 			break;
13981da177e4SLinus Torvalds 		default:
13998a702bbbSTrond Myklebust 			dprintk("RPC: %5u %s: unknown auth error: %x\n",
14008a702bbbSTrond Myklebust 					task->tk_pid, __FUNCTION__, n);
14011da177e4SLinus Torvalds 			error = -EIO;
14021da177e4SLinus Torvalds 		}
140346121cf7SChuck Lever 		dprintk("RPC: %5u %s: call rejected %d\n",
140446121cf7SChuck Lever 				task->tk_pid, __FUNCTION__, n);
14051da177e4SLinus Torvalds 		goto out_err;
14061da177e4SLinus Torvalds 	}
14071da177e4SLinus Torvalds 	if (!(p = rpcauth_checkverf(task, p))) {
14088a702bbbSTrond Myklebust 		dprintk("RPC: %5u %s: auth check failed\n",
14098a702bbbSTrond Myklebust 				task->tk_pid, __FUNCTION__);
1410abbcf28fSTrond Myklebust 		goto out_garbage;		/* bad verifier, retry */
14111da177e4SLinus Torvalds 	}
1412d8ed029dSAlexey Dobriyan 	len = p - (__be32 *)iov->iov_base - 1;
14131da177e4SLinus Torvalds 	if (len < 0)
14141da177e4SLinus Torvalds 		goto out_overflow;
14151da177e4SLinus Torvalds 	switch ((n = ntohl(*p++))) {
14161da177e4SLinus Torvalds 	case RPC_SUCCESS:
14171da177e4SLinus Torvalds 		return p;
14181da177e4SLinus Torvalds 	case RPC_PROG_UNAVAIL:
141946121cf7SChuck Lever 		dprintk("RPC: %5u %s: program %u is unsupported by server %s\n",
142046121cf7SChuck Lever 				task->tk_pid, __FUNCTION__,
14211da177e4SLinus Torvalds 				(unsigned int)task->tk_client->cl_prog,
14221da177e4SLinus Torvalds 				task->tk_client->cl_server);
1423cdf47706SAndreas Gruenbacher 		error = -EPFNOSUPPORT;
1424cdf47706SAndreas Gruenbacher 		goto out_err;
14251da177e4SLinus Torvalds 	case RPC_PROG_MISMATCH:
142646121cf7SChuck Lever 		dprintk("RPC: %5u %s: program %u, version %u unsupported by "
142746121cf7SChuck Lever 				"server %s\n", task->tk_pid, __FUNCTION__,
14281da177e4SLinus Torvalds 				(unsigned int)task->tk_client->cl_prog,
14291da177e4SLinus Torvalds 				(unsigned int)task->tk_client->cl_vers,
14301da177e4SLinus Torvalds 				task->tk_client->cl_server);
1431cdf47706SAndreas Gruenbacher 		error = -EPROTONOSUPPORT;
1432cdf47706SAndreas Gruenbacher 		goto out_err;
14331da177e4SLinus Torvalds 	case RPC_PROC_UNAVAIL:
143446121cf7SChuck Lever 		dprintk("RPC: %5u %s: proc %p unsupported by program %u, "
143546121cf7SChuck Lever 				"version %u on server %s\n",
143646121cf7SChuck Lever 				task->tk_pid, __FUNCTION__,
14371da177e4SLinus Torvalds 				task->tk_msg.rpc_proc,
14381da177e4SLinus Torvalds 				task->tk_client->cl_prog,
14391da177e4SLinus Torvalds 				task->tk_client->cl_vers,
14401da177e4SLinus Torvalds 				task->tk_client->cl_server);
1441cdf47706SAndreas Gruenbacher 		error = -EOPNOTSUPP;
1442cdf47706SAndreas Gruenbacher 		goto out_err;
14431da177e4SLinus Torvalds 	case RPC_GARBAGE_ARGS:
144446121cf7SChuck Lever 		dprintk("RPC: %5u %s: server saw garbage\n",
144546121cf7SChuck Lever 				task->tk_pid, __FUNCTION__);
14461da177e4SLinus Torvalds 		break;			/* retry */
14471da177e4SLinus Torvalds 	default:
14488a702bbbSTrond Myklebust 		dprintk("RPC: %5u %s: server accept status: %x\n",
14498a702bbbSTrond Myklebust 				task->tk_pid, __FUNCTION__, n);
14501da177e4SLinus Torvalds 		/* Also retry */
14511da177e4SLinus Torvalds 	}
14521da177e4SLinus Torvalds 
1453abbcf28fSTrond Myklebust out_garbage:
14541da177e4SLinus Torvalds 	task->tk_client->cl_stats->rpcgarbage++;
14551da177e4SLinus Torvalds 	if (task->tk_garb_retry) {
14561da177e4SLinus Torvalds 		task->tk_garb_retry--;
145746121cf7SChuck Lever 		dprintk("RPC: %5u %s: retrying\n",
145846121cf7SChuck Lever 				task->tk_pid, __FUNCTION__);
14591da177e4SLinus Torvalds 		task->tk_action = call_bind;
1460abbcf28fSTrond Myklebust out_retry:
1461abbcf28fSTrond Myklebust 		return ERR_PTR(-EAGAIN);
14621da177e4SLinus Torvalds 	}
14631da177e4SLinus Torvalds out_eio:
14641da177e4SLinus Torvalds 	error = -EIO;
14651da177e4SLinus Torvalds out_err:
14661da177e4SLinus Torvalds 	rpc_exit(task, error);
14678a702bbbSTrond Myklebust 	dprintk("RPC: %5u %s: call failed with error %d\n", task->tk_pid,
14688a702bbbSTrond Myklebust 			__FUNCTION__, error);
1469abbcf28fSTrond Myklebust 	return ERR_PTR(error);
14701da177e4SLinus Torvalds out_overflow:
14718a702bbbSTrond Myklebust 	dprintk("RPC: %5u %s: server reply was truncated.\n", task->tk_pid,
14728a702bbbSTrond Myklebust 			__FUNCTION__);
1473abbcf28fSTrond Myklebust 	goto out_garbage;
14741da177e4SLinus Torvalds }
14755ee0ed7dSTrond Myklebust 
1476d8ed029dSAlexey Dobriyan static int rpcproc_encode_null(void *rqstp, __be32 *data, void *obj)
14775ee0ed7dSTrond Myklebust {
14785ee0ed7dSTrond Myklebust 	return 0;
14795ee0ed7dSTrond Myklebust }
14805ee0ed7dSTrond Myklebust 
1481d8ed029dSAlexey Dobriyan static int rpcproc_decode_null(void *rqstp, __be32 *data, void *obj)
14825ee0ed7dSTrond Myklebust {
14835ee0ed7dSTrond Myklebust 	return 0;
14845ee0ed7dSTrond Myklebust }
14855ee0ed7dSTrond Myklebust 
14865ee0ed7dSTrond Myklebust static struct rpc_procinfo rpcproc_null = {
14875ee0ed7dSTrond Myklebust 	.p_encode = rpcproc_encode_null,
14885ee0ed7dSTrond Myklebust 	.p_decode = rpcproc_decode_null,
14895ee0ed7dSTrond Myklebust };
14905ee0ed7dSTrond Myklebust 
149164c91a1fSTrond Myklebust static int rpc_ping(struct rpc_clnt *clnt, int flags)
14925ee0ed7dSTrond Myklebust {
14935ee0ed7dSTrond Myklebust 	struct rpc_message msg = {
14945ee0ed7dSTrond Myklebust 		.rpc_proc = &rpcproc_null,
14955ee0ed7dSTrond Myklebust 	};
14965ee0ed7dSTrond Myklebust 	int err;
14975ee0ed7dSTrond Myklebust 	msg.rpc_cred = authnull_ops.lookup_cred(NULL, NULL, 0);
14985ee0ed7dSTrond Myklebust 	err = rpc_call_sync(clnt, &msg, flags);
14995ee0ed7dSTrond Myklebust 	put_rpccred(msg.rpc_cred);
15005ee0ed7dSTrond Myklebust 	return err;
15015ee0ed7dSTrond Myklebust }
1502188fef11STrond Myklebust 
15035e1550d6STrond Myklebust struct rpc_task *rpc_call_null(struct rpc_clnt *clnt, struct rpc_cred *cred, int flags)
15045e1550d6STrond Myklebust {
15055e1550d6STrond Myklebust 	struct rpc_message msg = {
15065e1550d6STrond Myklebust 		.rpc_proc = &rpcproc_null,
15075e1550d6STrond Myklebust 		.rpc_cred = cred,
15085e1550d6STrond Myklebust 	};
15095e1550d6STrond Myklebust 	return rpc_do_run_task(clnt, &msg, flags, &rpc_default_ops, NULL);
15105e1550d6STrond Myklebust }
15115e1550d6STrond Myklebust EXPORT_SYMBOL(rpc_call_null);
15125e1550d6STrond Myklebust 
1513188fef11STrond Myklebust #ifdef RPC_DEBUG
1514188fef11STrond Myklebust void rpc_show_tasks(void)
1515188fef11STrond Myklebust {
1516188fef11STrond Myklebust 	struct rpc_clnt *clnt;
1517188fef11STrond Myklebust 	struct rpc_task *t;
1518188fef11STrond Myklebust 
1519188fef11STrond Myklebust 	spin_lock(&rpc_client_lock);
1520188fef11STrond Myklebust 	if (list_empty(&all_clients))
1521188fef11STrond Myklebust 		goto out;
1522188fef11STrond Myklebust 	printk("-pid- proc flgs status -client- -prog- --rqstp- -timeout "
1523188fef11STrond Myklebust 		"-rpcwait -action- ---ops--\n");
1524188fef11STrond Myklebust 	list_for_each_entry(clnt, &all_clients, cl_clients) {
1525188fef11STrond Myklebust 		if (list_empty(&clnt->cl_tasks))
1526188fef11STrond Myklebust 			continue;
1527188fef11STrond Myklebust 		spin_lock(&clnt->cl_lock);
1528188fef11STrond Myklebust 		list_for_each_entry(t, &clnt->cl_tasks, tk_task) {
1529188fef11STrond Myklebust 			const char *rpc_waitq = "none";
1530188fef11STrond Myklebust 
1531188fef11STrond Myklebust 			if (RPC_IS_QUEUED(t))
1532188fef11STrond Myklebust 				rpc_waitq = rpc_qname(t->u.tk_wait.rpc_waitq);
1533188fef11STrond Myklebust 
1534188fef11STrond Myklebust 			printk("%5u %04d %04x %6d %8p %6d %8p %8ld %8s %8p %8p\n",
1535188fef11STrond Myklebust 				t->tk_pid,
1536188fef11STrond Myklebust 				(t->tk_msg.rpc_proc ? t->tk_msg.rpc_proc->p_proc : -1),
1537188fef11STrond Myklebust 				t->tk_flags, t->tk_status,
1538188fef11STrond Myklebust 				t->tk_client,
1539188fef11STrond Myklebust 				(t->tk_client ? t->tk_client->cl_prog : 0),
1540188fef11STrond Myklebust 				t->tk_rqstp, t->tk_timeout,
1541188fef11STrond Myklebust 				rpc_waitq,
1542188fef11STrond Myklebust 				t->tk_action, t->tk_ops);
1543188fef11STrond Myklebust 		}
1544188fef11STrond Myklebust 		spin_unlock(&clnt->cl_lock);
1545188fef11STrond Myklebust 	}
1546188fef11STrond Myklebust out:
1547188fef11STrond Myklebust 	spin_unlock(&rpc_client_lock);
1548188fef11STrond Myklebust }
1549188fef11STrond Myklebust #endif
1550