2005-04-17 02:20:36 +04:00
/*
* linux / fs / lockd / svc . c
*
* This is the central lockd service .
*
* FIXME : Separate the lockd NFS server functionality from the lockd NFS
* client functionality . Oh why didn ' t Sun create two separate
* services in the first place ?
*
* Authors : Olaf Kirch ( okir @ monad . swb . de )
*
* Copyright ( C ) 1995 , 1996 Olaf Kirch < okir @ monad . swb . de >
*/
# include <linux/module.h>
# include <linux/init.h>
# include <linux/sysctl.h>
# include <linux/moduleparam.h>
# include <linux/sched.h>
# include <linux/errno.h>
# include <linux/in.h>
# include <linux/uio.h>
# include <linux/smp.h>
2006-03-26 13:37:12 +04:00
# include <linux/mutex.h>
2008-02-08 00:34:55 +03:00
# include <linux/kthread.h>
2007-07-17 15:03:35 +04:00
# include <linux/freezer.h>
2005-04-17 02:20:36 +04:00
# include <linux/sunrpc/types.h>
# include <linux/sunrpc/stats.h>
# include <linux/sunrpc/clnt.h>
# include <linux/sunrpc/svc.h>
# include <linux/sunrpc/svcsock.h>
2006-10-02 13:17:45 +04:00
# include <net/ip.h>
2005-04-17 02:20:36 +04:00
# include <linux/lockd/lockd.h>
# include <linux/nfs.h>
2012-01-31 15:07:57 +04:00
# include "netns.h"
2005-04-17 02:20:36 +04:00
# define NLMDBG_FACILITY NLMDBG_SVC
# define LOCKD_BUFSIZE (1024 + NLMSVC_XDRSIZE)
# define ALLOWED_SIGS (sigmask(SIGKILL))
static struct svc_program nlmsvc_program ;
struct nlmsvc_binding * nlmsvc_ops ;
2008-12-23 23:21:33 +03:00
EXPORT_SYMBOL_GPL ( nlmsvc_ops ) ;
2005-04-17 02:20:36 +04:00
2006-03-26 13:37:12 +04:00
static DEFINE_MUTEX ( nlmsvc_mutex ) ;
2005-04-17 02:20:36 +04:00
static unsigned int nlmsvc_users ;
2008-02-08 00:34:55 +03:00
static struct task_struct * nlmsvc_task ;
2008-06-11 18:03:12 +04:00
static struct svc_rqst * nlmsvc_rqst ;
2005-04-17 02:20:36 +04:00
unsigned long nlmsvc_timeout ;
2012-01-31 15:07:57 +04:00
int lockd_net_id ;
2005-04-17 02:20:36 +04:00
/*
* These can be set at insmod time ( useful for NFS as root filesystem ) ,
* and also changed through the sysctl interface . - - Jamie Lokier , Aug 2003
*/
static unsigned long nlm_grace_period ;
static unsigned long nlm_timeout = LOCKD_DFLT_TIMEO ;
static int nlm_udpport , nlm_tcpport ;
2008-10-20 19:51:58 +04:00
/* RLIM_NOFILE defaults to 1024. That seems like a reasonable default here. */
static unsigned int nlm_max_connections = 1024 ;
2005-04-17 02:20:36 +04:00
/*
* Constants needed for the sysctl interface .
*/
static const unsigned long nlm_grace_period_min = 0 ;
static const unsigned long nlm_grace_period_max = 240 ;
static const unsigned long nlm_timeout_min = 3 ;
static const unsigned long nlm_timeout_max = 20 ;
static const int nlm_port_min = 0 , nlm_port_max = 65535 ;
2008-03-14 21:18:30 +03:00
# ifdef CONFIG_SYSCTL
2005-04-17 02:20:36 +04:00
static struct ctl_table_header * nlm_sysctl_table ;
2008-03-14 21:18:30 +03:00
# endif
2005-04-17 02:20:36 +04:00
2007-07-17 15:04:35 +04:00
static unsigned long get_lockd_grace_period ( void )
2005-04-17 02:20:36 +04:00
{
/* Note: nlm_timeout should always be nonzero */
if ( nlm_grace_period )
2007-07-17 15:04:35 +04:00
return roundup ( nlm_grace_period , nlm_timeout ) * HZ ;
2005-04-17 02:20:36 +04:00
else
2007-07-17 15:04:35 +04:00
return nlm_timeout * 5 * HZ ;
}
2012-07-25 16:56:50 +04:00
static void grace_ender ( struct work_struct * grace )
2007-07-17 15:04:35 +04:00
{
2012-07-25 16:56:50 +04:00
struct delayed_work * dwork = container_of ( grace , struct delayed_work ,
work ) ;
struct lockd_net * ln = container_of ( dwork , struct lockd_net ,
grace_period_end ) ;
locks_end_grace ( & ln - > lockd_manager ) ;
2005-04-17 02:20:36 +04:00
}
2012-07-25 16:57:22 +04:00
static void set_grace_period ( struct net * net )
2005-04-17 02:20:36 +04:00
{
2007-09-06 20:34:25 +04:00
unsigned long grace_period = get_lockd_grace_period ( ) ;
2012-07-25 16:57:22 +04:00
struct lockd_net * ln = net_generic ( net , lockd_net_id ) ;
2008-03-19 02:00:19 +03:00
2012-07-25 16:57:22 +04:00
locks_start_grace ( net , & ln - > lockd_manager ) ;
2012-07-25 16:56:43 +04:00
cancel_delayed_work_sync ( & ln - > grace_period_end ) ;
schedule_delayed_work ( & ln - > grace_period_end , grace_period ) ;
2005-04-17 02:20:36 +04:00
}
2009-05-07 00:32:54 +04:00
static void restart_grace ( void )
{
if ( nlmsvc_ops ) {
2012-07-25 16:57:22 +04:00
struct net * net = & init_net ;
struct lockd_net * ln = net_generic ( net , lockd_net_id ) ;
2012-07-25 16:56:43 +04:00
cancel_delayed_work_sync ( & ln - > grace_period_end ) ;
2012-07-25 16:56:50 +04:00
locks_end_grace ( & ln - > lockd_manager ) ;
2009-05-07 00:32:54 +04:00
nlmsvc_invalidate_all ( ) ;
2012-07-25 16:57:22 +04:00
set_grace_period ( net ) ;
2009-05-07 00:32:54 +04:00
}
}
2005-04-17 02:20:36 +04:00
/*
* This is the lockd kernel thread
*/
2008-02-08 00:34:55 +03:00
static int
lockd ( void * vrqstp )
2005-04-17 02:20:36 +04:00
{
2012-08-18 05:47:53 +04:00
int err = 0 ;
2008-02-08 00:34:55 +03:00
struct svc_rqst * rqstp = vrqstp ;
2005-04-17 02:20:36 +04:00
2008-02-08 00:34:55 +03:00
/* try_to_freeze() is called from svc_recv() */
2007-07-17 15:03:35 +04:00
set_freezable ( ) ;
2005-04-17 02:20:36 +04:00
2008-02-08 00:34:55 +03:00
/* Allow SIGKILL to tell lockd to drop all of its locks */
2005-04-17 02:20:36 +04:00
allow_signal ( SIGKILL ) ;
dprintk ( " NFS locking service started (ver " LOCKD_VERSION " ). \n " ) ;
if ( ! nlm_timeout )
nlm_timeout = LOCKD_DFLT_TIMEO ;
nlmsvc_timeout = nlm_timeout * HZ ;
/*
* The main request loop . We don ' t terminate until the last
2008-02-08 00:34:55 +03:00
* NFS mount or NFS daemon has gone away .
2005-04-17 02:20:36 +04:00
*/
2008-02-08 00:34:55 +03:00
while ( ! kthread_should_stop ( ) ) {
2005-04-17 02:20:36 +04:00
long timeout = MAX_SCHEDULE_TIMEOUT ;
2008-02-21 10:57:45 +03:00
RPC_IFDEBUG ( char buf [ RPC_MAX_ADDRBUFLEN ] ) ;
2005-04-17 02:20:36 +04:00
2008-10-20 19:51:58 +04:00
/* update sv_maxconn if it has changed */
rqstp - > rq_server - > sv_maxconn = nlm_max_connections ;
2005-04-17 02:20:36 +04:00
if ( signalled ( ) ) {
flush_signals ( current ) ;
2009-05-07 00:32:54 +04:00
restart_grace ( ) ;
2008-02-08 00:34:55 +03:00
continue ;
2005-04-17 02:20:36 +04:00
}
2008-01-24 19:11:34 +03:00
timeout = nlmsvc_retry_blocked ( ) ;
2005-04-17 02:20:36 +04:00
/*
* Find a socket with data available and call its
* recvfrom routine .
*/
2006-10-02 13:17:50 +04:00
err = svc_recv ( rqstp , timeout ) ;
2012-08-18 05:47:53 +04:00
if ( err = = - EAGAIN | | err = = - EINTR )
2005-04-17 02:20:36 +04:00
continue ;
2007-02-12 11:53:32 +03:00
dprintk ( " lockd: request from %s \n " ,
svc_print_addr ( rqstp , buf , sizeof ( buf ) ) ) ;
2005-04-17 02:20:36 +04:00
2006-10-02 13:17:50 +04:00
svc_process ( rqstp ) ;
2005-04-17 02:20:36 +04:00
}
2006-01-03 11:55:19 +03:00
flush_signals ( current ) ;
2008-02-08 00:34:55 +03:00
if ( nlmsvc_ops )
nlmsvc_invalidate_all ( ) ;
nlm_shutdown_hosts ( ) ;
return 0 ;
2005-04-17 02:20:36 +04:00
}
2009-03-19 03:47:59 +03:00
static int create_lockd_listener ( struct svc_serv * serv , const char * name ,
2012-01-31 15:07:48 +04:00
struct net * net , const int family ,
const unsigned short port )
2009-01-01 00:06:04 +03:00
{
struct svc_xprt * xprt ;
2012-01-31 15:07:48 +04:00
xprt = svc_find_xprt ( serv , name , net , family , 0 ) ;
2009-01-01 00:06:04 +03:00
if ( xprt = = NULL )
2012-01-31 15:07:48 +04:00
return svc_create_xprt ( serv , name , net , family , port ,
2009-03-19 03:47:59 +03:00
SVC_SOCK_DEFAULTS ) ;
2009-01-01 00:06:04 +03:00
svc_xprt_put ( xprt ) ;
return 0 ;
}
2012-01-31 15:07:48 +04:00
static int create_lockd_family ( struct svc_serv * serv , struct net * net ,
const int family )
2009-03-19 03:47:59 +03:00
{
int err ;
2012-01-31 15:07:48 +04:00
err = create_lockd_listener ( serv , " udp " , net , family , nlm_udpport ) ;
2009-03-19 03:47:59 +03:00
if ( err < 0 )
return err ;
2012-01-31 15:07:48 +04:00
return create_lockd_listener ( serv , " tcp " , net , family , nlm_tcpport ) ;
2009-03-19 03:47:59 +03:00
}
2007-02-12 11:53:29 +03:00
/*
2008-10-04 01:15:23 +04:00
* Ensure there are active UDP and TCP listeners for lockd .
*
* Even if we have only TCP NFS mounts and / or TCP NFSDs , some
* local services ( such as rpc . statd ) still require UDP , and
* some NFS servers do not yet support NLM over TCP .
*
* Returns zero if all listeners are available ; otherwise a
* negative errno value is returned .
2007-02-12 11:53:29 +03:00
*/
2012-01-31 15:07:48 +04:00
static int make_socks ( struct svc_serv * serv , struct net * net )
2006-10-02 13:17:45 +04:00
{
2007-02-12 11:53:29 +03:00
static int warned ;
2009-01-01 00:06:11 +03:00
int err ;
2007-02-12 11:53:29 +03:00
2012-01-31 15:07:48 +04:00
err = create_lockd_family ( serv , net , PF_INET ) ;
2009-01-01 00:06:11 +03:00
if ( err < 0 )
goto out_err ;
2012-01-31 15:07:48 +04:00
err = create_lockd_family ( serv , net , PF_INET6 ) ;
2009-03-19 03:47:59 +03:00
if ( err < 0 & & err ! = - EAFNOSUPPORT )
2009-01-01 00:06:11 +03:00
goto out_err ;
warned = 0 ;
return 0 ;
out_err :
if ( warned + + = = 0 )
2006-10-02 13:17:52 +04:00
printk ( KERN_WARNING
2009-01-01 00:06:11 +03:00
" lockd_up: makesock failed, error=%d \n " , err ) ;
2014-03-25 22:55:26 +04:00
svc_shutdown_net ( serv , net ) ;
2006-10-02 13:17:45 +04:00
return err ;
}
2012-04-25 18:22:40 +04:00
static int lockd_up_net ( struct svc_serv * serv , struct net * net )
2012-01-31 15:08:05 +04:00
{
struct lockd_net * ln = net_generic ( net , lockd_net_id ) ;
int error ;
2012-05-04 12:49:41 +04:00
if ( ln - > nlmsvc_users + + )
2012-01-31 15:08:05 +04:00
return 0 ;
2012-04-25 18:22:47 +04:00
error = svc_bind ( serv , net ) ;
2012-01-31 15:08:05 +04:00
if ( error )
2012-04-25 18:22:47 +04:00
goto err_bind ;
2012-01-31 15:08:05 +04:00
error = make_socks ( serv , net ) ;
if ( error < 0 )
goto err_socks ;
2012-07-25 16:57:29 +04:00
set_grace_period ( net ) ;
2012-04-25 18:23:16 +04:00
dprintk ( " lockd_up_net: per-net data created; net=%p \n " , net ) ;
2012-01-31 15:08:05 +04:00
return 0 ;
err_socks :
svc_rpcb_cleanup ( serv , net ) ;
2012-04-25 18:22:47 +04:00
err_bind :
2012-05-04 12:49:41 +04:00
ln - > nlmsvc_users - - ;
2012-01-31 15:08:05 +04:00
return error ;
}
2012-04-25 18:22:40 +04:00
static void lockd_down_net ( struct svc_serv * serv , struct net * net )
2012-01-31 15:08:05 +04:00
{
struct lockd_net * ln = net_generic ( net , lockd_net_id ) ;
if ( ln - > nlmsvc_users ) {
2012-01-31 15:08:29 +04:00
if ( - - ln - > nlmsvc_users = = 0 ) {
nlm_shutdown_hosts_net ( net ) ;
2012-07-25 16:57:29 +04:00
cancel_delayed_work_sync ( & ln - > grace_period_end ) ;
locks_end_grace ( & ln - > lockd_manager ) ;
2012-01-31 15:08:05 +04:00
svc_shutdown_net ( serv , net ) ;
2012-04-25 18:23:16 +04:00
dprintk ( " lockd_down_net: per-net data destroyed; net=%p \n " , net ) ;
2012-01-31 15:08:29 +04:00
}
2012-01-31 15:08:05 +04:00
} else {
printk ( KERN_ERR " lockd_down_net: no users! task=%p, net=%p \n " ,
nlmsvc_task , net ) ;
BUG ( ) ;
}
}
2012-04-25 18:23:09 +04:00
static int lockd_start_svc ( struct svc_serv * serv )
{
int error ;
if ( nlmsvc_rqst )
return 0 ;
/*
* Create the kernel thread and wait for it to start .
*/
nlmsvc_rqst = svc_prepare_thread ( serv , & serv - > sv_pools [ 0 ] , NUMA_NO_NODE ) ;
if ( IS_ERR ( nlmsvc_rqst ) ) {
error = PTR_ERR ( nlmsvc_rqst ) ;
printk ( KERN_WARNING
" lockd_up: svc_rqst allocation failed, error=%d \n " ,
error ) ;
goto out_rqst ;
}
svc_sock_update_bufs ( serv ) ;
serv - > sv_maxconn = nlm_max_connections ;
2014-09-02 21:58:57 +04:00
nlmsvc_task = kthread_create ( lockd , nlmsvc_rqst , " %s " , serv - > sv_name ) ;
2012-04-25 18:23:09 +04:00
if ( IS_ERR ( nlmsvc_task ) ) {
error = PTR_ERR ( nlmsvc_task ) ;
printk ( KERN_WARNING
" lockd_up: kthread_run failed, error=%d \n " , error ) ;
goto out_task ;
}
2014-08-03 21:03:07 +04:00
nlmsvc_rqst - > rq_task = nlmsvc_task ;
2014-09-02 21:58:57 +04:00
wake_up_process ( nlmsvc_task ) ;
2014-08-03 21:03:07 +04:00
2012-04-25 18:23:09 +04:00
dprintk ( " lockd_up: service started \n " ) ;
return 0 ;
out_task :
svc_exit_thread ( nlmsvc_rqst ) ;
nlmsvc_task = NULL ;
out_rqst :
nlmsvc_rqst = NULL ;
return error ;
}
2012-04-25 18:22:54 +04:00
static struct svc_serv * lockd_create_svc ( void )
2005-04-17 02:20:36 +04:00
{
2008-02-08 00:34:55 +03:00
struct svc_serv * serv ;
2005-04-17 02:20:36 +04:00
/*
* Check whether we ' re already up and running .
*/
2012-01-31 15:08:05 +04:00
if ( nlmsvc_rqst ) {
2012-04-25 18:22:54 +04:00
/*
* Note : increase service usage , because later in case of error
* svc_destroy ( ) will be called .
*/
svc_get ( nlmsvc_rqst - > rq_server ) ;
return nlmsvc_rqst - > rq_server ;
2012-01-31 15:08:05 +04:00
}
2005-04-17 02:20:36 +04:00
/*
* Sanity check : if there ' s no pid ,
* we should be the first user . . .
*/
2006-10-02 13:17:53 +04:00
if ( nlmsvc_users )
2005-04-17 02:20:36 +04:00
printk ( KERN_WARNING
" lockd_up: no pid, %d users?? \n " , nlmsvc_users ) ;
2009-03-19 03:46:29 +03:00
serv = svc_create ( & nlmsvc_program , LOCKD_BUFSIZE , NULL ) ;
2005-04-17 02:20:36 +04:00
if ( ! serv ) {
printk ( KERN_WARNING " lockd_up: create service failed \n " ) ;
2012-04-25 18:22:54 +04:00
return ERR_PTR ( - ENOMEM ) ;
}
2012-04-25 18:23:16 +04:00
dprintk ( " lockd_up: service created \n " ) ;
2012-04-25 18:22:54 +04:00
return serv ;
}
/*
* Bring up the lockd process if it ' s not already up .
*/
int lockd_up ( struct net * net )
{
struct svc_serv * serv ;
2012-04-25 18:23:02 +04:00
int error ;
2012-04-25 18:22:54 +04:00
mutex_lock ( & nlmsvc_mutex ) ;
serv = lockd_create_svc ( ) ;
if ( IS_ERR ( serv ) ) {
error = PTR_ERR ( serv ) ;
goto err_create ;
2005-04-17 02:20:36 +04:00
}
2012-04-25 18:22:47 +04:00
error = lockd_up_net ( serv , net ) ;
2008-10-04 01:15:23 +04:00
if ( error < 0 )
2012-04-25 18:22:47 +04:00
goto err_net ;
2005-04-17 02:20:36 +04:00
2012-04-25 18:23:09 +04:00
error = lockd_start_svc ( serv ) ;
if ( error < 0 )
2012-05-04 12:49:41 +04:00
goto err_start ;
2005-04-17 02:20:36 +04:00
2012-04-25 18:23:02 +04:00
nlmsvc_users + + ;
2005-04-17 02:20:36 +04:00
/*
* Note : svc_serv structures have an initial use count of 1 ,
* so we exit through here on both success and failure .
*/
2012-04-25 18:22:47 +04:00
err_net :
2005-04-17 02:20:36 +04:00
svc_destroy ( serv ) ;
2012-04-25 18:22:54 +04:00
err_create :
2006-03-26 13:37:12 +04:00
mutex_unlock ( & nlmsvc_mutex ) ;
2005-04-17 02:20:36 +04:00
return error ;
2012-05-04 12:49:41 +04:00
err_start :
2012-04-25 18:22:40 +04:00
lockd_down_net ( serv , net ) ;
2012-04-25 18:22:47 +04:00
goto err_net ;
2005-04-17 02:20:36 +04:00
}
2008-12-23 23:21:33 +03:00
EXPORT_SYMBOL_GPL ( lockd_up ) ;
2005-04-17 02:20:36 +04:00
/*
* Decrement the user count and bring down lockd if we ' re the last .
*/
void
2012-03-29 18:54:33 +04:00
lockd_down ( struct net * net )
2005-04-17 02:20:36 +04:00
{
2006-03-26 13:37:12 +04:00
mutex_lock ( & nlmsvc_mutex ) ;
2012-04-25 18:22:40 +04:00
lockd_down_net ( nlmsvc_rqst - > rq_server , net ) ;
2005-04-17 02:20:36 +04:00
if ( nlmsvc_users ) {
2012-05-04 12:49:41 +04:00
if ( - - nlmsvc_users )
2005-04-17 02:20:36 +04:00
goto out ;
2008-02-08 00:34:55 +03:00
} else {
printk ( KERN_ERR " lockd_down: no users! task=%p \n " ,
nlmsvc_task ) ;
BUG ( ) ;
2005-04-17 02:20:36 +04:00
}
2008-02-08 00:34:55 +03:00
if ( ! nlmsvc_task ) {
printk ( KERN_ERR " lockd_down: no lockd running. \n " ) ;
BUG ( ) ;
2005-04-17 02:20:36 +04:00
}
2008-02-08 00:34:55 +03:00
kthread_stop ( nlmsvc_task ) ;
2012-04-25 18:23:16 +04:00
dprintk ( " lockd_down: service stopped \n " ) ;
2008-06-11 18:03:12 +04:00
svc_exit_thread ( nlmsvc_rqst ) ;
2012-04-25 18:23:16 +04:00
dprintk ( " lockd_down: service destroyed \n " ) ;
2008-06-11 18:03:12 +04:00
nlmsvc_task = NULL ;
nlmsvc_rqst = NULL ;
2005-04-17 02:20:36 +04:00
out :
2006-03-26 13:37:12 +04:00
mutex_unlock ( & nlmsvc_mutex ) ;
2005-04-17 02:20:36 +04:00
}
2008-12-23 23:21:33 +03:00
EXPORT_SYMBOL_GPL ( lockd_down ) ;
2005-04-17 02:20:36 +04:00
2008-03-14 21:18:30 +03:00
# ifdef CONFIG_SYSCTL
2005-04-17 02:20:36 +04:00
/*
* Sysctl parameters ( same as module parameters , different interface ) .
*/
2014-06-07 01:38:02 +04:00
static struct ctl_table nlm_sysctls [ ] = {
2005-04-17 02:20:36 +04:00
{
. procname = " nlm_grace_period " ,
. data = & nlm_grace_period ,
2005-07-13 12:10:47 +04:00
. maxlen = sizeof ( unsigned long ) ,
2005-04-17 02:20:36 +04:00
. mode = 0644 ,
2009-11-16 14:11:48 +03:00
. proc_handler = proc_doulongvec_minmax ,
2005-04-17 02:20:36 +04:00
. extra1 = ( unsigned long * ) & nlm_grace_period_min ,
. extra2 = ( unsigned long * ) & nlm_grace_period_max ,
} ,
{
. procname = " nlm_timeout " ,
. data = & nlm_timeout ,
2005-07-13 12:10:47 +04:00
. maxlen = sizeof ( unsigned long ) ,
2005-04-17 02:20:36 +04:00
. mode = 0644 ,
2009-11-16 14:11:48 +03:00
. proc_handler = proc_doulongvec_minmax ,
2005-04-17 02:20:36 +04:00
. extra1 = ( unsigned long * ) & nlm_timeout_min ,
. extra2 = ( unsigned long * ) & nlm_timeout_max ,
} ,
{
. procname = " nlm_udpport " ,
. data = & nlm_udpport ,
. maxlen = sizeof ( int ) ,
. mode = 0644 ,
2009-11-16 14:11:48 +03:00
. proc_handler = proc_dointvec_minmax ,
2005-04-17 02:20:36 +04:00
. extra1 = ( int * ) & nlm_port_min ,
. extra2 = ( int * ) & nlm_port_max ,
} ,
{
. procname = " nlm_tcpport " ,
. data = & nlm_tcpport ,
. maxlen = sizeof ( int ) ,
. mode = 0644 ,
2009-11-16 14:11:48 +03:00
. proc_handler = proc_dointvec_minmax ,
2005-04-17 02:20:36 +04:00
. extra1 = ( int * ) & nlm_port_min ,
. extra2 = ( int * ) & nlm_port_max ,
} ,
2006-10-04 13:16:01 +04:00
{
. procname = " nsm_use_hostnames " ,
. data = & nsm_use_hostnames ,
. maxlen = sizeof ( int ) ,
. mode = 0644 ,
2009-11-16 14:11:48 +03:00
. proc_handler = proc_dointvec ,
2006-10-04 13:16:01 +04:00
} ,
2006-10-04 13:16:03 +04:00
{
. procname = " nsm_local_state " ,
. data = & nsm_local_state ,
. maxlen = sizeof ( int ) ,
. mode = 0644 ,
2009-11-16 14:11:48 +03:00
. proc_handler = proc_dointvec ,
2006-10-04 13:16:03 +04:00
} ,
2009-11-06 01:25:10 +03:00
{ }
2005-04-17 02:20:36 +04:00
} ;
2014-06-07 01:38:02 +04:00
static struct ctl_table nlm_sysctl_dir [ ] = {
2005-04-17 02:20:36 +04:00
{
. procname = " nfs " ,
. mode = 0555 ,
. child = nlm_sysctls ,
} ,
2009-11-06 01:25:10 +03:00
{ }
2005-04-17 02:20:36 +04:00
} ;
2014-06-07 01:38:02 +04:00
static struct ctl_table nlm_sysctl_root [ ] = {
2005-04-17 02:20:36 +04:00
{
. procname = " fs " ,
. mode = 0555 ,
. child = nlm_sysctl_dir ,
} ,
2009-11-06 01:25:10 +03:00
{ }
2005-04-17 02:20:36 +04:00
} ;
2008-03-14 21:18:30 +03:00
# endif /* CONFIG_SYSCTL */
2005-04-17 02:20:36 +04:00
/*
2007-02-17 21:13:42 +03:00
* Module ( and sysfs ) parameters .
2005-04-17 02:20:36 +04:00
*/
# define param_set_min_max(name, type, which_strtol, min, max) \
static int param_set_ # # name ( const char * val , struct kernel_param * kp ) \
{ \
char * endp ; \
__typeof__ ( type ) num = which_strtol ( val , & endp , 0 ) ; \
if ( endp = = val | | * endp | | num < ( min ) | | num > ( max ) ) \
return - EINVAL ; \
2012-02-07 08:35:42 +04:00
* ( ( type * ) kp - > arg ) = num ; \
2005-04-17 02:20:36 +04:00
return 0 ; \
}
static inline int is_callback ( u32 proc )
{
return proc = = NLMPROC_GRANTED
| | proc = = NLMPROC_GRANTED_MSG
| | proc = = NLMPROC_TEST_RES
| | proc = = NLMPROC_LOCK_RES
| | proc = = NLMPROC_CANCEL_RES
| | proc = = NLMPROC_UNLOCK_RES
| | proc = = NLMPROC_NSM_NOTIFY ;
}
static int lockd_authenticate ( struct svc_rqst * rqstp )
{
rqstp - > rq_client = NULL ;
switch ( rqstp - > rq_authop - > flavour ) {
case RPC_AUTH_NULL :
case RPC_AUTH_UNIX :
if ( rqstp - > rq_proc = = 0 )
return SVC_OK ;
if ( is_callback ( rqstp - > rq_proc ) ) {
/* Leave it to individual procedures to
* call nlmsvc_lookup_host ( rqstp )
*/
return SVC_OK ;
}
return svc_set_client ( rqstp ) ;
}
return SVC_DENIED ;
}
param_set_min_max ( port , int , simple_strtol , 0 , 65535 )
param_set_min_max ( grace_period , unsigned long , simple_strtoul ,
nlm_grace_period_min , nlm_grace_period_max )
param_set_min_max ( timeout , unsigned long , simple_strtoul ,
nlm_timeout_min , nlm_timeout_max )
MODULE_AUTHOR ( " Olaf Kirch <okir@monad.swb.de> " ) ;
MODULE_DESCRIPTION ( " NFS file locking service version " LOCKD_VERSION " . " ) ;
MODULE_LICENSE ( " GPL " ) ;
module_param_call ( nlm_grace_period , param_set_grace_period , param_get_ulong ,
& nlm_grace_period , 0644 ) ;
module_param_call ( nlm_timeout , param_set_timeout , param_get_ulong ,
& nlm_timeout , 0644 ) ;
module_param_call ( nlm_udpport , param_set_port , param_get_int ,
& nlm_udpport , 0644 ) ;
module_param_call ( nlm_tcpport , param_set_port , param_get_int ,
& nlm_tcpport , 0644 ) ;
2006-10-04 13:16:01 +04:00
module_param ( nsm_use_hostnames , bool , 0644 ) ;
2008-10-20 19:51:58 +04:00
module_param ( nlm_max_connections , uint , 0644 ) ;
2005-04-17 02:20:36 +04:00
2012-01-31 15:07:57 +04:00
static int lockd_init_net ( struct net * net )
{
2012-07-25 16:56:43 +04:00
struct lockd_net * ln = net_generic ( net , lockd_net_id ) ;
INIT_DELAYED_WORK ( & ln - > grace_period_end , grace_ender ) ;
2012-07-25 16:57:13 +04:00
INIT_LIST_HEAD ( & ln - > grace_list ) ;
2012-09-18 13:37:12 +04:00
spin_lock_init ( & ln - > nsm_clnt_lock ) ;
2012-01-31 15:07:57 +04:00
return 0 ;
}
static void lockd_exit_net ( struct net * net )
{
}
static struct pernet_operations lockd_net_ops = {
. init = lockd_init_net ,
. exit = lockd_exit_net ,
. id = & lockd_net_id ,
. size = sizeof ( struct lockd_net ) ,
} ;
2005-04-17 02:20:36 +04:00
/*
* Initialising and terminating the module .
*/
static int __init init_nlm ( void )
{
2012-01-31 15:07:57 +04:00
int err ;
2008-03-14 21:18:30 +03:00
# ifdef CONFIG_SYSCTL
2012-01-31 15:07:57 +04:00
err = - ENOMEM ;
2007-02-14 11:34:09 +03:00
nlm_sysctl_table = register_sysctl_table ( nlm_sysctl_root ) ;
2012-01-31 15:07:57 +04:00
if ( nlm_sysctl_table = = NULL )
goto err_sysctl ;
# endif
err = register_pernet_subsys ( & lockd_net_ops ) ;
if ( err )
goto err_pernet ;
2008-03-14 21:18:30 +03:00
return 0 ;
2012-01-31 15:07:57 +04:00
err_pernet :
# ifdef CONFIG_SYSCTL
unregister_sysctl_table ( nlm_sysctl_table ) ;
err_sysctl :
2014-05-02 01:15:02 +04:00
# endif
2012-01-31 15:07:57 +04:00
return err ;
2005-04-17 02:20:36 +04:00
}
static void __exit exit_nlm ( void )
{
/* FIXME: delete all NLM clients */
nlm_shutdown_hosts ( ) ;
2012-01-31 15:07:57 +04:00
unregister_pernet_subsys ( & lockd_net_ops ) ;
2008-03-14 21:18:30 +03:00
# ifdef CONFIG_SYSCTL
2005-04-17 02:20:36 +04:00
unregister_sysctl_table ( nlm_sysctl_table ) ;
2008-03-14 21:18:30 +03:00
# endif
2005-04-17 02:20:36 +04:00
}
module_init ( init_nlm ) ;
module_exit ( exit_nlm ) ;
/*
* Define NLM program and procedures
*/
static struct svc_version nlmsvc_version1 = {
. vs_vers = 1 ,
. vs_nproc = 17 ,
. vs_proc = nlmsvc_procedures ,
. vs_xdrsize = NLMSVC_XDRSIZE ,
} ;
static struct svc_version nlmsvc_version3 = {
. vs_vers = 3 ,
. vs_nproc = 24 ,
. vs_proc = nlmsvc_procedures ,
. vs_xdrsize = NLMSVC_XDRSIZE ,
} ;
# ifdef CONFIG_LOCKD_V4
static struct svc_version nlmsvc_version4 = {
. vs_vers = 4 ,
. vs_nproc = 24 ,
. vs_proc = nlmsvc_procedures4 ,
. vs_xdrsize = NLMSVC_XDRSIZE ,
} ;
# endif
static struct svc_version * nlmsvc_version [ ] = {
[ 1 ] = & nlmsvc_version1 ,
[ 3 ] = & nlmsvc_version3 ,
# ifdef CONFIG_LOCKD_V4
[ 4 ] = & nlmsvc_version4 ,
# endif
} ;
static struct svc_stat nlmsvc_stats ;
2006-03-24 14:15:34 +03:00
# define NLM_NRVERS ARRAY_SIZE(nlmsvc_version)
2005-04-17 02:20:36 +04:00
static struct svc_program nlmsvc_program = {
. pg_prog = NLM_PROGRAM , /* program number */
. pg_nvers = NLM_NRVERS , /* number of entries in nlmsvc_version */
. pg_vers = nlmsvc_version , /* version table */
. pg_name = " lockd " , /* service name */
. pg_class = " nfsd " , /* share authentication with nfsd */
. pg_stats = & nlmsvc_stats , /* stats table */
. pg_authenticate = & lockd_authenticate /* export authentication */
} ;