2001-08-20 12:03:02 +04:00
/*
* dm - table . 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 .
*/
/*
* Changelog
*
* 16 / 08 / 2001 - First version [ Joe Thornber ]
*/
2001-08-21 18:47:42 +04:00
# include "dm.h"
2001-08-31 16:49:31 +04:00
/* ceiling(n / size) * size */
2001-08-23 16:35:02 +04:00
static inline ulong round_up ( ulong n , ulong size )
2001-08-20 12:03:02 +04:00
{
ulong r = n % size ;
return n + ( r ? ( size - r ) : 0 ) ;
}
2001-08-31 16:49:31 +04:00
/* ceiling(n / size) */
2001-08-23 16:35:02 +04:00
static inline ulong div_up ( ulong n , ulong size )
2001-08-20 12:03:02 +04:00
{
2001-08-23 16:35:02 +04:00
return round_up ( n , size ) / size ;
2001-08-20 12:03:02 +04:00
}
2001-08-31 16:49:31 +04:00
/* ceiling(log_size(n)) */
static uint int_log ( ulong base , ulong n )
{
int result = 0 ;
while ( n ! = 1 ) {
n = div_up ( n , base ) ;
result + + ;
}
return result ;
}
/*
* return the highest key that you could lookup
* from the n ' th node on level l of the btree .
*/
2001-08-23 16:35:02 +04:00
static offset_t high ( struct mapped_device * md , int l , int n )
2001-08-20 12:03:02 +04:00
{
while ( 1 ) {
if ( n > = md - > counts [ l ] )
return ( offset_t ) - 1 ;
if ( l = = md - > depth - 1 )
return md - > index [ l ] [ ( ( n + 1 ) * KEYS_PER_NODE ) - 1 ] ;
l + + ;
n = ( n + 1 ) * ( KEYS_PER_NODE + 1 ) - 1 ;
}
2001-08-31 16:49:31 +04:00
return - 1 ;
2001-08-20 12:03:02 +04:00
}
2001-08-31 16:49:31 +04:00
/*
* fills in a level of the btree based on the
* highs of the level below it .
*/
2001-08-23 16:35:02 +04:00
static int setup_btree_index ( int l , struct mapped_device * md )
2001-08-20 12:03:02 +04:00
{
int n , c , cn ;
for ( n = 0 , cn = 0 ; n < md - > counts [ l ] ; n + + ) {
offset_t * k = md - > index [ l ] + ( n * KEYS_PER_NODE ) ;
for ( c = 0 ; c < KEYS_PER_NODE ; c + + )
2001-08-23 16:35:02 +04:00
k [ c ] = high ( md , l + 1 , cn + + ) ;
2001-08-31 16:49:31 +04:00
cn + + ; /* one extra for the child that's
greater than all keys */
2001-08-20 12:03:02 +04:00
}
2001-08-23 16:35:02 +04:00
return 0 ;
2001-08-20 12:03:02 +04:00
}
2001-08-31 16:49:31 +04:00
void dm_table_free ( struct mapped_device * md )
2001-08-20 12:03:02 +04:00
{
int i ;
2001-08-23 16:35:02 +04:00
for ( i = 0 ; i < md - > depth ; i + + ) {
2001-08-21 18:47:42 +04:00
vfree ( md - > index [ i ] ) ;
2001-08-23 16:35:02 +04:00
md - > index [ i ] = 0 ;
}
2001-08-20 12:03:02 +04:00
2001-08-21 18:47:42 +04:00
vfree ( md - > targets ) ;
2001-08-20 19:22:44 +04:00
2001-08-23 21:10:05 +04:00
md - > highs = 0 ;
2001-08-23 16:35:02 +04:00
md - > targets = 0 ;
2001-08-20 19:22:44 +04:00
md - > num_targets = 0 ;
md - > num_allocated = 0 ;
2001-08-20 12:03:02 +04:00
}
2001-08-31 16:49:31 +04:00
/*
* md - > highs , and md - > targets are managed as
* dynamic arrays during a table load .
*/
static int alloc_targets ( struct mapped_device * md , int num )
{
offset_t * n_highs ;
struct target * n_targets ;
if ( ! ( n_highs = vmalloc ( sizeof ( * n_highs ) * num ) ) )
return - ENOMEM ;
if ( ! ( n_targets = vmalloc ( sizeof ( * n_targets ) * num ) ) ) {
vfree ( n_highs ) ;
return - ENOMEM ;
}
if ( md - > num_targets ) {
memcpy ( n_highs , md - > highs ,
sizeof ( * n_highs ) * md - > num_targets ) ;
memcpy ( n_targets , md - > targets ,
sizeof ( * n_targets ) * md - > num_targets ) ;
}
vfree ( md - > highs ) ;
vfree ( md - > targets ) ;
md - > num_allocated = num ;
md - > highs = n_highs ;
md - > targets = n_targets ;
return 0 ;
}
2001-08-29 17:58:48 +04:00
int dm_table_start ( struct mapped_device * md )
2001-08-20 17:45:43 +04:00
{
2001-08-22 19:59:56 +04:00
int r ;
2001-08-21 18:47:42 +04:00
set_bit ( DM_LOADING , & md - > state ) ;
2001-08-20 19:22:44 +04:00
2001-08-31 16:49:31 +04:00
dm_table_free ( md ) ;
/* allocate a single nodes worth to start with */
if ( ( r = alloc_targets ( md , KEYS_PER_NODE ) ) )
2001-08-22 19:59:56 +04:00
return r ;
2001-08-21 18:47:42 +04:00
return 0 ;
2001-08-20 17:45:43 +04:00
}
2001-08-31 16:49:31 +04:00
static inline int check_space ( struct mapped_device * md )
{
if ( md - > num_targets > = md - > num_allocated )
return alloc_targets ( md , md - > num_allocated * 2 ) ;
return 0 ;
}
2001-08-29 17:58:48 +04:00
int dm_table_add_entry ( struct mapped_device * md , offset_t high ,
2001-08-31 16:49:31 +04:00
dm_map_fn target , void * context )
2001-08-20 17:45:43 +04:00
{
2001-08-31 16:49:31 +04:00
int r ;
if ( ( r = check_space ( md ) ) )
return r ;
2001-08-20 19:22:44 +04:00
md - > highs [ md - > num_targets ] = high ;
2001-08-29 17:58:48 +04:00
md - > targets [ md - > num_targets ] . map = target ;
md - > targets [ md - > num_targets ] . private = context ;
2001-08-20 19:22:44 +04:00
md - > num_targets + + ;
2001-08-31 16:49:31 +04:00
2001-08-21 18:47:42 +04:00
return 0 ;
2001-08-20 17:45:43 +04:00
}
2001-08-29 17:58:48 +04:00
int dm_table_complete ( struct mapped_device * md )
2001-08-20 17:45:43 +04:00
{
2001-08-31 16:49:31 +04:00
int i , leaf_nodes ;
2001-08-21 18:47:42 +04:00
clear_bit ( DM_LOADING , & md - > state ) ;
2001-08-20 19:22:44 +04:00
/* how many indexes will the btree have ? */
2001-08-31 16:49:31 +04:00
leaf_nodes = div_up ( md - > num_targets , KEYS_PER_NODE ) ;
i = 1 + int_log ( leaf_nodes , KEYS_PER_NODE + 1 ) ;
2001-08-20 19:22:44 +04:00
md - > depth = i ;
2001-08-23 16:35:02 +04:00
md - > counts [ md - > depth - 1 ] = div_up ( md - > num_targets , KEYS_PER_NODE ) ;
2001-08-20 19:22:44 +04:00
while ( - - i )
2001-08-23 16:35:02 +04:00
md - > counts [ i - 1 ] = div_up ( md - > counts [ i ] , KEYS_PER_NODE + 1 ) ;
2001-08-20 19:22:44 +04:00
2001-08-31 16:49:31 +04:00
for ( i = 0 ; i < ( md - > depth - 1 ) ; i + + ) {
2001-08-20 19:22:44 +04:00
size_t s = NODE_SIZE * md - > counts [ i ] ;
md - > index [ i ] = vmalloc ( s ) ;
memset ( md - > index [ i ] , - 1 , s ) ;
}
/* bottom layer is easy */
md - > index [ md - > depth - 1 ] = md - > highs ;
/* fill in higher levels */
for ( i = md - > depth - 1 ; i ; i - - )
2001-08-23 16:35:02 +04:00
setup_btree_index ( i - 1 , md ) ;
2001-08-20 19:22:44 +04:00
2001-08-21 18:47:42 +04:00
set_bit ( DM_LOADED , & md - > state ) ;
2001-08-23 16:35:02 +04:00
return 0 ;
2001-08-20 17:45:43 +04:00
}
2001-08-20 12:03:02 +04:00
2001-08-20 19:22:44 +04:00