2001-08-20 12:03:02 +04:00
/*
* dm - target . c
*
2001-09-25 19:23:20 +04:00
* Copyright ( C ) 2001 Sistina Software ( UK ) Limited
2001-08-20 12:03:02 +04:00
*
2001-09-25 19:23:20 +04:00
* This file is released under the GPL .
2001-08-20 12:03:02 +04:00
*/
/*
* 16 / 08 / 2001 - First Version [ Joe Thornber ]
*/
# include "dm.h"
2001-09-13 22:30:05 +04:00
# include <linux/kmod.h>
2001-08-20 12:03:02 +04:00
2001-09-26 18:32:07 +04:00
struct tt_internal {
struct target_type tt ;
struct list_head list ;
long use ;
} ;
2001-09-25 19:23:20 +04:00
static LIST_HEAD ( _targets ) ;
static rwlock_t _lock = RW_LOCK_UNLOCKED ;
2001-08-20 12:03:02 +04:00
2001-09-13 22:30:05 +04:00
# define DM_MOD_NAME_SIZE 32
2001-08-20 12:03:02 +04:00
2001-09-26 18:32:07 +04:00
static inline struct tt_internal * __find_target_type ( const char * name )
2001-08-20 12:03:02 +04:00
{
2001-09-26 18:32:07 +04:00
struct list_head * tmp ;
struct tt_internal * ti ;
2001-09-13 22:30:05 +04:00
2001-09-25 19:23:20 +04:00
for ( tmp = _targets . next ; tmp ! = & _targets ; tmp = tmp - > next ) {
2001-09-13 22:30:05 +04:00
2001-09-26 18:32:07 +04:00
ti = list_entry ( tmp , struct tt_internal , list ) ;
if ( ! strcmp ( name , ti - > tt . name ) )
2001-09-26 21:32:57 +04:00
return ti ;
2001-09-13 22:30:05 +04:00
}
2001-09-25 19:23:20 +04:00
return 0 ;
}
2001-09-26 18:32:07 +04:00
static struct tt_internal * get_target_type ( const char * name )
2001-09-25 19:23:20 +04:00
{
2001-09-26 18:32:07 +04:00
struct tt_internal * ti ;
2001-09-25 19:23:20 +04:00
read_lock ( & _lock ) ;
2001-09-26 21:32:57 +04:00
ti = __find_target_type ( name ) ;
2001-09-26 18:32:07 +04:00
if ( ti - > use = = 0 & & ti - > tt . module )
__MOD_INC_USE_COUNT ( ti - > tt . module ) ;
ti - > use + + ;
2001-09-25 19:23:20 +04:00
read_unlock ( & _lock ) ;
2001-09-26 21:32:57 +04:00
return ti ;
2001-09-25 19:23:20 +04:00
}
static void load_module ( const char * name )
{
char module_name [ DM_MOD_NAME_SIZE ] = " dm- " ;
/* Length check for strcat() below */
if ( strlen ( name ) > ( DM_MOD_NAME_SIZE - 4 ) )
2001-09-26 21:32:57 +04:00
return ;
2001-09-25 19:23:20 +04:00
strcat ( module_name , name ) ;
request_module ( module_name ) ;
}
struct target_type * dm_get_target_type ( const char * name )
{
2001-09-26 18:32:07 +04:00
struct tt_internal * ti = get_target_type ( name ) ;
2001-09-25 19:23:20 +04:00
2001-09-26 18:32:07 +04:00
if ( ! ti ) {
2001-09-25 19:23:20 +04:00
load_module ( name ) ;
2001-09-26 18:32:07 +04:00
ti = get_target_type ( name ) ;
2001-09-13 22:30:05 +04:00
}
2001-08-20 12:03:02 +04:00
2001-09-26 18:32:07 +04:00
return ti ? & ti - > tt : 0 ;
2001-08-20 12:03:02 +04:00
}
2001-09-13 22:30:05 +04:00
void dm_put_target_type ( struct target_type * t )
2001-08-20 12:03:02 +04:00
{
2001-09-26 21:32:57 +04:00
struct tt_internal * ti = ( struct tt_internal * ) t ;
2001-09-26 18:32:07 +04:00
2001-09-25 19:23:20 +04:00
read_lock ( & _lock ) ;
2001-09-26 18:32:07 +04:00
if ( - - ti - > use = = 0 & & ti - > tt . module )
2001-09-26 21:32:57 +04:00
__MOD_DEC_USE_COUNT ( ti - > tt . module ) ;
2001-09-25 19:23:20 +04:00
2001-09-26 18:32:07 +04:00
if ( ti - > use < 0 )
2001-09-13 22:30:05 +04:00
BUG ( ) ;
2001-09-25 19:23:20 +04:00
read_unlock ( & _lock ) ;
2001-09-13 22:30:05 +04:00
}
2001-08-20 12:03:02 +04:00
2001-09-26 21:32:57 +04:00
static struct tt_internal * alloc_target ( struct target_type * t )
2001-09-26 18:32:07 +04:00
{
2001-09-26 21:32:57 +04:00
struct tt_internal * ti = kmalloc ( sizeof ( * ti ) , GFP_KERNEL ) ;
2001-09-26 18:32:07 +04:00
if ( ti ) {
memset ( ti , 0 , sizeof ( * ti ) ) ;
2001-09-26 21:32:57 +04:00
ti - > tt = * t ;
2001-09-26 18:32:07 +04:00
}
return ti ;
}
2001-09-13 22:30:05 +04:00
int dm_register_target ( struct target_type * t )
{
int rv = 0 ;
2001-09-26 18:32:07 +04:00
struct tt_internal * ti = alloc_target ( t ) ;
if ( ! ti )
return - ENOMEM ;
2001-09-25 19:23:20 +04:00
write_lock ( & _lock ) ;
2001-09-26 18:32:07 +04:00
if ( __find_target_type ( t - > name ) )
2001-09-13 22:30:05 +04:00
rv = - EEXIST ;
2001-09-26 18:32:07 +04:00
else
list_add ( & ti - > list , & _targets ) ;
2001-09-25 19:23:20 +04:00
write_unlock ( & _lock ) ;
2001-09-13 22:30:05 +04:00
return rv ;
}
2001-08-20 12:03:02 +04:00
2001-09-13 22:30:05 +04:00
int dm_unregister_target ( struct target_type * t )
{
2001-09-26 18:32:07 +04:00
struct tt_internal * ti = ( struct tt_internal * ) t ;
2001-09-13 22:30:05 +04:00
int rv = - ETXTBSY ;
2001-08-20 12:03:02 +04:00
2001-09-25 19:23:20 +04:00
write_lock ( & _lock ) ;
2001-09-26 18:32:07 +04:00
if ( ti - > use = = 0 ) {
list_del ( & ti - > list ) ;
kfree ( ti ) ;
2001-09-13 22:30:05 +04:00
rv = 0 ;
}
2001-09-25 19:23:20 +04:00
write_unlock ( & _lock ) ;
2001-08-20 12:03:02 +04:00
2001-09-13 22:30:05 +04:00
return rv ;
2001-08-20 12:03:02 +04:00
}
/*
2001-08-31 16:49:31 +04:00
* io - err : always fails an io , useful for bringing
* up LV ' s that have holes in them .
2001-08-20 12:03:02 +04:00
*/
2001-09-26 18:32:07 +04:00
static int io_err_ctr ( struct dm_table * t , offset_t b , offset_t l ,
2001-09-26 21:32:57 +04:00
struct text_region * args , void * * context ,
dm_error_fn err , void * e_private )
2001-08-20 12:03:02 +04:00
{
2001-09-26 18:32:07 +04:00
* context = 0 ;
return 0 ;
2001-08-20 12:03:02 +04:00
}
2001-08-31 20:36:56 +04:00
static void io_err_dtr ( struct dm_table * t , void * c )
2001-08-20 12:03:02 +04:00
{
/* empty */
}
2001-09-14 20:22:02 +04:00
static int io_err_map ( struct buffer_head * bh , int rw , void * context )
2001-08-20 12:03:02 +04:00
{
buffer_IO_error ( bh ) ;
return 0 ;
}
2001-09-13 22:30:05 +04:00
static struct target_type error_target = {
name : " error " ,
ctr : io_err_ctr ,
dtr : io_err_dtr ,
map : io_err_map
2001-08-20 12:03:02 +04:00
} ;
2001-08-31 16:49:31 +04:00
int dm_target_init ( void )
2001-08-20 12:03:02 +04:00
{
2001-09-13 22:30:05 +04:00
return dm_register_target ( & error_target ) ;
2001-08-20 12:03:02 +04:00
}
2001-08-31 20:36:56 +04:00
EXPORT_SYMBOL ( dm_register_target ) ;
2001-09-13 22:30:05 +04:00
EXPORT_SYMBOL ( dm_unregister_target ) ;