2007-12-31 06:07:15 +03:00
/*
* linux / net / sunrpc / svc_xprt . c
*
* Author : Tom Tucker < tom @ opengridcomputing . com >
*/
# include <linux/sched.h>
# include <linux/errno.h>
# include <linux/fcntl.h>
# include <linux/net.h>
# include <linux/in.h>
# include <linux/inet.h>
# include <linux/udp.h>
# include <linux/tcp.h>
# include <linux/unistd.h>
# include <linux/slab.h>
# include <linux/netdevice.h>
# include <linux/skbuff.h>
# include <linux/file.h>
# include <linux/freezer.h>
# include <net/sock.h>
# include <net/checksum.h>
# include <net/ip.h>
# include <net/ipv6.h>
# include <net/tcp_states.h>
# include <linux/uaccess.h>
# include <asm/ioctls.h>
# include <linux/sunrpc/types.h>
# include <linux/sunrpc/clnt.h>
# include <linux/sunrpc/xdr.h>
# include <linux/sunrpc/svcsock.h>
# include <linux/sunrpc/stats.h>
# include <linux/sunrpc/svc_xprt.h>
# define RPCDBG_FACILITY RPCDBG_SVCXPRT
/* List of registered transport classes */
static DEFINE_SPINLOCK ( svc_xprt_class_lock ) ;
static LIST_HEAD ( svc_xprt_class_list ) ;
int svc_reg_xprt_class ( struct svc_xprt_class * xcl )
{
struct svc_xprt_class * cl ;
int res = - EEXIST ;
dprintk ( " svc: Adding svc transport class '%s' \n " , xcl - > xcl_name ) ;
INIT_LIST_HEAD ( & xcl - > xcl_list ) ;
spin_lock ( & svc_xprt_class_lock ) ;
/* Make sure there isn't already a class with the same name */
list_for_each_entry ( cl , & svc_xprt_class_list , xcl_list ) {
if ( strcmp ( xcl - > xcl_name , cl - > xcl_name ) = = 0 )
goto out ;
}
list_add_tail ( & xcl - > xcl_list , & svc_xprt_class_list ) ;
res = 0 ;
out :
spin_unlock ( & svc_xprt_class_lock ) ;
return res ;
}
EXPORT_SYMBOL_GPL ( svc_reg_xprt_class ) ;
void svc_unreg_xprt_class ( struct svc_xprt_class * xcl )
{
dprintk ( " svc: Removing svc transport class '%s' \n " , xcl - > xcl_name ) ;
spin_lock ( & svc_xprt_class_lock ) ;
list_del_init ( & xcl - > xcl_list ) ;
spin_unlock ( & svc_xprt_class_lock ) ;
}
EXPORT_SYMBOL_GPL ( svc_unreg_xprt_class ) ;
2007-12-31 06:07:46 +03:00
static void svc_xprt_free ( struct kref * kref )
{
struct svc_xprt * xprt =
container_of ( kref , struct svc_xprt , xpt_ref ) ;
struct module * owner = xprt - > xpt_class - > xcl_owner ;
2007-12-31 06:08:08 +03:00
if ( test_bit ( XPT_CACHE_AUTH , & xprt - > xpt_flags )
& & xprt - > xpt_auth_cache ! = NULL )
svcauth_unix_info_release ( xprt - > xpt_auth_cache ) ;
2007-12-31 06:07:46 +03:00
xprt - > xpt_ops - > xpo_free ( xprt ) ;
module_put ( owner ) ;
}
void svc_xprt_put ( struct svc_xprt * xprt )
{
kref_put ( & xprt - > xpt_ref , svc_xprt_free ) ;
}
EXPORT_SYMBOL_GPL ( svc_xprt_put ) ;
2007-12-31 06:07:15 +03:00
/*
* Called by transport drivers to initialize the transport independent
* portion of the transport instance .
*/
2007-12-31 06:07:50 +03:00
void svc_xprt_init ( struct svc_xprt_class * xcl , struct svc_xprt * xprt ,
struct svc_serv * serv )
2007-12-31 06:07:15 +03:00
{
memset ( xprt , 0 , sizeof ( * xprt ) ) ;
xprt - > xpt_class = xcl ;
xprt - > xpt_ops = xcl - > xcl_ops ;
2007-12-31 06:07:46 +03:00
kref_init ( & xprt - > xpt_ref ) ;
2007-12-31 06:07:50 +03:00
xprt - > xpt_server = serv ;
2007-12-31 06:07:53 +03:00
INIT_LIST_HEAD ( & xprt - > xpt_list ) ;
INIT_LIST_HEAD ( & xprt - > xpt_ready ) ;
2007-12-31 06:07:59 +03:00
mutex_init ( & xprt - > xpt_mutex ) ;
2007-12-31 06:08:08 +03:00
spin_lock_init ( & xprt - > xpt_lock ) ;
2007-12-31 06:07:15 +03:00
}
EXPORT_SYMBOL_GPL ( svc_xprt_init ) ;
2007-12-31 06:07:42 +03:00
int svc_create_xprt ( struct svc_serv * serv , char * xprt_name , unsigned short port ,
int flags )
{
struct svc_xprt_class * xcl ;
int ret = - ENOENT ;
struct sockaddr_in sin = {
. sin_family = AF_INET ,
. sin_addr . s_addr = INADDR_ANY ,
. sin_port = htons ( port ) ,
} ;
dprintk ( " svc: creating transport %s[%d] \n " , xprt_name , port ) ;
spin_lock ( & svc_xprt_class_lock ) ;
list_for_each_entry ( xcl , & svc_xprt_class_list , xcl_list ) {
if ( strcmp ( xprt_name , xcl - > xcl_name ) = = 0 ) {
spin_unlock ( & svc_xprt_class_lock ) ;
if ( try_module_get ( xcl - > xcl_owner ) ) {
struct svc_xprt * newxprt ;
ret = 0 ;
newxprt = xcl - > xcl_ops - > xpo_create
( serv ,
( struct sockaddr * ) & sin , sizeof ( sin ) ,
flags ) ;
if ( IS_ERR ( newxprt ) ) {
module_put ( xcl - > xcl_owner ) ;
ret = PTR_ERR ( newxprt ) ;
}
}
goto out ;
}
}
spin_unlock ( & svc_xprt_class_lock ) ;
dprintk ( " svc: transport %s not found \n " , xprt_name ) ;
out :
return ret ;
}
EXPORT_SYMBOL_GPL ( svc_create_xprt ) ;