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"
static int _alloc_targets ( struct mapped_device * md , int num ) ;
2001-08-20 12:03:02 +04:00
static inline ulong _round_up ( ulong n , ulong size )
{
ulong r = n % size ;
return n + ( r ? ( size - r ) : 0 ) ;
}
static inline ulong _div_up ( ulong n , ulong size )
{
return _round_up ( n , size ) / size ;
}
static offset_t _high ( struct mapped_device * md , int l , int n )
{
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 ;
}
}
static int _setup_btree_index ( int l , struct mapped_device * md )
{
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 + + )
k [ c ] = _high ( md , l + 1 , cn + + ) ;
cn + + ;
}
return 1 ;
}
2001-08-21 18:47:42 +04:00
void dm_free_table ( struct mapped_device * md )
2001-08-20 12:03:02 +04:00
{
int i ;
for ( i = 0 ; i < md - > depth ; i + + )
2001-08-21 18:47:42 +04:00
vfree ( md - > index [ i ] ) ;
2001-08-20 12:03:02 +04:00
2001-08-21 18:47:42 +04:00
vfree ( md - > targets ) ;
vfree ( md - > contexts ) ;
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-20 17:45:43 +04:00
int dm_start_table ( struct mapped_device * md )
{
2001-08-21 18:47:42 +04:00
set_bit ( DM_LOADING , & md - > state ) ;
2001-08-20 19:22:44 +04:00
2001-08-21 18:47:42 +04:00
dm_free_table ( md ) ;
if ( ! _alloc_targets ( md , 2 ) ) /* FIXME: increase once debugged 256 ? */
return - ENOMEM ;
return 0 ;
2001-08-20 17:45:43 +04:00
}
int dm_add_entry ( struct mapped_device * md , offset_t high ,
dm_map_fn target , void * context )
{
2001-08-21 18:47:42 +04:00
if ( md - > num_targets > = md - > num_targets & &
! _alloc_targets ( md , md - > num_allocated * 2 ) )
return - ENOMEM ;
2001-08-20 19:22:44 +04:00
md - > highs [ md - > num_targets ] = high ;
md - > targets [ md - > num_targets ] = target ;
md - > contexts [ md - > num_targets ] = context ;
md - > num_targets + + ;
2001-08-21 18:47:42 +04:00
return 0 ;
2001-08-20 17:45:43 +04:00
}
2001-08-20 19:22:44 +04:00
int dm_complete_table ( struct mapped_device * md )
2001-08-20 17:45:43 +04:00
{
2001-08-20 19:22:44 +04:00
int n , i ;
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 ? */
for ( n = _div_up ( md - > num_targets , KEYS_PER_NODE ) , i = 1 ; n ! = 1 ; i + + )
n = _div_up ( n , KEYS_PER_NODE + 1 ) ;
md - > depth = i ;
md - > counts [ md - > depth - 1 ] = _div_up ( md - > num_targets , KEYS_PER_NODE ) ;
while ( - - i )
md - > counts [ i - 1 ] = _div_up ( md - > counts [ i ] , KEYS_PER_NODE + 1 ) ;
for ( i = 0 ; i < md - > depth ; i + + ) {
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 - - )
_setup_btree_index ( i - 1 , md ) ;
2001-08-21 18:47:42 +04:00
set_bit ( DM_LOADED , & md - > state ) ;
2001-08-20 19:22:44 +04:00
return 1 ;
2001-08-20 17:45:43 +04:00
}
2001-08-20 12:03:02 +04:00
2001-08-21 18:47:42 +04:00
static int _alloc_targets ( struct mapped_device * md , int num )
2001-08-20 19:22:44 +04:00
{
offset_t * n_highs ;
dm_map_fn * n_targets ;
void * * n_contexts ;
if ( ! ( n_highs = vmalloc ( sizeof ( * n_highs ) * num ) ) )
return 0 ;
if ( ! ( n_targets = vmalloc ( sizeof ( * n_targets ) * num ) ) ) {
vfree ( n_highs ) ;
return 0 ;
}
if ( ! ( n_contexts = vmalloc ( sizeof ( * n_contexts ) * num ) ) ) {
vfree ( n_highs ) ;
vfree ( n_targets ) ;
return 0 ;
}
memcpy ( n_highs , md - > highs , sizeof ( * n_highs ) * md - > num_targets ) ;
memcpy ( n_targets , md - > targets , sizeof ( * n_targets ) * md - > num_targets ) ;
memcpy ( n_contexts , md - > contexts ,
sizeof ( * n_contexts ) * md - > num_targets ) ;
vfree ( md - > highs ) ;
vfree ( md - > targets ) ;
vfree ( md - > contexts ) ;
md - > num_allocated = num ;
md - > highs = n_highs ;
md - > targets = n_targets ;
md - > contexts = n_contexts ;
return 1 ;
}