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