2001-11-27 19:37:33 +03:00
/*
* Copyright ( C ) 2001 Sistina Software ( UK ) Limited .
*
* This file is released under the LGPL .
*/
2002-11-18 17:01:16 +03:00
# include "lib.h"
2001-11-27 19:37:33 +03:00
# include "metadata.h"
# include "hash.h"
2001-11-27 20:29:56 +03:00
# include "pool.h"
# include "disk-rep.h"
2003-09-18 00:35:57 +04:00
# include "lv_alloc.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 ;
} ;
2001-12-13 03:07:29 +03:00
static struct hash_table * _create_lv_maps ( struct pool * mem ,
struct volume_group * vg )
2001-11-27 19:37:33 +03:00
{
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 ;
}
2001-12-13 03:07:29 +03:00
list_iterate ( llh , & vg - > lvs ) {
2001-11-27 19:37:33 +03:00
ll = list_item ( llh , struct lv_list ) ;
if ( ! ( lvm = pool_alloc ( mem , sizeof ( * lvm ) ) ) ) {
stack ;
goto bad ;
}
2002-01-21 19:49:32 +03:00
lvm - > lv = ll - > lv ;
2001-11-27 20:29:56 +03:00
if ( ! ( lvm - > map = pool_zalloc ( mem , sizeof ( * lvm - > map )
2002-01-21 19:49:32 +03:00
* ll - > lv - > le_count ) ) ) {
2001-11-27 19:37:33 +03:00
stack ;
goto bad ;
}
2002-01-21 19:49:32 +03:00
if ( ! hash_insert ( maps , ll - > lv - > name , lvm ) ) {
2001-11-27 19:37:33 +03:00
stack ;
goto bad ;
}
}
return maps ;
2001-12-13 03:07:29 +03:00
bad :
2001-11-27 19:37:33 +03:00
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 , ' / ' )
2001-12-13 03:07:29 +03:00
+ 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
2001-12-13 03:07:29 +03:00
if ( ! lvm ) {
2001-11-27 23:03:45 +03:00
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 ;
2002-01-30 18:33:12 +03:00
2001-11-27 19:37:33 +03:00
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 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 ;
2002-11-18 17:01:16 +03:00
struct lv_segment * seg ;
2001-11-27 19:37:33 +03:00
2001-11-27 23:03:45 +03:00
while ( le < lvm - > lv - > le_count ) {
2003-09-18 00:35:57 +04:00
seg = alloc_lv_segment ( mem , 1 ) ;
2001-11-27 19:37:33 +03:00
seg - > lv = lvm - > lv ;
2002-11-18 17:01:16 +03:00
seg - > type = SEG_STRIPED ;
2001-11-27 19:37:33 +03:00
seg - > le = le ;
seg - > len = 0 ;
2003-04-25 02:23:24 +04:00
seg - > area_len = 0 ;
2001-11-29 17:13:43 +03:00
seg - > stripe_size = 0 ;
2003-04-25 02:23:24 +04:00
seg - > area_count = 1 ;
2001-11-27 19:37:33 +03:00
2003-04-25 02:23:24 +04:00
seg - > area [ 0 ] . type = AREA_PV ;
seg - > area [ 0 ] . u . pv . pv = lvm - > map [ le ] . pv ;
seg - > area [ 0 ] . u . pv . pe = lvm - > map [ le ] . pe ;
2001-11-29 17:13:43 +03:00
2003-04-25 02:23:24 +04:00
do {
2001-11-29 17:13:43 +03:00
seg - > len + + ;
2003-04-25 02:23:24 +04:00
seg - > area_len + + ;
} while ( ( lvm - > map [ le + seg - > len ] . pv = = seg - > area [ 0 ] . u . pv . pv ) & &
( seg - > area [ 0 ] . u . pv . pv & &
lvm - > map [ le + seg - > len ] . pe = = seg - > area [ 0 ] . u . pv . 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 ;
}
2002-11-18 17:01:16 +03:00
static int _check_stripe ( struct lv_map * lvm , struct lv_segment * seg ,
2002-01-25 23:24:14 +03:00
uint32_t base_le , uint32_t len )
2001-11-29 17:13:43 +03:00
{
2002-01-25 23:24:14 +03:00
uint32_t le , st ;
2001-11-29 17:13:43 +03:00
2002-01-25 23:24:14 +03:00
le = base_le + seg - > len ;
2001-11-29 17:13:43 +03:00
2002-01-25 23:24:14 +03:00
/*
* Is the next physical extent in every stripe adjacent to the last ?
*/
2003-04-25 02:23:24 +04:00
for ( st = 0 ; st < seg - > area_count ; st + + )
if ( ( lvm - > map [ le + st * len ] . pv ! = seg - > area [ st ] . u . pv . pv ) | |
( seg - > area [ st ] . u . pv . pv & &
lvm - > map [ le + st * len ] . pe ! =
seg - > area [ st ] . u . pv . pe + seg - > len ) )
2002-01-25 23:24:14 +03:00
return 0 ;
2001-12-13 03:07:29 +03:00
2002-01-25 23:24:14 +03:00
return 1 ;
}
2001-12-08 00:17:12 +03:00
2002-01-25 23:24:14 +03:00
static int _read_stripes ( struct pool * mem , struct lv_map * lvm )
{
uint32_t st , le = 0 , len ;
2002-11-18 17:01:16 +03:00
struct lv_segment * seg ;
2002-01-25 16:41:13 +03:00
/*
2002-01-25 23:24:14 +03:00
* Work out overall striped length
2002-01-25 16:41:13 +03:00
*/
2002-01-25 23:24:14 +03:00
if ( lvm - > lv - > le_count % lvm - > stripes ) {
log_error ( " Number of stripes (%u) incompatible "
" with logical extent count (%u) for %s " ,
2002-04-24 22:20:51 +04:00
lvm - > stripes , lvm - > lv - > le_count , lvm - > lv - > name ) ;
2001-11-29 17:13:43 +03:00
}
2002-01-25 23:24:14 +03:00
len = lvm - > lv - > le_count / lvm - > stripes ;
2001-11-29 17:13:43 +03:00
2002-01-25 23:24:14 +03:00
while ( le < len ) {
2003-09-18 00:35:57 +04:00
if ( ! ( seg = alloc_lv_segment ( mem , lvm - > stripes ) ) ) {
2002-01-25 23:24:14 +03:00
stack ;
return 0 ;
}
2001-12-13 03:07:29 +03:00
2002-01-25 23:24:14 +03:00
seg - > lv = lvm - > lv ;
2002-11-18 17:01:16 +03:00
seg - > type = SEG_STRIPED ;
2002-01-25 23:24:14 +03:00
seg - > stripe_size = lvm - > stripe_size ;
2003-04-25 02:23:24 +04:00
seg - > area_count = lvm - > stripes ;
seg - > le = seg - > area_count * le ;
2002-01-25 23:24:14 +03:00
seg - > len = 1 ;
2003-04-25 02:23:24 +04:00
seg - > area_len = 1 ;
2002-01-25 23:24:14 +03:00
/*
* Set up start positions of each stripe in this segment
*/
2003-04-25 02:23:24 +04:00
for ( st = 0 ; st < seg - > area_count ; st + + ) {
seg - > area [ st ] . u . pv . pv = lvm - > map [ le + st * len ] . pv ;
seg - > area [ st ] . u . pv . pe = lvm - > map [ le + st * len ] . pe ;
2002-01-25 16:41:13 +03:00
}
2002-01-25 23:24:14 +03:00
/*
* Find how many blocks are contiguous in all stripes
* and so can form part of this segment
*/
2003-04-25 02:23:24 +04:00
while ( _check_stripe ( lvm , seg , le , len ) ) {
2002-01-25 23:24:14 +03:00
seg - > len + + ;
2003-04-25 02:23:24 +04:00
seg - > area_len + + ;
}
2002-01-25 23:24:14 +03:00
le + = seg - > len ;
2003-04-25 02:23:24 +04:00
seg - > len * = seg - > area_count ;
2002-01-25 23:24:14 +03:00
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 ;
}
2001-12-13 03:07:29 +03:00
int import_extents ( struct pool * mem , struct volume_group * vg , struct list * pvds )
2001-11-27 19:37:33 +03:00
{
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 ;
}
2002-01-30 18:33:12 +03:00
if ( ! _check_maps_are_complete ( maps ) & & ! ( vg - > status & PARTIAL_VG ) ) {
2001-11-27 19:37:33 +03:00
stack ;
goto out ;
}
if ( ! _build_all_segments ( mem , maps ) ) {
log_err ( " Couldn't build extent segments. " ) ;
goto out ;
}
r = 1 ;
2001-12-13 03:07:29 +03:00
out :
2001-11-27 19:37:33 +03:00
if ( maps )
hash_destroy ( maps ) ;
pool_destroy ( scratch ) ;
return r ;
}