2001-08-20 12:03:02 +04:00
/*
* dm - target . c
*
* Copyright ( C ) 2001 Sistina Software
*
* This software is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation ; either version 2 , or ( at
* your option ) any later version .
*
* This software is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with GNU CC ; see the file COPYING . If not , write to
* the Free Software Foundation , 59 Temple Place - Suite 330 ,
* Boston , MA 02111 - 1307 , USA .
*/
/*
* 16 / 08 / 2001 - First Version [ Joe Thornber ]
*/
# include "dm.h"
2001-08-31 16:49:31 +04:00
static struct target_type * _targets ;
2001-08-20 12:03:02 +04:00
static spinlock_t _lock = SPIN_LOCK_UNLOCKED ;
2001-08-31 16:49:31 +04:00
struct target_type * __get_target ( const char * name )
2001-08-20 12:03:02 +04:00
{
2001-08-31 16:49:31 +04:00
struct target_type * t ;
2001-08-20 12:03:02 +04:00
for ( t = _targets ; t & & strcmp ( t - > name , name ) ; t = t - > next )
;
return t ;
}
2001-09-07 15:34:46 +04:00
struct target_type * dm_get_target_type ( const char * name )
2001-08-20 12:03:02 +04:00
{
2001-08-31 16:49:31 +04:00
struct target_type * t ;
2001-08-20 12:03:02 +04:00
spin_lock ( & _lock ) ;
t = __get_target ( name ) ;
spin_unlock ( & _lock ) ;
2001-08-23 20:45:43 +04:00
2001-08-20 12:03:02 +04:00
return t ;
}
2001-08-31 19:13:33 +04:00
/*
* register a new target_type .
*/
2001-08-31 20:36:56 +04:00
int dm_register_target ( const char * name , dm_ctr_fn ctr ,
dm_dtr_fn dtr , dm_map_fn map )
2001-08-20 12:03:02 +04:00
{
2001-08-31 16:49:31 +04:00
struct target_type * t =
kmalloc ( sizeof ( * t ) + strlen ( name ) + 1 , GFP_KERNEL ) ;
2001-08-20 12:03:02 +04:00
if ( ! t )
return - ENOMEM ;
spin_lock ( & _lock ) ;
if ( __get_target ( name ) ) {
WARN ( " mapper(%s) already registered \n " , name ) ;
spin_unlock ( & _lock ) ;
return - 1 ; /* FIXME: what's a good return value ? */
}
2001-08-22 19:12:31 +04:00
t - > name = ( char * ) ( t + 1 ) ;
2001-08-22 18:13:26 +04:00
strcpy ( t - > name , name ) ;
2001-08-20 12:03:02 +04:00
t - > ctr = ctr ;
t - > dtr = dtr ;
t - > map = map ;
t - > next = _targets ;
_targets = t ;
spin_unlock ( & _lock ) ;
return 0 ;
}
/*
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-07 15:34:46 +04:00
static int io_err_ctr ( struct dm_table * t , offset_t b , offset_t l ,
struct text_region * args , void * * result ,
dm_error_fn fn , void * private )
2001-08-20 12:03:02 +04:00
{
/* this takes no arguments */
* result = 0 ;
2001-08-23 16:35:02 +04:00
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-08-29 17:58:48 +04:00
static int io_err_map ( struct buffer_head * bh , void * context )
2001-08-20 12:03:02 +04:00
{
buffer_IO_error ( bh ) ;
return 0 ;
}
2001-08-31 16:49:31 +04:00
/*
* linear : maps a linear range of a device .
*/
2001-08-20 12:03:02 +04:00
struct linear_c {
kdev_t dev ;
2001-09-02 14:49:20 +04:00
int delta ; /* FIXME: we need a signed offset type */
2001-08-20 12:03:02 +04:00
} ;
2001-08-31 19:13:33 +04:00
/*
* construct a linear mapping .
2001-08-31 22:26:27 +04:00
* < dev_path > < offset >
2001-08-31 19:13:33 +04:00
*/
2001-09-07 15:34:46 +04:00
static int linear_ctr ( struct dm_table * t , offset_t b , offset_t l ,
struct text_region * args , void * * result ,
dm_error_fn fn , void * private )
2001-08-20 12:03:02 +04:00
{
struct linear_c * lc ;
2001-08-31 22:26:27 +04:00
unsigned int start ;
kdev_t dev ;
2001-08-23 16:35:02 +04:00
int r ;
2001-08-31 22:26:27 +04:00
char path [ 256 ] ;
2001-09-07 15:34:46 +04:00
struct text_region word ;
2001-08-20 12:03:02 +04:00
2001-09-07 15:34:46 +04:00
if ( ! dm_get_word ( args , & word ) ) {
fn ( " couldn't get device path " , private ) ;
return - EINVAL ;
}
2001-08-20 12:03:02 +04:00
2001-09-07 15:34:46 +04:00
dm_txt_copy ( path , sizeof ( path ) - 1 , & word ) ;
2001-08-20 12:03:02 +04:00
2001-09-07 15:34:46 +04:00
if ( ( r = dm_table_lookup_device ( path , & dev ) ) ) {
fn ( " no such device " , private ) ;
2001-08-23 16:35:02 +04:00
return r ;
2001-09-07 15:34:46 +04:00
}
2001-08-20 12:03:02 +04:00
2001-09-07 15:34:46 +04:00
if ( ! dm_get_number ( args , & start ) ) {
fn ( " destination start not given " , private ) ;
2001-08-23 16:35:02 +04:00
return - EINVAL ;
2001-08-20 12:03:02 +04:00
}
2001-09-07 15:34:46 +04:00
if ( ! ( lc = kmalloc ( sizeof ( lc ) , GFP_KERNEL ) ) ) {
fn ( " couldn't allocate memory for linear context \n " , private ) ;
return - ENOMEM ;
}
2001-08-31 22:26:27 +04:00
lc - > dev = dev ;
2001-09-02 14:49:20 +04:00
lc - > delta = ( int ) start - ( int ) b ;
2001-08-20 12:03:02 +04:00
2001-08-31 19:13:33 +04:00
if ( ( r = dm_table_add_device ( t , lc - > dev ) ) ) {
2001-09-07 15:34:46 +04:00
fn ( " failed to add destination device to list " , private ) ;
2001-08-20 20:12:22 +04:00
kfree ( lc ) ;
2001-08-23 20:45:43 +04:00
return r ;
2001-08-20 20:12:22 +04:00
}
2001-08-20 12:03:02 +04:00
* result = lc ;
2001-08-23 16:35:02 +04:00
return 0 ;
2001-08-20 12:03:02 +04:00
}
2001-08-31 20:36:56 +04:00
static void linear_dtr ( struct dm_table * t , void * c )
2001-08-20 12:03:02 +04:00
{
2001-08-31 20:36:56 +04:00
struct linear_c * lc = ( struct linear_c * ) c ;
dm_table_remove_device ( t , lc - > dev ) ;
2001-08-20 12:03:02 +04:00
kfree ( c ) ;
}
2001-08-29 17:58:48 +04:00
static int linear_map ( struct buffer_head * bh , void * context )
2001-08-20 12:03:02 +04:00
{
struct linear_c * lc = ( struct linear_c * ) context ;
bh - > b_rdev = lc - > dev ;
2001-09-02 14:49:20 +04:00
bh - > b_rsector = bh - > b_rsector + lc - > delta ;
2001-08-20 12:03:02 +04:00
return 1 ;
}
2001-08-31 16:49:31 +04:00
/*
* registers io - err and linear targets
*/
int dm_target_init ( void )
2001-08-20 12:03:02 +04:00
{
int ret ;
# define xx(n, fn) \
2001-08-31 20:36:56 +04:00
if ( ( ret = dm_register_target ( n , \
2001-08-20 12:03:02 +04:00
fn # # _ctr , fn # # _dtr , fn # # _map ) < 0 ) ) return ret
2001-08-23 16:35:02 +04:00
xx ( " io-err " , io_err ) ;
xx ( " linear " , linear ) ;
2001-08-20 12:03:02 +04:00
# undef xx
return 0 ;
}
2001-08-31 20:36:56 +04:00
EXPORT_SYMBOL ( dm_register_target ) ;