2005-04-17 02:20:36 +04:00
/*
* Copyright ( C ) 2001 Sistina Software ( UK ) Limited
*
* This file is released under the GPL .
*/
# include "dm.h"
# include <linux/module.h>
# include <linux/init.h>
# include <linux/kmod.h>
# include <linux/bio.h>
# include <linux/slab.h>
2006-06-26 11:27:35 +04:00
# define DM_MSG_PREFIX "target"
2005-04-17 02:20:36 +04:00
struct tt_internal {
struct target_type tt ;
struct list_head list ;
long use ;
} ;
static LIST_HEAD ( _targets ) ;
static DECLARE_RWSEM ( _lock ) ;
# define DM_MOD_NAME_SIZE 32
static inline struct tt_internal * __find_target_type ( const char * name )
{
struct tt_internal * ti ;
list_for_each_entry ( ti , & _targets , list )
if ( ! strcmp ( name , ti - > tt . name ) )
return ti ;
return NULL ;
}
static struct tt_internal * get_target_type ( const char * name )
{
struct tt_internal * ti ;
down_read ( & _lock ) ;
ti = __find_target_type ( name ) ;
if ( ti ) {
if ( ( ti - > use = = 0 ) & & ! try_module_get ( ti - > tt . module ) )
ti = NULL ;
else
ti - > use + + ;
}
up_read ( & _lock ) ;
return ti ;
}
static void load_module ( const char * name )
{
request_module ( " dm-%s " , name ) ;
}
struct target_type * dm_get_target_type ( const char * name )
{
struct tt_internal * ti = get_target_type ( name ) ;
if ( ! ti ) {
load_module ( name ) ;
ti = get_target_type ( name ) ;
}
return ti ? & ti - > tt : NULL ;
}
void dm_put_target_type ( struct target_type * t )
{
struct tt_internal * ti = ( struct tt_internal * ) t ;
down_read ( & _lock ) ;
if ( - - ti - > use = = 0 )
module_put ( ti - > tt . module ) ;
2006-04-01 03:08:12 +04:00
BUG_ON ( ti - > use < 0 ) ;
2005-04-17 02:20:36 +04:00
up_read ( & _lock ) ;
return ;
}
static struct tt_internal * alloc_target ( struct target_type * t )
{
2007-10-20 01:38:51 +04:00
struct tt_internal * ti = kzalloc ( sizeof ( * ti ) , GFP_KERNEL ) ;
2005-04-17 02:20:36 +04:00
2007-10-20 01:38:51 +04:00
if ( ti )
2005-04-17 02:20:36 +04:00
ti - > tt = * t ;
return ti ;
}
int dm_target_iterate ( void ( * iter_func ) ( struct target_type * tt ,
void * param ) , void * param )
{
struct tt_internal * ti ;
down_read ( & _lock ) ;
list_for_each_entry ( ti , & _targets , list )
iter_func ( & ti - > tt , param ) ;
up_read ( & _lock ) ;
return 0 ;
}
int dm_register_target ( struct target_type * t )
{
int rv = 0 ;
struct tt_internal * ti = alloc_target ( t ) ;
if ( ! ti )
return - ENOMEM ;
down_write ( & _lock ) ;
if ( __find_target_type ( t - > name ) )
rv = - EEXIST ;
else
list_add ( & ti - > list , & _targets ) ;
up_write ( & _lock ) ;
if ( rv )
kfree ( ti ) ;
return rv ;
}
2009-01-06 06:04:58 +03:00
void dm_unregister_target ( struct target_type * t )
2005-04-17 02:20:36 +04:00
{
struct tt_internal * ti ;
down_write ( & _lock ) ;
if ( ! ( ti = __find_target_type ( t - > name ) ) ) {
2009-01-06 06:04:58 +03:00
DMCRIT ( " Unregistering unrecognised target: %s " , t - > name ) ;
BUG ( ) ;
2005-04-17 02:20:36 +04:00
}
if ( ti - > use ) {
2009-01-06 06:04:58 +03:00
DMCRIT ( " Attempt to unregister target still in use: %s " ,
t - > name ) ;
BUG ( ) ;
2005-04-17 02:20:36 +04:00
}
list_del ( & ti - > list ) ;
kfree ( ti ) ;
up_write ( & _lock ) ;
}
/*
* io - err : always fails an io , useful for bringing
* up LVs that have holes in them .
*/
static int io_err_ctr ( struct dm_target * ti , unsigned int argc , char * * args )
{
return 0 ;
}
static void io_err_dtr ( struct dm_target * ti )
{
/* empty */
}
static int io_err_map ( struct dm_target * ti , struct bio * bio ,
union map_info * map_context )
{
return - EIO ;
}
static struct target_type error_target = {
. name = " error " ,
. version = { 1 , 0 , 1 } ,
. ctr = io_err_ctr ,
. dtr = io_err_dtr ,
. map = io_err_map ,
} ;
int __init dm_target_init ( void )
{
return dm_register_target ( & error_target ) ;
}
void dm_target_exit ( void )
{
2009-01-06 06:04:58 +03:00
dm_unregister_target ( & error_target ) ;
2005-04-17 02:20:36 +04:00
}
EXPORT_SYMBOL ( dm_register_target ) ;
EXPORT_SYMBOL ( dm_unregister_target ) ;