2001-08-20 12:03:02 +04:00
/*
* dm . h
*
* 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 .
*/
/*
* Internal header file for device mapper
*
* Changelog
*
* 16 / 08 / 2001 - First version [ Joe Thornber ]
*/
2001-08-28 17:04:44 +04:00
/*
* This driver attempts to provide a generic way of specifying logical
* devices which are mapped onto other devices .
*
* It does this by mapping sections of the logical device onto ' targets ' .
*
* When the logical device is accessed the make_request function looks up
* the correct target for the given sector , and then asks this target
* to do the remapping .
*
* ( dm - table . c ) A btree like structure is used to hold the sector
* range - > target mapping . Because we know all the entries in the
* btree in advance we can make a very compact tree , omitting pointers
* to child nodes , ( child nodes locations can be calculated ) . Each
* node of the btree is 1 level cache line in size , this gives a small
* performance boost .
*
* A userland test program for the btree gave the following results on a
* 1 Gigahertz Athlon machine :
*
* entries in btree lookups per second
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* 5 25 , 000 , 000
* 1000 7 , 700 , 000
* 10 , 000 , 000 3 , 800 , 000
*
* Of course these results should be taken with a pinch of salt ; the lookups
* were sequential and there were no other applications ( other than X + emacs )
* running to give any pressure on the level 1 cache .
*
* Typical LVM users would find they have very few targets for each
* LV ( probably less than 10 ) .
*
* ( dm - target . c ) Target types are not hard coded , instead the
* register_mapping_type function should be called . A target type is
* specified using three functions ( see the header ) :
*
* dm_ctr_fn - takes a string and contructs a target specific piece of
* context data .
* dm_dtr_fn - destroy contexts .
* dm_map_fn - function that takes a buffer_head and some previously
* constructed context and performs the remapping .
*
* Currently there are two two trivial mappers , which are
* automatically registered : ' linear ' , and ' io_error ' . Linear alone
* is enough to implement most LVM features ( omitting striped volumes
* and snapshots ) .
*
* ( dm - fs . c ) The driver is controlled through a / proc interface :
* / proc / device - mapper / control allows you to create and remove devices
* by ' cat ' ing a line of the following format :
*
* create < device name > [ minor no ]
* remove < device name >
*
* / proc / device - mapper / < device name > accepts the mapping table :
*
* begin
* < sector start > < length > < target name > < target args > . . .
* . . .
* end
*
* The begin / end lines are nasty , they should be handled by open / close
* for the file .
*
* At the moment the table assumes 32 bit keys ( sectors ) , the move to
* 64 bits will involve no interface changes , since the tables will be
* read in as ascii data . A different table implementation can
* therefor be provided at another time . Either just by changing offset_t
* to 64 bits , or maybe implementing a structure which looks up the keys in
* stages ( ie , 32 bits at a time ) .
*
* More interesting targets :
*
* striped mapping ; given a stripe size and a number of device regions
* this would stripe data across the regions . Especially useful , since
* we could limit each striped region to a 32 bit area and then avoid
* nasty 64 bit % ' s .
*
* mirror mapping ( reflector ? ) ; would set off a kernel thread slowly
* copying data from one region to another , ensuring that any new
* writes got copied to both destinations correctly . Great for
* implementing pvmove . Not sure how userland would be notified that
* the copying process had completed . Possibly by reading a / proc entry
* for the LV . Could also use poll ( ) for this kind of thing .
*/
2001-08-20 12:03:02 +04:00
# ifndef DM_INTERNAL_H
# define DM_INTERNAL_H
2001-08-21 18:47:42 +04:00
# include <linux/version.h>
# include <linux/major.h>
# include <linux/iobuf.h>
# include <linux/module.h>
# include <linux/fs.h>
# include <linux/slab.h>
# include <linux/vmalloc.h>
# include <linux/compatmac.h>
# include <linux/cache.h>
# include <linux/devfs_fs_kernel.h>
2001-08-23 16:35:02 +04:00
# include <linux/ctype.h>
2001-08-21 18:47:42 +04:00
# include <linux/device-mapper.h>
2001-08-20 12:03:02 +04:00
# define MAX_DEPTH 16
# define NODE_SIZE L1_CACHE_BYTES
# define KEYS_PER_NODE (NODE_SIZE / sizeof(offset_t))
2001-08-21 18:28:00 +04:00
# define DM_NAME_LEN 64
2001-08-20 12:03:02 +04:00
enum {
2001-08-21 18:28:00 +04:00
DM_LOADED = 0 ,
2001-08-20 12:03:02 +04:00
DM_LOADING ,
DM_ACTIVE ,
} ;
2001-08-20 20:12:22 +04:00
struct dev_list {
kdev_t dev ;
2001-08-21 18:28:00 +04:00
struct block_device * bd ;
2001-08-20 20:12:22 +04:00
struct dev_list * next ;
} ;
2001-08-20 12:03:02 +04:00
struct mapped_device {
kdev_t dev ;
char name [ DM_NAME_LEN ] ;
2001-08-21 18:28:00 +04:00
int use_count ;
2001-08-20 12:03:02 +04:00
int state ;
2001-08-28 17:04:44 +04:00
wait_queue_head_t wait ;
atomic_t pending ; /* # of 'in flight' buffers */
2001-08-20 12:03:02 +04:00
/* btree table */
int depth ;
int counts [ MAX_DEPTH ] ; /* in nodes */
offset_t * index [ MAX_DEPTH ] ;
int num_targets ;
int num_allocated ;
2001-08-20 19:22:44 +04:00
offset_t * highs ;
2001-08-20 12:03:02 +04:00
dm_map_fn * targets ;
void * * contexts ;
/* used by dm-fs.c */
devfs_handle_t devfs_entry ;
2001-08-22 19:01:09 +04:00
struct proc_dir_entry * pde ;
2001-08-20 20:12:22 +04:00
/* a list of devices used by this md */
struct dev_list * devices ;
2001-08-20 12:03:02 +04:00
} ;
struct target {
char * name ;
dm_ctr_fn ctr ;
dm_dtr_fn dtr ;
dm_map_fn map ;
struct target * next ;
} ;
2001-08-22 19:33:08 +04:00
extern struct block_device_operations dm_blk_dops ;
2001-08-21 18:28:00 +04:00
/* dm-target.c */
2001-08-20 12:03:02 +04:00
struct target * dm_get_target ( const char * name ) ;
int dm_std_targets ( void ) ;
/* dm.c */
2001-08-20 17:45:43 +04:00
struct mapped_device * dm_find_name ( const char * name ) ;
struct mapped_device * dm_find_minor ( int minor ) ;
2001-08-20 12:03:02 +04:00
2001-08-21 19:24:02 +04:00
int dm_create ( const char * name , int minor ) ;
int dm_remove ( const char * name ) ;
2001-08-21 18:28:00 +04:00
int dm_activate ( struct mapped_device * md ) ;
2001-08-20 20:12:22 +04:00
void dm_suspend ( struct mapped_device * md ) ;
2001-08-20 12:03:02 +04:00
/* dm-table.c */
2001-08-20 17:45:43 +04:00
int dm_start_table ( struct mapped_device * md ) ;
int dm_add_entry ( struct mapped_device * md , offset_t high ,
dm_map_fn target , void * context ) ;
int dm_complete_table ( struct mapped_device * md ) ;
2001-08-21 18:47:42 +04:00
void dm_free_table ( struct mapped_device * md ) ;
2001-08-20 17:45:43 +04:00
2001-08-20 12:03:02 +04:00
/* dm-fs.c */
int dm_init_fs ( void ) ;
2001-08-21 19:24:02 +04:00
void dm_fin_fs ( void ) ;
2001-08-20 12:03:02 +04:00
2001-08-22 19:01:09 +04:00
int dm_fs_add ( struct mapped_device * md ) ;
int dm_fs_remove ( struct mapped_device * md ) ;
2001-08-21 18:51:41 +04:00
# define WARN(f, x...) printk(KERN_WARNING "device-mapper: " f "\n" , ## x)
2001-08-21 18:47:42 +04:00
static inline int is_active ( struct mapped_device * md )
2001-08-21 18:28:00 +04:00
{
return test_bit ( DM_ACTIVE , & md - > state ) ;
}
2001-08-23 16:35:02 +04:00
static inline const char * eat_space ( const char * b , const char * e )
2001-08-21 18:28:00 +04:00
{
2001-08-23 16:35:02 +04:00
while ( b ! = e & & isspace ( ( int ) * b ) )
b + + ;
return b ;
2001-08-21 18:28:00 +04:00
}
2001-08-20 12:03:02 +04:00
# endif