2002-11-18 17:04:08 +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 .
2002-11-18 17:04:08 +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 ,
* Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
2002-11-18 17:04:08 +03:00
*/
# include "lib.h"
# include "metadata.h"
# include "import-export.h"
# include "display.h"
# include "toolcontext.h"
2003-07-05 02:34:56 +04:00
# include "lvmcache.h"
2003-09-18 00:35:57 +04:00
# include "lv_alloc.h"
2005-04-20 00:58:25 +04:00
# include "pv_alloc.h"
2004-09-16 22:40:56 +04:00
# include "segtype.h"
2004-05-05 01:25:57 +04:00
# include "text_import.h"
2002-11-18 17:04:08 +03:00
2005-10-17 03:03:59 +04:00
typedef int ( * section_fn ) ( struct format_instance * fid , struct dm_pool * mem ,
2002-11-18 17:04:08 +03:00
struct volume_group * vg , struct config_node * pvn ,
struct config_node * vgn ,
2010-03-16 20:30:00 +03:00
struct dm_hash_table * pv_hash ,
2010-03-31 21:20:02 +04:00
struct dm_hash_table * lv_hash ,
2010-03-17 05:11:18 +03:00
unsigned * scan_done_once ,
unsigned report_missing_devices ) ;
2002-11-18 17:04:08 +03:00
# define _read_int32(root, path, result) \
2005-03-11 01:34:17 +03:00
get_config_uint32 ( root , path , ( uint32_t * ) result )
2002-11-18 17:04:08 +03:00
# define _read_uint32(root, path, result) \
2004-03-08 21:28:45 +03:00
get_config_uint32 ( root , path , result )
2002-11-18 17:04:08 +03:00
# define _read_int64(root, path, result) \
2004-03-08 21:28:45 +03:00
get_config_uint64 ( root , path , result )
2002-11-18 17:04:08 +03:00
/*
* Logs an attempt to read an invalid format file .
*/
static void _invalid_format ( const char * str )
{
log_error ( " Can't process text format file - %s. " , str ) ;
}
/*
* Checks that the config file contains vg metadata , and that it
* we recognise the version number ,
*/
2004-03-08 21:28:45 +03:00
static int _check_version ( struct config_tree * cft )
2002-11-18 17:04:08 +03:00
{
struct config_node * cn ;
struct config_value * cv ;
/*
* Check the contents field .
*/
2004-03-08 21:28:45 +03:00
if ( ! ( cn = find_config_node ( cft - > root , CONTENTS_FIELD ) ) ) {
2002-11-18 17:04:08 +03:00
_invalid_format ( " missing contents field " ) ;
return 0 ;
}
cv = cn - > v ;
if ( ! cv | | cv - > type ! = CFG_STRING | | strcmp ( cv - > v . str , CONTENTS_VALUE ) ) {
_invalid_format ( " unrecognised contents field " ) ;
return 0 ;
}
/*
* Check the version number .
*/
2004-03-08 21:28:45 +03:00
if ( ! ( cn = find_config_node ( cft - > root , FORMAT_VERSION_FIELD ) ) ) {
2002-11-18 17:04:08 +03:00
_invalid_format ( " missing version number " ) ;
return 0 ;
}
cv = cn - > v ;
if ( ! cv | | cv - > type ! = CFG_INT | | cv - > v . i ! = FORMAT_VERSION_VALUE ) {
_invalid_format ( " unrecognised version number " ) ;
return 0 ;
}
return 1 ;
}
2008-01-10 21:35:51 +03:00
static int _is_converting ( struct logical_volume * lv )
{
struct lv_segment * seg ;
if ( lv - > status & MIRRORED ) {
seg = first_seg ( lv ) ;
/* Can't use is_temporary_mirror() because the metadata for
* seg_lv may not be read in and flags may not be set yet . */
if ( seg_type ( seg , 0 ) = = AREA_LV & &
strstr ( seg_lv ( seg , 0 ) - > name , MIRROR_SYNC_LAYER ) )
return 1 ;
}
return 0 ;
}
2002-11-18 17:04:08 +03:00
static int _read_id ( struct id * id , struct config_node * cn , const char * path )
{
struct config_value * cv ;
2004-03-08 21:28:45 +03:00
if ( ! ( cn = find_config_node ( cn , path ) ) ) {
2002-11-18 17:04:08 +03:00
log_error ( " Couldn't find uuid. " ) ;
return 0 ;
}
cv = cn - > v ;
if ( ! cv | | ! cv - > v . str ) {
log_error ( " uuid must be a string. " ) ;
return 0 ;
}
if ( ! id_read_format ( id , cv - > v . str ) ) {
log_error ( " Invalid uuid. " ) ;
return 0 ;
}
return 1 ;
}
2009-11-25 01:55:55 +03:00
static int _read_flag_config ( struct config_node * n , uint64_t * status , int type )
2008-07-10 15:30:57 +04:00
{
struct config_node * cn ;
* status = 0 ;
if ( ! ( cn = find_config_node ( n , " status " ) ) ) {
log_error ( " Could not find status flags. " ) ;
return 0 ;
}
if ( ! ( read_flags ( status , type | STATUS_FLAG , cn - > v ) ) ) {
log_error ( " Could not read status flags. " ) ;
return 0 ;
}
2008-07-11 13:19:54 +04:00
if ( ( cn = find_config_node ( n , " flags " ) ) ) {
2008-07-10 15:30:57 +04:00
if ( ! ( read_flags ( status , type , cn - > v ) ) ) {
log_error ( " Could not read flags. " ) ;
return 0 ;
}
}
return 1 ;
}
2005-10-17 03:03:59 +04:00
static int _read_pv ( struct format_instance * fid , struct dm_pool * mem ,
2002-11-18 17:04:08 +03:00
struct volume_group * vg , struct config_node * pvn ,
2007-08-22 18:38:18 +04:00
struct config_node * vgn __attribute ( ( unused ) ) ,
2010-03-31 21:20:02 +04:00
struct dm_hash_table * pv_hash ,
struct dm_hash_table * lv_hash __attribute ( ( unused ) ) ,
unsigned * scan_done_once ,
2010-03-17 05:11:18 +03:00
unsigned report_missing_devices )
2002-11-18 17:04:08 +03:00
{
struct physical_volume * pv ;
struct pv_list * pvl ;
struct config_node * cn ;
2006-10-19 16:53:47 +04:00
uint64_t size ;
2002-11-18 17:04:08 +03:00
2005-10-17 03:03:59 +04:00
if ( ! ( pvl = dm_pool_zalloc ( mem , sizeof ( * pvl ) ) ) | |
2008-01-30 16:19:47 +03:00
! ( pvl - > pv = dm_pool_zalloc ( mem , sizeof ( * pvl - > pv ) ) ) )
return_0 ;
2002-11-18 17:04:08 +03:00
pv = pvl - > pv ;
/*
* Add the pv to the pv hash for quick lookup when we read
* the lv segments .
*/
2008-01-30 16:19:47 +03:00
if ( ! dm_hash_insert ( pv_hash , pvn - > key , pv ) )
return_0 ;
2002-11-18 17:04:08 +03:00
if ( ! ( pvn = pvn - > child ) ) {
log_error ( " Empty pv section. " ) ;
return 0 ;
}
if ( ! _read_id ( & pv - > id , pvn , " id " ) ) {
2009-03-09 18:42:10 +03:00
log_error ( " Couldn't read uuid for physical volume. " ) ;
2002-11-18 17:04:08 +03:00
return 0 ;
}
/*
* Convert the uuid into a device .
*/
2010-03-16 20:30:00 +03:00
if ( ! ( pv - > dev = device_from_pvid ( fid - > fmt - > cmd , & pv - > id , scan_done_once ) ) ) {
2006-12-01 02:11:42 +03:00
char buffer [ 64 ] __attribute ( ( aligned ( 8 ) ) ) ;
2002-11-18 17:04:08 +03:00
if ( ! id_write_format ( & pv - > id , buffer , sizeof ( buffer ) ) )
2010-03-17 05:11:18 +03:00
buffer [ 0 ] = ' \0 ' ;
if ( report_missing_devices )
log_error ( " Couldn't find device with uuid %s. " , buffer ) ;
2002-11-18 17:04:08 +03:00
else
2010-03-17 05:11:18 +03:00
log_very_verbose ( " Couldn't find device with uuid %s. " , buffer ) ;
2002-11-18 17:04:08 +03:00
}
2008-01-30 16:19:47 +03:00
if ( ! ( pv - > vg_name = dm_pool_strdup ( mem , vg - > name ) ) )
return_0 ;
2002-11-18 17:04:08 +03:00
2006-04-13 01:23:04 +04:00
memcpy ( & pv - > vgid , & vg - > id , sizeof ( vg - > id ) ) ;
2008-07-10 15:30:57 +04:00
if ( ! _read_flag_config ( pvn , & pv - > status , PV_FLAGS ) ) {
2002-11-18 17:04:08 +03:00
log_error ( " Couldn't read status flags for physical volume. " ) ;
return 0 ;
}
2008-09-19 10:42:00 +04:00
if ( ! pv - > dev )
pv - > status | = MISSING_PV ;
2006-10-08 03:17:17 +04:00
/* Late addition */
_read_int64 ( pvn , " dev_size " , & pv - > size ) ;
2002-11-18 17:04:08 +03:00
if ( ! _read_int64 ( pvn , " pe_start " , & pv - > pe_start ) ) {
2009-03-09 18:42:10 +03:00
log_error ( " Couldn't read extent size for physical volume. " ) ;
2002-11-18 17:04:08 +03:00
return 0 ;
}
if ( ! _read_int32 ( pvn , " pe_count " , & pv - > pe_count ) ) {
log_error ( " Couldn't find extent count (pe_count) for "
" physical volume. " ) ;
return 0 ;
}
2008-11-04 01:14:30 +03:00
dm_list_init ( & pv - > tags ) ;
dm_list_init ( & pv - > segments ) ;
2004-03-08 20:19:15 +03:00
/* Optional tags */
2004-03-08 21:28:45 +03:00
if ( ( cn = find_config_node ( pvn , " tags " ) ) & &
2004-03-08 20:19:15 +03:00
! ( read_tags ( mem , & pv - > tags , cn - > v ) ) ) {
log_error ( " Couldn't read tags for physical volume %s in %s. " ,
2007-10-12 18:29:32 +04:00
pv_dev_name ( pv ) , vg - > name ) ;
2004-03-08 20:19:15 +03:00
return 0 ;
}
2002-11-18 17:04:08 +03:00
/* adjust the volume group. */
vg - > extent_count + = pv - > pe_count ;
vg - > free_count + = pv - > pe_count ;
pv - > pe_size = vg - > extent_size ;
2006-10-08 03:17:17 +04:00
2002-11-18 17:04:08 +03:00
pv - > pe_alloc_count = 0 ;
2008-09-19 08:28:58 +04:00
pv - > pe_align = 0 ;
2002-11-18 17:04:08 +03:00
pv - > fmt = fid - > fmt ;
2008-01-30 17:00:02 +03:00
/* Fix up pv size if missing or impossibly large */
if ( ( ! pv - > size | | pv - > size > ( 1ULL < < 62 ) ) & & pv - > dev ) {
if ( ! dev_get_size ( pv - > dev , & pv - > size ) ) {
log_error ( " %s: Couldn't get size. " , pv_dev_name ( pv ) ) ;
return 0 ;
}
log_verbose ( " Fixing up missing size (%s) "
" for PV %s " , display_size ( fid - > fmt - > cmd , pv - > size ) ,
pv_dev_name ( pv ) ) ;
if ( vg ) {
size = pv - > pe_count * ( uint64_t ) vg - > extent_size +
pv - > pe_start ;
if ( size > pv - > size )
2010-04-01 14:34:09 +04:00
log_warn ( " WARNING: Physical Volume %s is too "
" large for underlying device " ,
pv_dev_name ( pv ) ) ;
2008-01-30 17:00:02 +03:00
}
}
2006-10-19 16:53:47 +04:00
2008-01-30 16:19:47 +03:00
if ( ! alloc_pv_segment_whole_pv ( mem , pv ) )
return_0 ;
2005-04-20 00:58:25 +04:00
2002-11-18 17:04:08 +03:00
vg - > pv_count + + ;
2008-11-04 01:14:30 +03:00
dm_list_add ( & vg - > pvs , & pvl - > list ) ;
2002-11-18 17:04:08 +03:00
return 1 ;
}
static void _insert_segment ( struct logical_volume * lv , struct lv_segment * seg )
{
struct lv_segment * comp ;
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( comp , & lv - > segments ) {
2002-11-18 17:04:08 +03:00
if ( comp - > le > seg - > le ) {
2008-11-04 01:14:30 +03:00
dm_list_add ( & comp - > list , & seg - > list ) ;
2002-11-18 17:04:08 +03:00
return ;
}
}
lv - > le_count + = seg - > len ;
2008-11-04 01:14:30 +03:00
dm_list_add ( & lv - > segments , & seg - > list ) ;
2002-11-18 17:04:08 +03:00
}
2005-10-17 03:03:59 +04:00
static int _read_segment ( struct dm_pool * mem , struct volume_group * vg ,
2002-11-18 17:04:08 +03:00
struct logical_volume * lv , struct config_node * sn ,
2005-10-17 03:03:59 +04:00
struct dm_hash_table * pv_hash )
2002-11-18 17:04:08 +03:00
{
2004-05-05 01:25:57 +04:00
uint32_t area_count = 0u ;
2002-11-18 17:04:08 +03:00
struct lv_segment * seg ;
2009-07-09 15:28:09 +04:00
struct config_node * cn , * sn_child = sn - > child ;
2002-11-18 17:04:08 +03:00
struct config_value * cv ;
uint32_t start_extent , extent_count ;
2004-05-05 01:25:57 +04:00
struct segment_type * segtype ;
const char * segtype_str ;
2002-11-18 17:04:08 +03:00
2009-07-09 15:28:09 +04:00
if ( ! sn_child ) {
2002-11-18 17:04:08 +03:00
log_error ( " Empty segment section. " ) ;
return 0 ;
}
2009-07-09 15:28:09 +04:00
if ( ! _read_int32 ( sn_child , " start_extent " , & start_extent ) ) {
log_error ( " Couldn't read 'start_extent' for segment '%s' "
" of logical volume %s. " , sn - > key , lv - > name ) ;
2002-11-18 17:04:08 +03:00
return 0 ;
}
2009-07-09 15:28:09 +04:00
if ( ! _read_int32 ( sn_child , " extent_count " , & extent_count ) ) {
log_error ( " Couldn't read 'extent_count' for segment '%s' "
" of logical volume %s. " , sn - > key , lv - > name ) ;
2002-11-18 17:04:08 +03:00
return 0 ;
}
2004-05-05 01:25:57 +04:00
segtype_str = " striped " ;
2009-07-09 15:28:09 +04:00
if ( ( cn = find_config_node ( sn_child , " type " ) ) ) {
2002-11-18 17:04:08 +03:00
cv = cn - > v ;
if ( ! cv | | ! cv - > v . str ) {
log_error ( " Segment type must be a string. " ) ;
return 0 ;
}
2004-05-05 01:25:57 +04:00
segtype_str = cv - > v . str ;
2002-11-18 17:04:08 +03:00
}
2008-01-30 16:19:47 +03:00
if ( ! ( segtype = get_segtype_from_string ( vg - > cmd , segtype_str ) ) )
return_0 ;
2002-11-18 17:04:08 +03:00
2004-05-05 01:25:57 +04:00
if ( segtype - > ops - > text_import_area_count & &
2009-07-09 15:28:09 +04:00
! segtype - > ops - > text_import_area_count ( sn_child , & area_count ) )
2008-01-30 16:19:47 +03:00
return_0 ;
2003-04-30 19:22:36 +04:00
2005-04-22 19:44:00 +04:00
if ( ! ( seg = alloc_lv_segment ( mem , segtype , lv , start_extent ,
2005-06-01 20:51:55 +04:00
extent_count , 0 , 0 , NULL , area_count ,
extent_count , 0 , 0 , 0 ) ) ) {
2003-09-18 00:35:57 +04:00
log_error ( " Segment allocation failed " ) ;
2002-11-18 17:04:08 +03:00
return 0 ;
}
2004-05-05 01:25:57 +04:00
if ( seg - > segtype - > ops - > text_import & &
2009-07-09 15:28:09 +04:00
! seg - > segtype - > ops - > text_import ( seg , sn_child , pv_hash ) )
2008-01-30 16:19:47 +03:00
return_0 ;
2002-11-18 17:04:08 +03:00
2004-03-08 20:19:15 +03:00
/* Optional tags */
2009-07-09 15:28:09 +04:00
if ( ( cn = find_config_node ( sn_child , " tags " ) ) & &
2004-03-08 20:19:15 +03:00
! ( read_tags ( mem , & seg - > tags , cn - > v ) ) ) {
log_error ( " Couldn't read tags for a segment of %s/%s. " ,
vg - > name , lv - > name ) ;
return 0 ;
}
2004-05-05 01:25:57 +04:00
/*
* Insert into correct part of segment list .
*/
_insert_segment ( lv , seg ) ;
2002-11-18 17:04:08 +03:00
2005-05-09 20:59:01 +04:00
if ( seg_is_mirrored ( seg ) )
2004-05-05 01:25:57 +04:00
lv - > status | = MIRRORED ;
2002-11-18 17:04:08 +03:00
2005-05-09 20:59:01 +04:00
if ( seg_is_virtual ( seg ) )
2004-05-11 20:01:58 +04:00
lv - > status | = VIRTUAL ;
2008-01-10 21:35:51 +03:00
if ( _is_converting ( lv ) )
lv - > status | = CONVERTING ;
2004-05-05 01:25:57 +04:00
return 1 ;
}
2002-11-18 17:04:08 +03:00
2004-05-05 01:25:57 +04:00
int text_import_areas ( struct lv_segment * seg , const struct config_node * sn ,
2005-10-17 03:03:59 +04:00
const struct config_node * cn , struct dm_hash_table * pv_hash ,
2009-12-04 20:48:32 +03:00
uint64_t status )
2004-05-05 01:25:57 +04:00
{
unsigned int s ;
struct config_value * cv ;
struct logical_volume * lv1 ;
2009-07-09 15:29:41 +04:00
struct physical_volume * pv ;
const char * seg_name = config_parent_name ( sn ) ;
2002-11-18 17:04:08 +03:00
2004-05-05 01:25:57 +04:00
if ( ! seg - > area_count ) {
2009-07-09 15:29:41 +04:00
log_error ( " Zero areas not allowed for segment %s " , seg_name ) ;
2004-05-05 01:25:57 +04:00
return 0 ;
}
2002-11-18 17:04:08 +03:00
2004-05-05 01:25:57 +04:00
for ( cv = cn - > v , s = 0 ; cv & & s < seg - > area_count ; s + + , cv = cv - > next ) {
2002-11-18 17:04:08 +03:00
2004-05-05 01:25:57 +04:00
/* first we read the pv */
if ( cv - > type ! = CFG_STRING ) {
2009-07-09 15:29:41 +04:00
log_error ( " Bad volume name in areas array for segment %s. " , seg_name ) ;
2002-11-18 17:04:08 +03:00
return 0 ;
}
2004-05-05 01:25:57 +04:00
if ( ! cv - > next ) {
2009-07-09 15:29:41 +04:00
log_error ( " Missing offset in areas array for segment %s. " , seg_name ) ;
2003-04-25 02:23:24 +04:00
return 0 ;
}
2004-05-05 01:25:57 +04:00
if ( cv - > next - > type ! = CFG_INT ) {
2009-07-09 15:29:41 +04:00
log_error ( " Bad offset in areas array for segment %s. " , seg_name ) ;
2003-04-30 19:22:36 +04:00
return 0 ;
}
2004-05-05 01:25:57 +04:00
/* FIXME Cope if LV not yet read in */
2005-10-17 03:03:59 +04:00
if ( ( pv = dm_hash_lookup ( pv_hash , cv - > v . str ) ) ) {
2008-01-30 16:19:47 +03:00
if ( ! set_lv_segment_area_pv ( seg , s , pv , ( uint32_t ) cv - > next - > v . i ) )
return_0 ;
2004-05-05 01:25:57 +04:00
} else if ( ( lv1 = find_lv ( seg - > lv - > vg , cv - > v . str ) ) ) {
2008-01-16 22:00:59 +03:00
if ( ! set_lv_segment_area_lv ( seg , s , lv1 ,
( uint32_t ) cv - > next - > v . i ,
2009-12-04 20:48:32 +03:00
status ) )
2008-01-16 22:00:59 +03:00
return_0 ;
2004-05-05 01:25:57 +04:00
} else {
log_error ( " Couldn't find volume '%s' "
" for segment '%s'. " ,
2006-05-10 01:23:51 +04:00
cv - > v . str ? : " NULL " , seg_name ) ;
2002-11-18 17:04:08 +03:00
return 0 ;
}
2004-05-05 01:25:57 +04:00
cv = cv - > next ;
2002-11-18 17:04:08 +03:00
}
/*
2004-05-05 01:25:57 +04:00
* Check we read the correct number of stripes .
2002-11-18 17:04:08 +03:00
*/
2004-05-05 01:25:57 +04:00
if ( cv | | ( s < seg - > area_count ) ) {
log_error ( " Incorrect number of areas in area array "
" for segment '%s'. " , seg_name ) ;
return 0 ;
}
2002-11-18 17:04:08 +03:00
return 1 ;
}
2005-10-17 03:03:59 +04:00
static int _read_segments ( struct dm_pool * mem , struct volume_group * vg ,
2002-11-18 17:04:08 +03:00
struct logical_volume * lv , struct config_node * lvn ,
2005-10-17 03:03:59 +04:00
struct dm_hash_table * pv_hash )
2002-11-18 17:04:08 +03:00
{
struct config_node * sn ;
int count = 0 , seg_count ;
for ( sn = lvn ; sn ; sn = sn - > sib ) {
/*
* All sub - sections are assumed to be segments .
*/
if ( ! sn - > v ) {
2008-01-30 16:19:47 +03:00
if ( ! _read_segment ( mem , vg , lv , sn , pv_hash ) )
return_0 ;
2002-11-18 17:04:08 +03:00
count + + ;
}
/* FIXME Remove this restriction */
if ( ( lv - > status & SNAPSHOT ) & & count > 1 ) {
log_error ( " Only one segment permitted for snapshot " ) ;
return 0 ;
}
}
if ( ! _read_int32 ( lvn , " segment_count " , & seg_count ) ) {
2009-07-09 15:28:09 +04:00
log_error ( " Couldn't read segment count for logical volume %s. " ,
lv - > name ) ;
2002-11-18 17:04:08 +03:00
return 0 ;
}
if ( seg_count ! = count ) {
log_error ( " segment_count and actual number of segments "
2009-07-09 15:28:09 +04:00
" disagree for logical volume %s. " , lv - > name ) ;
2002-11-18 17:04:08 +03:00
return 0 ;
}
/*
* Check there are no gaps or overlaps in the lv .
*/
2008-01-30 16:19:47 +03:00
if ( ! check_lv_segments ( lv , 0 ) )
return_0 ;
2002-11-18 17:04:08 +03:00
/*
* Merge segments in case someones been editing things by hand .
*/
2008-01-30 16:19:47 +03:00
if ( ! lv_merge_segments ( lv ) )
return_0 ;
2002-11-18 17:04:08 +03:00
return 1 ;
}
2007-08-22 18:38:18 +04:00
static int _read_lvnames ( struct format_instance * fid __attribute ( ( unused ) ) ,
struct dm_pool * mem ,
2003-04-25 02:23:24 +04:00
struct volume_group * vg , struct config_node * lvn ,
2007-08-22 18:38:18 +04:00
struct config_node * vgn __attribute ( ( unused ) ) ,
2010-03-16 20:30:00 +03:00
struct dm_hash_table * pv_hash __attribute ( ( unused ) ) ,
2010-03-31 21:20:02 +04:00
struct dm_hash_table * lv_hash ,
2010-03-17 05:11:18 +03:00
unsigned * scan_done_once __attribute ( ( unused ) ) ,
unsigned report_missing_devices __attribute ( ( unused ) ) )
2002-11-18 17:04:08 +03:00
{
struct logical_volume * lv ;
struct config_node * cn ;
2009-09-28 21:46:15 +04:00
if ( ! ( lv = alloc_lv ( mem ) ) )
2008-01-30 16:19:47 +03:00
return_0 ;
2002-11-18 17:04:08 +03:00
2008-01-30 16:19:47 +03:00
if ( ! ( lv - > name = dm_pool_strdup ( mem , lvn - > key ) ) )
return_0 ;
2002-11-18 17:04:08 +03:00
if ( ! ( lvn = lvn - > child ) ) {
log_error ( " Empty logical volume section. " ) ;
return 0 ;
}
2008-07-10 15:30:57 +04:00
if ( ! _read_flag_config ( lvn , & lv - > status , LV_FLAGS ) ) {
log_error ( " Couldn't read status flags for logical volume %s. " ,
lv - > name ) ;
2002-11-18 17:04:08 +03:00
return 0 ;
}
2004-05-19 02:12:53 +04:00
lv - > alloc = ALLOC_INHERIT ;
2004-03-08 21:28:45 +03:00
if ( ( cn = find_config_node ( lvn , " allocation_policy " ) ) ) {
2002-11-18 17:04:08 +03:00
struct config_value * cv = cn - > v ;
if ( ! cv | | ! cv - > v . str ) {
log_error ( " allocation_policy must be a string. " ) ;
return 0 ;
}
lv - > alloc = get_alloc_from_string ( cv - > v . str ) ;
2008-01-30 16:19:47 +03:00
if ( lv - > alloc = = ALLOC_INVALID )
return_0 ;
2002-11-18 17:04:08 +03:00
}
if ( ! _read_int32 ( lvn , " read_ahead " , & lv - > read_ahead ) )
2007-11-09 19:51:54 +03:00
/* If not present, choice of auto or none is configurable */
lv - > read_ahead = vg - > cmd - > default_settings . read_ahead ;
else {
switch ( lv - > read_ahead ) {
case 0 :
lv - > read_ahead = DM_READ_AHEAD_AUTO ;
break ;
2008-01-31 15:35:31 +03:00
case ( uint32_t ) - 1 :
2007-11-09 19:51:54 +03:00
lv - > read_ahead = DM_READ_AHEAD_NONE ;
break ;
default :
;
}
}
2002-11-18 17:04:08 +03:00
2004-03-08 20:19:15 +03:00
/* Optional tags */
2004-03-08 21:28:45 +03:00
if ( ( cn = find_config_node ( lvn , " tags " ) ) & &
2004-03-08 20:19:15 +03:00
! ( read_tags ( mem , & lv - > tags , cn - > v ) ) ) {
log_error ( " Couldn't read tags for logical volume %s/%s. " ,
vg - > name , lv - > name ) ;
return 0 ;
}
2003-04-25 02:23:24 +04:00
2010-03-31 21:20:02 +04:00
if ( ! dm_hash_insert ( lv_hash , lv - > name , lv ) )
return_0 ;
2009-05-14 01:25:01 +04:00
return link_lv_to_vg ( vg , lv ) ;
2003-04-25 02:23:24 +04:00
}
2007-08-22 18:38:18 +04:00
static int _read_lvsegs ( struct format_instance * fid __attribute ( ( unused ) ) ,
struct dm_pool * mem ,
2003-04-25 02:23:24 +04:00
struct volume_group * vg , struct config_node * lvn ,
2007-08-22 18:38:18 +04:00
struct config_node * vgn __attribute ( ( unused ) ) ,
2010-03-16 20:30:00 +03:00
struct dm_hash_table * pv_hash ,
2010-03-31 21:20:02 +04:00
struct dm_hash_table * lv_hash ,
2010-03-17 05:11:18 +03:00
unsigned * scan_done_once __attribute ( ( unused ) ) ,
unsigned report_missing_devices __attribute ( ( unused ) ) )
2003-04-25 02:23:24 +04:00
{
struct logical_volume * lv ;
2010-03-31 21:20:02 +04:00
if ( ! ( lv = dm_hash_lookup ( lv_hash , lvn - > key ) ) ) {
2003-04-25 02:23:24 +04:00
log_error ( " Lost logical volume reference %s " , lvn - > key ) ;
return 0 ;
}
if ( ! ( lvn = lvn - > child ) ) {
log_error ( " Empty logical volume section. " ) ;
return 0 ;
}
/* FIXME: read full lvid */
if ( ! _read_id ( & lv - > lvid . id [ 1 ] , lvn , " id " ) ) {
log_error ( " Couldn't read uuid for logical volume %s. " ,
lv - > name ) ;
return 0 ;
}
memcpy ( & lv - > lvid . id [ 0 ] , & lv - > vg - > id , sizeof ( lv - > lvid . id [ 0 ] ) ) ;
2008-01-30 16:19:47 +03:00
if ( ! _read_segments ( mem , vg , lv , lvn , pv_hash ) )
return_0 ;
2003-04-25 02:23:24 +04:00
2002-11-18 17:04:08 +03:00
lv - > size = ( uint64_t ) lv - > le_count * ( uint64_t ) vg - > extent_size ;
2005-04-07 16:39:44 +04:00
lv - > minor = - 1 ;
if ( ( lv - > status & FIXED_MINOR ) & &
! _read_int32 ( lvn , " minor " , & lv - > minor ) ) {
log_error ( " Couldn't read minor number for logical "
" volume %s. " , lv - > name ) ;
return 0 ;
}
lv - > major = - 1 ;
if ( ( lv - > status & FIXED_MINOR ) & &
! _read_int32 ( lvn , " major " , & lv - > major ) ) {
log_error ( " Couldn't read major number for logical "
" volume %s. " , lv - > name ) ;
2002-11-18 17:04:08 +03:00
}
return 1 ;
}
static int _read_sections ( struct format_instance * fid ,
const char * section , section_fn fn ,
2005-10-17 03:03:59 +04:00
struct dm_pool * mem ,
2002-11-18 17:04:08 +03:00
struct volume_group * vg , struct config_node * vgn ,
2010-03-31 21:20:02 +04:00
struct dm_hash_table * pv_hash ,
struct dm_hash_table * lv_hash ,
int optional ,
2010-03-17 05:11:18 +03:00
unsigned * scan_done_once )
2002-11-18 17:04:08 +03:00
{
struct config_node * n ;
2010-03-17 05:11:18 +03:00
/* Only report missing devices when doing a scan */
unsigned report_missing_devices = scan_done_once ? ! * scan_done_once : 1 ;
2002-11-18 17:04:08 +03:00
2004-03-08 21:28:45 +03:00
if ( ! ( n = find_config_node ( vgn , section ) ) ) {
2002-11-18 17:04:08 +03:00
if ( ! optional ) {
log_error ( " Couldn't find section '%s'. " , section ) ;
return 0 ;
}
return 1 ;
}
for ( n = n - > child ; n ; n = n - > sib ) {
2010-03-31 21:20:02 +04:00
if ( ! fn ( fid , mem , vg , n , vgn , pv_hash , lv_hash , scan_done_once , report_missing_devices ) )
2008-01-30 16:19:47 +03:00
return_0 ;
2002-11-18 17:04:08 +03:00
}
return 1 ;
}
static struct volume_group * _read_vg ( struct format_instance * fid ,
2010-03-17 05:11:18 +03:00
struct config_tree * cft ,
unsigned use_cached_pvs )
2002-11-18 17:04:08 +03:00
{
struct config_node * vgn , * cn ;
struct volume_group * vg ;
2010-03-31 21:20:02 +04:00
struct dm_hash_table * pv_hash = NULL , * lv_hash = NULL ;
2009-04-10 13:59:18 +04:00
struct dm_pool * mem = dm_pool_create ( " lvm2 vg_read " , VG_MEMPOOL_CHUNK ) ;
2010-03-17 05:11:18 +03:00
unsigned scan_done_once = use_cached_pvs ;
2009-04-10 13:59:18 +04:00
if ( ! mem )
return_NULL ;
2002-11-18 17:04:08 +03:00
/* skip any top-level values */
2004-03-08 21:28:45 +03:00
for ( vgn = cft - > root ; ( vgn & & vgn - > v ) ; vgn = vgn - > sib ) ;
2002-11-18 17:04:08 +03:00
if ( ! vgn ) {
log_error ( " Couldn't find volume group in file. " ) ;
2009-04-10 13:59:18 +04:00
goto bad ;
2002-11-18 17:04:08 +03:00
}
2008-01-30 16:19:47 +03:00
if ( ! ( vg = dm_pool_zalloc ( mem , sizeof ( * vg ) ) ) )
2009-04-10 13:59:18 +04:00
goto_bad ;
vg - > vgmem = mem ;
2002-11-18 17:04:08 +03:00
vg - > cmd = fid - > fmt - > cmd ;
/* FIXME Determine format type from file contents */
/* eg Set to instance of fmt1 here if reading a format1 backup? */
vg - > fid = fid ;
2007-04-26 20:44:59 +04:00
if ( ! ( vg - > name = dm_pool_strdup ( mem , vgn - > key ) ) )
goto_bad ;
2002-11-18 17:04:08 +03:00
2007-04-26 20:44:59 +04:00
if ( ! ( vg - > system_id = dm_pool_zalloc ( mem , NAME_LEN ) ) )
goto_bad ;
2002-11-18 17:04:08 +03:00
vgn = vgn - > child ;
2004-03-08 21:28:45 +03:00
if ( ( cn = find_config_node ( vgn , " system_id " ) ) & & cn - > v ) {
2002-11-18 17:04:08 +03:00
if ( ! cn - > v - > v . str ) {
log_error ( " system_id must be a string " ) ;
goto bad ;
}
strncpy ( vg - > system_id , cn - > v - > v . str , NAME_LEN ) ;
}
if ( ! _read_id ( & vg - > id , vgn , " id " ) ) {
log_error ( " Couldn't read uuid for volume group %s. " , vg - > name ) ;
goto bad ;
}
if ( ! _read_int32 ( vgn , " seqno " , & vg - > seqno ) ) {
log_error ( " Couldn't read 'seqno' for volume group %s. " ,
vg - > name ) ;
goto bad ;
}
2008-07-10 15:30:57 +04:00
if ( ! _read_flag_config ( vgn , & vg - > status , VG_FLAGS ) ) {
log_error ( " Error reading flags of volume group %s. " ,
2002-11-18 17:04:08 +03:00
vg - > name ) ;
goto bad ;
}
if ( ! _read_int32 ( vgn , " extent_size " , & vg - > extent_size ) ) {
log_error ( " Couldn't read extent size for volume group %s. " ,
vg - > name ) ;
goto bad ;
}
/*
* ' extent_count ' and ' free_count ' get filled in
* implicitly when reading in the pv ' s and lv ' s .
*/
if ( ! _read_int32 ( vgn , " max_lv " , & vg - > max_lv ) ) {
log_error ( " Couldn't read 'max_lv' for volume group %s. " ,
vg - > name ) ;
goto bad ;
}
if ( ! _read_int32 ( vgn , " max_pv " , & vg - > max_pv ) ) {
log_error ( " Couldn't read 'max_pv' for volume group %s. " ,
vg - > name ) ;
goto bad ;
}
2004-05-19 02:12:53 +04:00
vg - > alloc = ALLOC_NORMAL ;
if ( ( cn = find_config_node ( vgn , " allocation_policy " ) ) ) {
struct config_value * cv = cn - > v ;
if ( ! cv | | ! cv - > v . str ) {
log_error ( " allocation_policy must be a string. " ) ;
return 0 ;
}
vg - > alloc = get_alloc_from_string ( cv - > v . str ) ;
2008-01-30 16:19:47 +03:00
if ( vg - > alloc = = ALLOC_INVALID )
return_0 ;
2004-05-19 02:12:53 +04:00
}
2002-11-18 17:04:08 +03:00
/*
2010-03-31 21:20:02 +04:00
* The pv hash memorises the pv section names - > pv
2002-11-18 17:04:08 +03:00
* structures .
*/
2005-10-17 03:03:59 +04:00
if ( ! ( pv_hash = dm_hash_create ( 32 ) ) ) {
2002-11-18 17:04:08 +03:00
log_error ( " Couldn't create hash table. " ) ;
goto bad ;
}
2008-11-04 01:14:30 +03:00
dm_list_init ( & vg - > pvs ) ;
2002-11-18 17:04:08 +03:00
if ( ! _read_sections ( fid , " physical_volumes " , _read_pv , mem , vg ,
2010-03-31 21:20:02 +04:00
vgn , pv_hash , lv_hash , 0 , & scan_done_once ) ) {
2002-11-18 17:04:08 +03:00
log_error ( " Couldn't find all physical volumes for volume "
" group %s. " , vg - > name ) ;
goto bad ;
}
2008-11-04 01:14:30 +03:00
dm_list_init ( & vg - > lvs ) ;
dm_list_init ( & vg - > tags ) ;
2009-07-27 21:43:39 +04:00
dm_list_init ( & vg - > removed_pvs ) ;
2004-03-08 20:19:15 +03:00
/* Optional tags */
2004-03-08 21:28:45 +03:00
if ( ( cn = find_config_node ( vgn , " tags " ) ) & &
2004-03-08 20:19:15 +03:00
! ( read_tags ( mem , & vg - > tags , cn - > v ) ) ) {
log_error ( " Couldn't read tags for volume group %s. " , vg - > name ) ;
goto bad ;
}
2003-04-25 02:23:24 +04:00
2010-03-31 21:20:02 +04:00
/*
* The lv hash memorises the lv section names - > lv
* structures .
*/
if ( ! ( lv_hash = dm_hash_create ( 32 ) ) ) {
log_error ( " Couldn't create hash table. " ) ;
goto bad ;
}
2003-04-25 02:23:24 +04:00
if ( ! _read_sections ( fid , " logical_volumes " , _read_lvnames , mem , vg ,
2010-03-31 21:20:02 +04:00
vgn , pv_hash , lv_hash , 1 , NULL ) ) {
2003-04-25 02:23:24 +04:00
log_error ( " Couldn't read all logical volume names for volume "
2002-11-18 17:04:08 +03:00
" group %s. " , vg - > name ) ;
goto bad ;
}
2003-04-25 02:23:24 +04:00
if ( ! _read_sections ( fid , " logical_volumes " , _read_lvsegs , mem , vg ,
2010-03-31 21:20:02 +04:00
vgn , pv_hash , lv_hash , 1 , NULL ) ) {
2003-04-25 02:23:24 +04:00
log_error ( " Couldn't read all logical volumes for "
" volume group %s. " , vg - > name ) ;
goto bad ;
}
2005-10-28 01:51:28 +04:00
if ( ! fixup_imported_mirrors ( vg ) ) {
log_error ( " Failed to fixup mirror pointers after import for "
" volume group %s. " , vg - > name ) ;
goto bad ;
}
2005-10-17 03:03:59 +04:00
dm_hash_destroy ( pv_hash ) ;
2010-03-31 21:20:02 +04:00
dm_hash_destroy ( lv_hash ) ;
2002-11-18 17:04:08 +03:00
/*
* Finished .
*/
return vg ;
bad :
if ( pv_hash )
2005-10-17 03:03:59 +04:00
dm_hash_destroy ( pv_hash ) ;
2002-11-18 17:04:08 +03:00
2010-03-31 21:20:02 +04:00
if ( lv_hash )
dm_hash_destroy ( lv_hash ) ;
2009-04-10 13:59:18 +04:00
dm_pool_destroy ( mem ) ;
2002-11-18 17:04:08 +03:00
return NULL ;
}
2005-10-17 03:03:59 +04:00
static void _read_desc ( struct dm_pool * mem ,
2004-03-08 21:28:45 +03:00
struct config_tree * cft , time_t * when , char * * desc )
2002-11-18 17:04:08 +03:00
{
const char * d ;
unsigned int u = 0u ;
2009-04-03 01:34:41 +04:00
int old_suppress ;
2002-11-18 17:04:08 +03:00
2009-04-03 01:34:41 +04:00
old_suppress = log_suppress ( 1 ) ;
2004-03-08 21:28:45 +03:00
d = find_config_str ( cft - > root , " description " , " " ) ;
2009-04-03 01:34:41 +04:00
log_suppress ( old_suppress ) ;
2005-10-17 03:03:59 +04:00
* desc = dm_pool_strdup ( mem , d ) ;
2002-11-18 17:04:08 +03:00
2004-03-08 21:28:45 +03:00
get_config_uint32 ( cft - > root , " creation_time " , & u ) ;
2002-11-18 17:04:08 +03:00
* when = u ;
}
2006-04-11 17:55:59 +04:00
static const char * _read_vgname ( const struct format_type * fmt ,
2006-04-11 21:42:15 +04:00
struct config_tree * cft , struct id * vgid ,
2009-11-25 01:55:55 +03:00
uint64_t * vgstatus , char * * creation_host )
2006-04-11 17:55:59 +04:00
{
2008-07-11 13:19:54 +04:00
struct config_node * vgn ;
2006-04-11 17:55:59 +04:00
struct dm_pool * mem = fmt - > cmd - > mem ;
char * vgname ;
2006-04-13 21:32:24 +04:00
int old_suppress ;
old_suppress = log_suppress ( 2 ) ;
* creation_host = dm_pool_strdup ( mem ,
find_config_str ( cft - > root ,
2008-01-30 17:00:02 +03:00
" creation_host " , " " ) ) ;
2006-04-13 21:32:24 +04:00
log_suppress ( old_suppress ) ;
2006-04-11 17:55:59 +04:00
/* skip any top-level values */
for ( vgn = cft - > root ; ( vgn & & vgn - > v ) ; vgn = vgn - > sib ) ;
if ( ! vgn ) {
log_error ( " Couldn't find volume group in file. " ) ;
return 0 ;
}
if ( ! ( vgname = dm_pool_strdup ( mem , vgn - > key ) ) )
return_0 ;
vgn = vgn - > child ;
if ( ! _read_id ( vgid , vgn , " id " ) ) {
log_error ( " Couldn't read uuid for volume group %s. " , vgname ) ;
return 0 ;
}
2008-07-10 15:30:57 +04:00
if ( ! _read_flag_config ( vgn , vgstatus , VG_FLAGS ) ) {
2006-04-11 21:42:15 +04:00
log_error ( " Couldn't find status flags for volume group %s. " ,
vgname ) ;
return 0 ;
}
2006-04-11 17:55:59 +04:00
return vgname ;
}
2002-11-18 17:04:08 +03:00
static struct text_vg_version_ops _vsn1_ops = {
2006-05-10 01:23:51 +04:00
. check_version = _check_version ,
. read_vg = _read_vg ,
. read_desc = _read_desc ,
. read_vgname = _read_vgname ,
2002-11-18 17:04:08 +03:00
} ;
struct text_vg_version_ops * text_vg_vsn1_init ( void )
{
return & _vsn1_ops ;
2006-05-10 01:23:51 +04:00
}