2005-04-17 02:20:36 +04:00
/*
* Copyright ( C ) 2003 Sistina Software .
* Copyright ( C ) 2004 Red Hat , Inc . All rights reserved .
*
* Module Author : Heinz Mauelshagen
*
* This file is released under the GPL .
*
* Path selector registration .
*/
2008-10-21 20:44:59 +04:00
# include <linux/device-mapper.h>
2005-04-17 02:20:36 +04:00
# include "dm-path-selector.h"
# include <linux/slab.h>
struct ps_internal {
struct path_selector_type pst ;
struct list_head list ;
} ;
# define pst_to_psi(__pst) container_of((__pst), struct ps_internal, pst)
static LIST_HEAD ( _path_selectors ) ;
static DECLARE_RWSEM ( _ps_lock ) ;
2005-05-06 03:16:09 +04:00
static struct ps_internal * __find_path_selector_type ( const char * name )
2005-04-17 02:20:36 +04:00
{
struct ps_internal * psi ;
list_for_each_entry ( psi , & _path_selectors , list ) {
if ( ! strcmp ( name , psi - > pst . name ) )
return psi ;
}
return NULL ;
}
static struct ps_internal * get_path_selector ( const char * name )
{
struct ps_internal * psi ;
down_read ( & _ps_lock ) ;
psi = __find_path_selector_type ( name ) ;
2009-04-02 22:55:27 +04:00
if ( psi & & ! try_module_get ( psi - > pst . module ) )
psi = NULL ;
2005-04-17 02:20:36 +04:00
up_read ( & _ps_lock ) ;
return psi ;
}
struct path_selector_type * dm_get_path_selector ( const char * name )
{
struct ps_internal * psi ;
if ( ! name )
return NULL ;
psi = get_path_selector ( name ) ;
if ( ! psi ) {
request_module ( " dm-%s " , name ) ;
psi = get_path_selector ( name ) ;
}
return psi ? & psi - > pst : NULL ;
}
void dm_put_path_selector ( struct path_selector_type * pst )
{
struct ps_internal * psi ;
if ( ! pst )
return ;
down_read ( & _ps_lock ) ;
psi = __find_path_selector_type ( pst - > name ) ;
if ( ! psi )
goto out ;
2009-04-02 22:55:27 +04:00
module_put ( psi - > pst . module ) ;
2005-04-17 02:20:36 +04:00
out :
up_read ( & _ps_lock ) ;
}
static struct ps_internal * _alloc_path_selector ( struct path_selector_type * pst )
{
2007-10-20 01:38:51 +04:00
struct ps_internal * psi = kzalloc ( sizeof ( * psi ) , GFP_KERNEL ) ;
2005-04-17 02:20:36 +04:00
2007-10-20 01:38:51 +04:00
if ( psi )
2005-04-17 02:20:36 +04:00
psi - > pst = * pst ;
return psi ;
}
int dm_register_path_selector ( struct path_selector_type * pst )
{
int r = 0 ;
struct ps_internal * psi = _alloc_path_selector ( pst ) ;
if ( ! psi )
return - ENOMEM ;
down_write ( & _ps_lock ) ;
if ( __find_path_selector_type ( pst - > name ) ) {
kfree ( psi ) ;
r = - EEXIST ;
} else
list_add ( & psi - > list , & _path_selectors ) ;
up_write ( & _ps_lock ) ;
return r ;
}
int dm_unregister_path_selector ( struct path_selector_type * pst )
{
struct ps_internal * psi ;
down_write ( & _ps_lock ) ;
psi = __find_path_selector_type ( pst - > name ) ;
if ( ! psi ) {
up_write ( & _ps_lock ) ;
return - EINVAL ;
}
list_del ( & psi - > list ) ;
up_write ( & _ps_lock ) ;
kfree ( psi ) ;
return 0 ;
}
EXPORT_SYMBOL_GPL ( dm_register_path_selector ) ;
EXPORT_SYMBOL_GPL ( dm_unregister_path_selector ) ;