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
static LIST_HEAD ( _targets ) ;
static DECLARE_RWSEM ( _lock ) ;
# define DM_MOD_NAME_SIZE 32
2009-04-02 22:55:28 +04:00
static inline struct target_type * __find_target_type ( const char * name )
2005-04-17 02:20:36 +04:00
{
2009-04-02 22:55:28 +04:00
struct target_type * tt ;
2005-04-17 02:20:36 +04:00
2009-04-02 22:55:28 +04:00
list_for_each_entry ( tt , & _targets , list )
if ( ! strcmp ( name , tt - > name ) )
return tt ;
2005-04-17 02:20:36 +04:00
return NULL ;
}
2009-04-02 22:55:28 +04:00
static struct target_type * get_target_type ( const char * name )
2005-04-17 02:20:36 +04:00
{
2009-04-02 22:55:28 +04:00
struct target_type * tt ;
2005-04-17 02:20:36 +04:00
down_read ( & _lock ) ;
2009-04-02 22:55:28 +04:00
tt = __find_target_type ( name ) ;
if ( tt & & ! try_module_get ( tt - > module ) )
tt = NULL ;
2005-04-17 02:20:36 +04:00
up_read ( & _lock ) ;
2009-04-02 22:55:28 +04:00
return tt ;
2005-04-17 02:20:36 +04:00
}
static void load_module ( const char * name )
{
request_module ( " dm-%s " , name ) ;
}
struct target_type * dm_get_target_type ( const char * name )
{
2009-04-02 22:55:28 +04:00
struct target_type * tt = get_target_type ( name ) ;
2005-04-17 02:20:36 +04:00
2009-04-02 22:55:28 +04:00
if ( ! tt ) {
2005-04-17 02:20:36 +04:00
load_module ( name ) ;
2009-04-02 22:55:28 +04:00
tt = get_target_type ( name ) ;
2005-04-17 02:20:36 +04:00
}
2009-04-02 22:55:28 +04:00
return tt ;
2005-04-17 02:20:36 +04:00
}
2009-04-02 22:55:28 +04:00
void dm_put_target_type ( struct target_type * tt )
2005-04-17 02:20:36 +04:00
{
down_read ( & _lock ) ;
2009-04-02 22:55:28 +04:00
module_put ( tt - > module ) ;
2005-04-17 02:20:36 +04:00
up_read ( & _lock ) ;
}
int dm_target_iterate ( void ( * iter_func ) ( struct target_type * tt ,
void * param ) , void * param )
{
2009-04-02 22:55:28 +04:00
struct target_type * tt ;
2005-04-17 02:20:36 +04:00
down_read ( & _lock ) ;
2009-04-02 22:55:28 +04:00
list_for_each_entry ( tt , & _targets , list )
iter_func ( tt , param ) ;
2005-04-17 02:20:36 +04:00
up_read ( & _lock ) ;
return 0 ;
}
2009-04-02 22:55:28 +04:00
int dm_register_target ( struct target_type * tt )
2005-04-17 02:20:36 +04:00
{
int rv = 0 ;
down_write ( & _lock ) ;
2009-04-02 22:55:28 +04:00
if ( __find_target_type ( tt - > name ) )
2005-04-17 02:20:36 +04:00
rv = - EEXIST ;
else
2009-04-02 22:55:28 +04:00
list_add ( & tt - > list , & _targets ) ;
2005-04-17 02:20:36 +04:00
up_write ( & _lock ) ;
return rv ;
}
2009-04-02 22:55:28 +04:00
void dm_unregister_target ( struct target_type * tt )
2005-04-17 02:20:36 +04:00
{
down_write ( & _lock ) ;
2009-04-02 22:55:28 +04:00
if ( ! __find_target_type ( tt - > name ) ) {
DMCRIT ( " Unregistering unrecognised target: %s " , tt - > name ) ;
2009-01-06 06:04:58 +03:00
BUG ( ) ;
2005-04-17 02:20:36 +04:00
}
2009-04-02 22:55:28 +04:00
list_del ( & tt - > list ) ;
2005-04-17 02:20:36 +04:00
up_write ( & _lock ) ;
}
/*
* io - err : always fails an io , useful for bringing
* up LVs that have holes in them .
*/
2009-04-02 22:55:28 +04:00
static int io_err_ctr ( struct dm_target * tt , unsigned int argc , char * * args )
2005-04-17 02:20:36 +04:00
{
return 0 ;
}
2009-04-02 22:55:28 +04:00
static void io_err_dtr ( struct dm_target * tt )
2005-04-17 02:20:36 +04:00
{
/* empty */
}
2009-04-02 22:55:28 +04:00
static int io_err_map ( struct dm_target * tt , struct bio * bio ,
2005-04-17 02:20:36 +04:00
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 ) ;