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>
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 )
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
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
}
}
2006-08-23 04:06:21 +04:00
static struct rpc_clnt * rpc_new_client ( struct rpc_xprt * xprt , char * servname , struct rpc_program * program , u32 vers , rpc_authflavor_t flavor )
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 ;
int len ;
2007-01-31 20:14:08 +03:00
dprintk ( " RPC: creating %s client for %s (xprt %p) \n " ,
program - > name , servname , xprt ) ;
2005-04-17 02:20:36 +04:00
err = - EINVAL ;
if ( ! xprt )
2006-03-14 08:20:47 +03:00
goto out_no_xprt ;
2005-04-17 02:20:36 +04:00
if ( vers > = program - > nrvers | | ! ( version = program - > version [ vers ] ) )
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 ;
len = strlen ( servname ) + 1 ;
if ( len > sizeof ( clnt - > cl_inline_name ) ) {
char * buf = kmalloc ( len , GFP_KERNEL ) ;
if ( buf ! = 0 )
clnt - > cl_server = buf ;
else
len = sizeof ( clnt - > cl_inline_name ) ;
}
strlcpy ( clnt - > cl_server , servname , len ) ;
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 ;
clnt - > cl_rtt = & clnt - > cl_rtt_default ;
rpc_init_rtt ( & clnt - > cl_rtt_default , xprt - > timeout . to_initval ) ;
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 ;
2005-06-22 21:16:23 +04:00
auth = rpcauth_create ( flavor , clnt ) ;
if ( IS_ERR ( auth ) ) {
2005-04-17 02:20:36 +04:00
printk ( KERN_INFO " RPC: Couldn't create auth handle (flavor %u) \n " ,
flavor ) ;
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 :
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 ;
xprt = xprt_create_transport ( args - > protocol , args - > address ,
args - > addrsize , args - > timeout ) ;
if ( IS_ERR ( xprt ) )
return ( struct rpc_clnt * ) xprt ;
/*
* 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 ;
dprintk ( " RPC: creating %s client for %s (xprt %p) \n " ,
2007-01-31 20:14:08 +03:00
args - > program - > name , args - > servername , xprt ) ;
2006-08-23 04:06:20 +04:00
clnt = rpc_new_client ( xprt , args - > servername , args - > program ,
args - > version , args - > authflavor ) ;
if ( IS_ERR ( clnt ) )
return clnt ;
if ( ! ( args - > flags & RPC_CLNT_CREATE_NOPING ) ) {
int err = rpc_ping ( clnt , RPC_TASK_SOFT | RPC_TASK_NOINTR ) ;
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_INTR )
clnt - > cl_intr = 1 ;
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 ;
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
new - > cl_parent = clnt ;
2007-06-15 00:40:32 +04:00
kref_get ( & clnt - > cl_kref ) ;
2006-09-05 20:55:57 +04:00
new - > cl_xprt = xprt_get ( clnt - > cl_xprt ) ;
2005-04-17 02:20:36 +04:00
/* Turn off autobind on clones */
new - > cl_autobind = 0 ;
2007-06-15 00:40:14 +04:00
INIT_LIST_HEAD ( & new - > cl_tasks ) ;
2007-06-16 22:17:01 +04:00
spin_lock_init ( & new - > cl_lock ) ;
2005-04-17 02:20:36 +04:00
rpc_init_rtt ( & new - > cl_rtt_default , clnt - > cl_xprt - > timeout . to_initval ) ;
if ( new - > cl_auth )
atomic_inc ( & new - > cl_auth - > au_count ) ;
2007-06-15 00:40:14 +04:00
rpc_register_client ( new ) ;
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
}
/*
* 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-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 ) ;
if ( clnt - > cl_auth ) {
rpcauth_destroy ( clnt - > cl_auth ) ;
clnt - > cl_auth = NULL ;
}
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 ) ;
2005-04-17 02:20:36 +04:00
kfree ( clnt ) ;
}
/*
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 ) ;
kref_put ( & clnt - > cl_kref , rpc_free_client ) ;
}
2005-06-22 21:16:23 +04:00
/**
* rpc_bind_new_program - bind a new RPC program to an existing client
* @ old - old rpc_client
* @ program - rpc program to set
* @ vers - rpc program version
*
* 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 ,
int vers )
{
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 ;
err = rpc_ping ( clnt , RPC_TASK_SOFT | RPC_TASK_NOINTR ) ;
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 ;
}
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 ,
} ;
2005-04-17 02:20:36 +04:00
/*
2005-06-22 21:16:28 +04:00
* Export the signal mask handling for synchronous code that
2005-04-17 02:20:36 +04:00
* sleeps on RPC calls
*/
2006-01-03 11:55:19 +03:00
# define RPC_INTR_SIGNALS (sigmask(SIGHUP) | sigmask(SIGINT) | sigmask(SIGQUIT) | sigmask(SIGTERM))
2007-02-10 02:38:13 +03:00
2005-06-22 21:16:28 +04:00
static void rpc_save_sigmask ( sigset_t * oldset , int intr )
{
2006-01-03 11:55:19 +03:00
unsigned long sigallow = sigmask ( SIGKILL ) ;
2005-06-22 21:16:28 +04:00
sigset_t sigmask ;
/* Block all signals except those listed in sigallow */
if ( intr )
sigallow | = RPC_INTR_SIGNALS ;
siginitsetinv ( & sigmask , sigallow ) ;
sigprocmask ( SIG_BLOCK , & sigmask , oldset ) ;
}
static inline void rpc_task_sigmask ( struct rpc_task * task , sigset_t * oldset )
{
rpc_save_sigmask ( oldset , ! RPC_TASK_UNINTERRUPTIBLE ( task ) ) ;
}
static inline void rpc_restore_sigmask ( sigset_t * oldset )
{
sigprocmask ( SIG_SETMASK , oldset , NULL ) ;
}
2005-04-17 02:20:36 +04:00
void rpc_clnt_sigmask ( struct rpc_clnt * clnt , sigset_t * oldset )
{
2005-06-22 21:16:28 +04:00
rpc_save_sigmask ( oldset , clnt - > cl_intr ) ;
2005-04-17 02:20:36 +04:00
}
void rpc_clnt_sigunmask ( struct rpc_clnt * clnt , sigset_t * oldset )
{
2005-06-22 21:16:28 +04:00
rpc_restore_sigmask ( oldset ) ;
2005-04-17 02:20:36 +04:00
}
/*
* New rpc_call implementation
*/
int rpc_call_sync ( struct rpc_clnt * clnt , struct rpc_message * msg , int flags )
{
struct rpc_task * task ;
sigset_t oldset ;
int status ;
BUG_ON ( flags & RPC_TASK_ASYNC ) ;
2006-01-03 11:55:04 +03:00
task = rpc_new_task ( clnt , flags , & rpc_default_ops , NULL ) ;
2005-04-17 02:20:36 +04:00
if ( task = = NULL )
2006-11-12 06:18:03 +03:00
return - ENOMEM ;
2005-04-17 02:20:36 +04:00
2005-06-22 21:16:28 +04:00
/* Mask signals on RPC calls _and_ GSS_AUTH upcalls */
rpc_task_sigmask ( task , & oldset ) ;
2005-04-17 02:20:36 +04:00
/* Set up the call info struct and execute the task */
2007-02-04 00:38:41 +03:00
rpc_call_setup ( task , msg , 0 ) ;
if ( task - > tk_status = = 0 ) {
atomic_inc ( & task - > tk_count ) ;
rpc_execute ( 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 ) ;
2006-11-12 06:18:03 +03:00
rpc_restore_sigmask ( & oldset ) ;
2005-04-17 02:20:36 +04:00
return status ;
}
/*
* New rpc_call implementation
*/
int
rpc_call_async ( struct rpc_clnt * clnt , 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 ;
sigset_t oldset ;
int status ;
flags | = RPC_TASK_ASYNC ;
/* Create/initialize a new RPC task */
status = - ENOMEM ;
2006-01-03 11:55:04 +03:00
if ( ! ( task = rpc_new_task ( clnt , flags , tk_ops , data ) ) )
2006-03-21 02:11:10 +03:00
goto out_release ;
2005-04-17 02:20:36 +04:00
2005-06-22 21:16:28 +04:00
/* Mask signals on GSS_AUTH upcalls */
2007-02-10 02:38:13 +03:00
rpc_task_sigmask ( task , & oldset ) ;
2005-06-22 21:16:28 +04:00
2005-04-17 02:20:36 +04:00
rpc_call_setup ( task , msg , 0 ) ;
/* Set up the call info struct and execute the task */
status = task - > tk_status ;
if ( status = = 0 )
rpc_execute ( task ) ;
else
2007-01-24 22:54:53 +03:00
rpc_put_task ( task ) ;
2005-04-17 02:20:36 +04:00
2007-02-10 02:38:13 +03:00
rpc_restore_sigmask ( & oldset ) ;
2006-03-21 02:11:10 +03:00
return status ;
out_release :
2006-10-19 00:01:05 +04:00
rpc_release_calldata ( tk_ops , data ) ;
2005-04-17 02:20:36 +04:00
return status ;
}
void
rpc_call_setup ( struct rpc_task * task , struct rpc_message * msg , int flags )
{
task - > tk_msg = * msg ;
task - > tk_flags | = flags ;
/* Bind the user cred */
if ( task - > tk_msg . rpc_cred ! = NULL )
rpcauth_holdcred ( task ) ;
else
rpcauth_bindcred ( task ) ;
if ( task - > tk_status = = 0 )
task - > tk_action = call_start ;
else
2006-01-03 11:55:03 +03:00
task - > tk_action = rpc_exit_task ;
2005-04-17 02:20:36 +04:00
}
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
* @ size : length of target buffer
*
* 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
*
*/
char * rpc_peeraddr2str ( struct rpc_clnt * clnt , enum rpc_display_format_t format )
{
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
}
/*
* 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 ;
}
/*
* 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-03-30 00:47:53 +04:00
unsigned int slack = task - > tk_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 ( ) ) {
2005-04-17 02:20:36 +04:00
xprt_release ( task ) ;
task - > tk_action = call_reserve ;
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 ;
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 ;
2006-10-19 00:01:06 +04:00
lock_kernel ( ) ;
2005-10-14 00:54:48 +04:00
task - > tk_status = rpcauth_wrap_req ( task , encode , req , p ,
task - > tk_msg . rpc_argp ) ;
2006-10-19 00:01:06 +04:00
unlock_kernel ( ) ;
2005-10-14 00:54:48 +04:00
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 )
{
int status = - EACCES ;
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 ) {
case - EACCES :
2007-01-31 20:14:08 +03:00
dprintk ( " RPC: %5u remote rpcbind: RPC program/version "
" unavailable \n " , task - > tk_pid ) ;
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-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 ) ;
status = - EIO ;
}
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 )
xprt_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 ) {
lock_kernel ( ) ;
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
unlock_kernel ( ) ;
}
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 )
xprt_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
xprt_release ( task ) ; /* Must do to obtain new XID */
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
*/
printk ( KERN_WARNING
" call_verify: XDR representation not a multiple of "
" 4 bytes: 0x%x \n " , task - > tk_rqstp - > rq_rcv_buf . len ) ;
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 ) {
printk ( KERN_WARNING " call_verify: not an RPC reply: %x \n " , 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 ) ;
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 :
printk ( KERN_WARNING " call_verify: unknown auth error: %x \n " , n ) ;
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 ) ) ) {
printk ( KERN_WARNING " call_verify: auth check failed \n " ) ;
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 :
printk ( KERN_WARNING " call_verify: server accept status: %x \n " , n ) ;
/* 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
}
printk ( KERN_WARNING " RPC %s: retry failed, exit EIO \n " , __FUNCTION__ ) ;
out_eio :
error = - EIO ;
out_err :
rpc_exit ( task , error ) ;
2006-01-03 11:55:03 +03:00
return ERR_PTR ( error ) ;
2005-04-17 02:20:36 +04:00
out_overflow :
printk ( KERN_WARNING " RPC %s: server reply was truncated. \n " , __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 ,
} ;
int rpc_ping ( struct rpc_clnt * clnt , int flags )
{
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 ;
}