2001-11-27 19:37:33 +03:00
/*
* Copyright ( C ) 2001 Sistina Software ( UK ) Limited .
*
* This file is released under the LGPL .
*/
# include "metadata.h"
# include "hash.h"
# include "dbg_malloc.h"
2001-11-27 20:29:56 +03:00
# include "log.h"
# include "pool.h"
# include "disk-rep.h"
2001-11-27 19:37:33 +03:00
/*
* After much thought I have decided it is easier ,
* and probably no less efficient , to convert the
* pe - > le map to a full le - > pe map , and then
* process this to get the segments form that
* we ' re after . Any code which goes directly from
* the pe - > le map to segments would be gladly
* accepted , if it is less complicated than this
* file .
*/
struct pe_specifier {
struct physical_volume * pv ;
uint32_t pe ;
} ;
struct lv_map {
struct logical_volume * lv ;
2001-11-27 20:29:56 +03:00
uint32_t stripes ;
uint32_t stripe_size ;
2001-11-27 19:37:33 +03:00
struct pe_specifier * map ;
} ;
static struct hash_table *
_create_lv_maps ( struct pool * mem , struct volume_group * vg )
{
struct hash_table * maps = hash_create ( 32 ) ;
struct list * llh ;
struct lv_list * ll ;
struct lv_map * lvm ;
if ( ! maps ) {
log_err ( " Unable to create hash table for holding "
" extent maps. " ) ;
return NULL ;
}
list_iterate ( llh , & vg - > lvs ) {
ll = list_item ( llh , struct lv_list ) ;
if ( ! ( lvm = pool_alloc ( mem , sizeof ( * lvm ) ) ) ) {
stack ;
goto bad ;
}
2001-11-27 20:29:56 +03:00
lvm - > lv = & ll - > lv ;
if ( ! ( lvm - > map = pool_zalloc ( mem , sizeof ( * lvm - > map )
* ll - > lv . le_count ) ) ) {
2001-11-27 19:37:33 +03:00
stack ;
goto bad ;
}
2001-11-27 20:29:56 +03:00
if ( ! hash_insert ( maps , ll - > lv . name , lvm ) ) {
2001-11-27 19:37:33 +03:00
stack ;
goto bad ;
}
}
return maps ;
bad :
hash_destroy ( maps ) ;
return NULL ;
}
static int _fill_lv_array ( struct lv_map * * lvs ,
struct hash_table * maps , struct disk_list * dl )
{
struct list * lvh ;
struct lv_map * lvm ;
2001-11-27 23:03:45 +03:00
memset ( lvs , 0 , sizeof ( * lvs ) * MAX_LV ) ;
2001-11-27 19:37:33 +03:00
list_iterate ( lvh , & dl - > lvds ) {
struct lvd_list * ll = list_item ( lvh , struct lvd_list ) ;
2001-11-28 16:45:50 +03:00
if ( ! ( lvm = hash_lookup ( maps , strrchr ( ll - > lvd . lv_name , ' / ' )
+ 1 ) ) ) {
2001-11-27 19:37:33 +03:00
log_err ( " Physical volume (%s) contains an "
" unknown logical volume (%s). " ,
dev_name ( dl - > dev ) , ll - > lvd . lv_name ) ;
return 0 ;
}
2001-11-27 20:29:56 +03:00
lvm - > stripes = ll - > lvd . lv_stripes ;
lvm - > stripe_size = ll - > lvd . lv_stripesize ;
2001-11-27 23:03:45 +03:00
lvs [ ll - > lvd . lv_number ] = lvm ;
2001-11-27 19:37:33 +03:00
}
return 1 ;
}
2001-11-27 20:29:56 +03:00
static int _fill_maps ( struct hash_table * maps , struct volume_group * vg ,
struct list * pvds )
2001-11-27 19:37:33 +03:00
{
struct list * pvdh ;
2001-11-27 20:29:56 +03:00
struct disk_list * dl ;
struct physical_volume * pv ;
struct lv_map * lvms [ MAX_LV ] , * lvm ;
struct pe_disk * e ;
uint32_t i , lv_num , le ;
2001-11-27 19:37:33 +03:00
list_iterate ( pvdh , pvds ) {
dl = list_item ( pvdh , struct disk_list ) ;
pv = find_pv ( vg , dl - > dev ) ;
e = dl - > extents ;
/* build an array of lv's for this pv */
2001-11-27 20:29:56 +03:00
if ( ! _fill_lv_array ( lvms , maps , dl ) ) {
2001-11-27 19:37:33 +03:00
stack ;
return 0 ;
}
for ( i = 0 ; i < dl - > pvd . pe_total ; i + + ) {
lv_num = e [ i ] . lv_num ;
if ( lv_num = = UNMAPPED_EXTENT )
continue ;
2001-11-29 17:13:43 +03:00
2001-11-28 16:45:50 +03:00
else {
2001-11-27 19:37:33 +03:00
lv_num - - ;
2001-11-27 20:29:56 +03:00
lvm = lvms [ lv_num ] ;
2001-11-27 23:03:45 +03:00
if ( ! lvm ) {
log_err ( " invalid lv in extent map " ) ;
return 0 ;
}
2001-11-27 19:37:33 +03:00
le = e [ i ] . le_num ;
if ( le > = lvm - > lv - > le_count ) {
log_err ( " logical extent number "
" out of bounds " ) ;
return 0 ;
}
2001-11-27 23:03:45 +03:00
if ( lvm - > map [ le ] . pv ) {
log_err ( " logical extent (%u) "
" already mapped. " , le ) ;
return 0 ;
}
2001-11-27 19:37:33 +03:00
lvm - > map [ le ] . pv = pv ;
lvm - > map [ le ] . pe = i ;
}
}
}
return 1 ;
}
static int _check_single_map ( struct lv_map * lvm )
{
uint32_t i ;
for ( i = 0 ; i < lvm - > lv - > le_count ; i + + ) {
if ( ! lvm - > map [ i ] . pv ) {
log_err ( " Logical volume (%s) contains an incomplete "
" mapping table. " , lvm - > lv - > name ) ;
return 0 ;
}
}
return 1 ;
}
static int _check_maps_are_complete ( struct hash_table * maps )
{
struct hash_node * n ;
2001-11-27 20:29:56 +03:00
struct lv_map * lvm ;
2001-11-27 19:37:33 +03:00
for ( n = hash_get_first ( maps ) ; n ; n = hash_get_next ( maps , n ) ) {
lvm = ( struct lv_map * ) hash_get_data ( maps , n ) ;
if ( ! _check_single_map ( lvm ) ) {
stack ;
return 0 ;
}
}
return 1 ;
}
2001-11-29 17:13:43 +03:00
static struct stripe_segment * _alloc_seg ( struct pool * mem , uint32_t stripes )
2001-11-27 19:37:33 +03:00
{
2001-11-29 17:13:43 +03:00
struct stripe_segment * seg ;
uint32_t len = sizeof ( * seg ) + ( stripes * sizeof ( seg - > area [ 0 ] ) ) ;
2001-11-27 19:37:33 +03:00
2001-11-29 17:13:43 +03:00
if ( ! ( seg = pool_zalloc ( mem , len ) ) ) {
stack ;
return NULL ;
2001-11-27 19:37:33 +03:00
}
2001-11-29 17:13:43 +03:00
return seg ;
2001-11-27 19:37:33 +03:00
}
2001-11-29 17:13:43 +03:00
static int _read_linear ( struct pool * mem , struct lv_map * lvm )
2001-11-27 19:37:33 +03:00
{
2001-11-29 17:13:43 +03:00
uint32_t le = 0 ;
2001-11-27 19:37:33 +03:00
struct stripe_segment * seg ;
2001-11-27 23:03:45 +03:00
while ( le < lvm - > lv - > le_count ) {
2001-11-29 17:13:43 +03:00
seg = _alloc_seg ( mem , 1 ) ;
2001-11-27 19:37:33 +03:00
seg - > lv = lvm - > lv ;
seg - > le = le ;
seg - > len = 0 ;
2001-11-29 17:13:43 +03:00
seg - > stripe_size = 0 ;
seg - > stripes = 1 ;
2001-11-27 19:37:33 +03:00
2001-11-29 17:13:43 +03:00
seg - > area [ 0 ] . pv = lvm - > map [ le ] . pv ;
seg - > area [ 0 ] . pe = lvm - > map [ le ] . pe ;
do
seg - > len + + ;
2001-11-27 19:37:33 +03:00
2001-11-29 17:13:43 +03:00
while ( ( lvm - > map [ le + seg - > len ] . pv = = seg - > area [ 0 ] . pv ) & &
( lvm - > map [ le + seg - > len ] . pe = = seg - > area [ 0 ] . pe +
seg - > len ) ) ;
2001-11-27 19:37:33 +03:00
2001-11-29 17:13:43 +03:00
le + = seg - > len ;
2001-11-27 19:37:33 +03:00
2001-11-27 20:29:56 +03:00
list_add ( & lvm - > lv - > segments , & seg - > list ) ;
2001-11-27 19:37:33 +03:00
}
return 1 ;
}
2001-11-29 17:13:43 +03:00
static int _read_stripes ( struct pool * mem , struct lv_map * lvm )
{
2001-12-08 00:17:12 +03:00
uint32_t stripes = lvm - > stripes , s , le = 0 , pe ;
2001-11-29 17:13:43 +03:00
struct stripe_segment * seg ;
struct pe_specifier * pes ;
2001-12-08 00:17:12 +03:00
while ( le < lvm - > lv - > le_count ) {
if ( ! ( seg = _alloc_seg ( mem , stripes ) ) ) {
stack ;
return 0 ;
}
2001-11-29 17:13:43 +03:00
2001-12-08 00:17:12 +03:00
seg - > lv = lvm - > lv ;
seg - > le = le ;
seg - > len = 0 ;
seg - > stripe_size = lvm - > stripe_size ;
seg - > stripes = stripes ;
seg - > area [ 0 ] . pv = lvm - > map [ le ] . pv ;
seg - > area [ 0 ] . pe = lvm - > map [ le ] . pe ;
2001-11-29 17:13:43 +03:00
2001-12-08 00:17:12 +03:00
do
seg - > len + + ;
while ( ( lvm - > map [ le + seg - > len ] . pv = = seg - > area [ 0 ] . pv ) & &
( lvm - > map [ le + seg - > len ] . pe = = seg - > area [ 0 ] . pe +
seg - > len ) ) ;
2001-11-29 17:13:43 +03:00
2001-12-08 00:17:12 +03:00
for ( s = 1 ; s < stripes ; s + + ) {
pes = & lvm - > map [ le + s * seg - > len ] ;
seg - > area [ s ] . pv = pes - > pv ;
seg - > area [ s ] . pe = pes - > pe ;
for ( pe = 0 ; pe < seg - > len ; pe + + ) {
if ( lvm - > map [ le + s * seg - > len + pe ] . pe ! =
pes - > pe + pe ) {
log_error ( " Incompatible striping at LE "
" %d on %s " ,
le + s * seg - > len + pe ,
seg - > lv - > name ) ;
return 0 ;
}
}
}
seg - > len * = stripes ;
le + = seg - > len ;
list_add ( & lvm - > lv - > segments , & seg - > list ) ;
2001-11-29 17:13:43 +03:00
}
return 1 ;
}
static int _build_segments ( struct pool * mem , struct lv_map * lvm )
{
return ( lvm - > stripes > 1 ? _read_stripes ( mem , lvm ) :
_read_linear ( mem , lvm ) ) ;
}
2001-11-27 19:37:33 +03:00
static int _build_all_segments ( struct pool * mem , struct hash_table * maps )
{
struct hash_node * n ;
struct lv_map * lvm ;
for ( n = hash_get_first ( maps ) ; n ; n = hash_get_next ( maps , n ) ) {
lvm = ( struct lv_map * ) hash_get_data ( maps , n ) ;
if ( ! _build_segments ( mem , lvm ) ) {
stack ;
return 0 ;
}
}
return 1 ;
}
int import_extents ( struct pool * mem , struct volume_group * vg ,
struct list * pvds )
{
int r = 0 ;
struct pool * scratch = pool_create ( 10 * 1024 ) ;
struct hash_table * maps ;
if ( ! scratch ) {
stack ;
return 0 ;
}
if ( ! ( maps = _create_lv_maps ( scratch , vg ) ) ) {
log_err ( " Couldn't allocate logical volume maps. " ) ;
goto out ;
}
2001-11-27 20:29:56 +03:00
if ( ! _fill_maps ( maps , vg , pvds ) ) {
2001-11-27 19:37:33 +03:00
log_err ( " Couldn't fill logical volume maps. " ) ;
goto out ;
}
if ( ! _check_maps_are_complete ( maps ) ) {
stack ;
goto out ;
}
if ( ! _build_all_segments ( mem , maps ) ) {
log_err ( " Couldn't build extent segments. " ) ;
goto out ;
}
r = 1 ;
out :
if ( maps )
hash_destroy ( maps ) ;
pool_destroy ( scratch ) ;
return r ;
}