2001-09-25 16:49:28 +04:00
/*
2008-01-30 17:00:02 +03:00
* Copyright ( C ) 2001 - 2004 Sistina Software , Inc . All rights reserved .
2008-06-11 19:02:52 +04:00
* Copyright ( C ) 2004 - 2008 Red Hat , Inc . All rights reserved .
2001-09-25 16:49:28 +04: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
2001-09-25 16:49:28 +04:00
*/
2001-10-06 01:39:30 +04:00
# include "tools.h"
2005-11-29 00:00:37 +03:00
# include "lv_alloc.h"
2006-05-11 22:39:24 +04:00
# include "xlate.h"
2001-09-25 16:49:28 +04:00
2002-01-01 00:27:39 +03:00
# include <sys/stat.h>
2004-06-15 21:23:49 +04:00
# include <sys/wait.h>
2002-01-01 00:27:39 +03:00
2006-04-19 19:33:07 +04:00
/* Command line args */
2007-08-07 13:06:05 +04:00
unsigned arg_count ( const struct cmd_context * cmd , int a )
2006-04-19 19:33:07 +04:00
{
return cmd - > args [ a ] . count ;
}
const char * arg_value ( struct cmd_context * cmd , int a )
{
return cmd - > args [ a ] . value ;
}
const char * arg_str_value ( struct cmd_context * cmd , int a , const char * def )
{
return arg_count ( cmd , a ) ? cmd - > args [ a ] . value : def ;
}
int32_t arg_int_value ( struct cmd_context * cmd , int a , const int32_t def )
{
return arg_count ( cmd , a ) ? cmd - > args [ a ] . i_value : def ;
}
uint32_t arg_uint_value ( struct cmd_context * cmd , int a , const uint32_t def )
{
return arg_count ( cmd , a ) ? cmd - > args [ a ] . ui_value : def ;
}
2006-05-10 01:23:51 +04:00
int64_t arg_int64_value ( struct cmd_context * cmd , int a , const int64_t def )
2006-04-19 19:33:07 +04:00
{
return arg_count ( cmd , a ) ? cmd - > args [ a ] . i64_value : def ;
}
uint64_t arg_uint64_value ( struct cmd_context * cmd , int a , const uint64_t def )
{
return arg_count ( cmd , a ) ? cmd - > args [ a ] . ui64_value : def ;
}
const void * arg_ptr_value ( struct cmd_context * cmd , int a , const void * def )
{
return arg_count ( cmd , a ) ? cmd - > args [ a ] . ptr : def ;
}
sign_t arg_sign_value ( struct cmd_context * cmd , int a , const sign_t def )
{
return arg_count ( cmd , a ) ? cmd - > args [ a ] . sign : def ;
}
2006-10-02 20:15:03 +04:00
percent_t arg_percent_value ( struct cmd_context * cmd , int a , const percent_t def )
2006-09-26 13:35:43 +04:00
{
return arg_count ( cmd , a ) ? cmd - > args [ a ] . percent : def ;
}
2006-04-19 19:33:07 +04:00
int arg_count_increment ( struct cmd_context * cmd , int a )
{
return cmd - > args [ a ] . count + + ;
}
const char * command_name ( struct cmd_context * cmd )
{
return cmd - > command - > name ;
}
2006-08-26 03:02:33 +04:00
/*
* Strip dev_dir if present
*/
2007-03-09 23:47:41 +03:00
char * skip_dev_dir ( struct cmd_context * cmd , const char * vg_name ,
unsigned * dev_dir_found )
2006-08-26 03:02:33 +04:00
{
2007-03-09 23:47:41 +03:00
const char * dmdir = dm_dir ( ) ;
size_t dmdir_len = strlen ( dmdir ) , vglv_sz ;
char * vgname , * lvname , * layer , * vglv ;
2006-08-26 03:02:33 +04:00
2007-03-09 23:47:41 +03:00
/* FIXME Do this properly */
2006-08-26 03:02:33 +04:00
if ( * vg_name = = ' / ' ) {
while ( * vg_name = = ' / ' )
vg_name + + ;
vg_name - - ;
}
2007-03-09 23:47:41 +03:00
/* Reformat string if /dev/mapper found */
if ( ! strncmp ( vg_name , dmdir , dmdir_len ) & & vg_name [ dmdir_len ] = = ' / ' ) {
if ( dev_dir_found )
* dev_dir_found = 1 ;
vg_name + = dmdir_len ;
while ( * vg_name = = ' / ' )
vg_name + + ;
if ( ! dm_split_lvm_name ( cmd - > mem , vg_name , & vgname , & lvname , & layer ) | |
* layer ) {
log_error ( " skip_dev_dir: Couldn't split up device name %s " ,
vg_name ) ;
return ( char * ) vg_name ;
}
vglv_sz = strlen ( vgname ) + strlen ( lvname ) + 2 ;
if ( ! ( vglv = dm_pool_alloc ( cmd - > mem , vglv_sz ) ) | |
dm_snprintf ( vglv , vglv_sz , " %s%s%s " , vgname ,
* lvname ? " / " : " " ,
lvname ) < 0 ) {
log_error ( " vg/lv string alloc failed " ) ;
return ( char * ) vg_name ;
}
return vglv ;
}
2006-08-26 03:02:33 +04:00
if ( ! strncmp ( vg_name , cmd - > dev_dir , strlen ( cmd - > dev_dir ) ) ) {
2007-03-09 23:47:41 +03:00
if ( dev_dir_found )
* dev_dir_found = 1 ;
2006-08-26 03:02:33 +04:00
vg_name + = strlen ( cmd - > dev_dir ) ;
while ( * vg_name = = ' / ' )
vg_name + + ;
2007-03-09 23:47:41 +03:00
} else if ( dev_dir_found )
* dev_dir_found = 0 ;
2006-08-26 03:02:33 +04:00
return ( char * ) vg_name ;
}
2005-01-19 20:31:51 +03:00
/*
* Metadata iteration functions
*/
2007-08-07 13:06:05 +04:00
int process_each_lv_in_vg ( struct cmd_context * cmd ,
const struct volume_group * vg ,
2008-11-04 01:14:30 +03:00
const struct dm_list * arg_lvnames ,
const struct dm_list * tags ,
2002-11-18 17:04:08 +03:00
void * handle ,
2007-08-07 13:06:05 +04:00
process_single_lv_fn_t process_single )
2001-11-19 18:20:50 +03:00
{
2008-06-11 00:07:04 +04:00
int ret_max = ECMD_PROCESSED ;
2001-11-19 18:20:50 +03:00
int ret = 0 ;
2006-05-10 01:23:51 +04:00
unsigned process_all = 0 ;
unsigned process_lv = 0 ;
unsigned tags_supplied = 0 ;
unsigned lvargs_supplied = 0 ;
unsigned lvargs_matched = 0 ;
2001-11-19 18:20:50 +03:00
2003-10-16 00:02:46 +04:00
struct lv_list * lvl ;
2001-11-19 18:20:50 +03:00
2007-06-19 08:36:12 +04:00
if ( ! vg_check_status ( vg , EXPORTED_VG ) )
2001-11-19 18:20:50 +03:00
return ECMD_FAILED ;
2002-01-29 20:23:33 +03:00
2008-11-04 01:14:30 +03:00
if ( tags & & ! dm_list_empty ( tags ) )
2004-03-08 20:19:15 +03:00
tags_supplied = 1 ;
2008-11-04 01:14:30 +03:00
if ( arg_lvnames & & ! dm_list_empty ( arg_lvnames ) )
2004-03-08 20:19:15 +03:00
lvargs_supplied = 1 ;
/* Process all LVs in this VG if no restrictions given */
if ( ! tags_supplied & & ! lvargs_supplied )
process_all = 1 ;
/* Or if VG tags match */
if ( ! process_lv & & tags_supplied & &
2004-05-11 22:45:11 +04:00
str_list_match_list ( tags , & vg - > tags ) ) {
2004-03-08 20:19:15 +03:00
process_all = 1 ;
2004-05-11 22:45:11 +04:00
}
2004-03-08 20:19:15 +03:00
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( lvl , & vg - > lvs ) {
2005-04-07 16:39:44 +04:00
if ( lvl - > lv - > status & SNAPSHOT )
continue ;
2004-03-08 20:19:15 +03:00
/* Should we process this LV? */
if ( process_all )
process_lv = 1 ;
else
process_lv = 0 ;
/* LV tag match? */
if ( ! process_lv & & tags_supplied & &
2004-05-11 22:45:11 +04:00
str_list_match_list ( tags , & lvl - > lv - > tags ) ) {
2004-03-08 20:19:15 +03:00
process_lv = 1 ;
2004-05-11 22:45:11 +04:00
}
2004-03-08 20:19:15 +03:00
/* LV name match? */
2004-05-05 22:31:38 +04:00
if ( lvargs_supplied & &
str_list_match_item ( arg_lvnames , lvl - > lv - > name ) ) {
2004-03-08 20:19:15 +03:00
process_lv = 1 ;
2004-05-05 22:31:38 +04:00
lvargs_matched + + ;
}
2004-03-08 20:19:15 +03:00
if ( ! process_lv )
continue ;
2003-10-16 00:02:46 +04:00
ret = process_single ( cmd , lvl - > lv , handle ) ;
2001-11-19 18:20:50 +03:00
if ( ret > ret_max )
ret_max = ret ;
2007-06-15 14:11:14 +04:00
if ( sigint_caught ( ) )
return ret_max ;
2001-11-19 18:20:50 +03:00
}
2008-11-04 01:14:30 +03:00
if ( lvargs_supplied & & lvargs_matched ! = dm_list_size ( arg_lvnames ) ) {
2004-05-05 22:31:38 +04:00
log_error ( " One or more specified logical volume(s) not found. " ) ;
if ( ret_max < ECMD_FAILED )
ret_max = ECMD_FAILED ;
}
2001-11-19 18:20:50 +03:00
return ret_max ;
}
2002-02-11 23:50:53 +03:00
int process_each_lv ( struct cmd_context * cmd , int argc , char * * argv ,
2007-08-22 18:38:18 +04:00
uint32_t 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 ;
2008-06-11 00:07:04 +04:00
int ret_max = ECMD_PROCESSED ;
2001-11-14 21:38:07 +03:00
int ret = 0 ;
2002-11-18 17:04:08 +03:00
int consistent ;
2001-11-14 21:38:07 +03:00
2008-11-04 01:14:30 +03:00
struct dm_list * tags_arg ;
struct dm_list * vgnames ; /* VGs to process */
2005-06-01 20:51:55 +04:00
struct str_list * sll , * strl ;
2001-11-14 21:38:07 +03:00
struct volume_group * vg ;
2008-11-04 01:14:30 +03:00
struct dm_list tags , lvnames ;
struct dm_list arg_lvnames ; /* Cmdline vgname or vgname/lvname */
2004-03-08 20:19:15 +03:00
char * vglv ;
size_t vglv_sz ;
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
2008-11-04 01:14:30 +03:00
dm_list_init ( & tags ) ;
dm_list_init ( & arg_lvnames ) ;
2004-03-08 20:19:15 +03:00
2001-11-14 21:38:07 +03:00
if ( argc ) {
2008-11-04 01:14:30 +03:00
struct dm_list arg_vgnames ;
2004-03-08 20:19:15 +03:00
2001-11-14 21:38:07 +03:00
log_verbose ( " Using logical volume(s) on command line " ) ;
2008-11-04 01:14:30 +03:00
dm_list_init ( & arg_vgnames ) ;
2004-03-08 20:19:15 +03:00
2001-11-14 21:38:07 +03:00
for ( ; opt < argc ; opt + + ) {
2004-03-08 20:19:15 +03:00
const char * lv_name = argv [ opt ] ;
2003-07-05 02:34:56 +04:00
char * vgname_def ;
2007-03-09 23:47:41 +03:00
unsigned dev_dir_found = 0 ;
2002-11-18 17:04:08 +03:00
2004-03-08 20:19:15 +03:00
/* Do we have a tag or vgname or lvname? */
2002-11-18 17:04:08 +03:00
vgname = lv_name ;
2004-03-08 20:19:15 +03:00
if ( * vgname = = ' @ ' ) {
if ( ! validate_name ( vgname + 1 ) ) {
log_error ( " Skipping invalid tag %s " ,
vgname ) ;
continue ;
}
if ( ! str_list_add ( cmd - > mem , & tags ,
2005-10-17 03:03:59 +04:00
dm_pool_strdup ( cmd - > mem ,
2004-03-08 20:19:15 +03:00
vgname + 1 ) ) ) {
log_error ( " strlist allocation failed " ) ;
return ECMD_FAILED ;
}
continue ;
}
/* FIXME Jumbled parsing */
2007-03-09 23:47:41 +03:00
vgname = skip_dev_dir ( cmd , vgname , & dev_dir_found ) ;
2003-07-05 02:34:56 +04:00
if ( * vgname = = ' / ' ) {
log_error ( " \" %s \" : Invalid path for Logical "
2004-03-08 20:19:15 +03:00
" Volume " , argv [ opt ] ) ;
2003-07-05 02:34:56 +04:00
if ( ret_max < ECMD_FAILED )
ret_max = ECMD_FAILED ;
continue ;
}
2004-03-08 20:19:15 +03:00
lv_name = vgname ;
2002-11-18 17:04:08 +03:00
if ( strchr ( vgname , ' / ' ) ) {
/* Must be an LV */
2004-03-08 20:19:15 +03:00
lv_name = strchr ( vgname , ' / ' ) ;
while ( * lv_name = = ' / ' )
lv_name + + ;
if ( ! ( vgname = extract_vgname ( cmd , vgname ) ) ) {
2002-11-18 17:04:08 +03:00
if ( ret_max < ECMD_FAILED )
ret_max = ECMD_FAILED ;
continue ;
}
2004-03-08 20:19:15 +03:00
} else if ( ! dev_dir_found & &
2004-05-11 22:45:11 +04:00
( vgname_def = default_vgname ( cmd ) ) ) {
2003-07-05 02:34:56 +04:00
vgname = vgname_def ;
2004-03-08 20:19:15 +03:00
} else
lv_name = NULL ;
2003-07-05 02:34:56 +04:00
2004-03-08 20:19:15 +03:00
if ( ! str_list_add ( cmd - > mem , & arg_vgnames ,
2005-10-17 03:03:59 +04:00
dm_pool_strdup ( cmd - > mem , vgname ) ) ) {
2004-03-08 20:19:15 +03:00
log_error ( " strlist allocation failed " ) ;
2002-01-29 20:23:33 +03:00
return ECMD_FAILED ;
}
2004-03-08 20:19:15 +03:00
if ( ! lv_name ) {
if ( ! str_list_add ( cmd - > mem , & arg_lvnames ,
2005-10-17 03:03:59 +04:00
dm_pool_strdup ( cmd - > mem ,
2004-05-11 22:45:11 +04:00
vgname ) ) ) {
2004-03-08 20:19:15 +03:00
log_error ( " strlist allocation failed " ) ;
return ECMD_FAILED ;
}
} else {
vglv_sz = strlen ( vgname ) + strlen ( lv_name ) + 2 ;
2005-10-17 03:03:59 +04:00
if ( ! ( vglv = dm_pool_alloc ( cmd - > mem , vglv_sz ) ) | |
2006-08-21 16:54:53 +04:00
dm_snprintf ( vglv , vglv_sz , " %s/%s " , vgname ,
2004-03-08 20:19:15 +03:00
lv_name ) < 0 ) {
log_error ( " vg/lv string alloc failed " ) ;
return ECMD_FAILED ;
}
2004-06-15 21:23:49 +04:00
if ( ! str_list_add ( cmd - > mem , & arg_lvnames , vglv ) ) {
2004-03-08 20:19:15 +03:00
log_error ( " strlist allocation failed " ) ;
return ECMD_FAILED ;
}
2001-11-14 21:38:07 +03:00
}
}
2004-03-08 20:19:15 +03:00
vgnames = & arg_vgnames ;
2004-05-11 22:45:11 +04:00
}
2004-03-08 20:19:15 +03:00
2008-11-04 01:14:30 +03:00
if ( ! argc | | ! dm_list_empty ( & tags ) ) {
2002-01-16 17:43:27 +03:00
log_verbose ( " Finding all logical volumes " ) ;
2008-11-04 01:14:30 +03:00
if ( ! ( vgnames = get_vgs ( cmd , 0 ) ) | | dm_list_empty ( vgnames ) ) {
2001-11-14 21:38:07 +03:00
log_error ( " No volume groups found " ) ;
2004-05-20 20:18:58 +04:00
return ret_max ;
2001-11-14 21:38:07 +03:00
}
2004-03-08 20:19:15 +03:00
}
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( strl , vgnames ) {
2005-06-01 20:51:55 +04:00
vgname = strl - > str ;
2007-11-02 23:40:05 +03:00
if ( is_orphan_vg ( vgname ) )
2004-03-08 20:19:15 +03:00
continue ; /* FIXME Unnecessary? */
if ( ! lock_vol ( cmd , vgname , lock_type ) ) {
log_error ( " Can't lock %s: skipping " , vgname ) ;
continue ;
}
if ( lock_type & LCK_WRITE )
consistent = 1 ;
else
consistent = 0 ;
2006-04-13 01:23:04 +04:00
if ( ! ( vg = vg_read ( cmd , vgname , NULL , & consistent ) ) | | ! consistent ) {
2004-03-08 20:19:15 +03:00
unlock_vg ( cmd , vgname ) ;
if ( ! vg )
log_error ( " Volume group \" %s \" "
" not found " , vgname ) ;
2006-09-02 05:18:17 +04:00
else {
2007-06-06 23:40:28 +04:00
if ( ! vg_check_status ( vg , CLUSTERED ) ) {
2006-09-02 05:18:17 +04:00
if ( ret_max < ECMD_FAILED )
ret_max = ECMD_FAILED ;
continue ;
}
2004-03-08 20:19:15 +03:00
log_error ( " Volume group \" %s \" "
" inconsistent " , vgname ) ;
2006-09-02 05:18:17 +04:00
}
2004-05-11 22:45:11 +04:00
if ( ! vg | | ! ( vg = recover_vg ( cmd , vgname , lock_type ) ) ) {
2004-03-08 20:19:15 +03:00
if ( ret_max < ECMD_FAILED )
ret_max = ECMD_FAILED ;
continue ;
}
}
2007-06-06 23:40:28 +04:00
if ( ! vg_check_status ( vg , CLUSTERED ) ) {
2006-09-02 05:18:17 +04:00
unlock_vg ( cmd , vgname ) ;
if ( ret_max < ECMD_FAILED )
ret_max = ECMD_FAILED ;
continue ;
}
2004-03-08 20:19:15 +03:00
tags_arg = & tags ;
2008-11-04 01:14:30 +03:00
dm_list_init ( & lvnames ) ; /* LVs to be processed in this VG */
dm_list_iterate_items ( sll , & arg_lvnames ) {
2004-03-08 20:19:15 +03:00
const char * vg_name = sll - > str ;
const char * lv_name = strchr ( vg_name , ' / ' ) ;
if ( ( ! lv_name & & ! strcmp ( vg_name , vgname ) ) ) {
/* Process all LVs in this VG */
tags_arg = NULL ;
2008-11-04 01:14:30 +03:00
dm_list_init ( & lvnames ) ;
2004-03-08 20:19:15 +03:00
break ;
} else if ( ! strncmp ( vg_name , vgname , strlen ( vgname ) ) & &
2007-08-22 18:38:18 +04:00
strlen ( vgname ) = = ( size_t ) ( lv_name - vg_name ) ) {
2004-03-08 20:19:15 +03:00
if ( ! str_list_add ( cmd - > mem , & lvnames ,
2005-10-17 03:03:59 +04:00
dm_pool_strdup ( cmd - > mem ,
2004-03-08 20:19:15 +03:00
lv_name + 1 ) ) ) {
2004-05-11 22:45:11 +04:00
log_error ( " strlist allocation failed " ) ;
return ECMD_FAILED ;
2002-11-18 17:04:08 +03:00
}
2001-11-14 21:38:07 +03:00
}
}
2004-03-08 20:19:15 +03:00
ret = process_each_lv_in_vg ( cmd , vg , & lvnames , tags_arg ,
handle , process_single ) ;
unlock_vg ( cmd , vgname ) ;
if ( ret > ret_max )
ret_max = ret ;
2007-06-15 14:11:14 +04:00
if ( sigint_caught ( ) )
2008-06-11 19:02:52 +04:00
break ;
2001-11-14 21:38:07 +03:00
}
return ret_max ;
}
2005-04-20 00:58:25 +04:00
int process_each_segment_in_pv ( struct cmd_context * cmd ,
struct volume_group * vg ,
struct physical_volume * pv ,
void * handle ,
int ( * process_single ) ( struct cmd_context * cmd ,
struct volume_group * vg ,
struct pv_segment * pvseg ,
void * handle ) )
{
struct pv_segment * pvseg ;
2007-11-14 21:41:05 +03:00
const char * vg_name = NULL ;
2008-06-11 00:07:04 +04:00
int ret_max = ECMD_PROCESSED ;
2005-04-20 00:58:25 +04:00
int ret ;
2007-11-14 21:41:05 +03:00
2007-11-17 00:16:20 +03:00
if ( ! vg & & ! is_orphan ( pv ) ) {
2007-11-14 21:41:05 +03:00
vg_name = pv_vg_name ( pv ) ;
2007-11-15 05:20:03 +03:00
if ( ! ( vg = vg_lock_and_read ( cmd , vg_name , NULL , LCK_VG_READ ,
CLUSTERED , 0 ) ) ) {
log_error ( " Skipping volume group %s " , vg_name ) ;
return ECMD_FAILED ;
2007-11-14 21:41:05 +03:00
}
}
2005-04-20 00:58:25 +04:00
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( pvseg , & pv - > segments ) {
2005-04-20 00:58:25 +04:00
ret = process_single ( cmd , vg , pvseg , handle ) ;
if ( ret > ret_max )
ret_max = ret ;
2007-06-15 14:11:14 +04:00
if ( sigint_caught ( ) )
2007-11-16 00:30:52 +03:00
break ;
2005-04-20 00:58:25 +04:00
}
2007-11-14 21:41:05 +03:00
if ( vg_name )
unlock_vg ( cmd , vg_name ) ;
2005-04-20 00:58:25 +04:00
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 ;
2008-06-11 00:07:04 +04:00
int ret_max = ECMD_PROCESSED ;
2002-12-12 23:55:49 +03:00
int ret ;
2008-11-04 01:14:30 +03:00
dm_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 ;
2007-06-15 14:11:14 +04:00
if ( sigint_caught ( ) )
2008-06-11 00:07:04 +04:00
break ;
2002-12-12 23:55:49 +03:00
}
return ret_max ;
}
2004-03-08 20:19:15 +03:00
static int _process_one_vg ( struct cmd_context * cmd , const char * vg_name ,
2006-04-13 01:23:04 +04:00
const char * vgid ,
2008-11-04 01:14:30 +03:00
struct dm_list * tags , struct dm_list * arg_vgnames ,
2007-08-22 18:38:18 +04:00
uint32_t lock_type , int consistent , void * handle ,
2004-03-08 20:19:15 +03:00
int ret_max ,
int ( * process_single ) ( struct cmd_context * cmd ,
const char * vg_name ,
struct volume_group * vg ,
int consistent , void * handle ) )
{
struct volume_group * vg ;
int ret = 0 ;
if ( ! lock_vol ( cmd , vg_name , lock_type ) ) {
2007-11-02 23:40:05 +03:00
log_error ( " Can't lock volume group %s: skipping " , vg_name ) ;
2004-03-08 20:19:15 +03:00
return ret_max ;
}
log_verbose ( " Finding volume group \" %s \" " , vg_name ) ;
2006-05-10 21:49:25 +04:00
if ( ! ( vg = vg_read ( cmd , vg_name , vgid , & consistent ) ) ) {
log_error ( " Volume group \" %s \" not found " , vg_name ) ;
unlock_vg ( cmd , vg_name ) ;
2006-06-15 00:27:15 +04:00
return ECMD_FAILED ;
2006-05-10 21:49:25 +04:00
}
2004-03-08 20:19:15 +03:00
2007-06-06 23:40:28 +04:00
if ( ! vg_check_status ( vg , CLUSTERED ) ) {
2006-09-02 05:18:17 +04:00
unlock_vg ( cmd , vg_name ) ;
return ECMD_FAILED ;
}
2008-11-04 01:14:30 +03:00
if ( ! dm_list_empty ( tags ) ) {
2004-03-08 20:19:15 +03:00
/* Only process if a tag matches or it's on arg_vgnames */
if ( ! str_list_match_item ( arg_vgnames , vg_name ) & &
! str_list_match_list ( tags , & vg - > tags ) ) {
unlock_vg ( cmd , vg_name ) ;
return ret_max ;
}
}
if ( ( ret = process_single ( cmd , vg_name , vg , consistent ,
2004-05-11 22:45:11 +04:00
handle ) ) > ret_max ) {
2004-03-08 20:19:15 +03:00
ret_max = ret ;
2004-05-11 22:45:11 +04:00
}
2004-03-08 20:19:15 +03:00
unlock_vg ( cmd , vg_name ) ;
return ret_max ;
}
2002-02-12 00:00:35 +03:00
int process_each_vg ( struct cmd_context * cmd , int argc , char * * argv ,
2007-08-22 18:38:18 +04:00
uint32_t 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 ;
2008-06-11 00:07:04 +04:00
int ret_max = ECMD_PROCESSED ;
2001-10-06 01:39:30 +04:00
2004-03-08 20:19:15 +03:00
struct str_list * sl ;
2008-11-04 01:14:30 +03:00
struct dm_list * vgnames , * vgids ;
struct dm_list arg_vgnames , tags ;
2001-10-06 01:39:30 +04:00
2006-04-13 01:23:04 +04:00
const char * vg_name , * vgid ;
2002-02-11 18:42:34 +03:00
2008-11-04 01:14:30 +03:00
dm_list_init ( & tags ) ;
dm_list_init ( & arg_vgnames ) ;
2004-03-08 20:19:15 +03:00
2001-10-06 01:39:30 +04:00
if ( argc ) {
log_verbose ( " Using volume group(s) on command line " ) ;
2004-03-08 20:19:15 +03:00
2002-02-11 18:42:34 +03:00
for ( ; opt < argc ; opt + + ) {
vg_name = argv [ opt ] ;
2004-03-08 20:19:15 +03:00
if ( * vg_name = = ' @ ' ) {
if ( ! validate_name ( vg_name + 1 ) ) {
log_error ( " Skipping invalid tag %s " ,
vg_name ) ;
continue ;
}
if ( ! str_list_add ( cmd - > mem , & tags ,
2005-10-17 03:03:59 +04:00
dm_pool_strdup ( cmd - > mem ,
2004-03-08 20:19:15 +03:00
vg_name + 1 ) ) ) {
log_error ( " strlist allocation failed " ) ;
return ECMD_FAILED ;
}
continue ;
}
2007-03-09 23:47:41 +03:00
vg_name = skip_dev_dir ( cmd , vg_name , NULL ) ;
2002-04-24 22:20:51 +04:00
if ( strchr ( vg_name , ' / ' ) ) {
log_error ( " Invalid volume group name: %s " ,
vg_name ) ;
continue ;
}
2004-03-08 20:19:15 +03:00
if ( ! str_list_add ( cmd - > mem , & arg_vgnames ,
2005-10-17 03:03:59 +04:00
dm_pool_strdup ( cmd - > mem , vg_name ) ) ) {
2004-03-08 20:19:15 +03:00
log_error ( " strlist allocation failed " ) ;
return ECMD_FAILED ;
2002-02-11 18:42:34 +03:00
}
}
2004-03-08 20:19:15 +03:00
vgnames = & arg_vgnames ;
}
2008-11-04 01:14:30 +03:00
if ( ! argc | | ! dm_list_empty ( & tags ) ) {
2002-01-16 17:43:27 +03:00
log_verbose ( " Finding all volume groups " ) ;
2008-11-04 01:14:30 +03:00
if ( ! ( vgids = get_vgids ( cmd , 0 ) ) | | dm_list_empty ( vgids ) ) {
2001-10-06 01:39:30 +04:00
log_error ( " No volume groups found " ) ;
2004-05-20 20:18:58 +04:00
return ret_max ;
2001-10-06 01:39:30 +04:00
}
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( sl , vgids ) {
2006-04-13 01:23:04 +04:00
vgid = sl - > str ;
2006-04-14 01:08:29 +04:00
if ( ! vgid | | ! ( vg_name = vgname_from_vgid ( cmd - > mem , vgid ) ) | |
2007-11-02 16:06:42 +03:00
is_orphan_vg ( vg_name ) )
2006-04-13 01:23:04 +04:00
continue ;
ret_max = _process_one_vg ( cmd , vg_name , vgid , & tags ,
& arg_vgnames ,
lock_type , consistent , handle ,
ret_max , process_single ) ;
2007-06-15 14:11:14 +04:00
if ( sigint_caught ( ) )
return ret_max ;
2006-04-13 01:23:04 +04:00
}
} else {
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( sl , vgnames ) {
2006-04-13 01:23:04 +04:00
vg_name = sl - > str ;
2007-11-02 23:40:05 +03:00
if ( is_orphan_vg ( vg_name ) )
2006-04-13 01:23:04 +04:00
continue ; /* FIXME Unnecessary? */
ret_max = _process_one_vg ( cmd , vg_name , NULL , & tags ,
& arg_vgnames ,
lock_type , consistent , handle ,
ret_max , process_single ) ;
2007-06-15 14:11:14 +04:00
if ( sigint_caught ( ) )
return ret_max ;
2006-04-13 01:23:04 +04:00
}
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 ,
2008-11-04 01:14:30 +03:00
const struct dm_list * tags , void * handle ,
2007-08-07 13:06:05 +04:00
process_single_pv_fn_t process_single )
2001-11-19 18:20:50 +03:00
{
2008-06-11 00:07:04 +04:00
int ret_max = ECMD_PROCESSED ;
2001-11-19 18:20:50 +03:00
int ret = 0 ;
2003-10-16 00:02:46 +04:00
struct pv_list * pvl ;
2001-11-19 18:20:50 +03:00
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( pvl , & vg - > pvs ) {
if ( tags & & ! dm_list_empty ( tags ) & &
2004-05-11 22:45:11 +04:00
! str_list_match_list ( tags , & pvl - > pv - > tags ) ) {
2004-03-08 20:19:15 +03:00
continue ;
2004-05-11 22:45:11 +04:00
}
2003-10-16 00:02:46 +04:00
if ( ( ret = process_single ( cmd , vg , pvl - > pv , handle ) ) > ret_max )
2002-01-21 19:05:23 +03:00
ret_max = ret ;
2007-06-15 14:11:14 +04:00
if ( sigint_caught ( ) )
return ret_max ;
2004-03-08 20:19:15 +03:00
}
2002-01-21 19:05:23 +03:00
return ret_max ;
2001-11-19 18:20:50 +03:00
}
2004-06-19 23:27:00 +04:00
static int _process_all_devs ( struct cmd_context * cmd , void * handle ,
int ( * process_single ) ( struct cmd_context * cmd ,
struct volume_group * vg ,
struct physical_volume * pv ,
void * handle ) )
{
struct physical_volume * pv ;
struct physical_volume pv_dummy ;
struct dev_iter * iter ;
struct device * dev ;
2008-06-11 00:07:04 +04:00
int ret_max = ECMD_PROCESSED ;
2004-06-19 23:27:00 +04:00
int ret = 0 ;
2008-02-06 19:09:51 +03:00
if ( ! scan_vgs_for_pvs ( cmd ) ) {
stack ;
return ECMD_FAILED ;
}
2005-03-08 16:46:17 +03:00
if ( ! ( iter = dev_iter_create ( cmd - > filter , 1 ) ) ) {
2004-06-19 23:27:00 +04:00
log_error ( " dev_iter creation failed " ) ;
return ECMD_FAILED ;
}
while ( ( dev = dev_iter_get ( iter ) ) ) {
if ( ! ( pv = pv_read ( cmd , dev_name ( dev ) , NULL , NULL , 0 ) ) ) {
memset ( & pv_dummy , 0 , sizeof ( pv_dummy ) ) ;
2008-11-04 01:14:30 +03:00
dm_list_init ( & pv_dummy . tags ) ;
dm_list_init ( & pv_dummy . segments ) ;
2004-06-19 23:27:00 +04:00
pv_dummy . dev = dev ;
pv_dummy . fmt = NULL ;
pv = & pv_dummy ;
}
ret = process_single ( cmd , NULL , pv , handle ) ;
if ( ret > ret_max )
ret_max = ret ;
2007-06-15 14:11:14 +04:00
if ( sigint_caught ( ) )
2007-07-10 21:51:26 +04:00
break ;
2004-06-19 23:27:00 +04:00
}
dev_iter_destroy ( iter ) ;
return ret_max ;
}
2002-02-12 00:00:35 +03:00
int process_each_pv ( struct cmd_context * cmd , int argc , char * * argv ,
2007-11-14 21:41:05 +03:00
struct volume_group * vg , uint32_t lock_type , 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 ;
2008-06-11 00:07:04 +04:00
int ret_max = ECMD_PROCESSED ;
2001-10-12 01:35:55 +04:00
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 ;
2008-11-04 01:14:30 +03:00
struct dm_list * pvslist , * vgnames ;
struct dm_list tags ;
2004-03-08 20:19:15 +03:00
struct str_list * sll ;
char * tagname ;
int consistent = 1 ;
2008-01-16 21:15:26 +03:00
int scanned = 0 ;
2004-03-08 20:19:15 +03:00
2008-11-04 01:14:30 +03:00
dm_list_init ( & tags ) ;
2001-10-12 01:35:55 +04:00
if ( argc ) {
log_verbose ( " Using physical volume(s) on command line " ) ;
for ( ; opt < argc ; opt + + ) {
2004-03-08 20:19:15 +03:00
if ( * argv [ opt ] = = ' @ ' ) {
tagname = argv [ opt ] + 1 ;
if ( ! validate_name ( tagname ) ) {
log_error ( " Skipping invalid tag %s " ,
tagname ) ;
2004-05-05 22:31:38 +04:00
if ( ret_max < EINVALID_CMD_LINE )
ret_max = EINVALID_CMD_LINE ;
2004-03-08 20:19:15 +03:00
continue ;
}
if ( ! str_list_add ( cmd - > mem , & tags ,
2005-10-17 03:03:59 +04:00
dm_pool_strdup ( cmd - > mem ,
2004-03-08 20:19:15 +03:00
tagname ) ) ) {
log_error ( " strlist allocation failed " ) ;
return ECMD_FAILED ;
}
continue ;
}
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 {
2004-06-19 23:27:00 +04:00
if ( ! ( pv = pv_read ( cmd , argv [ opt ] , NULL ,
NULL , 1 ) ) ) {
2002-12-12 23:55:49 +03:00
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 ;
}
2008-01-16 21:15:26 +03:00
2008-01-30 17:00:02 +03:00
/*
* If a PV has no MDAs it may appear to be an
2008-01-16 21:15:26 +03:00
* orphan until the metadata is read off
* another PV in the same VG . Detecting this
* means checking every VG by scanning every
* PV on the system .
2008-01-30 17:00:02 +03:00
*/
2008-01-16 21:15:26 +03:00
if ( ! scanned & & is_orphan ( pv ) ) {
if ( ! scan_vgs_for_pvs ( cmd ) ) {
stack ;
ret_max = ECMD_FAILED ;
continue ;
}
scanned = 1 ;
if ( ! ( pv = pv_read ( cmd , argv [ opt ] ,
NULL , NULL , 1 ) ) ) {
log_error ( " Failed to read "
" physical volume "
" \" %s \" " , argv [ opt ] ) ;
ret_max = ECMD_FAILED ;
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 ;
2007-06-15 14:11:14 +04:00
if ( sigint_caught ( ) )
return ret_max ;
2001-10-12 01:35:55 +04:00
}
2008-11-04 01:14:30 +03:00
if ( ! dm_list_empty ( & tags ) & & ( vgnames = get_vgs ( cmd , 0 ) ) & &
! dm_list_empty ( vgnames ) ) {
dm_list_iterate_items ( sll , vgnames ) {
2007-11-14 21:41:05 +03:00
if ( ! lock_vol ( cmd , sll - > str , lock_type ) ) {
log_error ( " Can't lock %s: skipping " , sll - > str ) ;
continue ;
}
2006-05-10 21:49:25 +04:00
if ( ! ( vg = vg_read ( cmd , sll - > str , NULL , & consistent ) ) ) {
log_error ( " Volume group \" %s \" not found " , sll - > str ) ;
2007-11-14 21:41:05 +03:00
unlock_vg ( cmd , sll - > str ) ;
2006-05-10 21:49:25 +04:00
ret_max = ECMD_FAILED ;
continue ;
}
2007-11-14 21:41:05 +03:00
if ( ! consistent ) {
unlock_vg ( cmd , sll - > str ) ;
2004-03-08 20:19:15 +03:00
continue ;
2007-11-14 21:41:05 +03:00
}
2006-09-02 05:18:17 +04:00
2007-11-14 21:41:05 +03:00
if ( ! vg_check_status ( vg , CLUSTERED ) ) {
unlock_vg ( cmd , sll - > str ) ;
2006-09-02 05:18:17 +04:00
continue ;
2007-11-14 21:41:05 +03:00
}
2006-09-02 05:18:17 +04:00
2004-03-08 20:19:15 +03:00
ret = process_each_pv_in_vg ( cmd , vg , & tags ,
handle ,
process_single ) ;
2007-11-14 21:41:05 +03:00
unlock_vg ( cmd , sll - > str ) ;
2004-03-08 20:19:15 +03:00
if ( ret > ret_max )
ret_max = ret ;
2007-06-15 14:11:14 +04:00
if ( sigint_caught ( ) )
return ret_max ;
2004-03-08 20:19:15 +03:00
}
}
2001-10-12 01:35:55 +04:00
} else {
2002-12-12 23:55:49 +03:00
if ( vg ) {
log_verbose ( " Using all physical volume(s) in "
" volume group " ) ;
2004-03-08 20:19:15 +03:00
ret = process_each_pv_in_vg ( cmd , vg , NULL , handle ,
process_single ) ;
2003-10-22 02:06:07 +04:00
if ( ret > ret_max )
ret_max = ret ;
2007-06-15 14:11:14 +04:00
if ( sigint_caught ( ) )
return ret_max ;
2004-06-19 23:27:00 +04:00
} else if ( arg_count ( cmd , all_ARG ) ) {
ret = _process_all_devs ( cmd , handle , process_single ) ;
if ( ret > ret_max )
ret_max = ret ;
2007-06-15 14:11:14 +04:00
if ( sigint_caught ( ) )
return ret_max ;
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 ;
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( pvl , pvslist ) {
2003-10-16 00:02:46 +04:00
ret = process_single ( cmd , NULL , pvl - > pv ,
handle ) ;
2002-12-12 23:55:49 +03:00
if ( ret > ret_max )
ret_max = ret ;
2007-06-15 14:11:14 +04:00
if ( sigint_caught ( ) )
return ret_max ;
2002-12-12 23:55:49 +03:00
}
}
2001-10-12 01:35:55 +04:00
}
return ret_max ;
}
2005-01-19 20:31:51 +03:00
/*
* Determine volume group name from a logical volume name
*/
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 ;
}
2004-03-08 20:19:15 +03:00
2003-07-05 02:34:56 +04:00
/* 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 ;
}
2005-10-17 03:03:59 +04:00
vg_name = dm_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 ;
}
2005-01-19 20:31:51 +03:00
/*
* Extract default volume group name from environment
*/
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 ;
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 ;
2007-03-09 23:47:41 +03:00
vg_path = skip_dev_dir ( cmd , vg_path , NULL ) ;
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 ;
}
2005-10-17 03:03:59 +04:00
return dm_pool_strdup ( cmd - > mem , vg_path ) ;
2001-10-29 16:52:23 +03:00
}
2002-01-21 19:05:23 +03:00
2005-01-19 20:31:51 +03:00
/*
* Process physical extent range specifiers
*/
2006-10-22 03:18:43 +04:00
static int _add_pe_range ( struct dm_pool * mem , const char * pvname ,
2008-11-04 01:14:30 +03:00
struct dm_list * pe_ranges , uint32_t start , uint32_t count )
2003-04-25 02:23:24 +04:00
{
2004-08-18 01:55:23 +04:00
struct pe_range * per ;
2003-04-25 02:23:24 +04:00
2006-10-22 03:18:43 +04:00
log_debug ( " Adding PE range: start PE % " PRIu32 " length % " PRIu32
" on %s " , start , count , pvname ) ;
2003-04-25 02:23:24 +04:00
/* Ensure no overlap with existing areas */
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( per , pe_ranges ) {
2004-08-18 01:55:23 +04:00
if ( ( ( start < per - > start ) & & ( start + count - 1 > = per - > start ) )
| | ( ( start > = per - > start ) & &
( per - > start + per - > count - 1 ) > = start ) ) {
2006-10-22 03:18:43 +04:00
log_error ( " Overlapping PE ranges specified (% " PRIu32
" -% " PRIu32 " , % " PRIu32 " -% " PRIu32 " ) "
" on %s " ,
2004-08-18 01:55:23 +04:00
start , start + count - 1 , per - > start ,
2006-10-22 03:18:43 +04:00
per - > start + per - > count - 1 , pvname ) ;
2003-04-25 02:23:24 +04:00
return 0 ;
}
}
2005-10-17 03:03:59 +04:00
if ( ! ( per = dm_pool_alloc ( mem , sizeof ( * per ) ) ) ) {
2003-04-25 02:23:24 +04:00
log_error ( " Allocation of list failed " ) ;
return 0 ;
}
2004-08-18 01:55:23 +04:00
per - > start = start ;
per - > count = count ;
2008-11-04 01:14:30 +03:00
dm_list_add ( pe_ranges , & per - > list ) ;
2003-04-25 02:23:24 +04:00
return 1 ;
}
2007-09-12 00:12:54 +04:00
static int xstrtouint32 ( const char * s , char * * p , int base , uint32_t * result )
{
unsigned long ul ;
errno = 0 ;
ul = strtoul ( s , p , base ) ;
if ( errno | | * p = = s | | ( uint32_t ) ul ! = ul )
return - 1 ;
* result = ul ;
return 0 ;
}
2008-11-04 01:14:30 +03:00
static int _parse_pes ( struct dm_pool * mem , char * c , struct dm_list * pe_ranges ,
2006-10-22 03:18:43 +04:00
const char * pvname , uint32_t size )
2003-04-25 02:23:24 +04:00
{
char * endptr ;
uint32_t start , end ;
/* Default to whole PV */
if ( ! c ) {
2008-01-30 16:19:47 +03:00
if ( ! _add_pe_range ( mem , pvname , pe_ranges , UINT32_C ( 0 ) , size ) )
return_0 ;
2003-04-25 02:23:24 +04:00
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 ) ) {
2007-09-12 00:12:54 +04:00
if ( xstrtouint32 ( c , & endptr , 10 , & start ) )
2003-04-25 02:23:24 +04:00
goto error ;
c = endptr ;
/* Just one number given? */
if ( ! * c | | * c = = ' : ' )
end = start ;
}
/* Range? */
if ( * c = = ' - ' ) {
c + + ;
if ( isdigit ( * c ) ) {
2007-09-12 00:12:54 +04:00
if ( xstrtouint32 ( c , & endptr , 10 , & end ) )
2003-04-25 02:23:24 +04:00
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 ;
}
2008-01-30 16:19:47 +03:00
if ( ! _add_pe_range ( mem , pvname , pe_ranges , start , end - start + 1 ) )
return_0 ;
2003-04-25 02:23:24 +04:00
}
return 1 ;
error :
log_error ( " Physical extent parsing error at %s " , c ) ;
return 0 ;
}
2006-10-22 03:18:43 +04:00
static int _create_pv_entry ( struct dm_pool * mem , struct pv_list * pvl ,
2008-11-04 01:14:30 +03:00
char * colon , int allocatable_only , struct dm_list * r )
2004-03-08 20:19:15 +03:00
{
const char * pvname ;
2006-10-22 03:18:43 +04:00
struct pv_list * new_pvl = NULL , * pvl2 ;
2008-11-04 01:14:30 +03:00
struct dm_list * pe_ranges ;
2004-03-08 20:19:15 +03:00
2007-10-12 18:29:32 +04:00
pvname = pv_dev_name ( pvl - > pv ) ;
2004-08-18 01:55:23 +04:00
if ( allocatable_only & & ! ( pvl - > pv - > status & ALLOCATABLE_PV ) ) {
2004-03-08 20:19:15 +03:00
log_error ( " Physical volume %s not allocatable " , pvname ) ;
2006-10-22 03:18:43 +04:00
return 1 ;
2004-03-08 20:19:15 +03:00
}
2004-08-18 01:55:23 +04:00
if ( allocatable_only & &
( pvl - > pv - > pe_count = = pvl - > pv - > pe_alloc_count ) ) {
2004-05-11 22:45:11 +04:00
log_err ( " No free extents on physical volume \" %s \" " , pvname ) ;
2006-10-22 03:18:43 +04:00
return 1 ;
2004-03-08 20:19:15 +03:00
}
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( pvl2 , r )
2006-10-22 03:18:43 +04:00
if ( pvl - > pv - > dev = = pvl2 - > pv - > dev ) {
new_pvl = pvl2 ;
break ;
}
if ( ! new_pvl ) {
if ( ! ( new_pvl = dm_pool_alloc ( mem , sizeof ( * new_pvl ) ) ) ) {
log_err ( " Unable to allocate physical volume list. " ) ;
return 0 ;
}
2004-03-08 20:19:15 +03:00
2006-10-22 03:18:43 +04:00
memcpy ( new_pvl , pvl , sizeof ( * new_pvl ) ) ;
2004-03-08 20:19:15 +03:00
2006-10-22 03:18:43 +04:00
if ( ! ( pe_ranges = dm_pool_alloc ( mem , sizeof ( * pe_ranges ) ) ) ) {
log_error ( " Allocation of pe_ranges list failed " ) ;
return 0 ;
}
2008-11-04 01:14:30 +03:00
dm_list_init ( pe_ranges ) ;
2006-10-22 03:18:43 +04:00
new_pvl - > pe_ranges = pe_ranges ;
2008-11-04 01:14:30 +03:00
dm_list_add ( r , & new_pvl - > list ) ;
2004-03-08 20:19:15 +03:00
}
2004-08-18 01:55:23 +04:00
/* Determine selected physical extents */
2007-10-12 18:29:32 +04:00
if ( ! _parse_pes ( mem , colon , new_pvl - > pe_ranges , pv_dev_name ( pvl - > pv ) ,
2008-01-30 16:19:47 +03:00
pvl - > pv - > pe_count ) )
return_0 ;
2004-03-08 20:19:15 +03:00
2006-10-22 03:18:43 +04:00
return 1 ;
2004-03-08 20:19:15 +03:00
}
2008-11-04 01:14:30 +03:00
struct dm_list * create_pv_list ( struct dm_pool * mem , struct volume_group * vg , int argc ,
2004-08-18 01:55:23 +04:00
char * * argv , int allocatable_only )
2002-01-21 19:05:23 +03:00
{
2008-11-04 01:14:30 +03:00
struct dm_list * r ;
2004-03-08 20:19:15 +03:00
struct pv_list * pvl ;
2008-11-04 01:14:30 +03:00
struct dm_list tags , arg_pvnames ;
2004-05-11 22:45:11 +04:00
const char * pvname = NULL ;
2004-03-08 20:19:15 +03:00
char * colon , * tagname ;
2002-01-21 19:05:23 +03:00
int i ;
/* Build up list of PVs */
2005-10-17 03:03:59 +04:00
if ( ! ( r = dm_pool_alloc ( mem , sizeof ( * r ) ) ) ) {
2002-01-21 19:05:23 +03:00
log_error ( " Allocation of list failed " ) ;
return NULL ;
}
2008-11-04 01:14:30 +03:00
dm_list_init ( r ) ;
2002-01-21 19:05:23 +03:00
2008-11-04 01:14:30 +03:00
dm_list_init ( & tags ) ;
dm_list_init ( & arg_pvnames ) ;
2004-03-08 20:19:15 +03:00
2002-01-21 19:05:23 +03:00
for ( i = 0 ; i < argc ; i + + ) {
2004-03-08 20:19:15 +03:00
if ( * argv [ i ] = = ' @ ' ) {
tagname = argv [ i ] + 1 ;
if ( ! validate_name ( tagname ) ) {
log_error ( " Skipping invalid tag %s " , tagname ) ;
continue ;
}
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( pvl , & vg - > pvs ) {
2004-03-08 20:19:15 +03:00
if ( str_list_match_item ( & pvl - > pv - > tags ,
2004-05-19 01:55:55 +04:00
tagname ) ) {
2006-10-22 03:18:43 +04:00
if ( ! _create_pv_entry ( mem , pvl , NULL ,
allocatable_only ,
2008-01-30 16:19:47 +03:00
r ) )
return_NULL ;
2004-03-08 20:19:15 +03:00
}
2003-04-25 02:23:24 +04:00
}
2002-01-21 19:05:23 +03:00
continue ;
}
2004-03-08 20:19:15 +03:00
pvname = argv [ i ] ;
2003-04-25 02:23:24 +04:00
2004-03-08 20:19:15 +03:00
if ( ( colon = strchr ( pvname , ' : ' ) ) ) {
2005-10-17 03:03:59 +04:00
if ( ! ( pvname = dm_pool_strndup ( mem , pvname ,
2004-03-08 20:19:15 +03:00
( unsigned ) ( colon -
pvname ) ) ) ) {
log_error ( " Failed to clone PV name " ) ;
return NULL ;
}
2003-04-25 02:23:24 +04:00
}
2004-05-11 22:45:11 +04:00
if ( ! ( pvl = find_pv_in_vg ( vg , pvname ) ) ) {
log_err ( " Physical Volume \" %s \" not found in "
" Volume Group \" %s \" " , pvname , vg - > name ) ;
return NULL ;
}
2008-01-30 16:19:47 +03:00
if ( ! _create_pv_entry ( mem , pvl , colon , allocatable_only , r ) )
return_NULL ;
2002-01-21 19:05:23 +03:00
}
2008-11-04 01:14:30 +03:00
if ( dm_list_empty ( r ) )
2004-03-08 20:19:15 +03:00
log_error ( " No specified PVs have space available " ) ;
2008-11-04 01:14:30 +03:00
return dm_list_empty ( r ) ? NULL : r ;
2002-01-21 19:05:23 +03:00
}
2003-04-25 02:23:24 +04:00
2008-11-04 01:14:30 +03:00
struct dm_list * clone_pv_list ( struct dm_pool * mem , struct dm_list * pvsl )
2003-04-25 02:23:24 +04:00
{
2008-11-04 01:14:30 +03:00
struct dm_list * r ;
2003-04-25 02:23:24 +04:00
struct pv_list * pvl , * new_pvl ;
/* Build up list of PVs */
2005-10-17 03:03:59 +04:00
if ( ! ( r = dm_pool_alloc ( mem , sizeof ( * r ) ) ) ) {
2003-04-25 02:23:24 +04:00
log_error ( " Allocation of list failed " ) ;
return NULL ;
}
2008-11-04 01:14:30 +03:00
dm_list_init ( r ) ;
2003-04-25 02:23:24 +04:00
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( pvl , pvsl ) {
2005-10-17 03:03:59 +04:00
if ( ! ( new_pvl = dm_pool_zalloc ( mem , sizeof ( * new_pvl ) ) ) ) {
2003-04-25 02:23:24 +04:00
log_error ( " Unable to allocate physical volume list. " ) ;
return NULL ;
}
memcpy ( new_pvl , pvl , sizeof ( * new_pvl ) ) ;
2008-11-04 01:14:30 +03:00
dm_list_add ( r , & new_pvl - > list ) ;
2003-04-25 02:23:24 +04:00
}
return r ;
}
2004-06-15 21:23:49 +04:00
2005-01-19 20:31:51 +03:00
/*
* Attempt metadata recovery
*/
2005-01-19 20:30:50 +03:00
struct volume_group * recover_vg ( struct cmd_context * cmd , const char * vgname ,
2007-08-22 18:38:18 +04:00
uint32_t lock_type )
2005-01-19 20:30:50 +03:00
{
int consistent = 1 ;
2006-09-02 05:18:17 +04:00
/* Don't attempt automatic recovery without proper locking */
if ( lockingfailed ( ) )
return NULL ;
2005-01-19 20:30:50 +03:00
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 ;
}
2006-04-13 01:23:04 +04:00
return vg_read ( cmd , vgname , NULL , & consistent ) ;
2005-01-19 20:30:50 +03:00
}
2005-06-03 18:49:51 +04:00
int apply_lvname_restrictions ( const char * name )
{
if ( ! strncmp ( name , " snapshot " , 8 ) ) {
log_error ( " Names starting \" snapshot \" are reserved. "
" Please choose a different LV name. " ) ;
return 0 ;
}
if ( ! strncmp ( name , " pvmove " , 6 ) ) {
log_error ( " Names starting \" pvmove \" are reserved. "
" Please choose a different LV name. " ) ;
return 0 ;
}
if ( strstr ( name , " _mlog " ) ) {
log_error ( " Names including \" _mlog \" are reserved. "
" Please choose a different LV name. " ) ;
return 0 ;
}
if ( strstr ( name , " _mimage " ) ) {
log_error ( " Names including \" _mimage \" are reserved. "
" Please choose a different LV name. " ) ;
return 0 ;
}
return 1 ;
}
2008-03-25 18:24:59 +03:00
int is_reserved_lvname ( const char * name )
{
int rc , old_suppress ;
old_suppress = log_suppress ( 2 ) ;
rc = ! apply_lvname_restrictions ( name ) ;
log_suppress ( old_suppress ) ;
return rc ;
}
2008-01-15 00:07:58 +03:00
/*
* Set members of struct vgcreate_params from cmdline .
* Do preliminary validation with arg_ * ( ) interface .
* Further , more generic validation is done in validate_vgcreate_params ( ) .
2008-01-16 22:54:39 +03:00
* This function is to remain in tools directory .
2008-01-15 00:07:58 +03:00
*/
int fill_vg_create_params ( struct cmd_context * cmd ,
2008-01-16 01:56:30 +03:00
char * vg_name , struct vgcreate_params * vp_new ,
struct vgcreate_params * vp_def )
2008-01-15 00:07:58 +03:00
{
2008-01-16 01:56:30 +03:00
vp_new - > vg_name = skip_dev_dir ( cmd , vg_name , NULL ) ;
vp_new - > max_lv = arg_uint_value ( cmd , maxlogicalvolumes_ARG ,
vp_def - > max_lv ) ;
vp_new - > max_pv = arg_uint_value ( cmd , maxphysicalvolumes_ARG ,
vp_def - > max_pv ) ;
vp_new - > alloc = arg_uint_value ( cmd , alloc_ARG , vp_def - > alloc ) ;
2008-01-15 00:07:58 +03:00
/* Units of 512-byte sectors */
2008-01-16 01:56:30 +03:00
vp_new - > extent_size =
arg_uint_value ( cmd , physicalextentsize_ARG , vp_def - > extent_size ) ;
2008-01-15 00:07:58 +03:00
if ( arg_count ( cmd , clustered_ARG ) )
2008-01-30 17:00:02 +03:00
vp_new - > clustered =
2008-01-16 01:56:30 +03:00
! strcmp ( arg_str_value ( cmd , clustered_ARG ,
vp_def - > clustered ? " y " : " n " ) , " y " ) ;
2008-01-15 00:07:58 +03:00
else
/* Default depends on current locking type */
2008-01-16 01:56:30 +03:00
vp_new - > clustered = locking_is_clustered ( ) ;
2008-01-15 00:07:58 +03:00
if ( arg_sign_value ( cmd , physicalextentsize_ARG , 0 ) = = SIGN_MINUS ) {
log_error ( " Physical extent size may not be negative " ) ;
return 1 ;
}
if ( arg_sign_value ( cmd , maxlogicalvolumes_ARG , 0 ) = = SIGN_MINUS ) {
log_error ( " Max Logical Volumes may not be negative " ) ;
return 1 ;
}
if ( arg_sign_value ( cmd , maxphysicalvolumes_ARG , 0 ) = = SIGN_MINUS ) {
log_error ( " Max Physical Volumes may not be negative " ) ;
return 1 ;
}
return 0 ;
}