2009-02-24 18:30:21 +03:00
/*
2018-07-24 06:51:21 +03:00
* Copyright ( c ) 2006 , 2017 Oracle and / or its affiliates . All rights reserved .
2009-02-24 18:30:21 +03:00
*
* This software is available to you under a choice of one of two
* licenses . You may choose to be licensed under the terms of the GNU
* General Public License ( GPL ) Version 2 , available from the file
* COPYING in the main directory of this source tree , or the
* OpenIB . org BSD license below :
*
* Redistribution and use in source and binary forms , with or
* without modification , are permitted provided that the following
* conditions are met :
*
* - Redistributions of source code must retain the above
* copyright notice , this list of conditions and the following
* disclaimer .
*
* - Redistributions in binary form must reproduce the above
* copyright notice , this list of conditions and the following
* disclaimer in the documentation and / or other materials
* provided with the distribution .
*
* THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND ,
* EXPRESS OR IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY , FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT . IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM , DAMAGES OR OTHER LIABILITY , WHETHER IN AN
* ACTION OF CONTRACT , TORT OR OTHERWISE , ARISING FROM , OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE .
*
*/
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/in.h>
2018-07-24 06:51:21 +03:00
# include <linux/ipv6.h>
2009-02-24 18:30:21 +03:00
# include "rds.h"
# include "loop.h"
2020-06-25 23:46:00 +03:00
static char * const rds_trans_modules [ ] = {
[ RDS_TRANS_IB ] = " rds_rdma " ,
[ RDS_TRANS_GAP ] = NULL ,
[ RDS_TRANS_TCP ] = " rds_tcp " ,
} ;
2009-08-21 16:28:34 +04:00
static struct rds_transport * transports [ RDS_TRANS_COUNT ] ;
2009-02-24 18:30:21 +03:00
static DECLARE_RWSEM ( rds_trans_sem ) ;
2017-03-03 08:44:26 +03:00
void rds_trans_register ( struct rds_transport * trans )
2009-02-24 18:30:21 +03:00
{
BUG_ON ( strlen ( trans - > t_name ) + 1 > TRANSNAMSIZ ) ;
down_write ( & rds_trans_sem ) ;
2009-08-21 16:28:34 +04:00
if ( transports [ trans - > t_type ] )
printk ( KERN_ERR " RDS Transport type %d already registered \n " ,
trans - > t_type ) ;
else {
transports [ trans - > t_type ] = trans ;
printk ( KERN_INFO " Registered RDS/%s transport \n " , trans - > t_name ) ;
}
2009-02-24 18:30:21 +03:00
up_write ( & rds_trans_sem ) ;
}
2009-08-21 16:28:32 +04:00
EXPORT_SYMBOL_GPL ( rds_trans_register ) ;
2009-02-24 18:30:21 +03:00
void rds_trans_unregister ( struct rds_transport * trans )
{
down_write ( & rds_trans_sem ) ;
2009-08-21 16:28:34 +04:00
transports [ trans - > t_type ] = NULL ;
2009-02-24 18:30:21 +03:00
printk ( KERN_INFO " Unregistered RDS/%s transport \n " , trans - > t_name ) ;
up_write ( & rds_trans_sem ) ;
}
2009-08-21 16:28:32 +04:00
EXPORT_SYMBOL_GPL ( rds_trans_unregister ) ;
2009-02-24 18:30:21 +03:00
2010-07-23 21:32:31 +04:00
void rds_trans_put ( struct rds_transport * trans )
{
2015-07-02 18:58:21 +03:00
if ( trans )
2010-07-23 21:32:31 +04:00
module_put ( trans - > t_owner ) ;
}
2018-07-24 06:51:21 +03:00
struct rds_transport * rds_trans_get_preferred ( struct net * net ,
const struct in6_addr * addr ,
__u32 scope_id )
2009-02-24 18:30:21 +03:00
{
struct rds_transport * ret = NULL ;
2010-07-23 21:32:31 +04:00
struct rds_transport * trans ;
unsigned int i ;
2009-02-24 18:30:21 +03:00
2018-07-24 06:51:21 +03:00
if ( ipv6_addr_v4mapped ( addr ) ) {
if ( * ( u_int8_t * ) & addr - > s6_addr32 [ 3 ] = = IN_LOOPBACKNET )
return & rds_loop_transport ;
} else if ( ipv6_addr_loopback ( addr ) ) {
2009-02-24 18:30:21 +03:00
return & rds_loop_transport ;
2018-07-24 06:51:21 +03:00
}
2009-02-24 18:30:21 +03:00
down_read ( & rds_trans_sem ) ;
2010-07-23 21:32:31 +04:00
for ( i = 0 ; i < RDS_TRANS_COUNT ; i + + ) {
trans = transports [ i ] ;
2018-07-24 06:51:21 +03:00
if ( trans & & ( trans - > laddr_check ( net , addr , scope_id ) = = 0 ) & &
2010-07-23 21:32:31 +04:00
( ! trans - > t_owner | | try_module_get ( trans - > t_owner ) ) ) {
ret = trans ;
2009-02-24 18:30:21 +03:00
break ;
}
}
up_read ( & rds_trans_sem ) ;
return ret ;
}
2015-05-30 00:28:08 +03:00
struct rds_transport * rds_trans_get ( int t_type )
{
struct rds_transport * ret = NULL ;
struct rds_transport * trans ;
down_read ( & rds_trans_sem ) ;
2020-06-25 23:46:00 +03:00
trans = transports [ t_type ] ;
if ( ! trans ) {
up_read ( & rds_trans_sem ) ;
if ( rds_trans_modules [ t_type ] )
request_module ( rds_trans_modules [ t_type ] ) ;
down_read ( & rds_trans_sem ) ;
trans = transports [ t_type ] ;
2015-05-30 00:28:08 +03:00
}
2020-06-25 23:46:00 +03:00
if ( trans & & trans - > t_type = = t_type & &
( ! trans - > t_owner | | try_module_get ( trans - > t_owner ) ) )
ret = trans ;
2015-05-30 00:28:08 +03:00
up_read ( & rds_trans_sem ) ;
return ret ;
}
2009-02-24 18:30:21 +03:00
/*
* This returns the number of stats entries in the snapshot and only
* copies them using the iter if there is enough space for them . The
* caller passes in the global stats so that we can size and copy while
* holding the lock .
*/
unsigned int rds_trans_stats_info_copy ( struct rds_info_iterator * iter ,
unsigned int avail )
{
struct rds_transport * trans ;
unsigned int total = 0 ;
unsigned int part ;
2009-08-21 16:28:34 +04:00
int i ;
2009-02-24 18:30:21 +03:00
rds_info_iter_unmap ( iter ) ;
down_read ( & rds_trans_sem ) ;
2016-06-18 18:46:31 +03:00
for ( i = 0 ; i < RDS_TRANS_COUNT ; i + + ) {
2009-08-21 16:28:34 +04:00
trans = transports [ i ] ;
if ( ! trans | | ! trans - > stats_info_copy )
2009-02-24 18:30:21 +03:00
continue ;
part = trans - > stats_info_copy ( iter , avail ) ;
avail - = min ( avail , part ) ;
total + = part ;
}
up_read ( & rds_trans_sem ) ;
return total ;
}