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