2001-11-27 19:37:33 +03:00
/*
2008-01-30 17:00:02 +03:00
* Copyright ( C ) 2001 - 2004 Sistina Software , Inc . All rights reserved .
2007-08-21 00:55:30 +04:00
* Copyright ( C ) 2004 - 2007 Red Hat , Inc . All rights reserved .
2001-11-27 19:37:33 +03:00
*
2004-03-30 23:35:44 +04:00
* This file is part of LVM2 .
*
* This copyrighted material is made available to anyone wishing to use ,
* modify , copy , or redistribute it subject to the terms and conditions
2007-08-21 00:55:30 +04:00
* of the GNU Lesser General Public License v .2 .1 .
2004-03-30 23:35:44 +04:00
*
2007-08-21 00:55:30 +04:00
* You should have received a copy of the GNU Lesser General Public License
2004-03-30 23:35:44 +04:00
* along with this program ; if not , write to the Free Software Foundation ,
2016-01-21 13:49:46 +03:00
* Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA
2001-11-27 19:37:33 +03:00
*/
2002-11-18 17:01:16 +03:00
# include "lib.h"
2001-11-27 19:37:33 +03:00
# include "metadata.h"
2001-11-27 20:29:56 +03:00
# include "disk-rep.h"
2003-09-18 00:35:57 +04:00
# include "lv_alloc.h"
2004-05-05 01:25:57 +04:00
# include "display.h"
2004-09-16 22:40:56 +04:00
# include "segtype.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 ;
} ;
2005-10-17 03:03:59 +04:00
static struct dm_hash_table * _create_lv_maps ( struct dm_pool * mem ,
2001-12-13 03:07:29 +03:00
struct volume_group * vg )
2001-11-27 19:37:33 +03:00
{
2005-10-17 03:03:59 +04:00
struct dm_hash_table * maps = dm_hash_create ( 32 ) ;
2001-11-27 19:37:33 +03:00
struct lv_list * ll ;
struct lv_map * lvm ;
if ( ! maps ) {
2009-07-16 00:02:46 +04:00
log_error ( " Unable to create hash table for holding "
" extent maps. " ) ;
2001-11-27 19:37:33 +03:00
return NULL ;
}
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( ll , & vg - > lvs ) {
2005-04-07 16:39:44 +04:00
if ( ll - > lv - > status & SNAPSHOT )
continue ;
2001-11-27 19:37:33 +03:00
2007-04-26 20:44:59 +04:00
if ( ! ( lvm = dm_pool_alloc ( mem , sizeof ( * lvm ) ) ) )
goto_bad ;
2001-11-27 19:37:33 +03:00
2002-01-21 19:49:32 +03:00
lvm - > lv = ll - > lv ;
2011-03-30 16:30:39 +04:00
/*
* Alloc 1 extra element , so the loop in _area_length ( ) and
* _check_stripe ( ) finds the last map member as noncontinuous .
*/
2005-10-17 03:03:59 +04:00
if ( ! ( lvm - > map = dm_pool_zalloc ( mem , sizeof ( * lvm - > map )
2011-03-30 16:30:39 +04:00
* ( ll - > lv - > le_count + 1 ) ) ) )
2007-04-26 20:44:59 +04:00
goto_bad ;
2001-11-27 19:37:33 +03:00
2007-04-26 20:44:59 +04:00
if ( ! dm_hash_insert ( maps , ll - > lv - > name , lvm ) )
goto_bad ;
2001-11-27 19:37:33 +03:00
}
return maps ;
2001-12-13 03:07:29 +03:00
bad :
2005-10-17 03:03:59 +04:00
dm_hash_destroy ( maps ) ;
2001-11-27 19:37:33 +03:00
return NULL ;
}
static int _fill_lv_array ( struct lv_map * * lvs ,
2005-10-17 03:03:59 +04:00
struct dm_hash_table * maps , struct disk_list * dl )
2001-11-27 19:37:33 +03:00
{
2005-06-01 20:51:55 +04:00
struct lvd_list * ll ;
2001-11-27 19:37:33 +03:00
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
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( ll , & dl - > lvds ) {
2006-05-10 01:23:51 +04:00
if ( ! ( lvm = dm_hash_lookup ( maps , strrchr ( ( char * ) ll - > lvd . lv_name , ' / ' )
2001-12-13 03:07:29 +03:00
+ 1 ) ) ) {
2009-07-16 00:02:46 +04:00
log_error ( " Physical volume (%s) contains an "
" unknown logical volume (%s). " ,
2001-11-27 19:37:33 +03:00
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 ;
}
2005-10-17 03:03:59 +04:00
static int _fill_maps ( struct dm_hash_table * maps , struct volume_group * vg ,
2008-11-04 01:14:30 +03:00
struct dm_list * pvds )
2001-11-27 19:37:33 +03:00
{
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
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( dl , pvds ) {
2012-06-21 15:52:19 +04:00
if ( ! ( pv = find_pv ( vg , dl - > dev ) ) ) {
log_error ( " PV %s not found. " , dl - > dev - > pvid ) ;
return 0 ;
}
2001-11-27 19:37:33 +03:00
e = dl - > extents ;
/* build an array of lv's for this pv */
2008-01-30 16:19:47 +03:00
if ( ! _fill_lv_array ( lvms , maps , dl ) )
return_0 ;
2001-11-27 19:37:33 +03:00
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 ) {
2005-12-19 19:28:35 +03:00
log_error ( " Invalid LV in extent map "
" (PV %s, PE % " PRIu32
" , LV % " PRIu32
" , LE % " PRIu32 " ) " ,
dev_name ( pv - > dev ) , i ,
lv_num , e [ i ] . le_num ) ;
2001-11-27 23:03:45 +03:00
return 0 ;
}
2001-11-27 19:37:33 +03:00
le = e [ i ] . le_num ;
if ( le > = lvm - > lv - > le_count ) {
2009-07-16 00:02:46 +04:00
log_error ( " logical extent number "
" out of bounds " ) ;
2001-11-27 19:37:33 +03:00
return 0 ;
}
2001-11-27 23:03:45 +03:00
if ( lvm - > map [ le ] . pv ) {
2009-07-16 00:02:46 +04:00
log_error ( " logical extent (%u) "
" already mapped. " , le ) ;
2001-11-27 23:03:45 +03:00
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 ) {
2009-07-16 00:02:46 +04:00
log_error ( " Logical volume (%s) contains an incomplete "
" mapping table. " , lvm - > lv - > name ) ;
2001-11-27 19:37:33 +03:00
return 0 ;
}
}
return 1 ;
}
2005-10-17 03:03:59 +04:00
static int _check_maps_are_complete ( struct dm_hash_table * maps )
2001-11-27 19:37:33 +03:00
{
2005-10-17 03:03:59 +04:00
struct dm_hash_node * n ;
2001-11-27 20:29:56 +03:00
struct lv_map * lvm ;
2001-11-27 19:37:33 +03:00
2005-10-17 03:03:59 +04:00
for ( n = dm_hash_get_first ( maps ) ; n ; n = dm_hash_get_next ( maps , n ) ) {
lvm = ( struct lv_map * ) dm_hash_get_data ( maps , n ) ;
2001-11-27 19:37:33 +03:00
2008-01-30 16:19:47 +03:00
if ( ! _check_single_map ( lvm ) )
return_0 ;
2001-11-27 19:37:33 +03:00
}
return 1 ;
}
2007-03-15 16:38:28 +03:00
static uint32_t _area_length ( struct lv_map * lvm , uint32_t le )
{
uint32_t len = 0 ;
do
len + + ;
while ( ( lvm - > map [ le + len ] . pv = = lvm - > map [ le ] . pv ) & &
( lvm - > map [ le ] . pv & &
lvm - > map [ le + len ] . pe = = lvm - > map [ le ] . pe + len ) ) ;
return len ;
}
2004-05-05 01:25:57 +04:00
static int _read_linear ( struct cmd_context * cmd , struct lv_map * lvm )
2001-11-27 19:37:33 +03:00
{
2005-04-22 19:44:00 +04:00
uint32_t le = 0 , len ;
2002-11-18 17:01:16 +03:00
struct lv_segment * seg ;
2005-04-22 19:44:00 +04:00
struct segment_type * segtype ;
2015-09-22 21:04:12 +03:00
if ( ! ( segtype = get_segtype_from_string ( cmd , SEG_TYPE_NAME_STRIPED ) ) )
2008-01-30 16:19:47 +03:00
return_0 ;
2001-11-27 19:37:33 +03:00
2001-11-27 23:03:45 +03:00
while ( le < lvm - > lv - > le_count ) {
2007-03-15 16:38:28 +03:00
len = _area_length ( lvm , le ) ;
2005-04-22 19:44:00 +04:00
2011-10-23 20:02:01 +04:00
if ( ! ( seg = alloc_lv_segment ( segtype , lvm - > lv , le , len , 0 , 0 ,
2014-10-26 10:13:59 +03:00
NULL , 1 , len , 0 , 0 , 0 , NULL ) ) ) {
2005-04-22 19:44:00 +04:00
log_error ( " Failed to allocate linear segment. " ) ;
2004-05-05 01:25:57 +04:00
return 0 ;
}
2005-05-03 21:28:23 +04:00
if ( ! set_lv_segment_area_pv ( seg , 0 , lvm - > map [ le ] . pv ,
2007-03-15 16:38:28 +03:00
lvm - > map [ le ] . pe ) )
return_0 ;
2001-11-29 17:13:43 +03:00
2008-11-04 01:14:30 +03:00
dm_list_add ( & lvm - > lv - > segments , & seg - > list ) ;
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
}
return 1 ;
}
2005-04-22 19:44:00 +04:00
static int _check_stripe ( struct lv_map * lvm , uint32_t area_count ,
2007-03-15 16:38:28 +03:00
uint32_t area_len , uint32_t base_le ,
uint32_t total_area_len )
2001-11-29 17:13:43 +03:00
{
2005-04-22 19:44:00 +04:00
uint32_t st ;
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 ?
*/
2005-04-22 19:44:00 +04:00
for ( st = 0 ; st < area_count ; st + + )
2007-03-15 16:38:28 +03:00
if ( ( lvm - > map [ base_le + st * total_area_len + area_len ] . pv ! =
lvm - > map [ base_le + st * total_area_len ] . pv ) | |
( lvm - > map [ base_le + st * total_area_len ] . pv & &
lvm - > map [ base_le + st * total_area_len + area_len ] . pe ! =
lvm - > map [ base_le + st * total_area_len ] . pe + area_len ) )
2005-04-22 19:44:00 +04: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
2004-05-05 01:25:57 +04:00
static int _read_stripes ( struct cmd_context * cmd , struct lv_map * lvm )
2002-01-25 23:24:14 +03:00
{
2007-03-15 16:38:28 +03:00
uint32_t st , first_area_le = 0 , total_area_len ;
2005-04-22 19:44:00 +04:00
uint32_t area_len ;
2002-11-18 17:01:16 +03:00
struct lv_segment * seg ;
2005-04-22 19:44:00 +04:00
struct segment_type * segtype ;
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
}
2007-03-15 16:38:28 +03:00
total_area_len = lvm - > lv - > le_count / lvm - > stripes ;
2015-09-22 21:04:12 +03:00
if ( ! ( segtype = get_segtype_from_string ( cmd , SEG_TYPE_NAME_STRIPED ) ) )
2007-03-15 16:38:28 +03:00
return_0 ;
2005-04-22 19:44:00 +04:00
2007-03-15 16:38:28 +03:00
while ( first_area_le < total_area_len ) {
2005-04-22 19:44:00 +04:00
area_len = 1 ;
2001-12-13 03:07:29 +03:00
2008-01-30 17:00:02 +03:00
/*
2007-03-15 16:38:28 +03:00
* Find how many extents are contiguous in all stripes
2005-04-22 19:44:00 +04:00
* and so can form part of this segment
*/
while ( _check_stripe ( lvm , lvm - > stripes ,
2007-03-15 16:38:28 +03:00
area_len , first_area_le , total_area_len ) )
2005-04-22 19:44:00 +04:00
area_len + + ;
2011-10-23 20:02:01 +04:00
if ( ! ( seg = alloc_lv_segment ( segtype , lvm - > lv ,
2007-03-15 16:38:28 +03:00
lvm - > stripes * first_area_le ,
2005-04-22 19:44:00 +04:00
lvm - > stripes * area_len ,
2014-10-26 10:13:59 +03:00
0 , lvm - > stripe_size , NULL ,
2005-06-01 20:51:55 +04:00
lvm - > stripes ,
2010-04-08 04:28:57 +04:00
area_len , 0 , 0 , 0 , NULL ) ) ) {
2005-04-22 19:44:00 +04:00
log_error ( " Failed to allocate striped segment. " ) ;
2004-05-05 01:25:57 +04:00
return 0 ;
}
2002-01-25 23:24:14 +03:00
/*
* Set up start positions of each stripe in this segment
*/
2005-04-22 19:44:00 +04:00
for ( st = 0 ; st < seg - > area_count ; st + + )
2005-05-03 21:28:23 +04:00
if ( ! set_lv_segment_area_pv ( seg , st ,
2007-03-15 16:38:28 +03:00
lvm - > map [ first_area_le + st * total_area_len ] . pv ,
lvm - > map [ first_area_le + st * total_area_len ] . pe ) )
return_0 ;
2002-01-25 16:41:13 +03:00
2008-11-04 01:14:30 +03:00
dm_list_add ( & lvm - > lv - > segments , & seg - > list ) ;
2002-01-25 23:24:14 +03:00
2007-03-15 16:38:28 +03:00
first_area_le + = area_len ;
2002-01-25 23:24:14 +03:00
}
2001-11-29 17:13:43 +03:00
return 1 ;
}
2004-05-05 01:25:57 +04:00
static int _build_segments ( struct cmd_context * cmd , struct lv_map * lvm )
2001-11-29 17:13:43 +03:00
{
2004-05-05 01:25:57 +04:00
return ( lvm - > stripes > 1 ? _read_stripes ( cmd , lvm ) :
_read_linear ( cmd , lvm ) ) ;
2001-11-29 17:13:43 +03:00
}
2005-10-17 03:03:59 +04:00
static int _build_all_segments ( struct cmd_context * cmd , struct dm_hash_table * maps )
2001-11-27 19:37:33 +03:00
{
2005-10-17 03:03:59 +04:00
struct dm_hash_node * n ;
2001-11-27 19:37:33 +03:00
struct lv_map * lvm ;
2005-10-17 03:03:59 +04:00
for ( n = dm_hash_get_first ( maps ) ; n ; n = dm_hash_get_next ( maps , n ) ) {
lvm = ( struct lv_map * ) dm_hash_get_data ( maps , n ) ;
2008-01-30 16:19:47 +03:00
if ( ! _build_segments ( cmd , lvm ) )
return_0 ;
2001-11-27 19:37:33 +03:00
}
return 1 ;
}
2004-05-05 01:25:57 +04:00
int import_extents ( struct cmd_context * cmd , struct volume_group * vg ,
2008-11-04 01:14:30 +03:00
struct dm_list * pvds )
2001-11-27 19:37:33 +03:00
{
int r = 0 ;
2005-10-17 03:03:59 +04:00
struct dm_pool * scratch = dm_pool_create ( " lvm1 import_extents " , 10 * 1024 ) ;
struct dm_hash_table * maps ;
2001-11-27 19:37:33 +03:00
2008-01-30 16:19:47 +03:00
if ( ! scratch )
return_0 ;
2001-11-27 19:37:33 +03:00
if ( ! ( maps = _create_lv_maps ( scratch , vg ) ) ) {
2009-07-16 00:02:46 +04:00
log_error ( " Couldn't allocate logical volume maps. " ) ;
2001-11-27 19:37:33 +03:00
goto out ;
}
2001-11-27 20:29:56 +03:00
if ( ! _fill_maps ( maps , vg , pvds ) ) {
2009-07-16 00:02:46 +04:00
log_error ( " Couldn't fill logical volume maps. " ) ;
2001-11-27 19:37:33 +03:00
goto out ;
}
2008-01-30 16:19:47 +03:00
if ( ! _check_maps_are_complete ( maps ) & & ! ( vg - > status & PARTIAL_VG ) )
goto_out ;
2001-11-27 19:37:33 +03:00
2004-05-05 01:25:57 +04:00
if ( ! _build_all_segments ( cmd , maps ) ) {
2009-07-16 00:02:46 +04:00
log_error ( " Couldn't build extent segments. " ) ;
2001-11-27 19:37:33 +03:00
goto out ;
}
r = 1 ;
2001-12-13 03:07:29 +03:00
out :
2001-11-27 19:37:33 +03:00
if ( maps )
2005-10-17 03:03:59 +04:00
dm_hash_destroy ( maps ) ;
dm_pool_destroy ( scratch ) ;
2001-11-27 19:37:33 +03:00
return r ;
}