2001-08-20 12:03:02 +04:00
/*
* dm . 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 .
*/
/*
* procfs and devfs handling for device mapper
*
* Changelog
*
* 16 / 08 / 2001 - First version [ Joe Thornber ]
*/
# include "dm.h"
/*
* / dev / device - mapper / control is the control char device used to
* create / destroy mapping devices .
*
* When a mapping device called < name > is created it appears as
* / dev / device - mapper / < name > . In addition the interface to control the
* mapping will appear in / proc / device - mapper / < name > .
*/
const char * _fs_dir = " device-mapper " ;
2001-08-20 17:45:43 +04:00
const char * _control_name = " control " ;
2001-08-20 12:03:02 +04:00
static struct proc_dir_entry * _proc_dir ;
2001-08-20 17:45:43 +04:00
static struct proc_dir_entry * _control ;
2001-08-20 12:03:02 +04:00
static devfs_handle_t _dev_dir ;
2001-08-20 17:45:43 +04:00
static int _line_splitter ( struct file * file , const char * buffer ,
unsigned long * count , void * data )
typedef int ( process_fn ) ( const char * b , const char * e ) ;
struct pf_data {
process_fn data ;
int minor ;
} ;
2001-08-20 12:03:02 +04:00
int dm_init_fs ( )
{
2001-08-20 17:45:43 +04:00
struct pf_data * pfd = kmalloc ( sizeof ( * pfd ) , GFP_KERNEL ) ;
2001-08-20 12:03:02 +04:00
2001-08-20 17:45:43 +04:00
if ( ! pfd )
2001-08-20 12:03:02 +04:00
return 0 ;
2001-08-20 17:45:43 +04:00
_dev_dir = devfs_mk_dir ( 0 , _fs_dir , NULL ) ;
2001-08-20 12:03:02 +04:00
2001-08-20 17:45:43 +04:00
if ( ! ( _proc_dir = create_proc_entry ( _fs_dir , S_IFDIR , & proc_root ) ) )
goto fail ;
2001-08-20 12:03:02 +04:00
2001-08-20 17:45:43 +04:00
if ( ! ( _control = create_proc_entry ( _control_name , 0 , _proc_dir ) ) )
goto fail ;
2001-08-20 12:03:02 +04:00
2001-08-20 17:45:43 +04:00
_control - > write_proc = _line_splitter ;
2001-08-20 12:03:02 +04:00
2001-08-20 17:45:43 +04:00
pfd - > fn = _process_control ;
pfd - > minor = - 1 ;
_control - > data = pfd ;
return 1 ;
2001-08-20 12:03:02 +04:00
2001-08-20 17:45:43 +04:00
fail :
dm_fin_fs ( ) ;
return 0 ;
2001-08-20 12:03:02 +04:00
}
2001-08-20 17:45:43 +04:00
void dm_fin_fs ( void )
2001-08-20 12:03:02 +04:00
{
2001-08-20 17:45:43 +04:00
if ( _control ) {
remove_proc_entry ( _control_name , _proc_dir ) ;
_control = 0 ;
}
2001-08-20 12:03:02 +04:00
2001-08-20 17:45:43 +04:00
if ( _proc_dir ) {
remove_proc_entry ( _fs_dir , & proc_root ) ;
_proc_dir = 0 ;
}
2001-08-20 12:03:02 +04:00
2001-08-20 17:45:43 +04:00
if ( _dev_dir )
devfs_unregister ( _dev_dir ) ;
}
2001-08-20 12:03:02 +04:00
2001-08-20 17:45:43 +04:00
int _process_control ( const char * b , const char * e , int minor )
2001-08-20 12:03:02 +04:00
{
2001-08-20 17:45:43 +04:00
const char * wb , * we ;
char * name [ 64 ] ;
long minor = - 1 ;
int create = 0 ;
2001-08-20 12:03:02 +04:00
2001-08-20 17:45:43 +04:00
/*
* create < name > [ minor ]
* remove < name >
*/
if ( ! _get_word ( b , e , & wb , & we ) )
return - EINVAL ;
b = we ;
2001-08-20 12:03:02 +04:00
2001-08-20 17:45:43 +04:00
if ( ! _tok_cmp ( " create " , wb , we ) )
create = 1 ;
2001-08-20 12:03:02 +04:00
2001-08-20 17:45:43 +04:00
else if ( _tok_cmp ( " remove " , wb , we ) )
return - EINVAL ;
2001-08-20 12:03:02 +04:00
2001-08-20 17:45:43 +04:00
if ( ! _get_word ( b , e , & wb , & we ) )
return - EINVAL ;
b = we ;
2001-08-20 12:03:02 +04:00
2001-08-20 17:45:43 +04:00
_tok_cpy ( name , sizeof ( buffer ) , wb , we ) ;
2001-08-20 12:03:02 +04:00
2001-08-20 17:45:43 +04:00
if ( create ) {
if ( _get_word ( b , e , & wb , & we ) ) {
minor = simple_strtol ( wb , & we , 10 ) ;
2001-08-20 12:03:02 +04:00
2001-08-20 17:45:43 +04:00
if ( we = = wb )
return - EINVAL ;
}
_create_dm ( name , minor ) ;
2001-08-20 12:03:02 +04:00
2001-08-20 17:45:43 +04:00
} else {
if ( ! _get_word ( b , e , & wb , & we ) )
return - EINVAL ;
2001-08-20 12:03:02 +04:00
2001-08-20 17:45:43 +04:00
_tok_cpy ( name , sizeof ( buffer ) , wb , we ) ;
_remove_dm ( name , minor ) ;
2001-08-20 12:03:02 +04:00
}
2001-08-20 17:45:43 +04:00
return - EINVAL ;
2001-08-20 12:03:02 +04:00
}
2001-08-20 17:45:43 +04:00
static int _process_table ( const char * b , const char * e , int minor )
2001-08-20 12:03:02 +04:00
{
struct target * t ;
const char * wb , * we ;
char buffer [ 64 ] ;
int len ;
/*
* format of a line is :
* < highest valid sector > < target name > < target args >
*/
if ( ! _get_word ( b , e , & wb , & we ) | | ( we - wb ) > sizeof ( buffer ) )
return - EPARAM ;
len = we - wb ;
strncpy ( buffer , wb , we - wb ) ;
buffer [ len ] = ' \0 ' ;
if ( ! ( t = get_target ( buffer ) ) ) {
/* FIXME: add module loading here */
return - EPARAM ;
}
}
2001-08-20 17:45:43 +04:00
static int _process_table ( const char * b , const char * e , int minor )
2001-08-20 12:03:02 +04:00
{
2001-08-20 17:45:43 +04:00
const char * wb , * we ;
2001-08-20 12:03:02 +04:00
struct mapped_device * md = dm_get_dev ( minor ) ;
if ( ! md )
return - ENXIO ;
2001-08-20 17:45:43 +04:00
if ( ! _get_word ( b , e , & wb , & we ) )
return - EINVAL ;
if ( ! _tok_cmp ( " begin " , b , e ) ) {
/* suspend the device if it's active */
dm_suspend ( md ) ;
2001-08-20 12:03:02 +04:00
2001-08-20 17:45:43 +04:00
/* start loading a table */
dm_start_table ( md ) ;
2001-08-20 12:03:02 +04:00
2001-08-20 17:45:43 +04:00
} else if ( ! _tok_cmp ( " end " , b , e ) ) {
/* activate the device ... <evil chuckle> ... */
dm_complete_table ( md ) ;
dm_activate ( md ) ;
2001-08-20 12:03:02 +04:00
2001-08-20 17:45:43 +04:00
} else {
/* add the new entry */
int len = we - wb ;
char high_s [ 64 ] , * ptr ;
char target [ 64 ] ;
struct target * t ;
offset_t high ;
if ( len > sizeof ( high_s ) )
return 0 ;
strncpy ( high_s , wb , we - wb ) ;
high_s [ len ] = ' \0 ' ;
high = strtol ( high_s , & ptr , 10 ) ;
if ( ptr = = high_s )
return 0 ;
b = we ;
if ( ! _get_word ( b , e , & wb , & we ) )
return 0 ;
len = we - wb ;
if ( len > sizeof ( target ) )
return 0 ;
strncpy ( target , wb , len ) ;
target [ len ] = ' \0 ' ;
if ( ! ( t = dm_get_target ( target ) ) )
return 0 ;
dm_add_entry ( md , high , t , context ) ;
2001-08-20 12:03:02 +04:00
}
2001-08-20 17:45:43 +04:00
return 1 ;
}
static const char * _eat_space ( const char * b , const char * e )
{
while ( b ! = e & & isspace ( ( int ) * b ) )
b + + ;
return b ;
}
2001-08-20 12:03:02 +04:00
2001-08-20 17:45:43 +04:00
static int _get_word ( const char * b , const char * e ,
const char * * wb , const char * we )
{
b = _eat_space ( b , e ) ;
if ( b = = e )
return 0 ;
* wb = b ;
while ( b ! = e & & ! isspace ( ( int ) b ) )
b + + ;
* we = e ;
return 1 ;
}
static int _line_splitter ( struct file * file , const char * buffer ,
unsigned long * count , void * data )
{
const char * b = buffer , * e = buffer + count , * lb ;
struct pf_data * pfd = ( struct pf_data * ) data ;
while ( b < e ) {
b = _eat_space ( b , e ) ;
if ( b = = e )
return 0 ;
2001-08-20 12:03:02 +04:00
2001-08-20 17:45:43 +04:00
lb = b ;
while ( ( b ! = e ) & & * b ! = ' \n ' )
b + + ;
if ( ! pfd - > fn ( lb , b , pfd - > minor ) )
return lb - buffer ;
2001-08-20 12:03:02 +04:00
}
2001-08-20 17:45:43 +04:00
return count ;
}
static int _tok_cmp ( const char * str , const char * b , const char * e )
{
while ( * str & & b ! = e ) {
if ( * str < * b )
return - 1 ;
if ( * str > * b )
return 1 ;
str + + , b + + ;
}
if ( ! * str & & b = = e )
return 0 ;
if ( * str )
return 1 ;
2001-08-20 12:03:02 +04:00
2001-08-20 17:45:43 +04:00
return - 1 ;
2001-08-20 12:03:02 +04:00
}