2005-04-17 02:20:36 +04:00
/*
* linux / fs / lockd / mon . c
*
* The kernel statd client .
*
* Copyright ( C ) 1996 , Olaf Kirch < okir @ monad . swb . de >
*/
# include <linux/types.h>
# include <linux/utsname.h>
# include <linux/kernel.h>
# include <linux/sunrpc/clnt.h>
2007-09-10 21:48:23 +04:00
# include <linux/sunrpc/xprtsock.h>
2005-04-17 02:20:36 +04:00
# include <linux/sunrpc/svc.h>
# include <linux/lockd/lockd.h>
# include <linux/lockd/sm_inter.h>
# define NLMDBG_FACILITY NLMDBG_MONITOR
2008-03-14 21:25:39 +03:00
# define XDR_ADDRBUF_LEN (20)
2005-04-17 02:20:36 +04:00
static struct rpc_clnt * nsm_create ( void ) ;
static struct rpc_program nsm_program ;
/*
* Local NSM state
*/
2006-10-04 13:16:03 +04:00
int nsm_local_state ;
2005-04-17 02:20:36 +04:00
/*
* Common procedure for SM_MON / SM_UNMON calls
*/
static int
2006-10-04 13:15:56 +04:00
nsm_mon_unmon ( struct nsm_handle * nsm , u32 proc , struct nsm_res * res )
2005-04-17 02:20:36 +04:00
{
struct rpc_clnt * clnt ;
int status ;
struct nsm_args args ;
2006-03-20 21:44:23 +03:00
struct rpc_message msg = {
. rpc_argp = & args ,
. rpc_resp = res ,
} ;
2005-04-17 02:20:36 +04:00
clnt = nsm_create ( ) ;
if ( IS_ERR ( clnt ) ) {
status = PTR_ERR ( clnt ) ;
goto out ;
}
2006-10-04 13:15:56 +04:00
memset ( & args , 0 , sizeof ( args ) ) ;
2006-10-04 13:16:01 +04:00
args . mon_name = nsm - > sm_name ;
2008-09-03 22:35:54 +04:00
args . addr = nsm_addr_in ( nsm ) - > sin_addr . s_addr ;
2005-04-17 02:20:36 +04:00
args . prog = NLM_PROGRAM ;
2006-10-04 13:15:56 +04:00
args . vers = 3 ;
2005-04-17 02:20:36 +04:00
args . proc = NLMPROC_NSM_NOTIFY ;
memset ( res , 0 , sizeof ( * res ) ) ;
2006-03-20 21:44:23 +03:00
msg . rpc_proc = & clnt - > cl_procinfo [ proc ] ;
status = rpc_call_sync ( clnt , & msg , 0 ) ;
2005-04-17 02:20:36 +04:00
if ( status < 0 )
printk ( KERN_DEBUG " nsm_mon_unmon: rpc failed, status=%d \n " ,
status ) ;
else
status = 0 ;
2007-06-10 03:49:36 +04:00
rpc_shutdown_client ( clnt ) ;
2005-04-17 02:20:36 +04:00
out :
return status ;
}
/*
* Set up monitoring of a remote host
*/
int
nsm_monitor ( struct nlm_host * host )
{
2006-10-04 13:15:53 +04:00
struct nsm_handle * nsm = host - > h_nsmhandle ;
2005-04-17 02:20:36 +04:00
struct nsm_res res ;
int status ;
dprintk ( " lockd: nsm_monitor(%s) \n " , host - > h_name ) ;
2006-10-04 13:15:53 +04:00
BUG_ON ( nsm = = NULL ) ;
if ( nsm - > sm_monitored )
2006-10-04 13:15:51 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
2006-10-04 13:15:56 +04:00
status = nsm_mon_unmon ( nsm , SM_MON , & res ) ;
2005-04-17 02:20:36 +04:00
if ( status < 0 | | res . status ! = 0 )
printk ( KERN_NOTICE " lockd: cannot monitor %s \n " , host - > h_name ) ;
else
2006-10-04 13:15:53 +04:00
nsm - > sm_monitored = 1 ;
2005-04-17 02:20:36 +04:00
return status ;
}
/*
* Cease to monitor remote host
*/
int
nsm_unmonitor ( struct nlm_host * host )
{
2006-10-04 13:15:53 +04:00
struct nsm_handle * nsm = host - > h_nsmhandle ;
2005-04-17 02:20:36 +04:00
struct nsm_res res ;
2006-10-04 13:15:51 +04:00
int status = 0 ;
2005-04-17 02:20:36 +04:00
2006-10-04 13:15:53 +04:00
if ( nsm = = NULL )
2006-10-04 13:15:51 +04:00
return 0 ;
2006-10-04 13:15:53 +04:00
host - > h_nsmhandle = NULL ;
2006-10-04 13:15:51 +04:00
2006-10-04 13:15:56 +04:00
if ( atomic_read ( & nsm - > sm_count ) = = 1
& & nsm - > sm_monitored & & ! nsm - > sm_sticky ) {
dprintk ( " lockd: nsm_unmonitor(%s) \n " , host - > h_name ) ;
status = nsm_mon_unmon ( nsm , SM_UNMON , & res ) ;
2006-10-04 13:15:51 +04:00
if ( status < 0 )
2006-10-04 13:15:56 +04:00
printk ( KERN_NOTICE " lockd: cannot unmonitor %s \n " ,
host - > h_name ) ;
else
nsm - > sm_monitored = 0 ;
2006-10-04 13:15:51 +04:00
}
2006-10-04 13:15:53 +04:00
nsm_release ( nsm ) ;
2005-04-17 02:20:36 +04:00
return status ;
}
/*
* Create NSM client for the local host
*/
static struct rpc_clnt *
nsm_create ( void )
{
2006-08-23 04:06:20 +04:00
struct sockaddr_in sin = {
. sin_family = AF_INET ,
. sin_addr . s_addr = htonl ( INADDR_LOOPBACK ) ,
. sin_port = 0 ,
} ;
struct rpc_create_args args = {
2007-09-10 21:48:23 +04:00
. protocol = XPRT_TRANSPORT_UDP ,
2006-08-23 04:06:20 +04:00
. address = ( struct sockaddr * ) & sin ,
. addrsize = sizeof ( sin ) ,
. servername = " localhost " ,
. program = & nsm_program ,
. version = SM_VERSION ,
. authflavor = RPC_AUTH_NULL ,
} ;
return rpc_create ( & args ) ;
2005-04-17 02:20:36 +04:00
}
/*
* XDR functions for NSM .
2008-03-14 21:26:01 +03:00
*
* See http : //www.opengroup.org/ for details on the Network
* Status Monitor wire protocol .
2005-04-17 02:20:36 +04:00
*/
2008-03-14 21:25:32 +03:00
static __be32 * xdr_encode_nsm_string ( __be32 * p , char * string )
{
size_t len = strlen ( string ) ;
if ( len > SM_MAXSTRLEN )
len = SM_MAXSTRLEN ;
return xdr_encode_opaque ( p , string , len ) ;
}
2008-03-14 21:25:39 +03:00
/*
* " mon_name " specifies the host to be monitored .
*
* Linux uses a text version of the IP address of the remote
* host as the host identifier ( the " mon_name " argument ) .
*
* Linux statd always looks up the canonical hostname first for
* whatever remote hostname it receives , so this works alright .
*/
static __be32 * xdr_encode_mon_name ( __be32 * p , struct nsm_args * argp )
{
char buffer [ XDR_ADDRBUF_LEN + 1 ] ;
char * name = argp - > mon_name ;
if ( ! nsm_use_hostnames ) {
snprintf ( buffer , XDR_ADDRBUF_LEN ,
NIPQUAD_FMT , NIPQUAD ( argp - > addr ) ) ;
name = buffer ;
}
return xdr_encode_nsm_string ( p , name ) ;
}
2008-03-14 21:25:46 +03:00
/*
* The " my_id " argument specifies the hostname and RPC procedure
* to be called when the status manager receives notification
* ( via the SM_NOTIFY call ) that the state of host " mon_name "
* has changed .
*/
static __be32 * xdr_encode_my_id ( __be32 * p , struct nsm_args * argp )
{
p = xdr_encode_nsm_string ( p , utsname ( ) - > nodename ) ;
if ( ! p )
return ERR_PTR ( - EIO ) ;
* p + + = htonl ( argp - > prog ) ;
* p + + = htonl ( argp - > vers ) ;
* p + + = htonl ( argp - > proc ) ;
return p ;
}
2008-03-14 21:25:53 +03:00
/*
* The " mon_id " argument specifies the non - private arguments
* of an SM_MON or SM_UNMON call .
*/
static __be32 * xdr_encode_mon_id ( __be32 * p , struct nsm_args * argp )
{
p = xdr_encode_mon_name ( p , argp ) ;
if ( ! p )
return ERR_PTR ( - EIO ) ;
return xdr_encode_my_id ( p , argp ) ;
}
2008-03-14 21:26:08 +03:00
/*
* The " priv " argument may contain private information required
* by the SM_MON call . This information will be supplied in the
* SM_NOTIFY call .
*
* Linux provides the raw IP address of the monitored host ,
* left in network byte order .
*/
static __be32 * xdr_encode_priv ( __be32 * p , struct nsm_args * argp )
{
* p + + = argp - > addr ;
* p + + = 0 ;
* p + + = 0 ;
* p + + = 0 ;
return p ;
}
2005-04-17 02:20:36 +04:00
static int
2006-10-20 10:28:46 +04:00
xdr_encode_mon ( struct rpc_rqst * rqstp , __be32 * p , struct nsm_args * argp )
2005-04-17 02:20:36 +04:00
{
2008-03-14 21:26:01 +03:00
p = xdr_encode_mon_id ( p , argp ) ;
2005-04-17 02:20:36 +04:00
if ( IS_ERR ( p ) )
return PTR_ERR ( p ) ;
2006-10-04 13:15:56 +04:00
2008-03-14 21:26:08 +03:00
p = xdr_encode_priv ( p , argp ) ;
if ( IS_ERR ( p ) )
return PTR_ERR ( p ) ;
2005-04-17 02:20:36 +04:00
rqstp - > rq_slen = xdr_adjust_iovec ( rqstp - > rq_svec , p ) ;
return 0 ;
}
static int
2006-10-20 10:28:46 +04:00
xdr_encode_unmon ( struct rpc_rqst * rqstp , __be32 * p , struct nsm_args * argp )
2005-04-17 02:20:36 +04:00
{
2008-03-14 21:26:01 +03:00
p = xdr_encode_mon_id ( p , argp ) ;
2005-04-17 02:20:36 +04:00
if ( IS_ERR ( p ) )
return PTR_ERR ( p ) ;
rqstp - > rq_slen = xdr_adjust_iovec ( rqstp - > rq_svec , p ) ;
return 0 ;
}
static int
2006-10-20 10:28:46 +04:00
xdr_decode_stat_res ( struct rpc_rqst * rqstp , __be32 * p , struct nsm_res * resp )
2005-04-17 02:20:36 +04:00
{
resp - > status = ntohl ( * p + + ) ;
resp - > state = ntohl ( * p + + ) ;
dprintk ( " nsm: xdr_decode_stat_res status %d state %d \n " ,
resp - > status , resp - > state ) ;
return 0 ;
}
static int
2006-10-20 10:28:46 +04:00
xdr_decode_stat ( struct rpc_rqst * rqstp , __be32 * p , struct nsm_res * resp )
2005-04-17 02:20:36 +04:00
{
resp - > state = ntohl ( * p + + ) ;
return 0 ;
}
# define SM_my_name_sz (1+XDR_QUADLEN(SM_MAXSTRLEN))
2008-03-14 21:26:01 +03:00
# define SM_my_id_sz (SM_my_name_sz+3)
# define SM_mon_name_sz (1+XDR_QUADLEN(SM_MAXSTRLEN))
# define SM_mon_id_sz (SM_mon_name_sz+SM_my_id_sz)
2008-03-14 21:26:08 +03:00
# define SM_priv_sz (XDR_QUADLEN(SM_PRIV_SIZE))
# define SM_mon_sz (SM_mon_id_sz+SM_priv_sz)
2005-04-17 02:20:36 +04:00
# define SM_monres_sz 2
# define SM_unmonres_sz 1
static struct rpc_procinfo nsm_procedures [ ] = {
[ SM_MON ] = {
. p_proc = SM_MON ,
. p_encode = ( kxdrproc_t ) xdr_encode_mon ,
. p_decode = ( kxdrproc_t ) xdr_decode_stat_res ,
2007-03-30 00:47:53 +04:00
. p_arglen = SM_mon_sz ,
. p_replen = SM_monres_sz ,
2006-03-20 21:44:22 +03:00
. p_statidx = SM_MON ,
. p_name = " MONITOR " ,
2005-04-17 02:20:36 +04:00
} ,
[ SM_UNMON ] = {
. p_proc = SM_UNMON ,
. p_encode = ( kxdrproc_t ) xdr_encode_unmon ,
. p_decode = ( kxdrproc_t ) xdr_decode_stat ,
2007-03-30 00:47:53 +04:00
. p_arglen = SM_mon_id_sz ,
. p_replen = SM_unmonres_sz ,
2006-03-20 21:44:22 +03:00
. p_statidx = SM_UNMON ,
. p_name = " UNMONITOR " ,
2005-04-17 02:20:36 +04:00
} ,
} ;
static struct rpc_version nsm_version1 = {
2006-03-24 14:15:34 +03:00
. number = 1 ,
. nrprocs = ARRAY_SIZE ( nsm_procedures ) ,
2005-04-17 02:20:36 +04:00
. procs = nsm_procedures
} ;
static struct rpc_version * nsm_version [ ] = {
[ 1 ] = & nsm_version1 ,
} ;
static struct rpc_stat nsm_stats ;
static struct rpc_program nsm_program = {
. name = " statd " ,
. number = SM_PROGRAM ,
2006-03-24 14:15:34 +03:00
. nrvers = ARRAY_SIZE ( nsm_version ) ,
2005-04-17 02:20:36 +04:00
. version = nsm_version ,
. stats = & nsm_stats
} ;