2001-08-20 12:03:02 +04:00
/*
* dm . h
*
* Copyright ( C ) 2001 Sistina Software
*
2001-09-26 18:32:07 +04:00
* This file is released under the GPL .
2001-08-20 12:03:02 +04:00
*/
/*
* 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
*
2001-08-31 16:49:31 +04:00
* 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 .
2001-08-28 17:04:44 +04:00
*
* 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-09-13 22:30:05 +04:00
# include <linux/list.h>
2001-08-21 18:47:42 +04:00
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-09-04 14:17:28 +04:00
# define CHILDREN_PER_NODE (KEYS_PER_NODE + 1)
2001-09-17 20:55:31 +04:00
# define DM_NAME_LEN 128
2001-09-07 15:34:46 +04:00
# define MAX_TARGET_LINE 256
2001-08-20 12:03:02 +04:00
enum {
2001-08-31 19:13:33 +04:00
DM_BOUND = 0 , /* device has been bound to a table */
DM_ACTIVE , /* device is running */
2001-08-20 12:03:02 +04:00
} ;
2001-09-26 18:32:07 +04:00
/*
* list of devices that a metadevice uses
* and hence should open / close .
*/
struct dm_dev {
atomic_t count ;
struct list_head list ;
kdev_t dev ;
struct block_device * bd ;
} ;
2001-08-31 16:49:31 +04:00
/*
* io that had to be deferred while we were
* suspended
*/
2001-08-28 18:05:22 +04:00
struct deferred_io {
int rw ;
struct buffer_head * bh ;
struct deferred_io * next ;
} ;
2001-08-31 16:49:31 +04:00
/*
* btree leaf , these do the actual mapping
*/
struct target {
2001-09-02 14:49:20 +04:00
struct target_type * type ;
2001-08-29 17:58:48 +04:00
void * private ;
} ;
2001-08-31 19:13:33 +04:00
/*
* the btree
*/
struct dm_table {
/* btree table */
int depth ;
int counts [ MAX_DEPTH ] ; /* in nodes */
offset_t * index [ MAX_DEPTH ] ;
int num_targets ;
int num_allocated ;
offset_t * highs ;
struct target * targets ;
2001-09-19 14:32:09 +04:00
2001-09-26 18:32:07 +04:00
/* a list of devices used by this table */
2001-09-26 23:48:20 +04:00
struct list_head devices ;
2001-08-31 19:13:33 +04:00
} ;
2001-08-31 16:49:31 +04:00
/*
* the actual device struct
*/
2001-08-20 12:03:02 +04:00
struct mapped_device {
kdev_t dev ;
char name [ DM_NAME_LEN ] ;
2001-09-18 20:52:50 +04:00
struct inode * inode ;
2001-08-20 12:03:02 +04:00
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
2001-08-28 18:05:22 +04:00
/* a list of io's that arrived while we were suspended */
2001-09-26 18:32:07 +04:00
atomic_t pending ;
wait_queue_head_t wait ;
2001-08-28 18:05:22 +04:00
struct deferred_io * deferred ;
2001-08-31 19:13:33 +04:00
struct dm_table * map ;
2001-08-20 12:03:02 +04:00
/* used by dm-fs.c */
devfs_handle_t devfs_entry ;
} ;
2001-08-22 19:33:08 +04:00
extern struct block_device_operations dm_blk_dops ;
2001-08-21 18:28:00 +04:00
2001-08-31 19:13:33 +04:00
2001-08-21 18:28:00 +04:00
/* dm-target.c */
2001-09-26 18:32:07 +04:00
int dm_target_init ( void ) ;
2001-09-07 15:34:46 +04:00
struct target_type * dm_get_target_type ( const char * name ) ;
2001-09-13 22:30:05 +04:00
void dm_put_target_type ( struct target_type * t ) ;
2001-08-31 19:13:33 +04:00
2001-08-20 12:03:02 +04:00
/* dm.c */
2001-08-29 17:58:48 +04:00
struct mapped_device * dm_find_by_minor ( int minor ) ;
2001-08-20 12:03:02 +04:00
2001-09-18 20:52:50 +04:00
struct mapped_device * dm_create ( const char * name , int minor ) ;
int dm_remove ( struct mapped_device * md ) ;
2001-09-07 15:34:46 +04:00
int dm_activate ( struct mapped_device * md , struct dm_table * t ) ;
int dm_deactivate ( 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
2001-08-31 19:13:33 +04:00
2001-08-20 12:03:02 +04:00
/* dm-table.c */
2001-08-31 19:13:33 +04:00
struct dm_table * dm_table_create ( void ) ;
2001-09-26 18:32:07 +04:00
void dm_table_destroy ( struct dm_table * t ) ;
2001-08-31 19:13:33 +04:00
2001-09-02 14:49:20 +04:00
int dm_table_add_target ( struct dm_table * t , offset_t high ,
struct target_type * type , void * private ) ;
2001-08-31 19:13:33 +04:00
int dm_table_complete ( struct dm_table * t ) ;
2001-09-07 15:34:46 +04:00
/* dm-parse.c */
typedef int ( * extract_line_fn ) ( struct text_region * line ,
void * private ) ;
2001-09-26 18:32:07 +04:00
struct dm_table * dm_parse ( extract_line_fn line_fn , void * line_private ,
dm_error_fn err_fn , void * err_private ) ;
2001-09-07 15:34:46 +04:00
static inline int dm_empty_tok ( struct text_region * txt )
{
return txt - > b > = txt - > e ;
}
2001-08-20 12:03:02 +04:00
/* dm-fs.c */
2001-09-26 18:32:07 +04:00
int dm_fs_init ( void ) ;
void dm_fs_exit ( void ) ;
2001-08-20 12:03:02 +04:00
2001-08-22 19:01:09 +04:00
2001-08-21 18:51:41 +04:00
# define WARN(f, x...) printk(KERN_WARNING "device-mapper: " f "\n" , ## x)
2001-09-04 14:17:28 +04:00
/*
* calculate the index of the child node of the
* n ' th node k ' th key .
*/
static inline int get_child ( int n , int k )
{
return ( n * CHILDREN_PER_NODE ) + k ;
}
/*
* returns the n ' th node of level l from table t .
*/
static inline offset_t * get_node ( struct dm_table * t , int l , int n )
{
return t - > index [ l ] + ( n * KEYS_PER_NODE ) ;
}
2001-08-31 20:36:56 +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-20 12:03:02 +04:00
# endif