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