2005-04-17 02:20:36 +04:00
/*
* linux / fs / lockd / host . c
*
* Management for NLM peer hosts . The nlm_host struct is shared
* between client and server implementation . The only reason to
* do so is to reduce code bloat .
*
* Copyright ( C ) 1996 , Olaf Kirch < okir @ monad . swb . de >
*/
# include <linux/types.h>
# include <linux/slab.h>
# include <linux/in.h>
2008-08-28 00:57:23 +04:00
# include <linux/in6.h>
2005-04-17 02:20:36 +04:00
# include <linux/sunrpc/clnt.h>
# include <linux/sunrpc/svc.h>
# include <linux/lockd/lockd.h>
2006-03-26 13:37:12 +04:00
# include <linux/mutex.h>
2005-04-17 02:20:36 +04:00
2008-08-28 00:57:23 +04:00
# include <net/ipv6.h>
2005-04-17 02:20:36 +04:00
# define NLMDBG_FACILITY NLMDBG_HOSTCACHE
# define NLM_HOST_NRHASH 32
# define NLM_HOST_REBIND (60 * HZ)
2008-02-08 05:03:37 +03:00
# define NLM_HOST_EXPIRE (300 * HZ)
# define NLM_HOST_COLLECT (120 * HZ)
2005-04-17 02:20:36 +04:00
2006-10-04 13:15:56 +04:00
static struct hlist_head nlm_hosts [ NLM_HOST_NRHASH ] ;
2010-12-14 18:05:03 +03:00
# define for_each_host(host, pos, chain, table) \
for ( ( chain ) = ( table ) ; \
( chain ) < ( table ) + NLM_HOST_NRHASH ; + + ( chain ) ) \
hlist_for_each_entry ( ( host ) , ( pos ) , ( chain ) , h_hash )
# define for_each_host_safe(host, pos, next, chain, table) \
for ( ( chain ) = ( table ) ; \
( chain ) < ( table ) + NLM_HOST_NRHASH ; + + ( chain ) ) \
hlist_for_each_entry_safe ( ( host ) , ( pos ) , ( next ) , \
( chain ) , h_hash )
2005-04-17 02:20:36 +04:00
static unsigned long next_gc ;
static int nrhosts ;
2006-03-26 13:37:12 +04:00
static DEFINE_MUTEX ( nlm_host_mutex ) ;
2005-04-17 02:20:36 +04:00
static void nlm_gc_hosts ( void ) ;
2008-10-03 20:50:07 +04:00
struct nlm_lookup_host_info {
const int server ; /* search for server|client */
2008-10-03 20:50:14 +04:00
const struct sockaddr * sap ; /* address to search for */
const size_t salen ; /* it's length */
2008-10-03 20:50:07 +04:00
const unsigned short protocol ; /* transport to search for*/
const u32 version ; /* NLM version to search for */
const char * hostname ; /* remote's hostname */
const size_t hostname_len ; /* it's length */
2008-10-03 20:50:14 +04:00
const struct sockaddr * src_sap ; /* our address (optional) */
2008-10-03 20:50:07 +04:00
const size_t src_len ; /* it's length */
2008-12-23 23:21:38 +03:00
const int noresvport ; /* use non-priv port */
2008-10-03 20:50:07 +04:00
} ;
2008-09-03 22:36:08 +04:00
/*
* Hash function must work well on big - and little - endian platforms
*/
static unsigned int __nlm_hash32 ( const __be32 n )
{
unsigned int hash = ( __force u32 ) n ^ ( ( __force u32 ) n > > 16 ) ;
return hash ^ ( hash > > 8 ) ;
}
static unsigned int __nlm_hash_addr4 ( const struct sockaddr * sap )
{
const struct sockaddr_in * sin = ( struct sockaddr_in * ) sap ;
return __nlm_hash32 ( sin - > sin_addr . s_addr ) ;
}
static unsigned int __nlm_hash_addr6 ( const struct sockaddr * sap )
{
const struct sockaddr_in6 * sin6 = ( struct sockaddr_in6 * ) sap ;
const struct in6_addr addr = sin6 - > sin6_addr ;
return __nlm_hash32 ( addr . s6_addr32 [ 0 ] ) ^
__nlm_hash32 ( addr . s6_addr32 [ 1 ] ) ^
__nlm_hash32 ( addr . s6_addr32 [ 2 ] ) ^
__nlm_hash32 ( addr . s6_addr32 [ 3 ] ) ;
}
static unsigned int nlm_hash_address ( const struct sockaddr * sap )
{
unsigned int hash ;
switch ( sap - > sa_family ) {
case AF_INET :
hash = __nlm_hash_addr4 ( sap ) ;
break ;
case AF_INET6 :
hash = __nlm_hash_addr6 ( sap ) ;
break ;
default :
hash = 0 ;
}
return hash & ( NLM_HOST_NRHASH - 1 ) ;
}
2005-04-17 02:20:36 +04:00
/*
* Common host lookup routine for server & client
*/
2008-10-03 20:50:07 +04:00
static struct nlm_host * nlm_lookup_host ( struct nlm_lookup_host_info * ni )
2005-04-17 02:20:36 +04:00
{
2006-10-04 13:15:56 +04:00
struct hlist_head * chain ;
struct hlist_node * pos ;
struct nlm_host * host ;
2006-10-04 13:15:53 +04:00
struct nsm_handle * nsm = NULL ;
2005-04-17 02:20:36 +04:00
2006-03-26 13:37:12 +04:00
mutex_lock ( & nlm_host_mutex ) ;
2005-04-17 02:20:36 +04:00
if ( time_after_eq ( jiffies , next_gc ) )
nlm_gc_hosts ( ) ;
2006-10-04 13:15:53 +04:00
/* We may keep several nlm_host objects for a peer, because each
* nlm_host is identified by
* ( address , protocol , version , server / client )
* We could probably simplify this a little by putting all those
* different NLM rpc_clients into one single nlm_host object .
* This would allow us to have one nlm_host per address .
*/
2008-10-03 20:50:14 +04:00
chain = & nlm_hosts [ nlm_hash_address ( ni - > sap ) ] ;
2006-10-04 13:15:56 +04:00
hlist_for_each_entry ( host , pos , chain , h_hash ) {
2009-08-14 20:57:54 +04:00
if ( ! rpc_cmp_addr ( nlm_addr ( host ) , ni - > sap ) )
2006-10-04 13:15:53 +04:00
continue ;
/* See if we have an NSM handle for this client */
2006-10-04 13:16:15 +04:00
if ( ! nsm )
nsm = host - > h_nsmhandle ;
2006-10-04 13:15:53 +04:00
2008-10-03 20:50:07 +04:00
if ( host - > h_proto ! = ni - > protocol )
2005-04-17 02:20:36 +04:00
continue ;
2008-10-03 20:50:07 +04:00
if ( host - > h_version ! = ni - > version )
2005-04-17 02:20:36 +04:00
continue ;
2008-10-03 20:50:07 +04:00
if ( host - > h_server ! = ni - > server )
2005-04-17 02:20:36 +04:00
continue ;
2010-11-02 16:11:55 +03:00
if ( ni - > server & & ni - > src_len ! = 0 & &
2009-08-14 20:57:54 +04:00
! rpc_cmp_addr ( nlm_srcaddr ( host ) , ni - > src_sap ) )
2007-07-10 00:25:29 +04:00
continue ;
2005-04-17 02:20:36 +04:00
2006-10-04 13:15:56 +04:00
/* Move to head of hash chain. */
hlist_del ( & host - > h_hash ) ;
hlist_add_head ( & host - > h_hash , chain ) ;
2006-10-04 13:15:54 +04:00
nlm_get_host ( host ) ;
2008-08-28 00:57:23 +04:00
dprintk ( " lockd: nlm_lookup_host found host %s (%s) \n " ,
host - > h_name , host - > h_addrbuf ) ;
2006-10-04 13:15:54 +04:00
goto out ;
2005-04-17 02:20:36 +04:00
}
2008-08-28 00:57:15 +04:00
/*
* The host wasn ' t in our hash table . If we don ' t
* have an NSM handle for it yet , create one .
2006-10-04 13:15:53 +04:00
*/
2008-08-28 00:57:15 +04:00
if ( nsm )
atomic_inc ( & nsm - > sm_count ) ;
else {
host = NULL ;
2008-12-06 03:04:01 +03:00
nsm = nsm_get_handle ( ni - > sap , ni - > salen ,
ni - > hostname , ni - > hostname_len ) ;
2008-08-28 00:57:23 +04:00
if ( ! nsm ) {
dprintk ( " lockd: nlm_lookup_host failed; "
" no nsm handle \n " ) ;
2008-08-28 00:57:15 +04:00
goto out ;
2008-08-28 00:57:23 +04:00
}
2008-08-28 00:57:15 +04:00
}
2005-04-17 02:20:36 +04:00
2006-09-27 12:49:37 +04:00
host = kzalloc ( sizeof ( * host ) , GFP_KERNEL ) ;
2006-10-04 13:15:53 +04:00
if ( ! host ) {
nsm_release ( nsm ) ;
2008-08-28 00:57:23 +04:00
dprintk ( " lockd: nlm_lookup_host failed; no memory \n " ) ;
2006-10-04 13:15:53 +04:00
goto out ;
}
host - > h_name = nsm - > sm_name ;
2008-12-04 22:19:53 +03:00
host - > h_addrbuf = nsm - > sm_addrbuf ;
2008-10-03 20:50:14 +04:00
memcpy ( nlm_addr ( host ) , ni - > sap , ni - > salen ) ;
host - > h_addrlen = ni - > salen ;
2009-08-09 23:09:38 +04:00
rpc_set_port ( nlm_addr ( host ) , 0 ) ;
2008-10-03 20:50:14 +04:00
memcpy ( nlm_srcaddr ( host ) , ni - > src_sap , ni - > src_len ) ;
2010-11-02 16:11:55 +03:00
host - > h_srcaddrlen = ni - > src_len ;
2008-10-03 20:50:07 +04:00
host - > h_version = ni - > version ;
host - > h_proto = ni - > protocol ;
2005-04-17 02:20:36 +04:00
host - > h_rpcclnt = NULL ;
2006-06-09 17:40:24 +04:00
mutex_init ( & host - > h_mutex ) ;
2005-04-17 02:20:36 +04:00
host - > h_nextrebind = jiffies + NLM_HOST_REBIND ;
host - > h_expires = jiffies + NLM_HOST_EXPIRE ;
atomic_set ( & host - > h_count , 1 ) ;
init_waitqueue_head ( & host - > h_gracewait ) ;
2006-06-09 17:40:27 +04:00
init_rwsem ( & host - > h_rwsem ) ;
2005-04-17 02:20:36 +04:00
host - > h_state = 0 ; /* pseudo NSM state */
host - > h_nsmstate = 0 ; /* real NSM state */
2006-10-04 13:15:53 +04:00
host - > h_nsmhandle = nsm ;
2008-10-03 20:50:07 +04:00
host - > h_server = ni - > server ;
2008-12-23 23:21:38 +03:00
host - > h_noresvport = ni - > noresvport ;
2006-10-04 13:15:56 +04:00
hlist_add_head ( & host - > h_hash , chain ) ;
2005-04-17 02:20:36 +04:00
INIT_LIST_HEAD ( & host - > h_lockowners ) ;
spin_lock_init ( & host - > h_lock ) ;
2006-03-20 21:44:40 +03:00
INIT_LIST_HEAD ( & host - > h_granted ) ;
INIT_LIST_HEAD ( & host - > h_reclaim ) ;
2005-04-17 02:20:36 +04:00
2008-02-08 05:03:37 +03:00
nrhosts + + ;
2008-08-28 00:57:23 +04:00
dprintk ( " lockd: nlm_lookup_host created host %s \n " ,
host - > h_name ) ;
2006-10-04 13:15:53 +04:00
out :
2006-03-26 13:37:12 +04:00
mutex_unlock ( & nlm_host_mutex ) ;
2005-04-17 02:20:36 +04:00
return host ;
}
2006-10-04 13:16:00 +04:00
/*
* Destroy a host
*/
static void
nlm_destroy_host ( struct nlm_host * host )
{
struct rpc_clnt * clnt ;
BUG_ON ( ! list_empty ( & host - > h_lockowners ) ) ;
BUG_ON ( atomic_read ( & host - > h_count ) ) ;
nsm_unmonitor ( host ) ;
2008-12-04 22:21:31 +03:00
nsm_release ( host - > h_nsmhandle ) ;
2006-10-04 13:16:00 +04:00
2007-06-15 00:40:31 +04:00
clnt = host - > h_rpcclnt ;
if ( clnt ! = NULL )
rpc_shutdown_client ( clnt ) ;
2006-10-04 13:16:00 +04:00
kfree ( host ) ;
}
2008-10-03 20:50:21 +04:00
/**
* nlmclnt_lookup_host - Find an NLM host handle matching a remote server
* @ sap : network address of server
* @ salen : length of server address
* @ protocol : transport protocol to use
* @ version : NLM protocol version
* @ hostname : ' \0 ' - terminated hostname of server
2008-12-23 23:21:38 +03:00
* @ noresvport : 1 if non - privileged port should be used
2008-10-03 20:50:21 +04:00
*
* Returns an nlm_host structure that matches the passed - in
* [ server address , transport protocol , NLM version , server hostname ] .
* If one doesn ' t already exist in the host cache , a new handle is
* created and returned .
2006-12-07 07:38:29 +03:00
*/
2008-10-03 20:50:21 +04:00
struct nlm_host * nlmclnt_lookup_host ( const struct sockaddr * sap ,
const size_t salen ,
const unsigned short protocol ,
2008-12-23 23:21:38 +03:00
const u32 version ,
const char * hostname ,
int noresvport )
2006-12-07 07:38:29 +03:00
{
2008-10-03 20:50:07 +04:00
struct nlm_lookup_host_info ni = {
. server = 0 ,
2008-10-03 20:50:21 +04:00
. sap = sap ,
. salen = salen ,
. protocol = protocol ,
2008-10-03 20:50:07 +04:00
. version = version ,
. hostname = hostname ,
2008-10-03 20:50:21 +04:00
. hostname_len = strlen ( hostname ) ,
2008-12-23 23:21:38 +03:00
. noresvport = noresvport ,
2008-10-03 20:50:07 +04:00
} ;
2007-07-10 00:25:29 +04:00
2008-10-03 20:50:07 +04:00
dprintk ( " lockd: %s(host='%s', vers=%u, proto=%s) \n " , __func__ ,
( hostname ? hostname : " <none> " ) , version ,
2008-10-03 20:50:21 +04:00
( protocol = = IPPROTO_UDP ? " udp " : " tcp " ) ) ;
2008-10-03 20:50:07 +04:00
return nlm_lookup_host ( & ni ) ;
2006-12-07 07:38:29 +03:00
}
2008-10-03 20:50:29 +04:00
/**
* nlmsvc_lookup_host - Find an NLM host handle matching a remote client
* @ rqstp : incoming NLM request
* @ hostname : name of client host
* @ hostname_len : length of client hostname
*
* Returns an nlm_host structure that matches the [ client address ,
* transport protocol , NLM version , client hostname ] of the passed - in
* NLM request . If one doesn ' t already exist in the host cache , a
* new handle is created and returned .
*
* Before possibly creating a new nlm_host , construct a sockaddr
* for a specific source address in case the local system has
* multiple network addresses . The family of the address in
* rq_daddr is guaranteed to be the same as the family of the
* address in rq_addr , so it ' s safe to use the same family for
* the source address .
2006-12-07 07:38:29 +03:00
*/
2008-10-03 20:50:29 +04:00
struct nlm_host * nlmsvc_lookup_host ( const struct svc_rqst * rqstp ,
const char * hostname ,
const size_t hostname_len )
2006-12-07 07:38:29 +03:00
{
2008-10-03 20:50:29 +04:00
struct sockaddr_in sin = {
2008-08-28 00:57:31 +04:00
. sin_family = AF_INET ,
2008-10-03 20:50:29 +04:00
} ;
struct sockaddr_in6 sin6 = {
. sin6_family = AF_INET6 ,
2008-08-28 00:57:31 +04:00
} ;
2008-10-03 20:50:07 +04:00
struct nlm_lookup_host_info ni = {
. server = 1 ,
2008-10-03 20:50:14 +04:00
. sap = svc_addr ( rqstp ) ,
. salen = rqstp - > rq_addrlen ,
2008-10-03 20:50:07 +04:00
. protocol = rqstp - > rq_prot ,
. version = rqstp - > rq_vers ,
. hostname = hostname ,
. hostname_len = hostname_len ,
2008-10-03 20:50:29 +04:00
. src_len = rqstp - > rq_addrlen ,
2008-10-03 20:50:07 +04:00
} ;
dprintk ( " lockd: %s(host='%*s', vers=%u, proto=%s) \n " , __func__ ,
( int ) hostname_len , hostname , rqstp - > rq_vers ,
( rqstp - > rq_prot = = IPPROTO_UDP ? " udp " : " tcp " ) ) ;
2007-07-10 00:25:29 +04:00
2008-10-03 20:50:29 +04:00
switch ( ni . sap - > sa_family ) {
case AF_INET :
sin . sin_addr . s_addr = rqstp - > rq_daddr . addr . s_addr ;
ni . src_sap = ( struct sockaddr * ) & sin ;
break ;
case AF_INET6 :
ipv6_addr_copy ( & sin6 . sin6_addr , & rqstp - > rq_daddr . addr6 ) ;
ni . src_sap = ( struct sockaddr * ) & sin6 ;
break ;
default :
return NULL ;
}
2008-10-03 20:50:07 +04:00
return nlm_lookup_host ( & ni ) ;
2006-12-07 07:38:29 +03:00
}
2005-04-17 02:20:36 +04:00
/*
* Create the NLM RPC client for an NLM peer
*/
struct rpc_clnt *
nlm_bind_host ( struct nlm_host * host )
{
struct rpc_clnt * clnt ;
2008-12-04 22:19:53 +03:00
dprintk ( " lockd: nlm_bind_host %s (%s) \n " ,
host - > h_name , host - > h_addrbuf ) ;
2005-04-17 02:20:36 +04:00
/* Lock host handle */
2006-06-09 17:40:24 +04:00
mutex_lock ( & host - > h_mutex ) ;
2005-04-17 02:20:36 +04:00
/* If we've already created an RPC client, check whether
* RPC rebind is required
*/
if ( ( clnt = host - > h_rpcclnt ) ! = NULL ) {
2005-08-26 03:25:49 +04:00
if ( time_after_eq ( jiffies , host - > h_nextrebind ) ) {
2006-01-03 11:55:50 +03:00
rpc_force_rebind ( clnt ) ;
2005-04-17 02:20:36 +04:00
host - > h_nextrebind = jiffies + NLM_HOST_REBIND ;
2008-08-28 00:57:23 +04:00
dprintk ( " lockd: next rebind in %lu jiffies \n " ,
2005-04-17 02:20:36 +04:00
host - > h_nextrebind - jiffies ) ;
}
} else {
2007-05-15 00:50:44 +04:00
unsigned long increment = nlmsvc_timeout ;
2006-08-23 04:06:20 +04:00
struct rpc_timeout timeparms = {
. to_initval = increment ,
. to_increment = increment ,
. to_maxval = increment * 6UL ,
. to_retries = 5U ,
} ;
struct rpc_create_args args = {
2010-09-29 16:04:45 +04:00
. net = & init_net ,
2006-08-23 04:06:20 +04:00
. protocol = host - > h_proto ,
2008-09-03 22:35:39 +04:00
. address = nlm_addr ( host ) ,
. addrsize = host - > h_addrlen ,
2006-08-23 04:06:20 +04:00
. timeout = & timeparms ,
. servername = host - > h_name ,
. program = & nlm_program ,
. version = host - > h_version ,
. authflavor = RPC_AUTH_UNIX ,
2008-02-06 19:34:11 +03:00
. flags = ( RPC_CLNT_CREATE_NOPING |
2006-08-23 04:06:20 +04:00
RPC_CLNT_CREATE_AUTOBIND ) ,
} ;
2008-02-06 19:34:11 +03:00
/*
* lockd retries server side blocks automatically so we want
* those to be soft RPC calls . Client side calls need to be
* hard RPC tasks .
*/
if ( ! host - > h_server )
args . flags | = RPC_CLNT_CREATE_HARDRTRY ;
2008-12-23 23:21:38 +03:00
if ( host - > h_noresvport )
args . flags | = RPC_CLNT_CREATE_NONPRIVPORT ;
2010-11-02 16:11:55 +03:00
if ( host - > h_srcaddrlen )
args . saddress = nlm_srcaddr ( host ) ;
2008-02-06 19:34:11 +03:00
2006-08-23 04:06:20 +04:00
clnt = rpc_create ( & args ) ;
if ( ! IS_ERR ( clnt ) )
host - > h_rpcclnt = clnt ;
else {
printk ( " lockd: couldn't create RPC handle for %s \n " , host - > h_name ) ;
clnt = NULL ;
}
2005-04-17 02:20:36 +04:00
}
2006-06-09 17:40:24 +04:00
mutex_unlock ( & host - > h_mutex ) ;
2005-04-17 02:20:36 +04:00
return clnt ;
}
/*
* Force a portmap lookup of the remote lockd port
*/
void
nlm_rebind_host ( struct nlm_host * host )
{
dprintk ( " lockd: rebind host %s \n " , host - > h_name ) ;
if ( host - > h_rpcclnt & & time_after_eq ( jiffies , host - > h_nextrebind ) ) {
2006-01-03 11:55:50 +03:00
rpc_force_rebind ( host - > h_rpcclnt ) ;
2005-04-17 02:20:36 +04:00
host - > h_nextrebind = jiffies + NLM_HOST_REBIND ;
}
}
/*
* Increment NLM host count
*/
struct nlm_host * nlm_get_host ( struct nlm_host * host )
{
if ( host ) {
dprintk ( " lockd: get host %s \n " , host - > h_name ) ;
atomic_inc ( & host - > h_count ) ;
host - > h_expires = jiffies + NLM_HOST_EXPIRE ;
}
return host ;
}
/*
* Release NLM host after use
*/
void nlm_release_host ( struct nlm_host * host )
{
if ( host ! = NULL ) {
dprintk ( " lockd: release host %s \n " , host - > h_name ) ;
BUG_ON ( atomic_read ( & host - > h_count ) < 0 ) ;
2006-03-20 21:44:41 +03:00
if ( atomic_dec_and_test ( & host - > h_count ) ) {
BUG_ON ( ! list_empty ( & host - > h_lockowners ) ) ;
BUG_ON ( ! list_empty ( & host - > h_granted ) ) ;
BUG_ON ( ! list_empty ( & host - > h_reclaim ) ) ;
}
2005-04-17 02:20:36 +04:00
}
}
2010-12-14 18:05:13 +03:00
static struct nlm_host * next_host_state ( struct hlist_head * cache ,
struct nsm_handle * nsm ,
const struct nlm_reboot * info )
{
struct nlm_host * host = NULL ;
struct hlist_head * chain ;
struct hlist_node * pos ;
mutex_lock ( & nlm_host_mutex ) ;
for_each_host ( host , pos , chain , cache ) {
if ( host - > h_nsmhandle = = nsm
& & host - > h_nsmstate ! = info - > state ) {
host - > h_nsmstate = info - > state ;
host - > h_state + + ;
nlm_get_host ( host ) ;
mutex_unlock ( & nlm_host_mutex ) ;
goto out ;
}
}
out :
mutex_unlock ( & nlm_host_mutex ) ;
return host ;
}
2008-12-06 03:03:31 +03:00
/**
* nlm_host_rebooted - Release all resources held by rebooted host
* @ info : pointer to decoded results of NLM_SM_NOTIFY call
*
* We were notified that the specified host has rebooted . Release
* all resources held by that peer .
2006-10-04 13:15:52 +04:00
*/
2008-12-06 03:03:31 +03:00
void nlm_host_rebooted ( const struct nlm_reboot * info )
2006-10-04 13:15:52 +04:00
{
2006-10-04 13:15:55 +04:00
struct nsm_handle * nsm ;
2006-10-04 13:15:56 +04:00
struct nlm_host * host ;
2006-10-04 13:15:52 +04:00
2008-12-06 03:03:54 +03:00
nsm = nsm_reboot_lookup ( info ) ;
if ( unlikely ( nsm = = NULL ) )
2006-10-04 13:15:52 +04:00
return ;
2006-10-04 13:15:55 +04:00
/* Mark all hosts tied to this NSM state as having rebooted.
* We run the loop repeatedly , because we drop the host table
* lock for this .
* To avoid processing a host several times , we match the nsmstate .
*/
2010-12-14 18:05:13 +03:00
while ( ( host = next_host_state ( nlm_hosts , nsm , info ) ) ! = NULL ) {
if ( host - > h_server ) {
/* We're server for this guy, just ditch
* all the locks he held . */
nlmsvc_free_host_resources ( host ) ;
} else {
/* He's the server, initiate lock recovery. */
nlmclnt_recovery ( host ) ;
2006-10-04 13:15:55 +04:00
}
2010-12-14 18:05:13 +03:00
nlm_release_host ( host ) ;
2006-10-04 13:15:52 +04:00
}
2010-02-05 23:09:12 +03:00
nsm_release ( nsm ) ;
2006-10-04 13:15:52 +04:00
}
2005-04-17 02:20:36 +04:00
/*
* Shut down the hosts module .
* Note that this routine is called only at server shutdown time .
*/
void
nlm_shutdown_hosts ( void )
{
2006-10-04 13:15:56 +04:00
struct hlist_head * chain ;
struct hlist_node * pos ;
2005-04-17 02:20:36 +04:00
struct nlm_host * host ;
dprintk ( " lockd: shutting down host module \n " ) ;
2006-03-26 13:37:12 +04:00
mutex_lock ( & nlm_host_mutex ) ;
2005-04-17 02:20:36 +04:00
/* First, make all hosts eligible for gc */
dprintk ( " lockd: nuking all hosts... \n " ) ;
2010-12-14 18:05:03 +03:00
for_each_host ( host , pos , chain , nlm_hosts ) {
host - > h_expires = jiffies - 1 ;
if ( host - > h_rpcclnt ) {
rpc_shutdown_client ( host - > h_rpcclnt ) ;
host - > h_rpcclnt = NULL ;
2008-01-29 18:30:55 +03:00
}
2005-04-17 02:20:36 +04:00
}
/* Then, perform a garbage collection pass */
nlm_gc_hosts ( ) ;
2006-03-26 13:37:12 +04:00
mutex_unlock ( & nlm_host_mutex ) ;
2005-04-17 02:20:36 +04:00
/* complain if any hosts are left */
if ( nrhosts ) {
printk ( KERN_WARNING " lockd: couldn't shutdown host module! \n " ) ;
dprintk ( " lockd: %d hosts left: \n " , nrhosts ) ;
2010-12-14 18:05:03 +03:00
for_each_host ( host , pos , chain , nlm_hosts ) {
dprintk ( " %s (cnt %d use %d exp %ld) \n " ,
host - > h_name , atomic_read ( & host - > h_count ) ,
host - > h_inuse , host - > h_expires ) ;
2005-04-17 02:20:36 +04:00
}
}
}
/*
* Garbage collect any unused NLM hosts .
* This GC combines reference counting for async operations with
* mark & sweep for resources held by remote clients .
*/
static void
nlm_gc_hosts ( void )
{
2006-10-04 13:15:56 +04:00
struct hlist_head * chain ;
struct hlist_node * pos , * next ;
struct nlm_host * host ;
2005-04-17 02:20:36 +04:00
dprintk ( " lockd: host garbage collection \n " ) ;
2010-12-14 18:05:03 +03:00
for_each_host ( host , pos , chain , nlm_hosts )
host - > h_inuse = 0 ;
2005-04-17 02:20:36 +04:00
/* Mark all hosts that hold locks, blocks or shares */
nlmsvc_mark_resources ( ) ;
2010-12-14 18:05:03 +03:00
for_each_host_safe ( host , pos , next , chain , nlm_hosts ) {
if ( atomic_read ( & host - > h_count ) | | host - > h_inuse
| | time_before ( jiffies , host - > h_expires ) ) {
dprintk ( " nlm_gc_hosts skipping %s "
" (cnt %d use %d exp %ld) \n " ,
host - > h_name , atomic_read ( & host - > h_count ) ,
host - > h_inuse , host - > h_expires ) ;
continue ;
2005-04-17 02:20:36 +04:00
}
2010-12-14 18:05:03 +03:00
dprintk ( " lockd: delete host %s \n " , host - > h_name ) ;
hlist_del_init ( & host - > h_hash ) ;
nlm_destroy_host ( host ) ;
nrhosts - - ;
2005-04-17 02:20:36 +04:00
}
next_gc = jiffies + NLM_HOST_COLLECT ;
}