2001-09-25 16:49:28 +04:00
/*
2001-12-20 14:52:54 +03:00
* Copyright ( C ) 2001 Sistina Software ( UK ) Limited .
2001-09-25 16:49:28 +04:00
*
2001-12-20 14:52:54 +03:00
* This file is released under the GPL .
2001-09-25 16:49:28 +04:00
*/
2001-10-06 01:39:30 +04:00
# include "tools.h"
2001-09-25 16:49:28 +04:00
2002-01-01 00:27:39 +03:00
# include <sys/stat.h>
2002-02-11 23:50:53 +03:00
int process_each_lv_in_vg ( struct cmd_context * cmd , struct volume_group * vg ,
2002-11-18 17:04:08 +03:00
void * handle ,
2002-02-12 00:00:35 +03:00
int ( * process_single ) ( struct cmd_context * cmd ,
2002-11-18 17:04:08 +03:00
struct logical_volume * lv ,
void * handle ) )
2001-11-19 18:20:50 +03:00
{
int ret_max = 0 ;
int ret = 0 ;
2003-10-16 00:02:46 +04:00
struct lv_list * lvl ;
2001-11-19 18:20:50 +03:00
if ( vg - > status & EXPORTED_VG ) {
2002-01-30 18:04:48 +03:00
log_error ( " Volume group \" %s \" is exported " , vg - > name ) ;
2001-11-19 18:20:50 +03:00
return ECMD_FAILED ;
}
2002-01-29 20:23:33 +03:00
2003-10-16 00:02:46 +04:00
list_iterate_items ( lvl , & vg - > lvs ) {
ret = process_single ( cmd , lvl - > lv , handle ) ;
2001-11-19 18:20:50 +03:00
if ( ret > ret_max )
ret_max = ret ;
}
return ret_max ;
}
2002-11-18 17:04:08 +03:00
struct volume_group * recover_vg ( struct cmd_context * cmd , const char * vgname ,
int lock_type )
{
int consistent = 1 ;
lock_type & = ~ LCK_TYPE_MASK ;
lock_type | = LCK_WRITE ;
if ( ! lock_vol ( cmd , vgname , lock_type ) ) {
log_error ( " Can't lock %s for metadata recovery: skipping " ,
vgname ) ;
return NULL ;
}
return vg_read ( cmd , vgname , & consistent ) ;
}
2002-02-11 23:50:53 +03:00
int process_each_lv ( struct cmd_context * cmd , int argc , char * * argv ,
2002-11-18 17:04:08 +03:00
int lock_type , void * handle ,
2002-02-12 00:00:35 +03:00
int ( * process_single ) ( struct cmd_context * cmd ,
2002-11-18 17:04:08 +03:00
struct logical_volume * lv ,
void * handle ) )
2001-11-14 21:38:07 +03:00
{
int opt = 0 ;
int ret_max = 0 ;
int ret = 0 ;
int vg_count = 0 ;
2002-11-18 17:04:08 +03:00
int consistent ;
2001-11-14 21:38:07 +03:00
2002-11-18 17:04:08 +03:00
struct list * slh , * vgnames ;
2001-11-14 21:38:07 +03:00
struct volume_group * vg ;
struct logical_volume * lv ;
2002-01-21 17:28:12 +03:00
struct lv_list * lvl ;
2001-11-14 21:38:07 +03:00
2002-12-20 02:25:55 +03:00
const char * vgname ;
2001-11-14 21:38:07 +03:00
if ( argc ) {
log_verbose ( " Using logical volume(s) on command line " ) ;
for ( ; opt < argc ; opt + + ) {
char * lv_name = argv [ opt ] ;
2003-07-05 02:34:56 +04:00
char * vgname_def ;
2002-11-18 17:04:08 +03:00
int vgname_provided = 1 ;
2003-07-05 02:34:56 +04:00
int dev_dir_found = 0 ;
2002-11-18 17:04:08 +03:00
/* Do we have a vgname or lvname? */
vgname = lv_name ;
2003-07-05 02:34:56 +04:00
if ( * vgname = = ' / ' ) {
while ( * vgname = = ' / ' )
vgname + + ;
vgname - - ;
}
2002-11-18 17:04:08 +03:00
if ( ! strncmp ( vgname , cmd - > dev_dir ,
2003-07-05 02:34:56 +04:00
strlen ( cmd - > dev_dir ) ) ) {
2002-11-18 17:04:08 +03:00
vgname + = strlen ( cmd - > dev_dir ) ;
2003-07-05 02:34:56 +04:00
dev_dir_found = 1 ;
while ( * vgname = = ' / ' )
vgname + + ;
}
if ( * vgname = = ' / ' ) {
log_error ( " \" %s \" : Invalid path for Logical "
" Volume " , lv_name ) ;
if ( ret_max < ECMD_FAILED )
ret_max = ECMD_FAILED ;
continue ;
}
2002-11-18 17:04:08 +03:00
if ( strchr ( vgname , ' / ' ) ) {
/* Must be an LV */
vgname_provided = 0 ;
if ( ! ( vgname = extract_vgname ( cmd , lv_name ) ) ) {
if ( ret_max < ECMD_FAILED )
ret_max = ECMD_FAILED ;
continue ;
}
2001-11-14 21:38:07 +03:00
}
2003-07-05 02:34:56 +04:00
if ( ! dev_dir_found & &
( vgname_def = default_vgname ( cmd ) ) ) {
vgname_provided = 0 ;
vgname = vgname_def ;
}
2002-11-18 17:04:08 +03:00
log_verbose ( " Finding volume group \" %s \" " , vgname ) ;
if ( ! lock_vol ( cmd , vgname , lock_type ) ) {
log_error ( " Can't lock %s: skipping " , vgname ) ;
2002-04-24 22:20:51 +04:00
continue ;
}
2002-11-18 17:04:08 +03:00
if ( lock_type & LCK_WRITE )
consistent = 1 ;
else
consistent = 0 ;
if ( ! ( vg = vg_read ( cmd , vgname , & consistent ) ) | |
! consistent ) {
unlock_vg ( cmd , vgname ) ;
if ( ! vg )
log_error ( " Volume group \" %s \" "
" not found " , vgname ) ;
else
log_error ( " Volume group \" %s \" "
" inconsistent " , vgname ) ;
if ( ! vg | | ! ( vg =
recover_vg ( cmd , vgname ,
lock_type ) ) ) {
unlock_vg ( cmd , vgname ) ;
if ( ret_max < ECMD_FAILED )
ret_max = ECMD_FAILED ;
continue ;
}
2001-11-14 21:38:07 +03:00
}
2002-01-29 20:23:33 +03:00
if ( vg - > status & EXPORTED_VG ) {
2002-01-30 18:04:48 +03:00
log_error ( " Volume group \" %s \" is exported " ,
2002-01-29 20:23:33 +03:00
vg - > name ) ;
2002-11-18 17:04:08 +03:00
unlock_vg ( cmd , vgname ) ;
2002-01-29 20:23:33 +03:00
return ECMD_FAILED ;
}
2002-11-18 17:04:08 +03:00
if ( vgname_provided ) {
if ( ( ret =
process_each_lv_in_vg ( cmd , vg , handle ,
process_single ) ) >
ret_max )
ret_max = ret ;
unlock_vg ( cmd , vgname ) ;
continue ;
}
2002-01-21 17:28:12 +03:00
if ( ! ( lvl = find_lv_in_vg ( vg , lv_name ) ) ) {
2002-01-30 18:04:48 +03:00
log_error ( " Can't find logical volume \" %s \" "
" in volume group \" %s \" " ,
2002-11-18 17:04:08 +03:00
lv_name , vgname ) ;
2001-11-14 21:38:07 +03:00
if ( ret_max < ECMD_FAILED )
ret_max = ECMD_FAILED ;
2002-11-18 17:04:08 +03:00
unlock_vg ( cmd , vgname ) ;
2001-11-14 21:38:07 +03:00
continue ;
}
2002-01-21 19:49:32 +03:00
lv = lvl - > lv ;
2001-11-14 21:38:07 +03:00
2002-11-18 17:04:08 +03:00
if ( ( ret = process_single ( cmd , lv , handle ) ) > ret_max )
2001-11-14 21:38:07 +03:00
ret_max = ret ;
2002-11-18 17:04:08 +03:00
unlock_vg ( cmd , vgname ) ;
2001-11-14 21:38:07 +03:00
}
} else {
2002-01-16 17:43:27 +03:00
log_verbose ( " Finding all logical volumes " ) ;
2002-11-18 17:04:08 +03:00
if ( ! ( vgnames = get_vgs ( cmd , 0 ) ) ) {
2001-11-14 21:38:07 +03:00
log_error ( " No volume groups found " ) ;
return ECMD_FAILED ;
}
2002-11-18 17:04:08 +03:00
list_iterate ( slh , vgnames ) {
vgname = list_item ( slh , struct str_list ) - > str ;
if ( ! vgname | | ! * vgname )
continue ; /* FIXME Unnecessary? */
if ( ! lock_vol ( cmd , vgname , lock_type ) ) {
log_error ( " Can't lock %s: skipping " , vgname ) ;
2002-04-24 22:20:51 +04:00
continue ;
}
2002-11-18 17:04:08 +03:00
if ( lock_type & LCK_WRITE )
consistent = 1 ;
else
consistent = 0 ;
if ( ! ( vg = vg_read ( cmd , vgname , & consistent ) ) | |
! consistent ) {
unlock_vg ( cmd , vgname ) ;
if ( ! vg )
log_error ( " Volume group \" %s \" "
" not found " , vgname ) ;
else
log_error ( " Volume group \" %s \" "
" inconsistent " , vgname ) ;
if ( ! vg | | ! ( vg =
recover_vg ( cmd , vgname ,
lock_type ) ) ) {
unlock_vg ( cmd , vgname ) ;
if ( ret_max < ECMD_FAILED )
ret_max = ECMD_FAILED ;
continue ;
}
2001-11-14 21:38:07 +03:00
}
2002-11-18 17:04:08 +03:00
ret = process_each_lv_in_vg ( cmd , vg , handle ,
process_single ) ;
unlock_vg ( cmd , vgname ) ;
2001-11-19 18:20:50 +03:00
if ( ret > ret_max )
ret_max = ret ;
2001-11-14 21:38:07 +03:00
vg_count + + ;
}
}
return ret_max ;
}
2002-12-12 23:55:49 +03:00
int process_each_segment_in_lv ( struct cmd_context * cmd ,
struct logical_volume * lv ,
void * handle ,
int ( * process_single ) ( struct cmd_context * cmd ,
struct lv_segment * seg ,
void * handle ) )
{
struct lv_segment * seg ;
int ret_max = 0 ;
int ret ;
2003-10-16 00:02:46 +04:00
list_iterate_items ( seg , & lv - > segments ) {
2002-12-12 23:55:49 +03:00
ret = process_single ( cmd , seg , handle ) ;
if ( ret > ret_max )
ret_max = ret ;
}
return ret_max ;
}
2002-02-12 00:00:35 +03:00
int process_each_vg ( struct cmd_context * cmd , int argc , char * * argv ,
2002-11-18 17:04:08 +03:00
int lock_type , int consistent , void * handle ,
2002-02-12 00:00:35 +03:00
int ( * process_single ) ( struct cmd_context * cmd ,
2002-11-18 17:04:08 +03:00
const char * vg_name ,
struct volume_group * vg ,
int consistent , void * handle ) )
2001-10-06 01:39:30 +04:00
{
int opt = 0 ;
int ret_max = 0 ;
int ret = 0 ;
2002-11-18 17:04:08 +03:00
struct list * slh , * vgnames ;
struct volume_group * vg ;
2001-10-06 01:39:30 +04:00
2003-07-05 02:34:56 +04:00
const char * vg_name ;
2002-04-24 22:20:51 +04:00
char * dev_dir = cmd - > dev_dir ;
2002-02-11 18:42:34 +03:00
2001-10-06 01:39:30 +04:00
if ( argc ) {
log_verbose ( " Using volume group(s) on command line " ) ;
2002-02-11 18:42:34 +03:00
for ( ; opt < argc ; opt + + ) {
vg_name = argv [ opt ] ;
2003-07-05 02:34:56 +04:00
if ( * vg_name = = ' / ' ) {
while ( * vg_name = = ' / ' )
vg_name + + ;
vg_name - - ;
}
2002-04-24 22:20:51 +04:00
if ( ! strncmp ( vg_name , dev_dir , strlen ( dev_dir ) ) )
vg_name + = strlen ( dev_dir ) ;
if ( strchr ( vg_name , ' / ' ) ) {
log_error ( " Invalid volume group name: %s " ,
vg_name ) ;
continue ;
}
2002-03-15 19:07:38 +03:00
if ( ! lock_vol ( cmd , vg_name , lock_type ) ) {
2002-02-11 18:42:34 +03:00
log_error ( " Can't lock %s: skipping " , vg_name ) ;
continue ;
}
2002-11-18 17:04:08 +03:00
log_verbose ( " Finding volume group \" %s \" " , vg_name ) ;
vg = vg_read ( cmd , vg_name , & consistent ) ;
if ( ( ret = process_single ( cmd , vg_name , vg , consistent ,
2003-05-06 16:13:19 +04:00
handle ) ) > ret_max )
2001-10-06 01:39:30 +04:00
ret_max = ret ;
2002-03-11 18:08:39 +03:00
unlock_vg ( cmd , vg_name ) ;
2002-02-11 18:42:34 +03:00
}
2001-10-06 01:39:30 +04:00
} else {
2002-01-16 17:43:27 +03:00
log_verbose ( " Finding all volume groups " ) ;
2002-11-18 17:04:08 +03:00
if ( ! ( vgnames = get_vgs ( cmd , 0 ) ) | | list_empty ( vgnames ) ) {
2001-10-06 01:39:30 +04:00
log_error ( " No volume groups found " ) ;
return ECMD_FAILED ;
}
2002-11-18 17:04:08 +03:00
list_iterate ( slh , vgnames ) {
vg_name = list_item ( slh , struct str_list ) - > str ;
if ( ! vg_name | | ! * vg_name )
continue ; /* FIXME Unnecessary? */
2002-03-15 19:07:38 +03:00
if ( ! lock_vol ( cmd , vg_name , lock_type ) ) {
2002-02-11 18:42:34 +03:00
log_error ( " Can't lock %s: skipping " , vg_name ) ;
continue ;
}
2002-11-18 17:04:08 +03:00
log_verbose ( " Finding volume group \" %s \" " , vg_name ) ;
vg = vg_read ( cmd , vg_name , & consistent ) ;
ret = process_single ( cmd , vg_name , vg , consistent ,
handle ) ;
2001-10-06 01:39:30 +04:00
if ( ret > ret_max )
ret_max = ret ;
2002-03-11 18:08:39 +03:00
unlock_vg ( cmd , vg_name ) ;
2001-10-06 01:39:30 +04:00
}
}
return ret_max ;
}
2001-10-08 22:44:22 +04:00
2002-02-11 23:50:53 +03:00
int process_each_pv_in_vg ( struct cmd_context * cmd , struct volume_group * vg ,
2002-11-18 17:04:08 +03:00
void * handle ,
2002-02-12 00:00:35 +03:00
int ( * process_single ) ( struct cmd_context * cmd ,
struct volume_group * vg ,
2002-11-18 17:04:08 +03:00
struct physical_volume * pv ,
void * handle ) )
2001-11-19 18:20:50 +03:00
{
int ret_max = 0 ;
int ret = 0 ;
2003-10-16 00:02:46 +04:00
struct pv_list * pvl ;
2001-11-19 18:20:50 +03:00
2003-10-16 00:02:46 +04:00
list_iterate_items ( pvl , & vg - > pvs )
if ( ( ret = process_single ( cmd , vg , pvl - > pv , handle ) ) > ret_max )
2002-01-21 19:05:23 +03:00
ret_max = ret ;
return ret_max ;
2001-11-19 18:20:50 +03:00
}
2002-02-12 00:00:35 +03:00
int process_each_pv ( struct cmd_context * cmd , int argc , char * * argv ,
2002-11-18 17:04:08 +03:00
struct volume_group * vg , void * handle ,
2002-02-12 00:00:35 +03:00
int ( * process_single ) ( struct cmd_context * cmd ,
struct volume_group * vg ,
2002-11-18 17:04:08 +03:00
struct physical_volume * pv ,
void * handle ) )
2001-10-12 01:35:55 +04:00
{
int opt = 0 ;
int ret_max = 0 ;
int ret = 0 ;
2002-01-21 17:28:12 +03:00
struct pv_list * pvl ;
2002-12-12 23:55:49 +03:00
struct physical_volume * pv ;
2003-10-16 00:02:46 +04:00
struct list * pvslist ;
2001-10-12 01:35:55 +04:00
if ( argc ) {
log_verbose ( " Using physical volume(s) on command line " ) ;
for ( ; opt < argc ; opt + + ) {
2002-12-12 23:55:49 +03:00
if ( vg ) {
if ( ! ( pvl = find_pv_in_vg ( vg , argv [ opt ] ) ) ) {
log_error ( " Physical Volume \" %s \" not "
" found in Volume Group "
" \" %s \" " , argv [ opt ] ,
vg - > name ) ;
2003-10-22 02:06:07 +04:00
ret_max = ECMD_FAILED ;
2002-12-12 23:55:49 +03:00
continue ;
}
pv = pvl - > pv ;
} else {
if ( ! ( pv = pv_read ( cmd , argv [ opt ] , NULL , NULL ) ) ) {
log_error ( " Failed to read physical "
" volume \" %s \" " , argv [ opt ] ) ;
2003-10-22 02:06:07 +04:00
ret_max = ECMD_FAILED ;
2002-12-12 23:55:49 +03:00
continue ;
}
2001-10-12 01:35:55 +04:00
}
2002-12-12 23:55:49 +03:00
ret = process_single ( cmd , vg , pv , handle ) ;
2001-10-12 01:35:55 +04:00
if ( ret > ret_max )
ret_max = ret ;
}
} else {
2002-12-12 23:55:49 +03:00
if ( vg ) {
log_verbose ( " Using all physical volume(s) in "
" volume group " ) ;
2003-10-22 02:06:07 +04:00
ret = process_each_pv_in_vg ( cmd , vg , handle , process_single ) ;
if ( ret > ret_max )
ret_max = ret ;
2002-12-12 23:55:49 +03:00
} else {
log_verbose ( " Scanning for physical volume names " ) ;
2002-12-20 02:25:55 +03:00
if ( ! ( pvslist = get_pvs ( cmd ) ) )
2002-12-12 23:55:49 +03:00
return ECMD_FAILED ;
2003-10-16 00:02:46 +04:00
list_iterate_items ( pvl , pvslist ) {
ret = process_single ( cmd , NULL , pvl - > pv ,
handle ) ;
2002-12-12 23:55:49 +03:00
if ( ret > ret_max )
ret_max = ret ;
}
}
2001-10-12 01:35:55 +04:00
}
return ret_max ;
}
2002-12-20 02:25:55 +03:00
const char * extract_vgname ( struct cmd_context * cmd , const char * lv_name )
2001-11-14 21:38:07 +03:00
{
2002-12-20 02:25:55 +03:00
const char * vg_name = lv_name ;
2001-11-06 22:02:26 +03:00
char * st ;
2002-04-24 22:20:51 +04:00
char * dev_dir = cmd - > dev_dir ;
2003-07-05 02:34:56 +04:00
int dev_dir_provided = 0 ;
2001-10-29 16:52:23 +03:00
/* Path supplied? */
2001-11-06 22:02:26 +03:00
if ( vg_name & & strchr ( vg_name , ' / ' ) ) {
2001-11-15 20:27:45 +03:00
/* Strip dev_dir (optional) */
2003-07-05 02:34:56 +04:00
if ( * vg_name = = ' / ' ) {
while ( * vg_name = = ' / ' )
vg_name + + ;
vg_name - - ;
}
if ( ! strncmp ( vg_name , dev_dir , strlen ( dev_dir ) ) ) {
2001-11-12 18:10:01 +03:00
vg_name + = strlen ( dev_dir ) ;
2003-07-05 02:34:56 +04:00
dev_dir_provided = 1 ;
while ( * vg_name = = ' / ' )
vg_name + + ;
}
if ( * vg_name = = ' / ' ) {
log_error ( " \" %s \" : Invalid path for Logical "
" Volume " , lv_name ) ;
return 0 ;
}
/* Require exactly one set of consecutive slashes */
if ( ( st = strchr ( vg_name , ' / ' ) ) )
while ( * st = = ' / ' )
st + + ;
2001-10-29 16:52:23 +03:00
2003-07-05 02:34:56 +04:00
if ( ! strchr ( vg_name , ' / ' ) | | strchr ( st , ' / ' ) ) {
2002-01-30 18:04:48 +03:00
log_error ( " \" %s \" : Invalid path for Logical Volume " ,
2001-11-14 21:38:07 +03:00
lv_name ) ;
2001-10-29 16:52:23 +03:00
return 0 ;
}
2002-04-24 22:20:51 +04:00
vg_name = pool_strdup ( cmd - > mem , vg_name ) ;
2001-10-29 16:52:23 +03:00
if ( ! vg_name ) {
log_error ( " Allocation of vg_name failed " ) ;
return 0 ;
}
* strchr ( vg_name , ' / ' ) = ' \0 ' ;
return vg_name ;
}
2001-11-06 22:02:26 +03:00
2002-04-24 22:20:51 +04:00
if ( ! ( vg_name = default_vgname ( cmd ) ) ) {
2001-11-06 22:02:26 +03:00
if ( lv_name )
2002-01-30 18:04:48 +03:00
log_error ( " Path required for Logical Volume \" %s \" " ,
2001-11-14 21:38:07 +03:00
lv_name ) ;
2001-11-06 22:02:26 +03:00
return 0 ;
}
2001-11-14 21:38:07 +03:00
2001-11-06 22:02:26 +03:00
return vg_name ;
}
2002-04-24 22:20:51 +04:00
char * default_vgname ( struct cmd_context * cmd )
2001-11-06 22:02:26 +03:00
{
char * vg_path ;
2002-04-24 22:20:51 +04:00
char * dev_dir = cmd - > dev_dir ;
2001-11-06 22:02:26 +03:00
2001-10-29 16:52:23 +03:00
/* Take default VG from environment? */
2001-11-14 21:38:07 +03:00
vg_path = getenv ( " LVM_VG_NAME " ) ;
2001-11-06 22:02:26 +03:00
if ( ! vg_path )
2001-10-29 16:52:23 +03:00
return 0 ;
2001-11-15 20:27:45 +03:00
/* Strip dev_dir (optional) */
2003-07-05 02:34:56 +04:00
if ( * vg_path = = ' / ' ) {
while ( * vg_path = = ' / ' )
vg_path + + ;
vg_path - - ;
}
2001-11-12 18:10:01 +03:00
if ( ! strncmp ( vg_path , dev_dir , strlen ( dev_dir ) ) )
vg_path + = strlen ( dev_dir ) ;
2001-10-29 16:52:23 +03:00
if ( strchr ( vg_path , ' / ' ) ) {
2002-01-30 18:04:48 +03:00
log_error ( " Environment Volume Group in LVM_VG_NAME invalid: "
" \" %s \" " , vg_path ) ;
2001-10-29 16:52:23 +03:00
return 0 ;
}
2002-04-24 22:20:51 +04:00
return pool_strdup ( cmd - > mem , vg_path ) ;
2001-10-29 16:52:23 +03:00
}
2002-01-21 19:05:23 +03:00
2003-04-25 02:23:24 +04:00
static int _add_alloc_area ( struct pool * mem , struct list * alloc_areas ,
uint32_t start , uint32_t count )
{
struct alloc_area * aa ;
log_debug ( " Adding alloc area: start PE % " PRIu32 " length % " PRIu32 ,
start , count ) ;
/* Ensure no overlap with existing areas */
2003-10-16 00:02:46 +04:00
list_iterate_items ( aa , alloc_areas ) {
2003-04-25 02:23:24 +04:00
if ( ( ( start < aa - > start ) & & ( start + count - 1 > = aa - > start ) ) | |
( ( start > = aa - > start ) & &
( aa - > start + aa - > count - 1 ) > = start ) ) {
log_error ( " Overlapping PE ranges detected (% " PRIu32
" -% " PRIu32 " , % " PRIu32 " -% " PRIu32 " ) " ,
start , start + count - 1 , aa - > start ,
aa - > start + aa - > count - 1 ) ;
return 0 ;
}
}
if ( ! ( aa = pool_alloc ( mem , sizeof ( * aa ) ) ) ) {
log_error ( " Allocation of list failed " ) ;
return 0 ;
}
aa - > start = start ;
aa - > count = count ;
list_add ( alloc_areas , & aa - > list ) ;
return 1 ;
}
static int _parse_pes ( struct pool * mem , char * c , struct list * alloc_areas ,
uint32_t size )
{
char * endptr ;
uint32_t start , end ;
/* Default to whole PV */
if ( ! c ) {
if ( ! _add_alloc_area ( mem , alloc_areas , UINT32_C ( 0 ) , size ) ) {
stack ;
return 0 ;
}
return 1 ;
}
while ( * c ) {
if ( * c ! = ' : ' )
goto error ;
c + + ;
/* Disallow :: and :\0 */
if ( * c = = ' : ' | | ! * c )
goto error ;
/* Default to whole range */
start = UINT32_C ( 0 ) ;
end = size - 1 ;
/* Start extent given? */
if ( isdigit ( * c ) ) {
start = ( uint32_t ) strtoul ( c , & endptr , 10 ) ;
if ( endptr = = c )
goto error ;
c = endptr ;
/* Just one number given? */
if ( ! * c | | * c = = ' : ' )
end = start ;
}
/* Range? */
if ( * c = = ' - ' ) {
c + + ;
if ( isdigit ( * c ) ) {
end = ( uint32_t ) strtoul ( c , & endptr , 10 ) ;
if ( endptr = = c )
goto error ;
c = endptr ;
}
}
if ( * c & & * c ! = ' : ' )
goto error ;
if ( ( start > end ) | | ( end > size - 1 ) ) {
log_error ( " PE range error: start extent % " PRIu32 " to "
" end extent % " PRIu32 , start , end ) ;
return 0 ;
}
if ( ! _add_alloc_area ( mem , alloc_areas , start , end - start + 1 ) ) {
stack ;
return 0 ;
}
}
return 1 ;
error :
log_error ( " Physical extent parsing error at %s " , c ) ;
return 0 ;
}
2002-01-21 19:05:23 +03:00
struct list * create_pv_list ( struct pool * mem ,
2002-01-29 20:23:33 +03:00
struct volume_group * vg , int argc , char * * argv )
2002-01-21 19:05:23 +03:00
{
struct list * r ;
2003-04-25 02:23:24 +04:00
struct list * alloc_areas ;
2002-01-21 19:05:23 +03:00
struct pv_list * pvl , * new_pvl ;
2003-04-25 02:23:24 +04:00
char * pvname = NULL , * colon ;
2002-01-21 19:05:23 +03:00
int i ;
/* Build up list of PVs */
if ( ! ( r = pool_alloc ( mem , sizeof ( * r ) ) ) ) {
log_error ( " Allocation of list failed " ) ;
return NULL ;
}
list_init ( r ) ;
for ( i = 0 ; i < argc ; i + + ) {
2003-04-25 02:23:24 +04:00
if ( ( colon = strchr ( argv [ i ] , ' : ' ) ) ) {
if ( ! ( pvname = pool_strndup ( mem , argv [ i ] ,
2003-05-06 16:13:19 +04:00
( unsigned ) ( colon -
argv [ i ] ) ) ) ) {
2003-04-25 02:23:24 +04:00
log_error ( " Failed to clone PV name " ) ;
return NULL ;
}
} else
pvname = argv [ i ] ;
2002-01-21 19:05:23 +03:00
2003-04-25 02:23:24 +04:00
if ( ! ( pvl = find_pv_in_vg ( vg , pvname ) ) ) {
2002-01-30 18:04:48 +03:00
log_err ( " Physical Volume \" %s \" not found in "
2003-04-25 02:23:24 +04:00
" Volume Group \" %s \" " , pvname , vg - > name ) ;
2002-01-21 19:05:23 +03:00
return NULL ;
}
2003-04-25 02:23:24 +04:00
if ( ! ( pvl - > pv - > status & ALLOCATABLE_PV ) ) {
log_error ( " Physical volume %s not allocatable " , pvname ) ;
continue ;
}
2002-04-24 22:20:51 +04:00
if ( pvl - > pv - > pe_count = = pvl - > pv - > pe_alloc_count ) {
2002-01-30 18:04:48 +03:00
log_err ( " No free extents on physical volume \" %s \" " ,
2003-04-25 02:23:24 +04:00
pvname ) ;
2002-01-21 19:05:23 +03:00
continue ;
}
if ( ! ( new_pvl = pool_alloc ( mem , sizeof ( * new_pvl ) ) ) ) {
log_err ( " Unable to allocate physical volume list. " ) ;
return NULL ;
}
memcpy ( new_pvl , pvl , sizeof ( * new_pvl ) ) ;
list_add ( r , & new_pvl - > list ) ;
2003-04-25 02:23:24 +04:00
if ( ! ( alloc_areas = pool_alloc ( mem , sizeof ( * alloc_areas ) ) ) ) {
log_error ( " Allocation of alloc_areas list failed " ) ;
return NULL ;
}
list_init ( alloc_areas ) ;
/* Specify which physical extents may be used for allocation */
if ( ! _parse_pes ( mem , colon , alloc_areas , pvl - > pv - > pe_count ) ) {
stack ;
return NULL ;
}
new_pvl - > alloc_areas = alloc_areas ;
2002-01-21 19:05:23 +03:00
}
2002-01-29 20:23:33 +03:00
return list_empty ( r ) ? NULL : r ;
2002-01-21 19:05:23 +03:00
}
2003-04-25 02:23:24 +04:00
struct list * clone_pv_list ( struct pool * mem , struct list * pvsl )
{
2003-10-16 00:02:46 +04:00
struct list * r ;
2003-04-25 02:23:24 +04:00
struct pv_list * pvl , * new_pvl ;
/* Build up list of PVs */
if ( ! ( r = pool_alloc ( mem , sizeof ( * r ) ) ) ) {
log_error ( " Allocation of list failed " ) ;
return NULL ;
}
list_init ( r ) ;
2003-10-16 00:02:46 +04:00
list_iterate_items ( pvl , pvsl ) {
2003-04-25 02:23:24 +04:00
if ( ! ( new_pvl = pool_zalloc ( mem , sizeof ( * new_pvl ) ) ) ) {
log_error ( " Unable to allocate physical volume list. " ) ;
return NULL ;
}
memcpy ( new_pvl , pvl , sizeof ( * new_pvl ) ) ;
list_add ( r , & new_pvl - > list ) ;
}
return r ;
}