2005-04-17 02:20:36 +04:00
/*
2005-08-12 00:25:47 +04:00
* linux / net / sunrpc / clnt . c
2005-04-17 02:20:36 +04:00
*
* This file contains the high - level RPC interface .
* It is modeled as a finite state machine to support both synchronous
* and asynchronous requests .
*
* - RPC header generation and argument serialization .
* - Credential refresh .
* - TCP connect handling .
* - Retry of operation when it is suspected the operation failed because
* of uid squashing on the server , or when the credentials were stale
* and need to be refreshed , or when a packet was damaged in transit .
* This may be have to be moved to the VFS layer .
*
* NB : BSD uses a more intelligent approach to guessing when a request
* or reply has been lost by keeping the RTO estimate for each procedure .
* We currently make do with a constant timeout value .
*
* Copyright ( C ) 1992 , 1993 Rick Sladkey < jrs @ world . std . com >
* Copyright ( C ) 1995 , 1996 Olaf Kirch < okir @ monad . swb . de >
*/
# include <asm/system.h>
# include <linux/module.h>
# include <linux/types.h>
# include <linux/mm.h>
# include <linux/slab.h>
2006-10-19 00:01:06 +04:00
# include <linux/smp_lock.h>
2005-04-17 02:20:36 +04:00
# include <linux/utsname.h>
2006-03-20 21:44:22 +03:00
# include <linux/workqueue.h>
2007-12-10 22:56:24 +03:00
# include <linux/in6.h>
2005-04-17 02:20:36 +04:00
# include <linux/sunrpc/clnt.h>
# include <linux/sunrpc/rpc_pipe_fs.h>
2006-03-20 21:44:22 +03:00
# include <linux/sunrpc/metrics.h>
2005-04-17 02:20:36 +04:00
# ifdef RPC_DEBUG
# define RPCDBG_FACILITY RPCDBG_CALL
# endif
2007-01-31 20:14:08 +03:00
# define dprint_status(t) \
dprintk ( " RPC: %5u %s (status %d) \n " , t - > tk_pid , \
__FUNCTION__ , t - > tk_status )
2007-06-16 22:18:40 +04:00
/*
* All RPC clients are linked into this list
*/
static LIST_HEAD ( all_clients ) ;
static DEFINE_SPINLOCK ( rpc_client_lock ) ;
2005-04-17 02:20:36 +04:00
static DECLARE_WAIT_QUEUE_HEAD ( destroy_wait ) ;
static void call_start ( struct rpc_task * task ) ;
static void call_reserve ( struct rpc_task * task ) ;
static void call_reserveresult ( struct rpc_task * task ) ;
static void call_allocate ( struct rpc_task * task ) ;
static void call_encode ( struct rpc_task * task ) ;
static void call_decode ( struct rpc_task * task ) ;
static void call_bind ( struct rpc_task * task ) ;
2005-08-12 00:25:11 +04:00
static void call_bind_status ( struct rpc_task * task ) ;
2005-04-17 02:20:36 +04:00
static void call_transmit ( struct rpc_task * task ) ;
static void call_status ( struct rpc_task * task ) ;
2005-11-10 05:45:24 +03:00
static void call_transmit_status ( struct rpc_task * task ) ;
2005-04-17 02:20:36 +04:00
static void call_refresh ( struct rpc_task * task ) ;
static void call_refreshresult ( struct rpc_task * task ) ;
static void call_timeout ( struct rpc_task * task ) ;
static void call_connect ( struct rpc_task * task ) ;
static void call_connect_status ( struct rpc_task * task ) ;
2006-09-27 09:29:38 +04:00
static __be32 * call_header ( struct rpc_task * task ) ;
static __be32 * call_verify ( struct rpc_task * task ) ;
2005-04-17 02:20:36 +04:00
2007-06-23 18:17:16 +04:00
static int rpc_ping ( struct rpc_clnt * clnt , int flags ) ;
2007-06-16 22:18:40 +04:00
static void rpc_register_client ( struct rpc_clnt * clnt )
{
spin_lock ( & rpc_client_lock ) ;
list_add ( & clnt - > cl_clients , & all_clients ) ;
spin_unlock ( & rpc_client_lock ) ;
}
static void rpc_unregister_client ( struct rpc_clnt * clnt )
{
spin_lock ( & rpc_client_lock ) ;
list_del ( & clnt - > cl_clients ) ;
spin_unlock ( & rpc_client_lock ) ;
}
2005-04-17 02:20:36 +04:00
static int
rpc_setup_pipedir ( struct rpc_clnt * clnt , char * dir_name )
{
2005-09-23 19:08:25 +04:00
static uint32_t clntid ;
2005-04-17 02:20:36 +04:00
int error ;
2006-03-20 21:44:49 +03:00
clnt - > cl_vfsmnt = ERR_PTR ( - ENOENT ) ;
clnt - > cl_dentry = ERR_PTR ( - ENOENT ) ;
2005-04-17 02:20:36 +04:00
if ( dir_name = = NULL )
return 0 ;
2006-03-20 21:44:49 +03:00
clnt - > cl_vfsmnt = rpc_get_mount ( ) ;
if ( IS_ERR ( clnt - > cl_vfsmnt ) )
return PTR_ERR ( clnt - > cl_vfsmnt ) ;
2005-09-23 19:08:25 +04:00
for ( ; ; ) {
snprintf ( clnt - > cl_pathname , sizeof ( clnt - > cl_pathname ) ,
" %s/clnt%x " , dir_name ,
( unsigned int ) clntid + + ) ;
clnt - > cl_pathname [ sizeof ( clnt - > cl_pathname ) - 1 ] = ' \0 ' ;
clnt - > cl_dentry = rpc_mkdir ( clnt - > cl_pathname , clnt ) ;
if ( ! IS_ERR ( clnt - > cl_dentry ) )
return 0 ;
2005-04-17 02:20:36 +04:00
error = PTR_ERR ( clnt - > cl_dentry ) ;
2005-09-23 19:08:25 +04:00
if ( error ! = - EEXIST ) {
printk ( KERN_INFO " RPC: Couldn't create pipefs entry %s, error %d \n " ,
clnt - > cl_pathname , error ) ;
2006-03-20 21:44:49 +03:00
rpc_put_mount ( ) ;
2005-09-23 19:08:25 +04:00
return error ;
}
2005-04-17 02:20:36 +04:00
}
}
2007-12-21 00:03:53 +03:00
static struct rpc_clnt * rpc_new_client ( const struct rpc_create_args * args , struct rpc_xprt * xprt )
2005-04-17 02:20:36 +04:00
{
2007-12-21 00:03:53 +03:00
struct rpc_program * program = args - > program ;
2005-04-17 02:20:36 +04:00
struct rpc_version * version ;
struct rpc_clnt * clnt = NULL ;
2005-06-22 21:16:23 +04:00
struct rpc_auth * auth ;
2005-04-17 02:20:36 +04:00
int err ;
2007-09-12 02:00:20 +04:00
size_t len ;
/* sanity check the name before trying to print it */
err = - EINVAL ;
2007-12-21 00:03:53 +03:00
len = strlen ( args - > servername ) ;
2007-09-12 02:00:20 +04:00
if ( len > RPC_MAXNETNAMELEN )
goto out_no_rpciod ;
len + + ;
2005-04-17 02:20:36 +04:00
2007-01-31 20:14:08 +03:00
dprintk ( " RPC: creating %s client for %s (xprt %p) \n " ,
2007-12-21 00:03:53 +03:00
program - > name , args - > servername , xprt ) ;
2005-04-17 02:20:36 +04:00
2007-06-15 01:26:17 +04:00
err = rpciod_up ( ) ;
if ( err )
goto out_no_rpciod ;
2005-04-17 02:20:36 +04:00
err = - EINVAL ;
if ( ! xprt )
2006-03-14 08:20:47 +03:00
goto out_no_xprt ;
2007-12-21 00:03:53 +03:00
if ( args - > version > = program - > nrvers )
goto out_err ;
version = program - > version [ args - > version ] ;
if ( version = = NULL )
2005-04-17 02:20:36 +04:00
goto out_err ;
err = - ENOMEM ;
2006-07-22 01:51:30 +04:00
clnt = kzalloc ( sizeof ( * clnt ) , GFP_KERNEL ) ;
2005-04-17 02:20:36 +04:00
if ( ! clnt )
goto out_err ;
clnt - > cl_parent = clnt ;
clnt - > cl_server = clnt - > cl_inline_name ;
if ( len > sizeof ( clnt - > cl_inline_name ) ) {
char * buf = kmalloc ( len , GFP_KERNEL ) ;
2007-12-21 00:03:53 +03:00
if ( buf ! = NULL )
2005-04-17 02:20:36 +04:00
clnt - > cl_server = buf ;
else
len = sizeof ( clnt - > cl_inline_name ) ;
}
2007-12-21 00:03:53 +03:00
strlcpy ( clnt - > cl_server , args - > servername , len ) ;
2005-04-17 02:20:36 +04:00
clnt - > cl_xprt = xprt ;
clnt - > cl_procinfo = version - > procs ;
clnt - > cl_maxproc = version - > nrprocs ;
clnt - > cl_protname = program - > name ;
clnt - > cl_prog = program - > number ;
clnt - > cl_vers = version - > number ;
clnt - > cl_stats = program - > stats ;
2006-03-20 21:44:22 +03:00
clnt - > cl_metrics = rpc_alloc_iostats ( clnt ) ;
2006-11-21 18:40:23 +03:00
err = - ENOMEM ;
if ( clnt - > cl_metrics = = NULL )
goto out_no_stats ;
2006-11-16 19:37:27 +03:00
clnt - > cl_program = program ;
2007-06-15 00:40:14 +04:00
INIT_LIST_HEAD ( & clnt - > cl_tasks ) ;
2007-06-16 22:17:01 +04:00
spin_lock_init ( & clnt - > cl_lock ) ;
2005-04-17 02:20:36 +04:00
2006-08-23 04:06:15 +04:00
if ( ! xprt_bound ( clnt - > cl_xprt ) )
2005-04-17 02:20:36 +04:00
clnt - > cl_autobind = 1 ;
2007-12-21 00:03:55 +03:00
clnt - > cl_timeout = xprt - > timeout ;
if ( args - > timeout ! = NULL ) {
memcpy ( & clnt - > cl_timeout_default , args - > timeout ,
sizeof ( clnt - > cl_timeout_default ) ) ;
clnt - > cl_timeout = & clnt - > cl_timeout_default ;
}
2005-04-17 02:20:36 +04:00
clnt - > cl_rtt = & clnt - > cl_rtt_default ;
2007-12-21 00:03:55 +03:00
rpc_init_rtt ( & clnt - > cl_rtt_default , clnt - > cl_timeout - > to_initval ) ;
2005-04-17 02:20:36 +04:00
2007-06-15 00:40:31 +04:00
kref_init ( & clnt - > cl_kref ) ;
2005-04-17 02:20:36 +04:00
err = rpc_setup_pipedir ( clnt , program - > pipe_dir_name ) ;
if ( err < 0 )
goto out_no_path ;
2007-12-21 00:03:53 +03:00
auth = rpcauth_create ( args - > authflavor , clnt ) ;
2005-06-22 21:16:23 +04:00
if ( IS_ERR ( auth ) ) {
2005-04-17 02:20:36 +04:00
printk ( KERN_INFO " RPC: Couldn't create auth handle (flavor %u) \n " ,
2007-12-21 00:03:53 +03:00
args - > authflavor ) ;
2005-06-22 21:16:23 +04:00
err = PTR_ERR ( auth ) ;
2005-04-17 02:20:36 +04:00
goto out_no_auth ;
}
/* save the nodename */
2006-10-02 13:18:11 +04:00
clnt - > cl_nodelen = strlen ( utsname ( ) - > nodename ) ;
2005-04-17 02:20:36 +04:00
if ( clnt - > cl_nodelen > UNX_MAXNODENAME )
clnt - > cl_nodelen = UNX_MAXNODENAME ;
2006-10-02 13:18:11 +04:00
memcpy ( clnt - > cl_nodename , utsname ( ) - > nodename , clnt - > cl_nodelen ) ;
2007-06-15 00:40:14 +04:00
rpc_register_client ( clnt ) ;
2005-04-17 02:20:36 +04:00
return clnt ;
out_no_auth :
2006-03-20 21:44:49 +03:00
if ( ! IS_ERR ( clnt - > cl_dentry ) ) {
2006-08-01 01:17:18 +04:00
rpc_rmdir ( clnt - > cl_dentry ) ;
2006-03-20 21:44:49 +03:00
rpc_put_mount ( ) ;
}
2005-04-17 02:20:36 +04:00
out_no_path :
2006-11-21 18:40:23 +03:00
rpc_free_iostats ( clnt - > cl_metrics ) ;
out_no_stats :
2005-04-17 02:20:36 +04:00
if ( clnt - > cl_server ! = clnt - > cl_inline_name )
kfree ( clnt - > cl_server ) ;
kfree ( clnt ) ;
out_err :
2006-09-05 20:55:57 +04:00
xprt_put ( xprt ) ;
2006-03-14 08:20:47 +03:00
out_no_xprt :
2007-06-15 01:26:17 +04:00
rpciod_down ( ) ;
out_no_rpciod :
2005-04-17 02:20:36 +04:00
return ERR_PTR ( err ) ;
}
2006-08-23 04:06:20 +04:00
/*
* rpc_create - create an RPC client and transport with one call
* @ args : rpc_clnt create argument structure
*
* Creates and initializes an RPC transport and an RPC client .
*
* It can ping the server in order to determine if it is up , and to see if
* it supports this program and version . RPC_CLNT_CREATE_NOPING disables
* this behavior so asynchronous tasks can also use rpc_create .
*/
struct rpc_clnt * rpc_create ( struct rpc_create_args * args )
{
struct rpc_xprt * xprt ;
struct rpc_clnt * clnt ;
2007-09-10 21:47:07 +04:00
struct xprt_create xprtargs = {
2007-09-10 21:47:57 +04:00
. ident = args - > protocol ,
2007-07-10 00:23:35 +04:00
. srcaddr = args - > saddress ,
2007-07-08 15:08:54 +04:00
. dstaddr = args - > address ,
. addrlen = args - > addrsize ,
} ;
2007-12-10 22:56:24 +03:00
char servername [ 48 ] ;
2006-08-23 04:06:20 +04:00
2007-07-08 15:08:54 +04:00
xprt = xprt_create_transport ( & xprtargs ) ;
2006-08-23 04:06:20 +04:00
if ( IS_ERR ( xprt ) )
return ( struct rpc_clnt * ) xprt ;
2007-07-01 20:13:22 +04:00
/*
* If the caller chooses not to specify a hostname , whip
* up a string representation of the passed - in address .
*/
if ( args - > servername = = NULL ) {
2007-12-10 22:56:24 +03:00
servername [ 0 ] = ' \0 ' ;
switch ( args - > address - > sa_family ) {
case AF_INET : {
struct sockaddr_in * sin =
( struct sockaddr_in * ) args - > address ;
snprintf ( servername , sizeof ( servername ) , NIPQUAD_FMT ,
NIPQUAD ( sin - > sin_addr . s_addr ) ) ;
break ;
}
case AF_INET6 : {
struct sockaddr_in6 * sin =
( struct sockaddr_in6 * ) args - > address ;
snprintf ( servername , sizeof ( servername ) , NIP6_FMT ,
NIP6 ( sin - > sin6_addr ) ) ;
break ;
}
default :
/* caller wants default server name, but
* address family isn ' t recognized . */
return ERR_PTR ( - EINVAL ) ;
}
2007-07-01 20:13:22 +04:00
args - > servername = servername ;
}
2007-12-10 22:56:24 +03:00
xprt = xprt_create_transport ( & xprtargs ) ;
if ( IS_ERR ( xprt ) )
return ( struct rpc_clnt * ) xprt ;
2006-08-23 04:06:20 +04:00
/*
* By default , kernel RPC client connects from a reserved port .
* CAP_NET_BIND_SERVICE will not be set for unprivileged requesters ,
* but it is always enabled for rpciod , which handles the connect
* operation .
*/
xprt - > resvport = 1 ;
if ( args - > flags & RPC_CLNT_CREATE_NONPRIVPORT )
xprt - > resvport = 0 ;
2007-12-21 00:03:53 +03:00
clnt = rpc_new_client ( args , xprt ) ;
2006-08-23 04:06:20 +04:00
if ( IS_ERR ( clnt ) )
return clnt ;
if ( ! ( args - > flags & RPC_CLNT_CREATE_NOPING ) ) {
2007-12-07 00:24:39 +03:00
int err = rpc_ping ( clnt , RPC_TASK_SOFT ) ;
2006-08-23 04:06:20 +04:00
if ( err ! = 0 ) {
rpc_shutdown_client ( clnt ) ;
return ERR_PTR ( err ) ;
}
}
clnt - > cl_softrtry = 1 ;
if ( args - > flags & RPC_CLNT_CREATE_HARDRTRY )
clnt - > cl_softrtry = 0 ;
if ( args - > flags & RPC_CLNT_CREATE_AUTOBIND )
clnt - > cl_autobind = 1 ;
2007-02-07 02:26:11 +03:00
if ( args - > flags & RPC_CLNT_CREATE_DISCRTRY )
clnt - > cl_discrtry = 1 ;
2006-08-23 04:06:20 +04:00
return clnt ;
}
2006-08-23 04:06:22 +04:00
EXPORT_SYMBOL_GPL ( rpc_create ) ;
2006-08-23 04:06:20 +04:00
2005-04-17 02:20:36 +04:00
/*
* This function clones the RPC client structure . It allows us to share the
* same transport while varying parameters such as the authentication
* flavour .
*/
struct rpc_clnt *
rpc_clone_client ( struct rpc_clnt * clnt )
{
struct rpc_clnt * new ;
2006-11-16 19:37:27 +03:00
int err = - ENOMEM ;
2005-04-17 02:20:36 +04:00
2006-11-21 06:21:34 +03:00
new = kmemdup ( clnt , sizeof ( * new ) , GFP_KERNEL ) ;
2005-04-17 02:20:36 +04:00
if ( ! new )
goto out_no_clnt ;
2007-06-18 01:07:54 +04:00
new - > cl_parent = clnt ;
/* Turn off autobind on clones */
new - > cl_autobind = 0 ;
INIT_LIST_HEAD ( & new - > cl_tasks ) ;
spin_lock_init ( & new - > cl_lock ) ;
2007-12-21 00:03:55 +03:00
rpc_init_rtt ( & new - > cl_rtt_default , clnt - > cl_timeout - > to_initval ) ;
2006-11-21 18:40:23 +03:00
new - > cl_metrics = rpc_alloc_iostats ( clnt ) ;
if ( new - > cl_metrics = = NULL )
goto out_no_stats ;
2007-06-15 00:40:31 +04:00
kref_init ( & new - > cl_kref ) ;
2006-11-16 19:37:27 +03:00
err = rpc_setup_pipedir ( new , clnt - > cl_program - > pipe_dir_name ) ;
if ( err ! = 0 )
goto out_no_path ;
2005-04-17 02:20:36 +04:00
if ( new - > cl_auth )
atomic_inc ( & new - > cl_auth - > au_count ) ;
2007-06-18 01:07:54 +04:00
xprt_get ( clnt - > cl_xprt ) ;
kref_get ( & clnt - > cl_kref ) ;
2007-06-15 00:40:14 +04:00
rpc_register_client ( new ) ;
2007-06-15 01:26:17 +04:00
rpciod_up ( ) ;
2005-04-17 02:20:36 +04:00
return new ;
2006-11-16 19:37:27 +03:00
out_no_path :
rpc_free_iostats ( new - > cl_metrics ) ;
2006-11-21 18:40:23 +03:00
out_no_stats :
kfree ( new ) ;
2005-04-17 02:20:36 +04:00
out_no_clnt :
2007-01-31 20:14:08 +03:00
dprintk ( " RPC: %s: returned error %d \n " , __FUNCTION__ , err ) ;
2006-11-16 19:37:27 +03:00
return ERR_PTR ( err ) ;
2005-04-17 02:20:36 +04:00
}
2007-07-14 23:39:59 +04:00
EXPORT_SYMBOL_GPL ( rpc_clone_client ) ;
2005-04-17 02:20:36 +04:00
/*
* Properly shut down an RPC client , terminating all outstanding
2007-06-10 03:49:36 +04:00
* requests .
2005-04-17 02:20:36 +04:00
*/
2007-06-15 00:40:32 +04:00
void rpc_shutdown_client ( struct rpc_clnt * clnt )
2005-04-17 02:20:36 +04:00
{
2007-06-15 00:40:31 +04:00
dprintk ( " RPC: shutting down %s client for %s \n " ,
clnt - > cl_protname , clnt - > cl_server ) ;
2005-04-17 02:20:36 +04:00
2007-06-15 00:40:31 +04:00
while ( ! list_empty ( & clnt - > cl_tasks ) ) {
2005-04-17 02:20:36 +04:00
rpc_killall_tasks ( clnt ) ;
2006-01-10 07:52:53 +03:00
wait_event_timeout ( destroy_wait ,
2007-06-15 00:40:31 +04:00
list_empty ( & clnt - > cl_tasks ) , 1 * HZ ) ;
2005-04-17 02:20:36 +04:00
}
2007-06-15 00:40:32 +04:00
rpc_release_client ( clnt ) ;
2005-04-17 02:20:36 +04:00
}
2007-07-14 23:39:59 +04:00
EXPORT_SYMBOL_GPL ( rpc_shutdown_client ) ;
2005-04-17 02:20:36 +04:00
/*
2007-06-15 00:40:31 +04:00
* Free an RPC client
2005-04-17 02:20:36 +04:00
*/
2007-06-15 00:40:31 +04:00
static void
rpc_free_client ( struct kref * kref )
2005-04-17 02:20:36 +04:00
{
2007-06-15 00:40:31 +04:00
struct rpc_clnt * clnt = container_of ( kref , struct rpc_clnt , cl_kref ) ;
2005-04-17 02:20:36 +04:00
2007-01-31 20:14:08 +03:00
dprintk ( " RPC: destroying %s client for %s \n " ,
2005-04-17 02:20:36 +04:00
clnt - > cl_protname , clnt - > cl_server ) ;
2006-08-14 21:11:15 +04:00
if ( ! IS_ERR ( clnt - > cl_dentry ) ) {
2006-08-01 01:17:18 +04:00
rpc_rmdir ( clnt - > cl_dentry ) ;
2006-08-14 21:11:15 +04:00
rpc_put_mount ( ) ;
}
2006-11-16 19:37:27 +03:00
if ( clnt - > cl_parent ! = clnt ) {
2007-06-15 00:40:32 +04:00
rpc_release_client ( clnt - > cl_parent ) ;
2006-11-16 19:37:27 +03:00
goto out_free ;
}
2005-04-17 02:20:36 +04:00
if ( clnt - > cl_server ! = clnt - > cl_inline_name )
kfree ( clnt - > cl_server ) ;
out_free :
2007-06-15 00:40:14 +04:00
rpc_unregister_client ( clnt ) ;
2006-03-20 21:44:22 +03:00
rpc_free_iostats ( clnt - > cl_metrics ) ;
clnt - > cl_metrics = NULL ;
2006-09-05 20:55:57 +04:00
xprt_put ( clnt - > cl_xprt ) ;
2007-06-15 01:26:17 +04:00
rpciod_down ( ) ;
2005-04-17 02:20:36 +04:00
kfree ( clnt ) ;
}
2007-06-27 00:57:41 +04:00
/*
* Free an RPC client
*/
static void
rpc_free_auth ( struct kref * kref )
{
struct rpc_clnt * clnt = container_of ( kref , struct rpc_clnt , cl_kref ) ;
if ( clnt - > cl_auth = = NULL ) {
rpc_free_client ( kref ) ;
return ;
}
/*
* Note : RPCSEC_GSS may need to send NULL RPC calls in order to
* release remaining GSS contexts . This mechanism ensures
* that it can do so safely .
*/
kref_init ( kref ) ;
rpcauth_release ( clnt - > cl_auth ) ;
clnt - > cl_auth = NULL ;
kref_put ( kref , rpc_free_client ) ;
}
2005-04-17 02:20:36 +04:00
/*
2007-06-15 00:40:31 +04:00
* Release reference to the RPC client
2005-04-17 02:20:36 +04:00
*/
void
rpc_release_client ( struct rpc_clnt * clnt )
{
2007-06-15 00:40:31 +04:00
dprintk ( " RPC: rpc_release_client(%p) \n " , clnt ) ;
2005-04-17 02:20:36 +04:00
2007-06-15 00:40:31 +04:00
if ( list_empty ( & clnt - > cl_tasks ) )
wake_up ( & destroy_wait ) ;
2007-06-27 00:57:41 +04:00
kref_put ( & clnt - > cl_kref , rpc_free_auth ) ;
2007-06-15 00:40:31 +04:00
}
2005-06-22 21:16:23 +04:00
/**
* rpc_bind_new_program - bind a new RPC program to an existing client
2008-02-14 02:03:23 +03:00
* @ old : old rpc_client
* @ program : rpc program to set
* @ vers : rpc program version
2005-06-22 21:16:23 +04:00
*
* Clones the rpc client and sets up a new RPC program . This is mainly
* of use for enabling different RPC programs to share the same transport .
* The Sun NFSv2 / v3 ACL protocol can do this .
*/
struct rpc_clnt * rpc_bind_new_program ( struct rpc_clnt * old ,
struct rpc_program * program ,
2007-09-12 02:00:09 +04:00
u32 vers )
2005-06-22 21:16:23 +04:00
{
struct rpc_clnt * clnt ;
struct rpc_version * version ;
int err ;
BUG_ON ( vers > = program - > nrvers | | ! program - > version [ vers ] ) ;
version = program - > version [ vers ] ;
clnt = rpc_clone_client ( old ) ;
if ( IS_ERR ( clnt ) )
goto out ;
clnt - > cl_procinfo = version - > procs ;
clnt - > cl_maxproc = version - > nrprocs ;
clnt - > cl_protname = program - > name ;
clnt - > cl_prog = program - > number ;
clnt - > cl_vers = version - > number ;
clnt - > cl_stats = program - > stats ;
2007-12-07 00:24:39 +03:00
err = rpc_ping ( clnt , RPC_TASK_SOFT ) ;
2005-06-22 21:16:23 +04:00
if ( err ! = 0 ) {
rpc_shutdown_client ( clnt ) ;
clnt = ERR_PTR ( err ) ;
}
2007-02-10 02:38:13 +03:00
out :
2005-06-22 21:16:23 +04:00
return clnt ;
}
2007-07-14 23:39:59 +04:00
EXPORT_SYMBOL_GPL ( rpc_bind_new_program ) ;
2005-06-22 21:16:23 +04:00
2005-04-17 02:20:36 +04:00
/*
* Default callback for async RPC calls
*/
static void
2006-01-03 11:55:04 +03:00
rpc_default_callback ( struct rpc_task * task , void * data )
2005-04-17 02:20:36 +04:00
{
}
2006-01-03 11:55:04 +03:00
static const struct rpc_call_ops rpc_default_ops = {
. rpc_call_done = rpc_default_callback ,
} ;
2007-07-14 23:39:59 +04:00
/**
* rpc_run_task - Allocate a new RPC task , then run rpc_execute against it
* @ task_setup_data : pointer to task initialisation data
*/
struct rpc_task * rpc_run_task ( const struct rpc_task_setup * task_setup_data )
2007-06-12 18:02:37 +04:00
{
struct rpc_task * task , * ret ;
2007-07-14 23:39:59 +04:00
task = rpc_new_task ( task_setup_data ) ;
2007-06-12 18:02:37 +04:00
if ( task = = NULL ) {
2007-07-14 23:39:59 +04:00
rpc_release_calldata ( task_setup_data - > callback_ops ,
task_setup_data - > callback_data ) ;
2007-10-26 02:19:37 +04:00
ret = ERR_PTR ( - ENOMEM ) ;
goto out ;
2007-06-12 18:02:37 +04:00
}
2007-10-26 02:32:34 +04:00
if ( task - > tk_status ! = 0 ) {
ret = ERR_PTR ( task - > tk_status ) ;
rpc_put_task ( task ) ;
goto out ;
2007-06-12 18:02:37 +04:00
}
atomic_inc ( & task - > tk_count ) ;
rpc_execute ( task ) ;
ret = task ;
out :
return ret ;
}
2007-07-14 23:39:59 +04:00
EXPORT_SYMBOL_GPL ( rpc_run_task ) ;
2007-06-12 18:02:37 +04:00
/**
* rpc_call_sync - Perform a synchronous RPC call
* @ clnt : pointer to RPC client
* @ msg : RPC call parameters
* @ flags : RPC call flags
2005-04-17 02:20:36 +04:00
*/
2008-02-14 19:11:30 +03:00
int rpc_call_sync ( struct rpc_clnt * clnt , const struct rpc_message * msg , int flags )
2005-04-17 02:20:36 +04:00
{
struct rpc_task * task ;
2007-07-14 23:39:59 +04:00
struct rpc_task_setup task_setup_data = {
. rpc_client = clnt ,
. rpc_message = msg ,
. callback_ops = & rpc_default_ops ,
. flags = flags ,
} ;
2007-06-12 18:02:37 +04:00
int status ;
2005-04-17 02:20:36 +04:00
BUG_ON ( flags & RPC_TASK_ASYNC ) ;
2007-07-14 23:39:59 +04:00
task = rpc_run_task ( & task_setup_data ) ;
2007-06-12 18:02:37 +04:00
if ( IS_ERR ( task ) )
return PTR_ERR ( task ) ;
2006-01-03 11:55:10 +03:00
status = task - > tk_status ;
2007-01-24 22:54:53 +03:00
rpc_put_task ( task ) ;
2005-04-17 02:20:36 +04:00
return status ;
}
2007-07-14 23:39:59 +04:00
EXPORT_SYMBOL_GPL ( rpc_call_sync ) ;
2005-04-17 02:20:36 +04:00
2007-06-12 18:02:37 +04:00
/**
* rpc_call_async - Perform an asynchronous RPC call
* @ clnt : pointer to RPC client
* @ msg : RPC call parameters
* @ flags : RPC call flags
2008-02-14 02:03:23 +03:00
* @ tk_ops : RPC call ops
2007-06-12 18:02:37 +04:00
* @ data : user call data
2005-04-17 02:20:36 +04:00
*/
int
2008-02-14 19:11:30 +03:00
rpc_call_async ( struct rpc_clnt * clnt , const struct rpc_message * msg , int flags ,
2006-01-03 11:55:04 +03:00
const struct rpc_call_ops * tk_ops , void * data )
2005-04-17 02:20:36 +04:00
{
struct rpc_task * task ;
2007-07-14 23:39:59 +04:00
struct rpc_task_setup task_setup_data = {
. rpc_client = clnt ,
. rpc_message = msg ,
. callback_ops = tk_ops ,
. callback_data = data ,
. flags = flags | RPC_TASK_ASYNC ,
} ;
2005-04-17 02:20:36 +04:00
2007-07-14 23:39:59 +04:00
task = rpc_run_task ( & task_setup_data ) ;
2007-06-12 18:02:37 +04:00
if ( IS_ERR ( task ) )
return PTR_ERR ( task ) ;
rpc_put_task ( task ) ;
return 0 ;
2005-04-17 02:20:36 +04:00
}
2007-07-14 23:39:59 +04:00
EXPORT_SYMBOL_GPL ( rpc_call_async ) ;
2005-04-17 02:20:36 +04:00
2007-10-26 02:40:21 +04:00
void
rpc_call_start ( struct rpc_task * task )
{
task - > tk_action = call_start ;
}
EXPORT_SYMBOL_GPL ( rpc_call_start ) ;
2006-08-23 04:06:17 +04:00
/**
* rpc_peeraddr - extract remote peer address from clnt ' s xprt
* @ clnt : RPC client structure
* @ buf : target buffer
2008-02-14 02:03:23 +03:00
* @ bufsize : length of target buffer
2006-08-23 04:06:17 +04:00
*
* Returns the number of bytes that are actually in the stored address .
*/
size_t rpc_peeraddr ( struct rpc_clnt * clnt , struct sockaddr * buf , size_t bufsize )
{
size_t bytes ;
struct rpc_xprt * xprt = clnt - > cl_xprt ;
bytes = sizeof ( xprt - > addr ) ;
if ( bytes > bufsize )
bytes = bufsize ;
memcpy ( buf , & clnt - > cl_xprt - > addr , bytes ) ;
2006-08-23 04:06:19 +04:00
return xprt - > addrlen ;
2006-08-23 04:06:17 +04:00
}
2006-08-23 04:06:22 +04:00
EXPORT_SYMBOL_GPL ( rpc_peeraddr ) ;
2006-08-23 04:06:17 +04:00
2006-08-23 04:06:18 +04:00
/**
* rpc_peeraddr2str - return remote peer address in printable format
* @ clnt : RPC client structure
* @ format : address format
*
*/
2008-01-08 02:34:48 +03:00
const char * rpc_peeraddr2str ( struct rpc_clnt * clnt ,
enum rpc_display_format_t format )
2006-08-23 04:06:18 +04:00
{
struct rpc_xprt * xprt = clnt - > cl_xprt ;
2006-12-06 00:35:37 +03:00
if ( xprt - > address_strings [ format ] ! = NULL )
return xprt - > address_strings [ format ] ;
else
return " unprintable " ;
2006-08-23 04:06:18 +04:00
}
2006-08-23 04:06:22 +04:00
EXPORT_SYMBOL_GPL ( rpc_peeraddr2str ) ;
2006-08-23 04:06:18 +04:00
2005-04-17 02:20:36 +04:00
void
rpc_setbufsize ( struct rpc_clnt * clnt , unsigned int sndsize , unsigned int rcvsize )
{
struct rpc_xprt * xprt = clnt - > cl_xprt ;
2005-08-26 03:25:56 +04:00
if ( xprt - > ops - > set_buffer_size )
xprt - > ops - > set_buffer_size ( xprt , sndsize , rcvsize ) ;
2005-04-17 02:20:36 +04:00
}
2007-07-14 23:39:59 +04:00
EXPORT_SYMBOL_GPL ( rpc_setbufsize ) ;
2005-04-17 02:20:36 +04:00
/*
* Return size of largest payload RPC client can support , in bytes
*
* For stream transports , this is one RPC record fragment ( see RFC
* 1831 ) , as we don ' t support multi - record requests yet . For datagram
* transports , this is the size of an IP packet minus the IP , UDP , and
* RPC header sizes .
*/
size_t rpc_max_payload ( struct rpc_clnt * clnt )
{
return clnt - > cl_xprt - > max_payload ;
}
2006-08-23 04:06:22 +04:00
EXPORT_SYMBOL_GPL ( rpc_max_payload ) ;
2005-04-17 02:20:36 +04:00
2006-01-03 11:55:50 +03:00
/**
* rpc_force_rebind - force transport to check that remote port is unchanged
* @ clnt : client to rebind
*
*/
void rpc_force_rebind ( struct rpc_clnt * clnt )
{
if ( clnt - > cl_autobind )
2006-08-23 04:06:15 +04:00
xprt_clear_bound ( clnt - > cl_xprt ) ;
2006-01-03 11:55:50 +03:00
}
2006-08-23 04:06:22 +04:00
EXPORT_SYMBOL_GPL ( rpc_force_rebind ) ;
2006-01-03 11:55:50 +03:00
2005-04-17 02:20:36 +04:00
/*
* Restart an ( async ) RPC call . Usually called from within the
* exit handler .
*/
void
rpc_restart_call ( struct rpc_task * task )
{
if ( RPC_ASSASSINATED ( task ) )
return ;
task - > tk_action = call_start ;
}
2007-07-14 23:39:59 +04:00
EXPORT_SYMBOL_GPL ( rpc_restart_call ) ;
2005-04-17 02:20:36 +04:00
/*
* 0. Initial state
*
* Other FSM states can be visited zero or more times , but
* this state is visited exactly once for each RPC .
*/
static void
call_start ( struct rpc_task * task )
{
struct rpc_clnt * clnt = task - > tk_client ;
2007-01-31 20:14:08 +03:00
dprintk ( " RPC: %5u call_start %s%d proc %d (%s) \n " , task - > tk_pid ,
clnt - > cl_protname , clnt - > cl_vers ,
task - > tk_msg . rpc_proc - > p_proc ,
( RPC_IS_ASYNC ( task ) ? " async " : " sync " ) ) ;
2005-04-17 02:20:36 +04:00
/* Increment call count */
task - > tk_msg . rpc_proc - > p_count + + ;
clnt - > cl_stats - > rpccnt + + ;
task - > tk_action = call_reserve ;
}
/*
* 1. Reserve an RPC call slot
*/
static void
call_reserve ( struct rpc_task * task )
{
2007-01-31 20:14:08 +03:00
dprint_status ( task ) ;
2005-04-17 02:20:36 +04:00
if ( ! rpcauth_uptodatecred ( task ) ) {
task - > tk_action = call_refresh ;
return ;
}
task - > tk_status = 0 ;
task - > tk_action = call_reserveresult ;
xprt_reserve ( task ) ;
}
/*
* 1 b . Grok the result of xprt_reserve ( )
*/
static void
call_reserveresult ( struct rpc_task * task )
{
int status = task - > tk_status ;
2007-01-31 20:14:08 +03:00
dprint_status ( task ) ;
2005-04-17 02:20:36 +04:00
/*
* After a call to xprt_reserve ( ) , we must have either
* a request slot or else an error status .
*/
task - > tk_status = 0 ;
if ( status > = 0 ) {
if ( task - > tk_rqstp ) {
task - > tk_action = call_allocate ;
return ;
}
printk ( KERN_ERR " %s: status=%d, but no request slot, exiting \n " ,
__FUNCTION__ , status ) ;
rpc_exit ( task , - EIO ) ;
return ;
}
/*
* Even though there was an error , we may have acquired
* a request slot somehow . Make sure not to leak it .
*/
if ( task - > tk_rqstp ) {
printk ( KERN_ERR " %s: status=%d, request allocated anyway \n " ,
__FUNCTION__ , status ) ;
xprt_release ( task ) ;
}
switch ( status ) {
case - EAGAIN : /* woken up; retry */
task - > tk_action = call_reserve ;
return ;
case - EIO : /* probably a shutdown */
break ;
default :
printk ( KERN_ERR " %s: unrecognized error %d, exiting \n " ,
__FUNCTION__ , status ) ;
break ;
}
rpc_exit ( task , status ) ;
}
/*
* 2. Allocate the buffer . For details , see sched . c : rpc_malloc .
2006-01-03 11:55:49 +03:00
* ( Note : buffer memory is freed in xprt_release ) .
2005-04-17 02:20:36 +04:00
*/
static void
call_allocate ( struct rpc_task * task )
{
2007-06-27 22:29:04 +04:00
unsigned int slack = task - > tk_msg . rpc_cred - > cr_auth - > au_cslack ;
2006-01-03 11:55:49 +03:00
struct rpc_rqst * req = task - > tk_rqstp ;
struct rpc_xprt * xprt = task - > tk_xprt ;
2007-03-30 00:47:53 +04:00
struct rpc_procinfo * proc = task - > tk_msg . rpc_proc ;
2005-04-17 02:20:36 +04:00
2007-01-31 20:14:08 +03:00
dprint_status ( task ) ;
2007-03-30 00:47:53 +04:00
task - > tk_status = 0 ;
2005-04-17 02:20:36 +04:00
task - > tk_action = call_bind ;
2007-03-30 00:47:53 +04:00
2006-01-03 11:55:49 +03:00
if ( req - > rq_buffer )
2005-04-17 02:20:36 +04:00
return ;
2007-03-30 00:47:53 +04:00
if ( proc - > p_proc ! = 0 ) {
BUG_ON ( proc - > p_arglen = = 0 ) ;
if ( proc - > p_decode ! = NULL )
BUG_ON ( proc - > p_replen = = 0 ) ;
}
2005-04-17 02:20:36 +04:00
2007-03-30 00:47:53 +04:00
/*
* Calculate the size ( in quads ) of the RPC call
* and reply headers , and convert both values
* to byte sizes .
*/
req - > rq_callsize = RPC_CALLHDRSIZE + ( slack < < 1 ) + proc - > p_arglen ;
req - > rq_callsize < < = 2 ;
req - > rq_rcvsize = RPC_REPHDRSIZE + slack + proc - > p_replen ;
req - > rq_rcvsize < < = 2 ;
2007-03-30 00:47:58 +04:00
req - > rq_buffer = xprt - > ops - > buf_alloc ( task ,
req - > rq_callsize + req - > rq_rcvsize ) ;
2007-03-30 00:47:53 +04:00
if ( req - > rq_buffer ! = NULL )
2005-04-17 02:20:36 +04:00
return ;
2007-01-31 20:14:08 +03:00
dprintk ( " RPC: %5u rpc_buffer allocation failed \n " , task - > tk_pid ) ;
2005-04-17 02:20:36 +04:00
2005-06-22 21:16:28 +04:00
if ( RPC_IS_ASYNC ( task ) | | ! signalled ( ) ) {
2007-10-01 20:06:44 +04:00
task - > tk_action = call_allocate ;
2005-04-17 02:20:36 +04:00
rpc_delay ( task , HZ > > 4 ) ;
return ;
}
rpc_exit ( task , - ERESTARTSYS ) ;
}
2005-11-10 05:45:24 +03:00
static inline int
rpc_task_need_encode ( struct rpc_task * task )
{
return task - > tk_rqstp - > rq_snd_buf . len = = 0 ;
}
static inline void
rpc_task_force_reencode ( struct rpc_task * task )
{
task - > tk_rqstp - > rq_snd_buf . len = 0 ;
}
2007-03-30 00:47:53 +04:00
static inline void
rpc_xdr_buf_init ( struct xdr_buf * buf , void * start , size_t len )
{
buf - > head [ 0 ] . iov_base = start ;
buf - > head [ 0 ] . iov_len = len ;
buf - > tail [ 0 ] . iov_len = 0 ;
buf - > page_len = 0 ;
2007-09-10 21:44:58 +04:00
buf - > flags = 0 ;
2007-03-30 00:47:53 +04:00
buf - > len = 0 ;
buf - > buflen = len ;
}
2005-04-17 02:20:36 +04:00
/*
* 3. Encode arguments of an RPC call
*/
static void
call_encode ( struct rpc_task * task )
{
struct rpc_rqst * req = task - > tk_rqstp ;
kxdrproc_t encode ;
2006-09-27 09:29:38 +04:00
__be32 * p ;
2005-04-17 02:20:36 +04:00
2007-01-31 20:14:08 +03:00
dprint_status ( task ) ;
2005-04-17 02:20:36 +04:00
2007-03-30 00:47:53 +04:00
rpc_xdr_buf_init ( & req - > rq_snd_buf ,
req - > rq_buffer ,
req - > rq_callsize ) ;
rpc_xdr_buf_init ( & req - > rq_rcv_buf ,
( char * ) req - > rq_buffer + req - > rq_callsize ,
req - > rq_rcvsize ) ;
2005-04-17 02:20:36 +04:00
/* Encode header and provided arguments */
encode = task - > tk_msg . rpc_proc - > p_encode ;
if ( ! ( p = call_header ( task ) ) ) {
printk ( KERN_INFO " RPC: call_header failed, exit EIO \n " ) ;
rpc_exit ( task , - EIO ) ;
return ;
}
2005-10-14 00:54:48 +04:00
if ( encode = = NULL )
return ;
task - > tk_status = rpcauth_wrap_req ( task , encode , req , p ,
task - > tk_msg . rpc_argp ) ;
if ( task - > tk_status = = - ENOMEM ) {
/* XXX: Is this sane? */
rpc_delay ( task , 3 * HZ ) ;
task - > tk_status = - EAGAIN ;
}
2005-04-17 02:20:36 +04:00
}
/*
* 4. Get the server port number if not yet set
*/
static void
call_bind ( struct rpc_task * task )
{
2006-08-23 04:06:15 +04:00
struct rpc_xprt * xprt = task - > tk_xprt ;
2005-04-17 02:20:36 +04:00
2007-01-31 20:14:08 +03:00
dprint_status ( task ) ;
2005-04-17 02:20:36 +04:00
2005-08-12 00:25:11 +04:00
task - > tk_action = call_connect ;
2006-08-23 04:06:15 +04:00
if ( ! xprt_bound ( xprt ) ) {
2005-08-12 00:25:11 +04:00
task - > tk_action = call_bind_status ;
2006-08-23 04:06:15 +04:00
task - > tk_timeout = xprt - > bind_timeout ;
2006-08-23 04:06:16 +04:00
xprt - > ops - > rpcbind ( task ) ;
2005-04-17 02:20:36 +04:00
}
}
/*
2005-08-12 00:25:11 +04:00
* 4 a . Sort out bind result
*/
static void
call_bind_status ( struct rpc_task * task )
{
2007-09-12 02:00:47 +04:00
int status = - EIO ;
2005-08-12 00:25:11 +04:00
if ( task - > tk_status > = 0 ) {
2007-01-31 20:14:08 +03:00
dprint_status ( task ) ;
2005-08-12 00:25:11 +04:00
task - > tk_status = 0 ;
task - > tk_action = call_connect ;
return ;
}
switch ( task - > tk_status ) {
2007-09-12 02:00:41 +04:00
case - EAGAIN :
dprintk ( " RPC: %5u rpcbind waiting for another request "
" to finish \n " , task - > tk_pid ) ;
/* avoid busy-waiting here -- could be a network outage. */
rpc_delay ( task , 5 * HZ ) ;
goto retry_timeout ;
2005-08-12 00:25:11 +04:00
case - EACCES :
2007-01-31 20:14:08 +03:00
dprintk ( " RPC: %5u remote rpcbind: RPC program/version "
" unavailable \n " , task - > tk_pid ) ;
2007-09-12 02:00:52 +04:00
/* fail immediately if this is an RPC ping */
if ( task - > tk_msg . rpc_proc - > p_proc = = 0 ) {
status = - EOPNOTSUPP ;
break ;
}
2005-10-07 07:12:58 +04:00
rpc_delay ( task , 3 * HZ ) ;
2006-08-31 23:44:52 +04:00
goto retry_timeout ;
2005-08-12 00:25:11 +04:00
case - ETIMEDOUT :
2007-01-31 20:14:08 +03:00
dprintk ( " RPC: %5u rpcbind request timed out \n " ,
2005-08-12 00:25:11 +04:00
task - > tk_pid ) ;
2006-08-31 23:44:52 +04:00
goto retry_timeout ;
2005-08-12 00:25:11 +04:00
case - EPFNOSUPPORT :
2007-09-12 02:00:47 +04:00
/* server doesn't support any rpcbind version we know of */
2007-01-31 20:14:08 +03:00
dprintk ( " RPC: %5u remote rpcbind service unavailable \n " ,
2005-08-12 00:25:11 +04:00
task - > tk_pid ) ;
break ;
case - EPROTONOSUPPORT :
2007-03-30 00:48:33 +04:00
dprintk ( " RPC: %5u remote rpcbind version unavailable, retrying \n " ,
2005-08-12 00:25:11 +04:00
task - > tk_pid ) ;
2007-03-30 00:48:33 +04:00
task - > tk_status = 0 ;
task - > tk_action = call_bind ;
return ;
2005-08-12 00:25:11 +04:00
default :
2007-01-31 20:14:08 +03:00
dprintk ( " RPC: %5u unrecognized rpcbind error (%d) \n " ,
2005-08-12 00:25:11 +04:00
task - > tk_pid , - task - > tk_status ) ;
}
rpc_exit ( task , status ) ;
return ;
2006-08-31 23:44:52 +04:00
retry_timeout :
task - > tk_action = call_timeout ;
2005-08-12 00:25:11 +04:00
}
/*
* 4 b . Connect to the RPC server
2005-04-17 02:20:36 +04:00
*/
static void
call_connect ( struct rpc_task * task )
{
2005-08-12 00:25:11 +04:00
struct rpc_xprt * xprt = task - > tk_xprt ;
2005-04-17 02:20:36 +04:00
2007-01-31 20:14:08 +03:00
dprintk ( " RPC: %5u call_connect xprt %p %s connected \n " ,
2005-08-12 00:25:11 +04:00
task - > tk_pid , xprt ,
( xprt_connected ( xprt ) ? " is " : " is not " ) ) ;
2005-04-17 02:20:36 +04:00
2005-08-12 00:25:11 +04:00
task - > tk_action = call_transmit ;
if ( ! xprt_connected ( xprt ) ) {
task - > tk_action = call_connect_status ;
if ( task - > tk_status < 0 )
return ;
xprt_connect ( task ) ;
2005-04-17 02:20:36 +04:00
}
}
/*
2005-08-12 00:25:11 +04:00
* 4 c . Sort out connect result
2005-04-17 02:20:36 +04:00
*/
static void
call_connect_status ( struct rpc_task * task )
{
struct rpc_clnt * clnt = task - > tk_client ;
int status = task - > tk_status ;
2007-01-31 20:14:08 +03:00
dprint_status ( task ) ;
2005-08-12 00:25:11 +04:00
2005-04-17 02:20:36 +04:00
task - > tk_status = 0 ;
if ( status > = 0 ) {
clnt - > cl_stats - > netreconn + + ;
task - > tk_action = call_transmit ;
return ;
}
2005-08-12 00:25:11 +04:00
/* Something failed: remote service port may have changed */
2006-01-03 11:55:50 +03:00
rpc_force_rebind ( clnt ) ;
2005-08-12 00:25:11 +04:00
2005-04-17 02:20:36 +04:00
switch ( status ) {
case - ENOTCONN :
case - EAGAIN :
2005-08-12 00:25:11 +04:00
task - > tk_action = call_bind ;
2006-08-31 23:44:52 +04:00
if ( ! RPC_IS_SOFT ( task ) )
return ;
/* if soft mounted, test if we've timed out */
case - ETIMEDOUT :
task - > tk_action = call_timeout ;
return ;
2005-04-17 02:20:36 +04:00
}
2006-08-31 23:44:52 +04:00
rpc_exit ( task , - EIO ) ;
2005-04-17 02:20:36 +04:00
}
/*
* 5. Transmit the RPC request , and wait for reply
*/
static void
call_transmit ( struct rpc_task * task )
{
2007-01-31 20:14:08 +03:00
dprint_status ( task ) ;
2005-04-17 02:20:36 +04:00
task - > tk_action = call_status ;
if ( task - > tk_status < 0 )
return ;
task - > tk_status = xprt_prepare_transmit ( task ) ;
if ( task - > tk_status ! = 0 )
return ;
2006-07-28 01:22:50 +04:00
task - > tk_action = call_transmit_status ;
2005-04-17 02:20:36 +04:00
/* Encode here so that rpcsec_gss can use correct sequence number. */
2005-11-10 05:45:24 +03:00
if ( rpc_task_need_encode ( task ) ) {
2006-07-28 01:22:50 +04:00
BUG_ON ( task - > tk_rqstp - > rq_bytes_sent ! = 0 ) ;
2005-04-17 02:20:36 +04:00
call_encode ( task ) ;
2005-10-19 01:20:11 +04:00
/* Did the encode result in an error condition? */
if ( task - > tk_status ! = 0 )
2006-07-28 01:22:50 +04:00
return ;
2005-10-19 01:20:11 +04:00
}
2005-04-17 02:20:36 +04:00
xprt_transmit ( task ) ;
if ( task - > tk_status < 0 )
return ;
2006-07-28 01:22:50 +04:00
/*
* On success , ensure that we call xprt_end_transmit ( ) before sleeping
* in order to allow access to the socket to other RPC requests .
*/
call_transmit_status ( task ) ;
if ( task - > tk_msg . rpc_proc - > p_decode ! = NULL )
return ;
task - > tk_action = rpc_exit_task ;
rpc_wake_up_task ( task ) ;
}
/*
* 5 a . Handle cleanup after a transmission
*/
static void
call_transmit_status ( struct rpc_task * task )
{
task - > tk_action = call_status ;
/*
* Special case : if we ' ve been waiting on the socket ' s write_space ( )
* callback , then don ' t call xprt_end_transmit ( ) .
*/
if ( task - > tk_status = = - EAGAIN )
return ;
xprt_end_transmit ( task ) ;
2005-11-10 05:45:24 +03:00
rpc_task_force_reencode ( task ) ;
2005-04-17 02:20:36 +04:00
}
/*
* 6. Sort out the RPC call status
*/
static void
call_status ( struct rpc_task * task )
{
struct rpc_clnt * clnt = task - > tk_client ;
struct rpc_rqst * req = task - > tk_rqstp ;
int status ;
if ( req - > rq_received > 0 & & ! req - > rq_bytes_sent )
task - > tk_status = req - > rq_received ;
2007-01-31 20:14:08 +03:00
dprint_status ( task ) ;
2005-04-17 02:20:36 +04:00
status = task - > tk_status ;
if ( status > = 0 ) {
task - > tk_action = call_decode ;
return ;
}
task - > tk_status = 0 ;
switch ( status ) {
2006-08-30 22:32:49 +04:00
case - EHOSTDOWN :
case - EHOSTUNREACH :
case - ENETUNREACH :
/*
* Delay any retries for 3 seconds , then handle as if it
* were a timeout .
*/
rpc_delay ( task , 3 * HZ ) ;
2005-04-17 02:20:36 +04:00
case - ETIMEDOUT :
task - > tk_action = call_timeout ;
2007-04-21 00:12:55 +04:00
if ( task - > tk_client - > cl_discrtry )
2007-11-07 02:40:12 +03:00
xprt_force_disconnect ( task - > tk_xprt ) ;
2005-04-17 02:20:36 +04:00
break ;
case - ECONNREFUSED :
case - ENOTCONN :
2006-01-03 11:55:50 +03:00
rpc_force_rebind ( clnt ) ;
2005-04-17 02:20:36 +04:00
task - > tk_action = call_bind ;
break ;
case - EAGAIN :
task - > tk_action = call_transmit ;
break ;
case - EIO :
/* shutdown or soft timeout */
rpc_exit ( task , status ) ;
break ;
default :
2006-01-03 11:55:52 +03:00
printk ( " %s: RPC call returned error %d \n " ,
2005-04-17 02:20:36 +04:00
clnt - > cl_protname , - status ) ;
rpc_exit ( task , status ) ;
}
}
/*
2006-07-28 01:22:50 +04:00
* 6 a . Handle RPC timeout
2005-04-17 02:20:36 +04:00
* We do not release the request slot , so we keep using the
* same XID for all retransmits .
*/
static void
call_timeout ( struct rpc_task * task )
{
struct rpc_clnt * clnt = task - > tk_client ;
if ( xprt_adjust_timeout ( task - > tk_rqstp ) = = 0 ) {
2007-01-31 20:14:08 +03:00
dprintk ( " RPC: %5u call_timeout (minor) \n " , task - > tk_pid ) ;
2005-04-17 02:20:36 +04:00
goto retry ;
}
2007-01-31 20:14:08 +03:00
dprintk ( " RPC: %5u call_timeout (major) \n " , task - > tk_pid ) ;
2006-03-20 21:44:17 +03:00
task - > tk_timeouts + + ;
2005-04-17 02:20:36 +04:00
if ( RPC_IS_SOFT ( task ) ) {
2006-01-03 11:55:52 +03:00
printk ( KERN_NOTICE " %s: server %s not responding, timed out \n " ,
2005-04-17 02:20:36 +04:00
clnt - > cl_protname , clnt - > cl_server ) ;
rpc_exit ( task , - EIO ) ;
return ;
}
2006-01-03 11:55:52 +03:00
if ( ! ( task - > tk_flags & RPC_CALL_MAJORSEEN ) ) {
2005-04-17 02:20:36 +04:00
task - > tk_flags | = RPC_CALL_MAJORSEEN ;
printk ( KERN_NOTICE " %s: server %s not responding, still trying \n " ,
clnt - > cl_protname , clnt - > cl_server ) ;
}
2006-01-03 11:55:50 +03:00
rpc_force_rebind ( clnt ) ;
2005-04-17 02:20:36 +04:00
retry :
clnt - > cl_stats - > rpcretrans + + ;
task - > tk_action = call_bind ;
task - > tk_status = 0 ;
}
/*
* 7. Decode the RPC reply
*/
static void
call_decode ( struct rpc_task * task )
{
struct rpc_clnt * clnt = task - > tk_client ;
struct rpc_rqst * req = task - > tk_rqstp ;
kxdrproc_t decode = task - > tk_msg . rpc_proc - > p_decode ;
2006-09-27 09:29:38 +04:00
__be32 * p ;
2005-04-17 02:20:36 +04:00
2007-01-31 20:14:08 +03:00
dprintk ( " RPC: %5u call_decode (status %d) \n " ,
task - > tk_pid , task - > tk_status ) ;
2005-04-17 02:20:36 +04:00
2006-01-03 11:55:52 +03:00
if ( task - > tk_flags & RPC_CALL_MAJORSEEN ) {
2005-04-17 02:20:36 +04:00
printk ( KERN_NOTICE " %s: server %s OK \n " ,
clnt - > cl_protname , clnt - > cl_server ) ;
task - > tk_flags & = ~ RPC_CALL_MAJORSEEN ;
}
if ( task - > tk_status < 12 ) {
if ( ! RPC_IS_SOFT ( task ) ) {
task - > tk_action = call_bind ;
clnt - > cl_stats - > rpcretrans + + ;
goto out_retry ;
}
2007-01-31 20:14:08 +03:00
dprintk ( " RPC: %s: too small RPC reply size (%d bytes) \n " ,
clnt - > cl_protname , task - > tk_status ) ;
2006-08-31 23:44:52 +04:00
task - > tk_action = call_timeout ;
goto out_retry ;
2005-04-17 02:20:36 +04:00
}
2006-03-20 21:44:51 +03:00
/*
* Ensure that we see all writes made by xprt_complete_rqst ( )
* before it changed req - > rq_received .
*/
smp_rmb ( ) ;
2005-04-17 02:20:36 +04:00
req - > rq_rcv_buf . len = req - > rq_private_buf . len ;
/* Check that the softirq receive buffer is valid */
WARN_ON ( memcmp ( & req - > rq_rcv_buf , & req - > rq_private_buf ,
sizeof ( req - > rq_rcv_buf ) ) ! = 0 ) ;
/* Verify the RPC header */
2006-01-03 11:55:03 +03:00
p = call_verify ( task ) ;
if ( IS_ERR ( p ) ) {
if ( p = = ERR_PTR ( - EAGAIN ) )
goto out_retry ;
return ;
2005-04-17 02:20:36 +04:00
}
2006-01-03 11:55:03 +03:00
task - > tk_action = rpc_exit_task ;
2005-04-17 02:20:36 +04:00
2006-10-19 00:01:06 +04:00
if ( decode ) {
2005-04-17 02:20:36 +04:00
task - > tk_status = rpcauth_unwrap_resp ( task , decode , req , p ,
task - > tk_msg . rpc_resp ) ;
2006-10-19 00:01:06 +04:00
}
2007-01-31 20:14:08 +03:00
dprintk ( " RPC: %5u call_decode result %d \n " , task - > tk_pid ,
task - > tk_status ) ;
2005-04-17 02:20:36 +04:00
return ;
out_retry :
req - > rq_received = req - > rq_private_buf . len = 0 ;
task - > tk_status = 0 ;
2007-04-21 00:12:55 +04:00
if ( task - > tk_client - > cl_discrtry )
2007-11-07 02:40:12 +03:00
xprt_force_disconnect ( task - > tk_xprt ) ;
2005-04-17 02:20:36 +04:00
}
/*
* 8. Refresh the credentials if rejected by the server
*/
static void
call_refresh ( struct rpc_task * task )
{
2007-01-31 20:14:08 +03:00
dprint_status ( task ) ;
2005-04-17 02:20:36 +04:00
task - > tk_action = call_refreshresult ;
task - > tk_status = 0 ;
task - > tk_client - > cl_stats - > rpcauthrefresh + + ;
rpcauth_refreshcred ( task ) ;
}
/*
* 8 a . Process the results of a credential refresh
*/
static void
call_refreshresult ( struct rpc_task * task )
{
int status = task - > tk_status ;
2007-01-31 20:14:08 +03:00
dprint_status ( task ) ;
2005-04-17 02:20:36 +04:00
task - > tk_status = 0 ;
task - > tk_action = call_reserve ;
if ( status > = 0 & & rpcauth_uptodatecred ( task ) )
return ;
if ( status = = - EACCES ) {
rpc_exit ( task , - EACCES ) ;
return ;
}
task - > tk_action = call_refresh ;
if ( status ! = - ETIMEDOUT )
rpc_delay ( task , 3 * HZ ) ;
return ;
}
/*
* Call header serialization
*/
2006-09-27 09:29:38 +04:00
static __be32 *
2005-04-17 02:20:36 +04:00
call_header ( struct rpc_task * task )
{
struct rpc_clnt * clnt = task - > tk_client ;
struct rpc_rqst * req = task - > tk_rqstp ;
2006-09-27 09:29:38 +04:00
__be32 * p = req - > rq_svec [ 0 ] . iov_base ;
2005-04-17 02:20:36 +04:00
/* FIXME: check buffer size? */
2005-08-26 03:25:49 +04:00
p = xprt_skip_transport_header ( task - > tk_xprt , p ) ;
2005-04-17 02:20:36 +04:00
* p + + = req - > rq_xid ; /* XID */
* p + + = htonl ( RPC_CALL ) ; /* CALL */
* p + + = htonl ( RPC_VERSION ) ; /* RPC version */
* p + + = htonl ( clnt - > cl_prog ) ; /* program number */
* p + + = htonl ( clnt - > cl_vers ) ; /* program version */
* p + + = htonl ( task - > tk_msg . rpc_proc - > p_proc ) ; /* procedure */
2005-06-22 21:16:19 +04:00
p = rpcauth_marshcred ( task , p ) ;
req - > rq_slen = xdr_adjust_iovec ( & req - > rq_svec [ 0 ] , p ) ;
return p ;
2005-04-17 02:20:36 +04:00
}
/*
* Reply header verification
*/
2006-09-27 09:29:38 +04:00
static __be32 *
2005-04-17 02:20:36 +04:00
call_verify ( struct rpc_task * task )
{
struct kvec * iov = & task - > tk_rqstp - > rq_rcv_buf . head [ 0 ] ;
int len = task - > tk_rqstp - > rq_rcv_buf . len > > 2 ;
2006-09-27 09:29:38 +04:00
__be32 * p = iov - > iov_base ;
u32 n ;
2005-04-17 02:20:36 +04:00
int error = - EACCES ;
2006-08-24 23:44:19 +04:00
if ( ( task - > tk_rqstp - > rq_rcv_buf . len & 3 ) ! = 0 ) {
/* RFC-1014 says that the representation of XDR data must be a
* multiple of four bytes
* - if it isn ' t pointer subtraction in the NFS client may give
* undefined results
*/
2007-06-28 02:30:26 +04:00
dprintk ( " RPC: %5u %s: XDR representation not a multiple of "
" 4 bytes: 0x%x \n " , task - > tk_pid , __FUNCTION__ ,
task - > tk_rqstp - > rq_rcv_buf . len ) ;
2006-08-24 23:44:19 +04:00
goto out_eio ;
}
2005-04-17 02:20:36 +04:00
if ( ( len - = 3 ) < 0 )
goto out_overflow ;
p + = 1 ; /* skip XID */
if ( ( n = ntohl ( * p + + ) ) ! = RPC_REPLY ) {
2007-06-28 02:30:26 +04:00
dprintk ( " RPC: %5u %s: not an RPC reply: %x \n " ,
task - > tk_pid , __FUNCTION__ , n ) ;
2006-01-03 11:55:03 +03:00
goto out_garbage ;
2005-04-17 02:20:36 +04:00
}
if ( ( n = ntohl ( * p + + ) ) ! = RPC_MSG_ACCEPTED ) {
if ( - - len < 0 )
goto out_overflow ;
switch ( ( n = ntohl ( * p + + ) ) ) {
case RPC_AUTH_ERROR :
break ;
case RPC_MISMATCH :
2007-01-31 20:14:08 +03:00
dprintk ( " RPC: %5u %s: RPC call version "
" mismatch! \n " ,
task - > tk_pid , __FUNCTION__ ) ;
2005-06-22 21:16:23 +04:00
error = - EPROTONOSUPPORT ;
goto out_err ;
2005-04-17 02:20:36 +04:00
default :
2007-01-31 20:14:08 +03:00
dprintk ( " RPC: %5u %s: RPC call rejected, "
" unknown error: %x \n " ,
task - > tk_pid , __FUNCTION__ , n ) ;
2005-04-17 02:20:36 +04:00
goto out_eio ;
}
if ( - - len < 0 )
goto out_overflow ;
switch ( ( n = ntohl ( * p + + ) ) ) {
case RPC_AUTH_REJECTEDCRED :
case RPC_AUTH_REJECTEDVERF :
case RPCSEC_GSS_CREDPROBLEM :
case RPCSEC_GSS_CTXPROBLEM :
if ( ! task - > tk_cred_retry )
break ;
task - > tk_cred_retry - - ;
2007-01-31 20:14:08 +03:00
dprintk ( " RPC: %5u %s: retry stale creds \n " ,
task - > tk_pid , __FUNCTION__ ) ;
2005-04-17 02:20:36 +04:00
rpcauth_invalcred ( task ) ;
2007-10-01 20:06:48 +04:00
/* Ensure we obtain a new XID! */
xprt_release ( task ) ;
2005-04-17 02:20:36 +04:00
task - > tk_action = call_refresh ;
2006-01-03 11:55:03 +03:00
goto out_retry ;
2005-04-17 02:20:36 +04:00
case RPC_AUTH_BADCRED :
case RPC_AUTH_BADVERF :
/* possibly garbled cred/verf? */
if ( ! task - > tk_garb_retry )
break ;
task - > tk_garb_retry - - ;
2007-01-31 20:14:08 +03:00
dprintk ( " RPC: %5u %s: retry garbled creds \n " ,
task - > tk_pid , __FUNCTION__ ) ;
2005-04-17 02:20:36 +04:00
task - > tk_action = call_bind ;
2006-01-03 11:55:03 +03:00
goto out_retry ;
2005-04-17 02:20:36 +04:00
case RPC_AUTH_TOOWEAK :
2006-03-20 21:44:11 +03:00
printk ( KERN_NOTICE " call_verify: server %s requires stronger "
" authentication. \n " , task - > tk_client - > cl_server ) ;
2005-04-17 02:20:36 +04:00
break ;
default :
2007-06-28 02:30:26 +04:00
dprintk ( " RPC: %5u %s: unknown auth error: %x \n " ,
task - > tk_pid , __FUNCTION__ , n ) ;
2005-04-17 02:20:36 +04:00
error = - EIO ;
}
2007-01-31 20:14:08 +03:00
dprintk ( " RPC: %5u %s: call rejected %d \n " ,
task - > tk_pid , __FUNCTION__ , n ) ;
2005-04-17 02:20:36 +04:00
goto out_err ;
}
if ( ! ( p = rpcauth_checkverf ( task , p ) ) ) {
2007-06-28 02:30:26 +04:00
dprintk ( " RPC: %5u %s: auth check failed \n " ,
task - > tk_pid , __FUNCTION__ ) ;
2006-01-03 11:55:03 +03:00
goto out_garbage ; /* bad verifier, retry */
2005-04-17 02:20:36 +04:00
}
2006-09-27 09:29:38 +04:00
len = p - ( __be32 * ) iov - > iov_base - 1 ;
2005-04-17 02:20:36 +04:00
if ( len < 0 )
goto out_overflow ;
switch ( ( n = ntohl ( * p + + ) ) ) {
case RPC_SUCCESS :
return p ;
case RPC_PROG_UNAVAIL :
2007-01-31 20:14:08 +03:00
dprintk ( " RPC: %5u %s: program %u is unsupported by server %s \n " ,
task - > tk_pid , __FUNCTION__ ,
2005-04-17 02:20:36 +04:00
( unsigned int ) task - > tk_client - > cl_prog ,
task - > tk_client - > cl_server ) ;
2005-06-22 21:16:23 +04:00
error = - EPFNOSUPPORT ;
goto out_err ;
2005-04-17 02:20:36 +04:00
case RPC_PROG_MISMATCH :
2007-01-31 20:14:08 +03:00
dprintk ( " RPC: %5u %s: program %u, version %u unsupported by "
" server %s \n " , task - > tk_pid , __FUNCTION__ ,
2005-04-17 02:20:36 +04:00
( unsigned int ) task - > tk_client - > cl_prog ,
( unsigned int ) task - > tk_client - > cl_vers ,
task - > tk_client - > cl_server ) ;
2005-06-22 21:16:23 +04:00
error = - EPROTONOSUPPORT ;
goto out_err ;
2005-04-17 02:20:36 +04:00
case RPC_PROC_UNAVAIL :
2007-01-31 20:14:08 +03:00
dprintk ( " RPC: %5u %s: proc %p unsupported by program %u, "
" version %u on server %s \n " ,
task - > tk_pid , __FUNCTION__ ,
2005-04-17 02:20:36 +04:00
task - > tk_msg . rpc_proc ,
task - > tk_client - > cl_prog ,
task - > tk_client - > cl_vers ,
task - > tk_client - > cl_server ) ;
2005-06-22 21:16:23 +04:00
error = - EOPNOTSUPP ;
goto out_err ;
2005-04-17 02:20:36 +04:00
case RPC_GARBAGE_ARGS :
2007-01-31 20:14:08 +03:00
dprintk ( " RPC: %5u %s: server saw garbage \n " ,
task - > tk_pid , __FUNCTION__ ) ;
2005-04-17 02:20:36 +04:00
break ; /* retry */
default :
2007-06-28 02:30:26 +04:00
dprintk ( " RPC: %5u %s: server accept status: %x \n " ,
task - > tk_pid , __FUNCTION__ , n ) ;
2005-04-17 02:20:36 +04:00
/* Also retry */
}
2006-01-03 11:55:03 +03:00
out_garbage :
2005-04-17 02:20:36 +04:00
task - > tk_client - > cl_stats - > rpcgarbage + + ;
if ( task - > tk_garb_retry ) {
task - > tk_garb_retry - - ;
2007-01-31 20:14:08 +03:00
dprintk ( " RPC: %5u %s: retrying \n " ,
task - > tk_pid , __FUNCTION__ ) ;
2005-04-17 02:20:36 +04:00
task - > tk_action = call_bind ;
2006-01-03 11:55:03 +03:00
out_retry :
return ERR_PTR ( - EAGAIN ) ;
2005-04-17 02:20:36 +04:00
}
out_eio :
error = - EIO ;
out_err :
rpc_exit ( task , error ) ;
2007-06-28 02:30:26 +04:00
dprintk ( " RPC: %5u %s: call failed with error %d \n " , task - > tk_pid ,
__FUNCTION__ , error ) ;
2006-01-03 11:55:03 +03:00
return ERR_PTR ( error ) ;
2005-04-17 02:20:36 +04:00
out_overflow :
2007-06-28 02:30:26 +04:00
dprintk ( " RPC: %5u %s: server reply was truncated. \n " , task - > tk_pid ,
__FUNCTION__ ) ;
2006-01-03 11:55:03 +03:00
goto out_garbage ;
2005-04-17 02:20:36 +04:00
}
2005-06-22 21:16:20 +04:00
2006-09-27 09:29:38 +04:00
static int rpcproc_encode_null ( void * rqstp , __be32 * data , void * obj )
2005-06-22 21:16:20 +04:00
{
return 0 ;
}
2006-09-27 09:29:38 +04:00
static int rpcproc_decode_null ( void * rqstp , __be32 * data , void * obj )
2005-06-22 21:16:20 +04:00
{
return 0 ;
}
static struct rpc_procinfo rpcproc_null = {
. p_encode = rpcproc_encode_null ,
. p_decode = rpcproc_decode_null ,
} ;
2007-06-23 18:17:16 +04:00
static int rpc_ping ( struct rpc_clnt * clnt , int flags )
2005-06-22 21:16:20 +04:00
{
struct rpc_message msg = {
. rpc_proc = & rpcproc_null ,
} ;
int err ;
msg . rpc_cred = authnull_ops . lookup_cred ( NULL , NULL , 0 ) ;
err = rpc_call_sync ( clnt , & msg , flags ) ;
put_rpccred ( msg . rpc_cred ) ;
return err ;
}
2007-06-16 22:18:40 +04:00
2007-06-23 18:17:16 +04:00
struct rpc_task * rpc_call_null ( struct rpc_clnt * clnt , struct rpc_cred * cred , int flags )
{
struct rpc_message msg = {
. rpc_proc = & rpcproc_null ,
. rpc_cred = cred ,
} ;
2007-07-14 23:39:59 +04:00
struct rpc_task_setup task_setup_data = {
. rpc_client = clnt ,
. rpc_message = & msg ,
. callback_ops = & rpc_default_ops ,
. flags = flags ,
} ;
2007-07-14 23:39:59 +04:00
return rpc_run_task ( & task_setup_data ) ;
2007-06-23 18:17:16 +04:00
}
2007-07-14 23:39:59 +04:00
EXPORT_SYMBOL_GPL ( rpc_call_null ) ;
2007-06-23 18:17:16 +04:00
2007-06-16 22:18:40 +04:00
# ifdef RPC_DEBUG
void rpc_show_tasks ( void )
{
struct rpc_clnt * clnt ;
struct rpc_task * t ;
spin_lock ( & rpc_client_lock ) ;
if ( list_empty ( & all_clients ) )
goto out ;
printk ( " -pid- proc flgs status -client- -prog- --rqstp- -timeout "
" -rpcwait -action- ---ops-- \n " ) ;
list_for_each_entry ( clnt , & all_clients , cl_clients ) {
if ( list_empty ( & clnt - > cl_tasks ) )
continue ;
spin_lock ( & clnt - > cl_lock ) ;
list_for_each_entry ( t , & clnt - > cl_tasks , tk_task ) {
const char * rpc_waitq = " none " ;
2007-09-12 02:00:25 +04:00
int proc ;
if ( t - > tk_msg . rpc_proc )
proc = t - > tk_msg . rpc_proc - > p_proc ;
else
proc = - 1 ;
2007-06-16 22:18:40 +04:00
if ( RPC_IS_QUEUED ( t ) )
rpc_waitq = rpc_qname ( t - > u . tk_wait . rpc_waitq ) ;
printk ( " %5u %04d %04x %6d %8p %6d %8p %8ld %8s %8p %8p \n " ,
2007-09-12 02:00:25 +04:00
t - > tk_pid , proc ,
2007-06-16 22:18:40 +04:00
t - > tk_flags , t - > tk_status ,
t - > tk_client ,
( t - > tk_client ? t - > tk_client - > cl_prog : 0 ) ,
t - > tk_rqstp , t - > tk_timeout ,
rpc_waitq ,
t - > tk_action , t - > tk_ops ) ;
}
spin_unlock ( & clnt - > cl_lock ) ;
}
out :
spin_unlock ( & rpc_client_lock ) ;
}
# endif