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 .
2014-09-27 20:53:08 +04:00
* Copyright ( C ) 2004 - 2014 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"
2002-01-01 00:27:39 +03:00
# include <sys/stat.h>
2013-09-03 18:06:16 +04:00
# include <signal.h>
# include <sys/wait.h>
2002-01-01 00:27:39 +03:00
2006-04-19 19:33:07 +04:00
const char * command_name ( struct cmd_context * cmd )
{
return cmd - > command - > name ;
}
2013-09-03 18:06:16 +04:00
static void _sigchld_handler ( int sig __attribute__ ( ( unused ) ) )
{
while ( wait4 ( - 1 , NULL , WNOHANG | WUNTRACED , NULL ) > 0 ) ;
}
/*
* returns :
* - 1 if the fork failed
* 0 if the parent
* 1 if the child
*/
int become_daemon ( struct cmd_context * cmd , int skip_lvm )
{
static const char devnull [ ] = " /dev/null " ;
int null_fd ;
pid_t pid ;
struct sigaction act = {
{ _sigchld_handler } ,
. sa_flags = SA_NOCLDSTOP ,
} ;
2013-09-06 04:49:43 +04:00
log_verbose ( " Forking background process: %s " , cmd - > cmd_line ) ;
2013-09-03 18:06:16 +04:00
sigaction ( SIGCHLD , & act , NULL ) ;
if ( ! skip_lvm )
sync_local_dev_names ( cmd ) ; /* Flush ops and reset dm cookie */
if ( ( pid = fork ( ) ) = = - 1 ) {
log_error ( " fork failed: %s " , strerror ( errno ) ) ;
return - 1 ;
}
/* Parent */
if ( pid > 0 )
return 0 ;
/* Child */
if ( setsid ( ) = = - 1 )
log_error ( " Background process failed to setsid: %s " ,
strerror ( errno ) ) ;
2013-09-06 04:49:43 +04:00
/* Set this to avoid discarding output from background process */
2013-09-16 23:20:26 +04:00
// #define DEBUG_CHILD
2013-09-06 04:49:43 +04:00
# ifndef DEBUG_CHILD
2013-09-03 18:06:16 +04:00
if ( ( null_fd = open ( devnull , O_RDWR ) ) = = - 1 ) {
log_sys_error ( " open " , devnull ) ;
_exit ( ECMD_FAILED ) ;
}
if ( ( dup2 ( null_fd , STDIN_FILENO ) < 0 ) | | /* reopen stdin */
( dup2 ( null_fd , STDOUT_FILENO ) < 0 ) | | /* reopen stdout */
( dup2 ( null_fd , STDERR_FILENO ) < 0 ) ) { /* reopen stderr */
log_sys_error ( " dup2 " , " redirect " ) ;
( void ) close ( null_fd ) ;
_exit ( ECMD_FAILED ) ;
}
if ( null_fd > STDERR_FILENO )
( void ) close ( null_fd ) ;
init_verbose ( VERBOSE_BASE_LEVEL ) ;
2013-09-06 04:49:43 +04:00
# endif /* DEBUG_CHILD */
2013-09-03 18:06:16 +04:00
strncpy ( * cmd - > argv , " (lvm2) " , strlen ( * cmd - > argv ) ) ;
if ( ! skip_lvm ) {
reset_locking ( ) ;
2014-03-22 01:26:39 +04:00
lvmcache_destroy ( cmd , 1 , 1 ) ;
2013-09-03 18:06:16 +04:00
if ( ! lvmcache_init ( ) )
/* FIXME Clean up properly here */
_exit ( ECMD_FAILED ) ;
}
dev_close_all ( ) ;
return 1 ;
}
2006-08-26 03:02:33 +04:00
/*
* Strip dev_dir if present
*/
2011-02-18 17:47:28 +03:00
const char * skip_dev_dir ( struct cmd_context * cmd , const char * vg_name ,
2014-07-11 14:25:18 +04:00
unsigned * dev_dir_found )
2006-08-26 03:02:33 +04:00
{
2014-09-28 14:54:20 +04:00
size_t devdir_len = strlen ( cmd - > dev_dir ) ;
const char * dmdir = dm_dir ( ) + devdir_len ;
2007-03-09 23:47:41 +03:00
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 */
2014-09-28 14:54:20 +04:00
if ( * vg_name = = ' / ' )
while ( vg_name [ 1 ] = = ' / ' )
2006-08-26 03:02:33 +04:00
vg_name + + ;
2014-09-28 14:54:20 +04:00
if ( strncmp ( vg_name , cmd - > dev_dir , devdir_len ) ) {
if ( dev_dir_found )
* dev_dir_found = 0 ;
} else {
2007-03-09 23:47:41 +03:00
if ( dev_dir_found )
* dev_dir_found = 1 ;
2014-09-28 14:54:20 +04:00
vg_name + = devdir_len ;
2007-03-09 23:47:41 +03:00
while ( * vg_name = = ' / ' )
vg_name + + ;
2014-09-28 14:54:20 +04:00
/* Reformat string if /dev/mapper found */
if ( ! strncmp ( vg_name , dmdir , dmdir_len ) & & vg_name [ dmdir_len + 1 ] = = ' / ' ) {
vg_name + = devdir_len + 1 ;
while ( * vg_name = = ' / ' )
vg_name + + ;
if ( ! dm_split_lvm_name ( cmd - > mem , vg_name , & vgname , & lvname , & layer ) | |
* layer ) {
2014-11-14 18:08:27 +03:00
log_error ( " skip_dev_dir: Couldn't split up device name %s. " ,
2014-09-28 14:54:20 +04:00
vg_name ) ;
return 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 ) {
2014-11-14 18:08:27 +03:00
log_error ( " vg/lv string alloc failed. " ) ;
2014-09-28 14:54:20 +04:00
return vg_name ;
}
return vglv ;
2007-03-09 23:47:41 +03:00
}
}
2011-02-18 17:47:28 +03:00
return vg_name ;
2006-08-26 03:02:33 +04:00
}
2013-10-02 00:20:10 +04:00
/*
2014-11-15 00:00:35 +03:00
* Three possible results :
* a ) return 0 , skip 0 : take the VG , and cmd will end in success
* b ) return 0 , skip 1 : skip the VG , and cmd will end in success
* c ) return 1 , skip * : skip the VG , and cmd will end in failure
*
* Case b is the special case , and includes the following :
* . The VG is inconsistent , and the command allows for inconsistent VGs .
* . The VG is clustered , the host cannot access clustered VG ' s ,
* and the command option has been used to ignore clustered vgs .
*
* Case c covers the other errors returned when reading the VG .
2013-10-02 00:20:10 +04:00
*/
2014-11-14 12:50:31 +03:00
int ignore_vg ( struct volume_group * vg , const char * vg_name , int allow_inconsistent , int * skip )
2013-10-02 00:20:10 +04:00
{
uint32_t read_error = vg_read_error ( vg ) ;
2014-11-14 12:50:31 +03:00
* skip = 0 ;
2013-10-02 00:20:10 +04:00
2014-11-14 12:50:31 +03:00
if ( ( read_error & FAILED_INCONSISTENT ) & & allow_inconsistent )
read_error & = ~ FAILED_INCONSISTENT ; /* Check for other errors */
2013-10-02 00:20:10 +04:00
2014-11-14 12:50:31 +03:00
if ( ( read_error & FAILED_CLUSTERED ) & & vg - > cmd - > ignore_clustered_vgs ) {
read_error & = ~ FAILED_CLUSTERED ; /* Check for other errors */
2013-10-02 00:20:10 +04:00
log_verbose ( " Skipping volume group %s " , vg_name ) ;
2014-11-14 12:50:31 +03:00
* skip = 1 ;
2013-10-02 00:20:10 +04:00
}
2014-11-14 12:50:31 +03:00
if ( read_error ! = SUCCESS ) {
log_error ( " Cannot process volume group %s " , vg_name ) ;
return 1 ;
}
return 0 ;
2013-10-02 00:20:10 +04:00
}
2005-01-19 20:31:51 +03:00
/*
* Metadata iteration functions
*/
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 ,
2010-04-14 03:57:41 +04:00
process_single_pvseg_fn_t process_single_pvseg )
2005-04-20 00:58:25 +04:00
{
struct pv_segment * pvseg ;
2008-06-11 00:07:04 +04:00
int ret_max = ECMD_PROCESSED ;
2005-04-20 00:58:25 +04:00
int ret ;
2009-04-21 16:59:18 +04:00
struct pv_segment _free_pv_segment = { . pv = pv } ;
2007-11-14 21:41:05 +03:00
2014-11-15 00:00:35 +03:00
if ( dm_list_empty ( & pv - > segments ) ) {
ret = process_single_pvseg ( cmd , NULL , & _free_pv_segment , handle ) ;
if ( ret ! = ECMD_PROCESSED )
stack ;
if ( ret > ret_max )
ret_max = ret ;
} else {
2009-04-21 16:59:18 +04:00
dm_list_iterate_items ( pvseg , & pv - > segments ) {
2014-11-14 12:50:31 +03:00
if ( sigint_caught ( ) )
return_ECMD_FAILED ;
2014-11-15 00:00:35 +03:00
ret = process_single_pvseg ( cmd , vg , pvseg , handle ) ;
if ( ret ! = ECMD_PROCESSED )
2013-07-01 18:30:12 +04:00
stack ;
2009-04-21 16:59:18 +04:00
if ( ret > ret_max )
ret_max = ret ;
}
2014-11-15 00:00:35 +03:00
}
2007-11-14 21:41:05 +03:00
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 ,
2010-04-14 03:57:41 +04:00
process_single_seg_fn_t process_single_seg )
2002-12-12 23:55:49 +03:00
{
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 ) {
2014-11-15 00:00:35 +03:00
if ( sigint_caught ( ) )
return_ECMD_FAILED ;
ret = process_single_seg ( cmd , seg , handle ) ;
if ( ret ! = ECMD_PROCESSED )
2014-11-14 12:50:31 +03:00
stack ;
2002-12-12 23:55:49 +03:00
if ( ret > ret_max )
ret_max = ret ;
}
return ret_max ;
}
2014-09-27 18:29:43 +04:00
static const char * _extract_vgname ( struct cmd_context * cmd , const char * lv_name ,
const char * * after )
{
const char * vg_name = lv_name ;
char * st , * pos ;
/* Strip dev_dir (optional) */
if ( ! ( vg_name = skip_dev_dir ( cmd , vg_name , NULL ) ) )
return_0 ;
/* Require exactly one set of consecutive slashes */
if ( ( st = pos = strchr ( vg_name , ' / ' ) ) )
while ( * st = = ' / ' )
st + + ;
if ( ! st | | strchr ( st , ' / ' ) ) {
2014-11-14 18:08:27 +03:00
log_error ( " \" %s \" : Invalid path for Logical Volume. " ,
2014-09-27 18:29:43 +04:00
lv_name ) ;
return 0 ;
}
if ( ! ( vg_name = dm_pool_strndup ( cmd - > mem , vg_name , pos - vg_name ) ) ) {
log_error ( " Allocation of vg_name failed. " ) ;
return 0 ;
}
if ( after )
* after = st ;
return vg_name ;
}
2014-10-07 01:02:00 +04:00
2014-10-06 18:22:01 +04:00
/*
* Extract default volume group name from environment
*/
static const char * _default_vgname ( struct cmd_context * cmd )
{
const char * vg_path ;
/* Take default VG from environment? */
vg_path = getenv ( " LVM_VG_NAME " ) ;
if ( ! vg_path )
return 0 ;
vg_path = skip_dev_dir ( cmd , vg_path , NULL ) ;
if ( strchr ( vg_path , ' / ' ) ) {
2014-11-14 18:08:27 +03:00
log_error ( " \" %s \" : Invalid environment var LVM_VG_NAME set for Volume Group. " ,
vg_path ) ;
2014-10-06 18:22:01 +04:00
return 0 ;
}
return dm_pool_strdup ( cmd - > mem , vg_path ) ;
}
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-10-29 16:52:23 +03:00
/* Path supplied? */
2001-11-06 22:02:26 +03:00
if ( vg_name & & strchr ( vg_name , ' / ' ) ) {
2014-09-27 18:29:43 +04:00
if ( ! ( vg_name = _extract_vgname ( cmd , lv_name , NULL ) ) )
return_NULL ;
2004-03-08 20:19:15 +03:00
2001-10-29 16:52:23 +03:00
return vg_name ;
}
2001-11-06 22:02:26 +03:00
2014-10-06 18:22:01 +04:00
if ( ! ( vg_name = _default_vgname ( cmd ) ) ) {
2001-11-06 22:02:26 +03:00
if ( lv_name )
2014-11-14 18:08:27 +03:00
log_error ( " Path required for Logical Volume \" %s \" . " ,
2001-11-14 21:38:07 +03:00
lv_name ) ;
2014-09-27 18:29:43 +04:00
return NULL ;
2001-11-06 22:02:26 +03:00
}
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
/*
* 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
2014-11-14 18:08:27 +03:00
" 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 ) {
2014-10-07 03:34:04 +04:00
if ( ( ( start < per - > start ) & & ( start + count - 1 > = per - > start ) ) | |
( ( start > = per - > start ) & &
2004-08-18 01:55:23 +04:00
( per - > start + per - > count - 1 ) > = start ) ) {
2006-10-22 03:18:43 +04:00
log_error ( " Overlapping PE ranges specified (% " PRIu32
" -% " PRIu32 " , % " PRIu32 " -% " PRIu32 " ) "
2014-11-14 18:08:27 +03:00
" 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 ) ) ) ) {
2014-11-14 18:08:27 +03:00
log_error ( " Allocation of list failed. " ) ;
2003-04-25 02:23:24 +04:00
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 ;
}
2014-10-07 03:34:04 +04:00
static int _xstrtouint32 ( const char * s , char * * p , int base , uint32_t * result )
2007-09-12 00:12:54 +04:00
{
unsigned long ul ;
errno = 0 ;
ul = strtoul ( s , p , base ) ;
2014-10-07 03:34:04 +04:00
2012-01-20 01:28:06 +04:00
if ( errno | | * p = = s | | ul > UINT32_MAX )
return 0 ;
2014-10-07 03:34:04 +04:00
2007-09-12 00:12:54 +04:00
* result = ul ;
2012-01-20 01:28:06 +04:00
return 1 ;
2007-09-12 00:12:54 +04:00
}
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 ;
2013-09-23 22:50:34 +04:00
uint32_t start , end , len ;
2003-04-25 02:23:24 +04:00
/* 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 ) ) {
2014-10-07 03:34:04 +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 ) ) {
2014-10-07 03:34:04 +04:00
if ( ! _xstrtouint32 ( c , & endptr , 10 , & end ) )
2003-04-25 02:23:24 +04:00
goto error ;
c = endptr ;
}
2013-09-23 22:50:34 +04:00
} else if ( * c = = ' + ' ) { /* Length? */
c + + ;
if ( isdigit ( * c ) ) {
2014-10-07 03:34:04 +04:00
if ( ! _xstrtouint32 ( c , & endptr , 10 , & len ) )
2013-09-23 22:50:34 +04:00
goto error ;
c = endptr ;
end = start + ( len ? ( len - 1 ) : 0 ) ;
}
2003-04-25 02:23:24 +04:00
}
2013-09-23 22:50:34 +04:00
2003-04-25 02:23:24 +04:00
if ( * c & & * c ! = ' : ' )
goto error ;
if ( ( start > end ) | | ( end > size - 1 ) ) {
log_error ( " PE range error: start extent % " PRIu32 " to "
2014-11-14 18:08:27 +03:00
" end extent % " PRIu32 " . " , start , end ) ;
2003-04-25 02:23:24 +04:00
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 :
2014-11-14 18:08:27 +03:00
log_error ( " Physical extent parsing error at %s. " , c ) ;
2003-04-25 02:23:24 +04:00
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 ) ) {
2012-10-16 12:14:41 +04:00
log_warn ( " Physical volume %s not allocatable. " , pvname ) ;
2006-10-22 03:18:43 +04:00
return 1 ;
2004-03-08 20:19:15 +03:00
}
2010-03-16 17:37:38 +03:00
if ( allocatable_only & & is_missing_pv ( pvl - > pv ) ) {
2012-10-16 12:14:41 +04:00
log_warn ( " Physical volume %s is missing. " , pvname ) ;
2009-04-23 20:45:30 +04:00
return 1 ;
}
2004-08-18 01:55:23 +04:00
if ( allocatable_only & &
( pvl - > pv - > pe_count = = pvl - > pv - > pe_alloc_count ) ) {
2012-10-16 12:14:41 +04:00
log_warn ( " 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 ;
}
2009-10-06 20:00:38 +04:00
2006-10-22 03:18:43 +04:00
if ( ! new_pvl ) {
if ( ! ( new_pvl = dm_pool_alloc ( mem , sizeof ( * new_pvl ) ) ) ) {
2009-07-16 00:02:46 +04:00
log_error ( " Unable to allocate physical volume list. " ) ;
2006-10-22 03:18:43 +04:00
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 ) ) ) ) {
2014-11-14 18:08:27 +03:00
log_error ( " Allocation of pe_ranges list failed. " ) ;
2006-10-22 03:18:43 +04:00
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 ;
2014-01-31 01:09:28 +04:00
struct dm_list tagsl , arg_pvnames ;
2010-09-23 16:02:33 +04:00
char * pvname = NULL ;
char * colon , * at_sign , * 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
2014-01-31 01:09:28 +04:00
dm_list_init ( & tagsl ) ;
2008-11-04 01:14:30 +03:00
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 + + ) {
2011-08-30 18:55:15 +04:00
dm_unescape_colons_and_at_signs ( argv [ i ] , & colon , & at_sign ) ;
2010-09-23 16:02:33 +04:00
if ( at_sign & & ( at_sign = = argv [ i ] ) ) {
tagname = at_sign + 1 ;
2010-11-17 13:19:29 +03:00
if ( ! validate_tag ( tagname ) ) {
2014-11-14 18:08:27 +03:00
log_error ( " Skipping invalid tag %s. " , tagname ) ;
2004-03-08 20:19:15 +03:00
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
2010-09-23 16:02:33 +04:00
if ( colon & & ! ( pvname = dm_pool_strndup ( mem , pvname ,
( unsigned ) ( colon - pvname ) ) ) ) {
2014-11-14 18:08:27 +03:00
log_error ( " Failed to clone PV name. " ) ;
2010-09-23 16:02:33 +04:00
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 ) ) ) {
2009-07-16 00:02:46 +04:00
log_error ( " Physical Volume \" %s \" not found in "
2014-11-14 18:08:27 +03:00
" Volume Group \" %s \" . " , pvname , vg - > name ) ;
2004-05-11 22:45:11 +04:00
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 ) )
2014-11-14 18:08:27 +03:00
log_error ( " No specified PVs have space available. " ) ;
2004-03-08 20:19:15 +03:00
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 ) ) ) ) {
2014-11-14 18:08:27 +03:00
log_error ( " Allocation of list failed. " ) ;
2003-04-25 02:23:24 +04:00
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
2014-11-14 18:08:27 +03:00
const char _pe_size_may_not_be_negative_msg [ ] = " Physical extent size may not be negative. " ;
2014-09-12 12:03:12 +04:00
int vgcreate_params_set_defaults ( struct cmd_context * cmd ,
struct vgcreate_params * vp_def ,
struct volume_group * vg )
2009-11-01 23:02:32 +03:00
{
2014-09-12 12:03:12 +04:00
int64_t extent_size ;
2009-11-01 23:02:32 +03:00
if ( vg ) {
vp_def - > vg_name = NULL ;
vp_def - > extent_size = vg - > extent_size ;
vp_def - > max_pv = vg - > max_pv ;
vp_def - > max_lv = vg - > max_lv ;
vp_def - > alloc = vg - > alloc ;
vp_def - > clustered = vg_is_clustered ( vg ) ;
2010-07-01 00:03:52 +04:00
vp_def - > vgmetadatacopies = vg - > mda_copies ;
2009-11-01 23:02:32 +03:00
} else {
vp_def - > vg_name = NULL ;
2014-09-12 12:03:12 +04:00
extent_size = find_config_tree_int64 ( cmd ,
allocation_physical_extent_size_CFG , NULL ) * 2 ;
if ( extent_size < 0 ) {
log_error ( _pe_size_may_not_be_negative_msg ) ;
return 0 ;
}
vp_def - > extent_size = ( uint32_t ) extent_size ;
2009-11-01 23:02:32 +03:00
vp_def - > max_pv = DEFAULT_MAX_PV ;
vp_def - > max_lv = DEFAULT_MAX_LV ;
vp_def - > alloc = DEFAULT_ALLOC_POLICY ;
vp_def - > clustered = DEFAULT_CLUSTERED ;
2010-07-01 00:03:52 +04:00
vp_def - > vgmetadatacopies = DEFAULT_VGMETADATACOPIES ;
2009-11-01 23:02:32 +03:00
}
2014-09-12 12:03:12 +04:00
return 1 ;
2009-11-01 23:02:32 +03:00
}
2008-01-15 00:07:58 +03:00
/*
2009-11-01 23:03:24 +03:00
* Set members of struct vgcreate_params from cmdline arguments .
2008-01-15 00:07:58 +03:00
* 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
*/
2009-11-01 23:03:24 +03:00
int vgcreate_params_set_from_args ( struct cmd_context * cmd ,
struct vgcreate_params * vp_new ,
struct vgcreate_params * vp_def )
2008-01-15 00:07:58 +03:00
{
2009-11-01 23:03:24 +03:00
vp_new - > vg_name = skip_dev_dir ( cmd , vp_def - > vg_name , NULL ) ;
2008-01-16 01:56:30 +03:00
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 ) ;
2012-03-02 01:14:43 +04:00
vp_new - > alloc = ( alloc_policy_t ) 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 ) )
2014-10-11 20:17:46 +04:00
vp_new - > clustered = arg_int_value ( cmd , clustered_ARG , vp_def - > clustered ) ;
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
2012-02-28 18:24:57 +04:00
if ( arg_sign_value ( cmd , physicalextentsize_ARG , SIGN_NONE ) = = SIGN_MINUS ) {
2014-09-12 12:03:12 +04:00
log_error ( _pe_size_may_not_be_negative_msg ) ;
2012-10-16 12:07:27 +04:00
return 0 ;
2008-01-15 00:07:58 +03:00
}
2011-03-02 23:00:09 +03:00
if ( arg_uint64_value ( cmd , physicalextentsize_ARG , 0 ) > MAX_EXTENT_SIZE ) {
2014-11-14 18:08:27 +03:00
log_error ( " Physical extent size cannot be larger than %s. " ,
2011-03-02 23:00:09 +03:00
display_size ( cmd , ( uint64_t ) MAX_EXTENT_SIZE ) ) ;
2012-10-16 12:07:27 +04:00
return 0 ;
2011-03-02 23:00:09 +03:00
}
2012-02-28 18:24:57 +04:00
if ( arg_sign_value ( cmd , maxlogicalvolumes_ARG , SIGN_NONE ) = = SIGN_MINUS ) {
2014-11-14 18:08:27 +03:00
log_error ( " Max Logical Volumes may not be negative. " ) ;
2012-10-16 12:07:27 +04:00
return 0 ;
2008-01-15 00:07:58 +03:00
}
2012-02-28 18:24:57 +04:00
if ( arg_sign_value ( cmd , maxphysicalvolumes_ARG , SIGN_NONE ) = = SIGN_MINUS ) {
2014-11-14 18:08:27 +03:00
log_error ( " Max Physical Volumes may not be negative. " ) ;
2012-10-16 12:07:27 +04:00
return 0 ;
2008-01-15 00:07:58 +03:00
}
2010-06-29 00:38:23 +04:00
if ( arg_count ( cmd , metadatacopies_ARG ) ) {
2010-07-01 00:03:52 +04:00
vp_new - > vgmetadatacopies = arg_int_value ( cmd , metadatacopies_ARG ,
2010-06-29 00:38:23 +04:00
DEFAULT_VGMETADATACOPIES ) ;
} else if ( arg_count ( cmd , vgmetadatacopies_ARG ) ) {
2010-07-01 00:03:52 +04:00
vp_new - > vgmetadatacopies = arg_int_value ( cmd , vgmetadatacopies_ARG ,
2010-06-29 00:38:23 +04:00
DEFAULT_VGMETADATACOPIES ) ;
} else {
2013-06-25 14:30:34 +04:00
vp_new - > vgmetadatacopies = find_config_tree_int ( cmd , metadata_vgmetadatacopies_CFG , NULL ) ;
2010-06-29 00:38:23 +04:00
}
2012-10-16 12:07:27 +04:00
return 1 ;
2008-01-15 00:07:58 +03:00
}
2008-12-19 17:22:48 +03:00
2013-04-11 15:51:08 +04:00
/* Shared code for changing activation state for vgchange/lvchange */
int lv_change_activate ( struct cmd_context * cmd , struct logical_volume * lv ,
activation_change_t activate )
{
2013-11-30 00:25:58 +04:00
int r = 1 ;
2014-11-02 19:48:21 +03:00
if ( lv_is_cache_pool ( lv ) ) {
if ( is_change_activating ( activate ) ) {
log_verbose ( " Skipping activation of cache pool %s. " ,
display_lvname ( lv ) ) ;
return 1 ;
}
if ( ! dm_list_empty ( & lv - > segs_using_this_lv ) ) {
log_verbose ( " Skipping deactivation of used cache pool %s. " ,
display_lvname ( lv ) ) ;
return 1 ;
}
/*
* Allow to pass only deactivation of unused cache pool .
* Useful only for recovery of failed zeroing of metadata LV .
*/
}
2013-11-30 00:25:58 +04:00
if ( lv_is_merging_origin ( lv ) ) {
/*
* For merging origin , its snapshot must be inactive .
* If it ' s still active and cannot be deactivated
* activation or deactivation of origin fails !
*
* When origin is deactivated and merging snapshot is thin
* it allows to deactivate origin , but still report error ,
* since the thin snapshot remains active .
*
* User could retry to deactivate it with another
* deactivation of origin , which is the only visible LV
*/
if ( ! deactivate_lv ( cmd , find_snapshot ( lv ) - > lv ) ) {
2014-02-18 23:52:17 +04:00
if ( is_change_activating ( activate ) ) {
2013-11-30 00:25:58 +04:00
log_error ( " Refusing to activate merging \" %s \" while snapshot \" %s \" is still active. " ,
lv - > name , find_snapshot ( lv ) - > lv - > name ) ;
return 0 ;
}
log_error ( " Cannot fully deactivate merging origin \" %s \" while snapshot \" %s \" is still active. " ,
lv - > name , find_snapshot ( lv ) - > lv - > name ) ;
r = 0 ; /* and continue to deactivate origin... */
}
}
2014-11-05 17:14:58 +03:00
if ( ! lv_active_change ( cmd , lv , activate , 0 ) )
2013-04-29 16:04:38 +04:00
return_0 ;
2013-04-11 15:51:08 +04:00
if ( background_polling ( ) & &
2014-02-18 23:52:17 +04:00
is_change_activating ( activate ) & &
2014-09-16 00:33:53 +04:00
( lv_is_pvmove ( lv ) | | lv_is_converting ( lv ) | | lv_is_merging ( lv ) ) )
2013-04-11 15:51:08 +04:00
lv_spawn_background_polling ( cmd , lv ) ;
2013-11-30 00:25:58 +04:00
return r ;
2013-04-11 15:51:08 +04:00
}
2008-12-19 17:22:48 +03:00
int lv_refresh ( struct cmd_context * cmd , struct logical_volume * lv )
{
2010-06-03 16:45:05 +04:00
if ( ! cmd - > partial_activation & & ( lv - > status & PARTIAL_LV ) ) {
activation: Add "degraded" activation mode
Currently, we have two modes of activation, an unnamed nominal mode
(which I will refer to as "complete") and "partial" mode. The
"complete" mode requires that a volume group be 'complete' - that
is, no missing PVs. If there are any missing PVs, no affected LVs
are allowed to activate - even RAID LVs which might be able to
tolerate a failure. The "partial" mode allows anything to be
activated (or at least attempted). If a non-redundant LV is
missing a portion of its addressable space due to a device failure,
it will be replaced with an error target. RAID LVs will either
activate or fail to activate depending on how badly their
redundancy is compromised.
This patch adds a third option, "degraded" mode. This mode can
be selected via the '--activationmode {complete|degraded|partial}'
option to lvchange/vgchange. It can also be set in lvm.conf.
The "degraded" activation mode allows RAID LVs with a sufficient
level of redundancy to activate (e.g. a RAID5 LV with one device
failure, a RAID6 with two device failures, or RAID1 with n-1
failures). RAID LVs with too many device failures are not allowed
to activate - nor are any non-redundant LVs that may have been
affected. This patch also makes the "degraded" mode the default
activation mode.
The degraded activation mode does not yet work in a cluster. A
new cluster lock flag (LCK_DEGRADED_MODE) will need to be created
to make that work. Currently, there is limited space for this
extra flag and I am looking for possible solutions. One possible
solution is to usurp LCK_CONVERT, as it is not used. When the
locking_type is 3, the degraded mode flag simply gets dropped and
the old ("complete") behavior is exhibited.
2014-07-10 07:56:11 +04:00
log_error ( " Refusing refresh of partial LV %s. "
" Use '--activationmode partial' to override. " ,
2010-06-03 16:45:05 +04:00
lv - > name ) ;
2013-11-29 14:10:41 +04:00
return 0 ;
2010-06-03 16:45:05 +04:00
}
2013-11-29 14:10:41 +04:00
if ( ! suspend_lv ( cmd , lv ) ) {
log_error ( " Failed to suspend %s. " , lv - > name ) ;
return 0 ;
}
2010-01-06 00:07:31 +03:00
2013-11-29 14:10:41 +04:00
if ( ! resume_lv ( cmd , lv ) ) {
log_error ( " Failed to reactivate %s. " , lv - > name ) ;
return 0 ;
}
2010-01-06 00:07:31 +03:00
2010-01-13 04:50:34 +03:00
/*
* check if snapshot merge should be polled
* - unfortunately : even though the dev_manager will clear
* the lv ' s merge attributes if a merge is not possible ;
* it is clearing a different instance of the lv ( as
* retrieved with lv_from_lvid )
* - fortunately : polldaemon will immediately shutdown if the
* origin doesn ' t have a status with a snapshot percentage
*/
2014-06-16 14:43:22 +04:00
if ( background_polling ( ) & & lv_is_merging_origin ( lv ) & & lv_is_active_locally ( lv ) )
2010-01-13 04:50:34 +03:00
lv_spawn_background_polling ( cmd , lv ) ;
2013-11-29 14:10:41 +04:00
return 1 ;
2008-12-19 17:22:48 +03:00
}
2008-12-22 12:00:51 +03:00
int vg_refresh_visible ( struct cmd_context * cmd , struct volume_group * vg )
{
struct lv_list * lvl ;
int r = 1 ;
2009-10-06 20:00:38 +04:00
2011-09-07 12:41:47 +04:00
sigint_allow ( ) ;
dm_list_iterate_items ( lvl , & vg - > lvs ) {
2013-07-01 18:30:12 +04:00
if ( sigint_caught ( ) ) {
r = 0 ;
stack ;
break ;
}
2011-09-07 12:41:47 +04:00
2013-07-01 18:30:12 +04:00
if ( lv_is_visible ( lvl - > lv ) & & ! lv_refresh ( cmd , lvl - > lv ) ) {
r = 0 ;
stack ;
}
2011-09-07 12:41:47 +04:00
}
sigint_restore ( ) ;
2009-10-06 20:00:38 +04:00
2008-12-22 12:00:51 +03:00
return r ;
}
2009-09-30 00:22:35 +04:00
void lv_spawn_background_polling ( struct cmd_context * cmd ,
struct logical_volume * lv )
{
const char * pvname ;
2014-09-16 00:33:53 +04:00
if ( lv_is_pvmove ( lv ) & &
2009-09-30 00:33:49 +04:00
( pvname = get_pvmove_pvname_from_lv_mirr ( lv ) ) ) {
2014-11-14 18:08:27 +03:00
log_verbose ( " Spawning background pvmove process for %s. " ,
2009-09-30 00:33:49 +04:00
pvname ) ;
pvmove_poll ( cmd , pvname , 1 ) ;
2014-09-16 00:33:53 +04:00
} else if ( lv_is_locked ( lv ) & &
( pvname = get_pvmove_pvname_from_lv ( lv ) ) ) {
2014-11-14 18:08:27 +03:00
log_verbose ( " Spawning background pvmove process for %s. " ,
2009-09-30 00:22:35 +04:00
pvname ) ;
pvmove_poll ( cmd , pvname , 1 ) ;
}
2014-09-16 00:33:53 +04:00
if ( lv_is_converting ( lv ) | | lv_is_merging ( lv ) ) {
2014-11-14 18:08:27 +03:00
log_verbose ( " Spawning background lvconvert process for %s. " ,
2009-09-30 00:22:35 +04:00
lv - > name ) ;
lvconvert_poll ( cmd , lv , 1 ) ;
}
}
2009-10-06 00:03:54 +04:00
/*
* Intial sanity checking of non - recovery related command - line arguments .
*
* Output arguments :
* pp : structure allocated by caller , fields written / validated here
*/
2009-11-01 22:51:54 +03:00
int pvcreate_params_validate ( struct cmd_context * cmd ,
2009-10-06 00:03:54 +04:00
int argc , char * * argv ,
struct pvcreate_params * pp )
{
if ( ! argc ) {
2014-11-14 18:08:27 +03:00
log_error ( " Please enter a physical volume path. " ) ;
2009-10-06 00:03:54 +04:00
return 0 ;
}
pp - > yes = arg_count ( cmd , yes_ARG ) ;
2012-03-02 01:14:43 +04:00
pp - > force = ( force_t ) arg_count ( cmd , force_ARG ) ;
2009-10-06 00:03:54 +04:00
if ( arg_int_value ( cmd , labelsector_ARG , 0 ) > = LABEL_SCAN_SECTORS ) {
2014-11-14 18:08:27 +03:00
log_error ( " labelsector must be less than %lu. " ,
2009-10-06 00:03:54 +04:00
LABEL_SCAN_SECTORS ) ;
return 0 ;
} else {
pp - > labelsector = arg_int64_value ( cmd , labelsector_ARG ,
DEFAULT_LABELSECTOR ) ;
}
if ( ! ( cmd - > fmt - > features & FMT_MDAS ) & &
2009-10-06 00:55:56 +04:00
( arg_count ( cmd , pvmetadatacopies_ARG ) | |
2009-10-06 00:03:54 +04:00
arg_count ( cmd , metadatasize_ARG ) | |
arg_count ( cmd , dataalignment_ARG ) | |
arg_count ( cmd , dataalignmentoffset_ARG ) ) ) {
log_error ( " Metadata and data alignment parameters only "
" apply to text format. " ) ;
return 0 ;
}
2013-05-28 14:37:22 +04:00
if ( ! ( cmd - > fmt - > features & FMT_BAS ) & &
arg_count ( cmd , bootloaderareasize_ARG ) ) {
log_error ( " Bootloader area parameters only "
2013-02-15 14:14:26 +04:00
" apply to text format. " ) ;
return 0 ;
}
2013-03-05 20:00:43 +04:00
if ( arg_count ( cmd , metadataignore_ARG ) )
pp - > metadataignore = arg_int_value ( cmd , metadataignore_ARG ,
DEFAULT_PVMETADATAIGNORE ) ;
else
2013-06-25 14:31:53 +04:00
pp - > metadataignore = find_config_tree_bool ( cmd , metadata_pvmetadataignore_CFG , NULL ) ;
2013-03-05 20:00:43 +04:00
2010-06-30 16:17:24 +04:00
if ( arg_count ( cmd , pvmetadatacopies_ARG ) & &
! arg_int_value ( cmd , pvmetadatacopies_ARG , - 1 ) & &
2010-07-01 00:03:52 +04:00
pp - > metadataignore ) {
2010-06-30 16:17:24 +04:00
log_error ( " metadataignore only applies to metadatacopies > 0 " ) ;
return 0 ;
}
2014-10-11 20:17:46 +04:00
pp - > zero = arg_int_value ( cmd , zero_ARG , 1 ) ;
2009-10-06 00:03:54 +04:00
2012-02-28 18:24:57 +04:00
if ( arg_sign_value ( cmd , dataalignment_ARG , SIGN_NONE ) = = SIGN_MINUS ) {
2014-11-14 18:08:27 +03:00
log_error ( " Physical volume data alignment may not be negative. " ) ;
2009-10-06 00:03:54 +04:00
return 0 ;
}
pp - > data_alignment = arg_uint64_value ( cmd , dataalignment_ARG , UINT64_C ( 0 ) ) ;
2012-01-26 01:52:53 +04:00
if ( pp - > data_alignment > UINT32_MAX ) {
2009-10-06 00:03:54 +04:00
log_error ( " Physical volume data alignment is too big. " ) ;
return 0 ;
}
2012-02-28 18:24:57 +04:00
if ( arg_sign_value ( cmd , dataalignmentoffset_ARG , SIGN_NONE ) = = SIGN_MINUS ) {
2009-10-06 00:03:54 +04:00
log_error ( " Physical volume data alignment offset may not be negative " ) ;
return 0 ;
}
pp - > data_alignment_offset = arg_uint64_value ( cmd , dataalignmentoffset_ARG , UINT64_C ( 0 ) ) ;
2012-01-26 01:52:53 +04:00
if ( pp - > data_alignment_offset > UINT32_MAX ) {
2009-10-06 00:03:54 +04:00
log_error ( " Physical volume data alignment offset is too big. " ) ;
return 0 ;
}
2014-04-10 15:43:46 +04:00
if ( ( pp - > data_alignment + pp - > data_alignment_offset ) & &
( pp - > rp . pe_start ! = PV_PE_START_CALC ) ) {
2014-04-10 16:46:40 +04:00
if ( ( pp - > data_alignment ? pp - > rp . pe_start % pp - > data_alignment : pp - > rp . pe_start ) ! = pp - > data_alignment_offset ) {
log_warn ( " WARNING: Ignoring data alignment %s "
" incompatible with restored pe_start value %s) " ,
display_size ( cmd , pp - > data_alignment + pp - > data_alignment_offset ) ,
display_size ( cmd , pp - > rp . pe_start ) ) ;
2014-04-10 15:43:46 +04:00
pp - > data_alignment = 0 ;
pp - > data_alignment_offset = 0 ;
}
2009-10-06 00:03:54 +04:00
}
2012-02-28 18:24:57 +04:00
if ( arg_sign_value ( cmd , metadatasize_ARG , SIGN_NONE ) = = SIGN_MINUS ) {
2014-11-14 18:08:27 +03:00
log_error ( " Metadata size may not be negative. " ) ;
2009-10-06 00:03:54 +04:00
return 0 ;
}
2013-05-28 14:37:22 +04:00
if ( arg_sign_value ( cmd , bootloaderareasize_ARG , SIGN_NONE ) = = SIGN_MINUS ) {
2014-11-14 18:08:27 +03:00
log_error ( " Bootloader area size may not be negative. " ) ;
2013-02-15 14:14:26 +04:00
return 0 ;
}
2009-10-06 00:03:54 +04:00
pp - > pvmetadatasize = arg_uint64_value ( cmd , metadatasize_ARG , UINT64_C ( 0 ) ) ;
if ( ! pp - > pvmetadatasize )
2013-06-25 14:30:34 +04:00
pp - > pvmetadatasize = find_config_tree_int ( cmd , metadata_pvmetadatasize_CFG , NULL ) ;
2009-10-06 00:03:54 +04:00
2009-10-06 00:55:56 +04:00
pp - > pvmetadatacopies = arg_int_value ( cmd , pvmetadatacopies_ARG , - 1 ) ;
2009-10-06 00:03:54 +04:00
if ( pp - > pvmetadatacopies < 0 )
2013-06-25 14:30:34 +04:00
pp - > pvmetadatacopies = find_config_tree_int ( cmd , metadata_pvmetadatacopies_CFG , NULL ) ;
2009-10-06 00:03:54 +04:00
2013-05-28 14:37:22 +04:00
pp - > rp . ba_size = arg_uint64_value ( cmd , bootloaderareasize_ARG , pp - > rp . ba_size ) ;
2013-02-15 14:14:26 +04:00
2009-10-06 00:03:54 +04:00
return 1 ;
}
2010-03-24 01:30:18 +03:00
int get_activation_monitoring_mode ( struct cmd_context * cmd ,
int * monitoring_mode )
{
* monitoring_mode = DEFAULT_DMEVENTD_MONITOR ;
if ( arg_count ( cmd , monitor_ARG ) & &
2010-05-06 15:15:55 +04:00
( arg_count ( cmd , ignoremonitoring_ARG ) | |
arg_count ( cmd , sysinit_ARG ) ) ) {
2014-11-14 18:08:27 +03:00
log_error ( " --ignoremonitoring or --sysinit option not allowed with --monitor option. " ) ;
2010-03-24 01:30:18 +03:00
return 0 ;
}
if ( arg_count ( cmd , monitor_ARG ) )
* monitoring_mode = arg_int_value ( cmd , monitor_ARG ,
DEFAULT_DMEVENTD_MONITOR ) ;
else if ( is_static ( ) | | arg_count ( cmd , ignoremonitoring_ARG ) | |
2010-05-06 15:15:55 +04:00
arg_count ( cmd , sysinit_ARG ) | |
2013-06-25 14:31:53 +04:00
! find_config_tree_bool ( cmd , activation_monitoring_CFG , NULL ) )
2010-03-24 01:30:18 +03:00
* monitoring_mode = DMEVENTD_MONITOR_IGNORE ;
2010-03-29 20:09:40 +04:00
2010-03-24 01:30:18 +03:00
return 1 ;
}
2010-04-13 05:54:32 +04:00
2014-07-23 00:20:18 +04:00
/*
* Read pool options from cmdline
*/
2013-06-27 13:22:02 +04:00
int get_pool_params ( struct cmd_context * cmd ,
2014-07-23 00:20:18 +04:00
const struct segment_type * segtype ,
2013-06-27 13:22:02 +04:00
int * passed_args ,
2014-07-23 00:20:18 +04:00
uint64_t * pool_metadata_size ,
int * pool_metadata_spare ,
2012-11-15 17:48:32 +04:00
uint32_t * chunk_size ,
thin_discards_t * discards ,
int * zero )
{
2013-03-06 14:58:09 +04:00
* passed_args = 0 ;
2012-11-26 14:20:13 +04:00
2014-07-23 00:20:18 +04:00
if ( segtype_is_thin_pool ( segtype ) | | segtype_is_thin ( segtype ) ) {
2014-10-31 13:41:03 +03:00
if ( arg_is_set ( cmd , zero_ARG ) ) {
2014-07-23 00:20:18 +04:00
* passed_args | = PASS_ARG_ZERO ;
2014-10-11 20:17:46 +04:00
* zero = arg_int_value ( cmd , zero_ARG , 1 ) ;
2014-11-14 18:11:16 +03:00
log_very_verbose ( " %s pool zeroing. " , * zero ? " Enabling " : " Disabling " ) ;
2014-07-23 00:20:18 +04:00
}
2014-10-31 13:41:03 +03:00
if ( arg_is_set ( cmd , discards_ARG ) ) {
2014-07-23 00:20:18 +04:00
* passed_args | = PASS_ARG_DISCARDS ;
* discards = ( thin_discards_t ) arg_uint_value ( cmd , discards_ARG , 0 ) ;
2014-11-14 18:08:27 +03:00
log_very_verbose ( " Setting pool discards to %s. " ,
2014-07-23 00:20:18 +04:00
get_pool_discards_name ( * discards ) ) ;
}
2012-11-15 17:48:32 +04:00
}
2012-11-26 14:20:13 +04:00
2014-10-31 13:41:49 +03:00
if ( arg_from_list_is_negative ( cmd , " may not be negative " ,
chunksize_ARG ,
pooldatasize_ARG ,
poolmetadatasize_ARG ,
- 1 ) )
return_0 ;
if ( arg_from_list_is_zero ( cmd , " may not be zero " ,
chunksize_ARG ,
pooldatasize_ARG ,
poolmetadatasize_ARG ,
- 1 ) )
return_0 ;
2014-07-23 00:20:18 +04:00
2014-10-31 13:41:49 +03:00
if ( arg_is_set ( cmd , chunksize_ARG ) ) {
2013-03-06 14:58:09 +04:00
* passed_args | = PASS_ARG_CHUNK_SIZE ;
2014-07-23 00:20:18 +04:00
* chunk_size = arg_uint_value ( cmd , chunksize_ARG , 0 ) ;
2014-10-05 00:36:41 +04:00
if ( ! validate_pool_chunk_size ( cmd , segtype , * chunk_size ) )
return_0 ;
2014-11-14 18:08:27 +03:00
log_very_verbose ( " Setting pool chunk size to %s. " ,
2012-11-26 14:20:13 +04:00
display_size ( cmd , * chunk_size ) ) ;
2013-08-06 13:42:40 +04:00
}
2013-03-06 14:58:09 +04:00
if ( arg_count ( cmd , poolmetadatasize_ARG ) ) {
2014-07-23 00:20:18 +04:00
if ( arg_sign_value ( cmd , poolmetadatasize_ARG , SIGN_NONE ) = = SIGN_MINUS ) {
log_error ( " Negative pool metadata size is invalid. " ) ;
return 0 ;
}
if ( arg_count ( cmd , poolmetadata_ARG ) ) {
log_error ( " Please specify either metadata logical volume or its size. " ) ;
return 0 ;
}
2013-03-06 14:58:09 +04:00
* passed_args | = PASS_ARG_POOL_METADATA_SIZE ;
2014-07-11 14:15:23 +04:00
* pool_metadata_size = arg_uint64_value ( cmd , poolmetadatasize_ARG ,
UINT64_C ( 0 ) ) ;
} else if ( arg_count ( cmd , poolmetadata_ARG ) )
* passed_args | = PASS_ARG_POOL_METADATA_SIZE ; /* fixed size */
2012-11-15 17:48:32 +04:00
2014-07-23 00:20:18 +04:00
/* TODO: default in lvm.conf ? */
* pool_metadata_spare = arg_int_value ( cmd , poolmetadataspare_ARG ,
DEFAULT_POOL_METADATA_SPARE ) ;
2012-11-15 17:48:32 +04:00
return 1 ;
}
2010-04-13 05:54:32 +04:00
/*
* Generic stripe parameter checks .
*/
static int _validate_stripe_params ( struct cmd_context * cmd , uint32_t * stripes ,
uint32_t * stripe_size )
{
if ( * stripes = = 1 & & * stripe_size ) {
2014-11-14 18:08:27 +03:00
log_print_unless_silent ( " Ignoring stripesize argument with single stripe. " ) ;
2010-04-13 05:54:32 +04:00
* stripe_size = 0 ;
}
if ( * stripes > 1 & & ! * stripe_size ) {
2013-06-25 14:30:34 +04:00
* stripe_size = find_config_tree_int ( cmd , metadata_stripesize_CFG , NULL ) * 2 ;
2014-11-14 18:08:27 +03:00
log_print_unless_silent ( " Using default stripesize %s. " ,
2010-04-13 05:54:32 +04:00
display_size ( cmd , ( uint64_t ) * stripe_size ) ) ;
}
if ( * stripes < 1 | | * stripes > MAX_STRIPES ) {
2014-11-14 18:08:27 +03:00
log_error ( " Number of stripes (%d) must be between %d and %d. " ,
2010-04-13 05:54:32 +04:00
* stripes , 1 , MAX_STRIPES ) ;
return 0 ;
}
if ( * stripes > 1 & & ( * stripe_size < STRIPE_SIZE_MIN | |
* stripe_size & ( * stripe_size - 1 ) ) ) {
2014-11-14 18:08:27 +03:00
log_error ( " Invalid stripe size %s. " ,
2010-04-13 05:54:32 +04:00
display_size ( cmd , ( uint64_t ) * stripe_size ) ) ;
return 0 ;
}
return 1 ;
}
/*
* The stripe size is limited by the size of a uint32_t , but since the
* value given by the user is doubled , and the final result must be a
* power of 2 , we must divide UINT_MAX by four and add 1 ( to round it
* up to the power of 2 )
*/
int get_stripe_params ( struct cmd_context * cmd , uint32_t * stripes , uint32_t * stripe_size )
{
/* stripes_long_ARG takes precedence (for lvconvert) */
2011-01-24 16:38:31 +03:00
* stripes = arg_uint_value ( cmd , arg_count ( cmd , stripes_long_ARG ) ? stripes_long_ARG : stripes_ARG , 1 ) ;
2010-04-13 05:54:32 +04:00
* stripe_size = arg_uint_value ( cmd , stripesize_ARG , 0 ) ;
if ( * stripe_size ) {
2012-02-28 18:24:57 +04:00
if ( arg_sign_value ( cmd , stripesize_ARG , SIGN_NONE ) = = SIGN_MINUS ) {
2014-11-14 18:08:27 +03:00
log_error ( " Negative stripesize is invalid. " ) ;
2010-04-13 05:54:32 +04:00
return 0 ;
}
2014-07-11 14:25:18 +04:00
if ( arg_uint64_value ( cmd , stripesize_ARG , 0 ) > STRIPE_SIZE_LIMIT * 2 ) {
2014-11-14 18:08:27 +03:00
log_error ( " Stripe size cannot be larger than %s. " ,
2010-04-13 05:54:32 +04:00
display_size ( cmd , ( uint64_t ) STRIPE_SIZE_LIMIT ) ) ;
return 0 ;
}
}
return _validate_stripe_params ( cmd , stripes , stripe_size ) ;
}
2014-11-19 20:39:29 +03:00
static int _validate_cachepool_params ( struct dm_config_tree * tree )
{
return 1 ;
}
struct dm_config_tree * get_cachepolicy_params ( struct cmd_context * cmd )
{
const char * str ;
struct arg_value_group_list * group ;
struct dm_config_tree * result = NULL , * prev = NULL , * current = NULL ;
2014-11-20 19:49:32 +03:00
struct dm_config_node * cn ;
2014-11-20 13:30:19 +03:00
int ok = 0 ;
2014-11-19 20:39:29 +03:00
dm_list_iterate_items ( group , & cmd - > arg_value_groups ) {
2014-11-20 13:30:19 +03:00
if ( ! grouped_arg_is_set ( group - > arg_values , cachesettings_ARG ) )
2014-11-19 20:39:29 +03:00
continue ;
current = dm_config_create ( ) ;
if ( ! current )
2014-11-20 13:30:19 +03:00
goto_out ;
2014-11-19 20:39:29 +03:00
if ( prev )
current - > cascade = prev ;
prev = current ;
if ( ! ( str = grouped_arg_str_value ( group - > arg_values ,
2014-11-20 13:30:19 +03:00
cachesettings_ARG ,
2014-11-19 20:39:29 +03:00
NULL ) ) )
2014-11-20 13:30:19 +03:00
goto_out ;
2014-11-19 20:39:29 +03:00
if ( ! dm_config_parse ( current , str , str + strlen ( str ) ) )
2014-11-20 13:30:19 +03:00
goto_out ;
2014-11-19 20:39:29 +03:00
}
result = dm_config_flatten ( current ) ;
2014-11-20 13:30:19 +03:00
if ( ! ( cn = dm_config_create_node ( result , " policy_settings " ) ) )
goto_out ;
2014-11-19 20:39:29 +03:00
cn - > child = result - > root ;
result - > root = cn ;
2014-11-20 13:30:19 +03:00
if ( arg_count ( cmd , cachepolicy_ARG ) ) {
if ( ! ( cn = dm_config_create_node ( result , " policy " ) ) )
goto_out ;
result - > root - > sib = cn ;
if ( ! ( cn - > v = dm_config_create_value ( result ) ) )
goto_out ;
cn - > v - > v . str = arg_str_value ( cmd , cachepolicy_ARG , NULL ) ;
2014-11-19 20:39:29 +03:00
}
2014-11-20 13:30:19 +03:00
if ( ! _validate_cachepool_params ( result ) )
goto_out ;
ok = 1 ;
out :
if ( ! ok ) {
2014-11-19 20:39:29 +03:00
dm_config_destroy ( result ) ;
result = NULL ;
}
while ( prev ) {
current = prev - > cascade ;
dm_config_destroy ( prev ) ;
prev = current ;
}
return result ;
}
2011-01-24 16:38:31 +03:00
/* FIXME move to lib */
static int _pv_change_tag ( struct physical_volume * pv , const char * tag , int addtag )
{
if ( addtag ) {
if ( ! str_list_add ( pv - > fmt - > cmd - > mem , & pv - > tags , tag ) ) {
2014-11-14 18:08:27 +03:00
log_error ( " Failed to add tag %s to physical volume %s. " ,
2011-01-24 16:38:31 +03:00
tag , pv_dev_name ( pv ) ) ;
return 0 ;
}
2012-02-08 16:52:58 +04:00
} else
str_list_del ( & pv - > tags , tag ) ;
2011-01-24 16:38:31 +03:00
return 1 ;
}
/* Set exactly one of VG, LV or PV */
int change_tag ( struct cmd_context * cmd , struct volume_group * vg ,
struct logical_volume * lv , struct physical_volume * pv , int arg )
{
const char * tag ;
struct arg_value_group_list * current_group ;
dm_list_iterate_items ( current_group , & cmd - > arg_value_groups ) {
if ( ! grouped_arg_is_set ( current_group - > arg_values , arg ) )
continue ;
if ( ! ( tag = grouped_arg_str_value ( current_group - > arg_values , arg , NULL ) ) ) {
2014-11-14 18:08:27 +03:00
log_error ( " Failed to get tag. " ) ;
2011-01-24 16:38:31 +03:00
return 0 ;
}
if ( vg & & ! vg_change_tag ( vg , tag , arg = = addtag_ARG ) )
return_0 ;
else if ( lv & & ! lv_change_tag ( lv , tag , arg = = addtag_ARG ) )
return_0 ;
else if ( pv & & ! _pv_change_tag ( pv , tag , arg = = addtag_ARG ) )
return_0 ;
}
return 1 ;
}
2011-09-15 19:26:40 +04:00
2013-07-29 20:51:27 +04:00
int process_each_label ( struct cmd_context * cmd , int argc , char * * argv , void * handle ,
process_single_label_fn_t process_single_label )
{
struct label * label ;
struct dev_iter * iter ;
struct device * dev ;
int ret_max = ECMD_PROCESSED ;
2013-11-23 01:27:32 +04:00
int ret ;
2013-07-29 20:51:27 +04:00
int opt = 0 ;
if ( argc ) {
for ( ; opt < argc ; opt + + ) {
2014-10-02 14:00:57 +04:00
if ( ! ( dev = dev_cache_get ( argv [ opt ] , cmd - > full_filter ) ) ) {
2013-07-29 20:51:27 +04:00
log_error ( " Failed to find device "
2014-11-14 18:08:27 +03:00
" \" %s \" . " , argv [ opt ] ) ;
2013-07-29 20:51:27 +04:00
ret_max = ECMD_FAILED ;
continue ;
}
2013-08-21 03:32:51 +04:00
if ( ! label_read ( dev , & label , 0 ) ) {
2014-11-14 18:08:27 +03:00
log_error ( " No physical volume label read from %s. " ,
2013-08-21 03:32:51 +04:00
argv [ opt ] ) ;
ret_max = ECMD_FAILED ;
2013-07-29 20:51:27 +04:00
continue ;
2013-08-21 03:32:51 +04:00
}
2013-07-29 20:51:27 +04:00
ret = process_single_label ( cmd , label , handle ) ;
if ( ret > ret_max )
ret_max = ret ;
if ( sigint_caught ( ) )
break ;
}
return ret_max ;
}
2014-10-02 14:00:57 +04:00
if ( ! ( iter = dev_iter_create ( cmd - > full_filter , 1 ) ) ) {
2014-11-14 18:08:27 +03:00
log_error ( " dev_iter creation failed. " ) ;
2013-07-29 20:51:27 +04:00
return ECMD_FAILED ;
}
while ( ( dev = dev_iter_get ( iter ) ) )
{
if ( ! label_read ( dev , & label , 0 ) )
continue ;
ret = process_single_label ( cmd , label , handle ) ;
if ( ret > ret_max )
ret_max = ret ;
if ( sigint_caught ( ) )
break ;
}
dev_iter_destroy ( iter ) ;
return ret_max ;
}
2014-09-27 20:53:08 +04:00
2014-10-23 16:26:16 +04:00
/*
* Parse persistent major minor parameters .
*
* - - persistent is unspecified = > state is deduced
* from presence of options - - minor or - - major .
*
* - Mn = > - - minor or - - major not allowed .
*
* - My = > - - minor is required ( and also - - major on < = 2.4 )
*/
2014-09-27 20:53:08 +04:00
int get_and_validate_major_minor ( const struct cmd_context * cmd ,
const struct format_type * fmt ,
int32_t * major , int32_t * minor )
{
2014-10-23 16:26:16 +04:00
if ( arg_count ( cmd , minor_ARG ) > 1 ) {
log_error ( " Option --minor may not be repeated. " ) ;
return 0 ;
}
if ( arg_count ( cmd , major_ARG ) > 1 ) {
log_error ( " Option -j|--major may not be repeated. " ) ;
return 0 ;
}
/* Check with default 'y' */
if ( ! arg_int_value ( cmd , persistent_ARG , 1 ) ) { /* -Mn */
2014-09-27 20:53:08 +04:00
if ( arg_is_set ( cmd , minor_ARG ) | | arg_is_set ( cmd , major_ARG ) ) {
2014-10-23 16:26:16 +04:00
log_error ( " Options --major and --minor are incompatible with -Mn. " ) ;
2014-09-27 20:53:08 +04:00
return 0 ;
}
* major = * minor = - 1 ;
return 1 ;
}
2014-10-23 16:26:16 +04:00
/* -1 cannot be entered as an argument for --major, --minor */
* major = arg_int_value ( cmd , major_ARG , - 1 ) ;
* minor = arg_int_value ( cmd , minor_ARG , - 1 ) ;
2014-09-27 20:53:08 +04:00
2014-10-23 16:26:16 +04:00
if ( arg_is_set ( cmd , persistent_ARG ) ) { /* -My */
if ( * minor = = - 1 ) {
log_error ( " Please specify minor number with --minor when using -My. " ) ;
return 0 ;
}
2014-09-27 20:53:08 +04:00
}
if ( ! strncmp ( cmd - > kernel_vsn , " 2.4. " , 4 ) ) {
/* Major is required for 2.4 */
2014-10-23 16:26:16 +04:00
if ( arg_is_set ( cmd , persistent_ARG ) & & * major < 0 ) {
log_error ( " Please specify major number with --major when using -My. " ) ;
2014-09-27 20:53:08 +04:00
return 0 ;
}
} else {
2014-10-23 16:26:16 +04:00
if ( * major ! = - 1 ) {
log_warn ( " WARNING: Ignoring supplied major number %d - "
2014-09-27 20:53:08 +04:00
" kernel assigns major numbers dynamically. "
" Using major number %d instead. " ,
2014-10-23 16:26:16 +04:00
* major , cmd - > dev_types - > device_mapper_major ) ;
2014-09-27 20:53:08 +04:00
}
2014-10-23 16:26:16 +04:00
/* Stay with dynamic major:minor if minor is not specified. */
* major = ( * minor = = - 1 ) ? - 1 : cmd - > dev_types - > device_mapper_major ;
2014-09-27 20:53:08 +04:00
}
2014-10-23 16:26:16 +04:00
if ( ( * minor ! = - 1 ) & & ! validate_major_minor ( cmd , fmt , * major , * minor ) )
2014-09-27 20:53:08 +04:00
return_0 ;
return 1 ;
}
2014-09-28 14:57:39 +04:00
/*
* Validate lvname parameter
*
* If it contains vgname , it is extracted from lvname .
* If there is passed vgname , it is compared whether its the same name .
*/
int validate_lvname_param ( struct cmd_context * cmd , const char * * vg_name ,
const char * * lv_name )
{
const char * vgname ;
const char * lvname ;
if ( ! lv_name | | ! * lv_name )
return 1 ; /* NULL lvname is ok */
/* If contains VG name, extract it. */
if ( strchr ( * lv_name , ( int ) ' / ' ) ) {
if ( ! ( vgname = _extract_vgname ( cmd , * lv_name , & lvname ) ) )
return_0 ;
if ( ! * vg_name )
* vg_name = vgname ;
else if ( strcmp ( vgname , * vg_name ) ) {
log_error ( " Please use a single volume group name "
2014-11-14 18:08:27 +03:00
" ( \" %s \" or \" %s \" ). " , vgname , * vg_name ) ;
2014-09-28 14:57:39 +04:00
return 0 ;
}
* lv_name = lvname ;
}
2014-09-30 23:45:10 +04:00
if ( ! validate_name ( * lv_name ) ) {
log_error ( " Logical volume name \" %s \" is invalid. " ,
* lv_name ) ;
return 0 ;
}
2014-09-28 14:57:39 +04:00
return 1 ;
}
2014-10-03 23:47:19 +04:00
2014-10-08 13:14:33 +04:00
/*
* Validate lvname parameter
* This name must follow restriction rules on prefixes and suffixes .
*
* If it contains vgname , it is extracted from lvname .
* If there is passed vgname , it is compared whether its the same name .
*/
int validate_restricted_lvname_param ( struct cmd_context * cmd , const char * * vg_name ,
const char * * lv_name )
{
if ( ! validate_lvname_param ( cmd , vg_name , lv_name ) )
return_0 ;
if ( lv_name & & * lv_name & & ! apply_lvname_restrictions ( * lv_name ) )
return_0 ;
return - 1 ;
}
2014-10-03 23:47:19 +04:00
struct vgnameid_list {
struct dm_list list ;
const char * vg_name ;
const char * vgid ;
} ;
/*
* Extract list of VG names and list of tags from command line arguments .
*/
static int _get_arg_vgnames ( struct cmd_context * cmd ,
int argc , char * * argv ,
struct dm_list * arg_vgnames ,
struct dm_list * arg_tags )
{
int opt = 0 ;
int ret_max = ECMD_PROCESSED ;
const char * vg_name ;
2014-11-14 18:08:27 +03:00
log_verbose ( " Using volume group(s) on command line. " ) ;
2014-10-03 23:47:19 +04:00
for ( ; opt < argc ; opt + + ) {
vg_name = argv [ opt ] ;
if ( * vg_name = = ' @ ' ) {
if ( ! validate_tag ( vg_name + 1 ) ) {
log_error ( " Skipping invalid tag: %s " , vg_name ) ;
if ( ret_max < EINVALID_CMD_LINE )
ret_max = EINVALID_CMD_LINE ;
continue ;
}
if ( ! str_list_add ( cmd - > mem , arg_tags ,
dm_pool_strdup ( cmd - > mem , vg_name + 1 ) ) ) {
2014-11-14 18:08:27 +03:00
log_error ( " strlist allocation failed. " ) ;
2014-10-03 23:47:19 +04:00
return ECMD_FAILED ;
}
continue ;
}
vg_name = skip_dev_dir ( cmd , vg_name , NULL ) ;
if ( strchr ( vg_name , ' / ' ) ) {
2014-11-14 18:08:27 +03:00
log_error ( " Invalid volume group name %s. " , vg_name ) ;
2014-10-03 23:47:19 +04:00
if ( ret_max < EINVALID_CMD_LINE )
ret_max = EINVALID_CMD_LINE ;
continue ;
}
if ( ! str_list_add ( cmd - > mem , arg_vgnames ,
dm_pool_strdup ( cmd - > mem , vg_name ) ) ) {
2014-11-14 18:08:27 +03:00
log_error ( " strlist allocation failed. " ) ;
2014-10-03 23:47:19 +04:00
return ECMD_FAILED ;
}
}
return ret_max ;
}
/*
* FIXME Add arg to include ( or not ) entries with duplicate vg names ?
*
* Obtain complete list of VG name / vgid pairs known on the system .
*/
static int _get_vgnameids_on_system ( struct cmd_context * cmd ,
2014-10-07 03:34:04 +04:00
struct dm_list * vgnameids_on_system ,
2014-10-07 03:53:56 +04:00
const char * only_this_vgname , int include_internal )
2014-10-03 23:47:19 +04:00
{
struct vgnameid_list * vgnl ;
struct dm_list * vgids ;
struct dm_str_list * sl ;
const char * vgid ;
2014-10-07 03:53:56 +04:00
if ( only_this_vgname ) {
vgnl = dm_pool_alloc ( cmd - > mem , sizeof ( * vgnl ) ) ;
if ( ! vgnl ) {
2014-11-14 18:08:27 +03:00
log_error ( " name_id_list allocation failed. " ) ;
2014-10-07 03:53:56 +04:00
return ECMD_FAILED ;
}
vgnl - > vg_name = dm_pool_strdup ( cmd - > mem , only_this_vgname ) ;
vgnl - > vgid = NULL ;
dm_list_add ( vgnameids_on_system , & vgnl - > list ) ;
return ECMD_PROCESSED ;
}
2014-11-14 18:08:27 +03:00
log_verbose ( " Finding all volume groups. " ) ;
2014-10-03 23:47:19 +04:00
if ( ! lvmetad_vg_list_to_lvmcache ( cmd ) )
stack ;
/*
* Start with complete vgid list because multiple VGs might have same name .
*/
2014-10-07 03:34:04 +04:00
vgids = get_vgids ( cmd , include_internal ) ;
2014-10-03 23:47:19 +04:00
if ( ! vgids | | dm_list_empty ( vgids ) ) {
stack ;
return ECMD_PROCESSED ;
}
/* FIXME get_vgids() should provide these pairings directly */
dm_list_iterate_items ( sl , vgids ) {
if ( ! ( vgid = sl - > str ) )
continue ;
if ( ! ( vgnl = dm_pool_alloc ( cmd - > mem , sizeof ( * vgnl ) ) ) ) {
2014-11-14 18:08:27 +03:00
log_error ( " vgnameid_list allocation failed. " ) ;
2014-10-03 23:47:19 +04:00
return ECMD_FAILED ;
}
vgnl - > vgid = dm_pool_strdup ( cmd - > mem , vgid ) ;
vgnl - > vg_name = lvmcache_vgname_from_vgid ( cmd - > mem , vgid ) ;
dm_list_add ( vgnameids_on_system , & vgnl - > list ) ;
}
return ECMD_PROCESSED ;
}
static int _process_vgnameid_list ( struct cmd_context * cmd , uint32_t flags ,
struct dm_list * vgnameids_to_process ,
struct dm_list * arg_vgnames ,
struct dm_list * arg_tags , void * handle ,
process_single_vg_fn_t process_single_vg )
{
struct volume_group * vg ;
struct vgnameid_list * vgnl ;
const char * vg_name ;
const char * vg_uuid ;
int ret_max = ECMD_PROCESSED ;
2014-11-15 00:00:35 +03:00
int ret ;
int skip ;
2014-10-03 23:47:19 +04:00
int process_all = 0 ;
/*
* If no VG names or tags were supplied , then process all VGs .
*/
if ( dm_list_empty ( arg_vgnames ) & & dm_list_empty ( arg_tags ) )
process_all = 1 ;
dm_list_iterate_items ( vgnl , vgnameids_to_process ) {
2014-11-14 12:50:31 +03:00
if ( sigint_caught ( ) )
return_ECMD_FAILED ;
2014-10-03 23:47:19 +04:00
vg_name = vgnl - > vg_name ;
vg_uuid = vgnl - > vgid ;
2014-11-15 00:00:35 +03:00
skip = 0 ;
2014-10-03 23:47:19 +04:00
vg = vg_read ( cmd , vg_name , vg_uuid , flags ) ;
2014-11-14 12:50:31 +03:00
if ( ignore_vg ( vg , vg_name , flags & READ_ALLOW_INCONSISTENT , & skip ) ) {
2014-10-03 23:47:19 +04:00
stack ;
2014-11-15 00:00:35 +03:00
ret_max = ECMD_FAILED ;
release_vg ( vg ) ;
continue ;
}
if ( skip ) {
release_vg ( vg ) ;
continue ;
2014-11-14 12:50:31 +03:00
}
2014-10-03 23:47:19 +04:00
2014-11-15 00:00:35 +03:00
/* Process this VG? */
if ( process_all | |
( ! dm_list_empty ( arg_vgnames ) & & str_list_match_item ( arg_vgnames , vg_name ) ) | |
( ! dm_list_empty ( arg_tags ) & & str_list_match_list ( arg_tags , & vg - > tags , NULL ) ) ) {
ret = process_single_vg ( cmd , vg_name , vg , handle ) ;
if ( ret ! = ECMD_PROCESSED )
stack ;
if ( ret > ret_max )
ret_max = ret ;
}
if ( vg_read_error ( vg ) )
release_vg ( vg ) ;
else
unlock_and_release_vg ( cmd , vg , vg_name ) ;
2014-10-03 23:47:19 +04:00
}
return ret_max ;
}
/*
* Copy the contents of a str_list of VG names to a name list , filling
* in the vgid with NULL ( unknown ) .
*/
2014-10-04 02:37:49 +04:00
static int _copy_str_to_vgnameid_list ( struct cmd_context * cmd , struct dm_list * sll ,
struct dm_list * vgnll )
2014-10-03 23:47:19 +04:00
{
const char * vgname ;
struct dm_str_list * sl ;
struct vgnameid_list * vgnl ;
dm_list_iterate_items ( sl , sll ) {
vgname = sl - > str ;
vgnl = dm_pool_alloc ( cmd - > mem , sizeof ( * vgnl ) ) ;
if ( ! vgnl ) {
2014-11-14 18:08:27 +03:00
log_error ( " vgnameid_list allocation failed. " ) ;
2014-10-03 23:47:19 +04:00
return ECMD_FAILED ;
}
vgnl - > vgid = NULL ;
vgnl - > vg_name = dm_pool_strdup ( cmd - > mem , vgname ) ;
dm_list_add ( vgnll , & vgnl - > list ) ;
}
return ECMD_PROCESSED ;
}
/*
* Call process_single_vg ( ) for each VG selected by the command line arguments .
*/
int process_each_vg ( struct cmd_context * cmd , int argc , char * * argv ,
uint32_t flags , void * handle ,
process_single_vg_fn_t process_single_vg )
{
struct dm_list arg_tags ; /* str_list */
struct dm_list arg_vgnames ; /* str_list */
struct dm_list vgnameids_on_system ; /* vgnameid_list */
struct dm_list vgnameids_to_process ; /* vgnameid_list */
int enable_all_vgs = ( cmd - > command - > flags & ALL_VGS_IS_DEFAULT ) ;
int ret ;
dm_list_init ( & arg_tags ) ;
dm_list_init ( & arg_vgnames ) ;
dm_list_init ( & vgnameids_on_system ) ;
dm_list_init ( & vgnameids_to_process ) ;
/*
* Find any VGs or tags explicitly provided on the command line .
*/
if ( ( ret = _get_arg_vgnames ( cmd , argc , argv , & arg_vgnames , & arg_tags ) ) ! = ECMD_PROCESSED ) {
stack ;
return ret ;
}
/*
* Obtain the complete list of VGs present on the system if it is needed because :
* any tags were supplied and need resolving ; or
* no VG names were given and the command defaults to processing all VGs .
*/
if ( ( ( dm_list_empty ( & arg_vgnames ) & & enable_all_vgs ) | | ! dm_list_empty ( & arg_tags ) ) & &
2014-10-07 03:53:56 +04:00
( ( ret = _get_vgnameids_on_system ( cmd , & vgnameids_on_system , NULL , 0 ) ) ! = ECMD_PROCESSED ) ) {
2014-10-03 23:47:19 +04:00
stack ;
return ret ;
}
if ( dm_list_empty ( & arg_vgnames ) & & dm_list_empty ( & vgnameids_on_system ) ) {
2014-10-04 02:37:49 +04:00
/* FIXME Should be log_print, but suppressed for reporting cmds */
2014-11-14 18:11:43 +03:00
log_verbose ( " No volume groups found. " ) ;
2014-10-03 23:47:19 +04:00
return ECMD_PROCESSED ;
}
/*
* If we obtained a full list of VGs on the system , we need to work through them all ;
* otherwise we can merely work through the VG names provided .
*/
if ( ! dm_list_empty ( & vgnameids_on_system ) )
dm_list_splice ( & vgnameids_to_process , & vgnameids_on_system ) ;
2014-10-04 02:37:49 +04:00
else if ( ( ret = _copy_str_to_vgnameid_list ( cmd , & arg_vgnames , & vgnameids_to_process ) ) ! = ECMD_PROCESSED ) {
2014-10-03 23:47:19 +04:00
stack ;
return ret ;
}
return _process_vgnameid_list ( cmd , flags , & vgnameids_to_process ,
& arg_vgnames , & arg_tags , handle , process_single_vg ) ;
}
2014-10-04 02:37:49 +04:00
int process_each_lv_in_vg ( struct cmd_context * cmd , struct volume_group * vg ,
struct dm_list * arg_lvnames , const struct dm_list * tags_in ,
2014-10-07 19:45:45 +04:00
int stop_on_error ,
2014-10-04 02:37:49 +04:00
void * handle , process_single_lv_fn_t process_single_lv )
{
int ret_max = ECMD_PROCESSED ;
int ret = 0 ;
unsigned process_all = 0 ;
unsigned tags_supplied = 0 ;
unsigned lvargs_supplied = 0 ;
struct lv_list * lvl ;
struct dm_str_list * sl ;
if ( ! vg_check_status ( vg , EXPORTED_VG ) )
return_ECMD_FAILED ;
if ( tags_in & & ! dm_list_empty ( tags_in ) )
tags_supplied = 1 ;
if ( arg_lvnames & & ! dm_list_empty ( arg_lvnames ) )
lvargs_supplied = 1 ;
/* Process all LVs in this VG if no restrictions given
* or if VG tags match . */
if ( ( ! tags_supplied & & ! lvargs_supplied ) | |
( tags_supplied & & str_list_match_list ( tags_in , & vg - > tags , NULL ) ) )
process_all = 1 ;
/*
* FIXME : In case of remove it goes through deleted entries ,
* but it works since entries are allocated from vg mem pool .
*/
dm_list_iterate_items ( lvl , & vg - > lvs ) {
2014-11-14 12:50:31 +03:00
if ( sigint_caught ( ) )
return_ECMD_FAILED ;
2014-10-04 02:37:49 +04:00
if ( lvl - > lv - > status & SNAPSHOT )
continue ;
/* Skip availability change for non-virt snaps when processing all LVs */
/* FIXME: pass process_all to process_single_lv() */
if ( process_all & & arg_count ( cmd , activate_ARG ) & &
lv_is_cow ( lvl - > lv ) & & ! lv_is_virtual_origin ( origin_from_cow ( lvl - > lv ) ) )
continue ;
if ( lv_is_virtual_origin ( lvl - > lv ) & & ! arg_count ( cmd , all_ARG ) ) {
if ( lvargs_supplied & &
str_list_match_item ( arg_lvnames , lvl - > lv - > name ) )
log_print_unless_silent ( " Ignoring virtual origin logical volume %s. " ,
display_lvname ( lvl - > lv ) ) ;
continue ;
}
/*
* Only let hidden LVs through it - - all was used or the LVs
* were specifically named on the command line .
*/
if ( ! lvargs_supplied & & ! lv_is_visible ( lvl - > lv ) & & ! arg_count ( cmd , all_ARG ) )
continue ;
/* Only process the LV if the name matches or process_all is set or if an LV tag matches */
if ( lvargs_supplied & & str_list_match_item ( arg_lvnames , lvl - > lv - > name ) )
/* Remove LV from list of unprocessed LV names */
str_list_del ( arg_lvnames , lvl - > lv - > name ) ;
else if ( ! process_all & &
( ! tags_supplied | | ! str_list_match_list ( tags_in , & lvl - > lv - > tags , NULL ) ) )
continue ;
2014-11-14 18:08:27 +03:00
log_very_verbose ( " Processing LV %s in VG %s. " , lvl - > lv - > name , vg - > name ) ;
2014-10-04 02:37:49 +04:00
2014-11-15 00:00:35 +03:00
ret = process_single_lv ( cmd , lvl - > lv , handle ) ;
if ( ret ! = ECMD_PROCESSED )
2014-11-14 12:50:31 +03:00
stack ;
2014-10-04 02:37:49 +04:00
if ( ret > ret_max )
ret_max = ret ;
2014-10-07 19:45:45 +04:00
if ( stop_on_error & & ret ! = ECMD_PROCESSED )
return ret_max ;
2014-10-04 02:37:49 +04:00
}
if ( lvargs_supplied ) {
/*
* FIXME : lvm supports removal of LV with all its dependencies
* this leads to miscalculation that depends on the order of args .
*/
dm_list_iterate_items ( sl , arg_lvnames ) {
log_error ( " Failed to find logical volume \" %s/%s \" " ,
vg - > name , sl - > str ) ;
if ( ret_max < ECMD_FAILED )
ret_max = ECMD_FAILED ;
}
}
return ret_max ;
}
/*
* If arg is tag , add it to arg_tags
* else the arg is either vgname or vgname / lvname :
* - add the vgname of each arg to arg_vgnames
* - if arg has no lvname , add just vgname arg_lvnames ,
* it represents all lvs in the vg
* - if arg has lvname , add vgname / lvname to arg_lvnames
*/
static int _get_arg_lvnames ( struct cmd_context * cmd ,
int argc , char * * argv ,
struct dm_list * arg_vgnames ,
struct dm_list * arg_lvnames ,
struct dm_list * arg_tags )
{
int opt = 0 ;
int ret_max = ECMD_PROCESSED ;
char * vglv ;
size_t vglv_sz ;
const char * vgname ;
const char * lv_name ;
const char * tmp_lv_name ;
2014-10-06 18:22:01 +04:00
const char * vgname_def ;
2014-10-04 02:37:49 +04:00
unsigned dev_dir_found ;
2014-11-14 18:08:27 +03:00
log_verbose ( " Using logical volume(s) on command line. " ) ;
2014-10-04 02:37:49 +04:00
for ( ; opt < argc ; opt + + ) {
lv_name = argv [ opt ] ;
dev_dir_found = 0 ;
/* Do we have a tag or vgname or lvname? */
vgname = lv_name ;
if ( * vgname = = ' @ ' ) {
if ( ! validate_tag ( vgname + 1 ) ) {
2014-11-14 18:08:27 +03:00
log_error ( " Skipping invalid tag %s. " , vgname ) ;
2014-10-04 02:37:49 +04:00
continue ;
}
if ( ! str_list_add ( cmd - > mem , arg_tags ,
dm_pool_strdup ( cmd - > mem , vgname + 1 ) ) ) {
2014-11-14 18:08:27 +03:00
log_error ( " strlist allocation failed. " ) ;
2014-10-04 02:37:49 +04:00
return ECMD_FAILED ;
}
continue ;
}
/* FIXME Jumbled parsing */
vgname = skip_dev_dir ( cmd , vgname , & dev_dir_found ) ;
if ( * vgname = = ' / ' ) {
2014-11-14 18:08:27 +03:00
log_error ( " \" %s \" : Invalid path for Logical Volume. " ,
2014-10-04 02:37:49 +04:00
argv [ opt ] ) ;
if ( ret_max < ECMD_FAILED )
ret_max = ECMD_FAILED ;
continue ;
}
lv_name = vgname ;
if ( ( tmp_lv_name = strchr ( vgname , ' / ' ) ) ) {
/* Must be an LV */
lv_name = tmp_lv_name ;
while ( * lv_name = = ' / ' )
lv_name + + ;
if ( ! ( vgname = extract_vgname ( cmd , vgname ) ) ) {
if ( ret_max < ECMD_FAILED ) {
stack ;
ret_max = ECMD_FAILED ;
}
continue ;
}
} else if ( ! dev_dir_found & &
2014-10-06 18:22:01 +04:00
( vgname_def = _default_vgname ( cmd ) ) )
2014-10-04 02:37:49 +04:00
vgname = vgname_def ;
else
lv_name = NULL ;
if ( ! str_list_add ( cmd - > mem , arg_vgnames ,
dm_pool_strdup ( cmd - > mem , vgname ) ) ) {
2014-11-14 18:08:27 +03:00
log_error ( " strlist allocation failed. " ) ;
2014-10-04 02:37:49 +04:00
return ECMD_FAILED ;
}
if ( ! lv_name ) {
if ( ! str_list_add ( cmd - > mem , arg_lvnames ,
dm_pool_strdup ( cmd - > mem , vgname ) ) ) {
2014-11-14 18:08:27 +03:00
log_error ( " strlist allocation failed. " ) ;
2014-10-04 02:37:49 +04:00
return ECMD_FAILED ;
}
} else {
vglv_sz = strlen ( vgname ) + strlen ( lv_name ) + 2 ;
if ( ! ( vglv = dm_pool_alloc ( cmd - > mem , vglv_sz ) ) | |
dm_snprintf ( vglv , vglv_sz , " %s/%s " , vgname , lv_name ) < 0 ) {
2014-11-14 18:08:27 +03:00
log_error ( " vg/lv string alloc failed. " ) ;
2014-10-04 02:37:49 +04:00
return ECMD_FAILED ;
}
if ( ! str_list_add ( cmd - > mem , arg_lvnames , vglv ) ) {
2014-11-14 18:08:27 +03:00
log_error ( " strlist allocation failed. " ) ;
2014-10-04 02:37:49 +04:00
return ECMD_FAILED ;
}
}
}
return ret_max ;
}
static int _process_lv_vgnameid_list ( struct cmd_context * cmd , uint32_t flags ,
struct dm_list * vgnameids_to_process ,
struct dm_list * arg_vgnames ,
struct dm_list * arg_lvnames ,
struct dm_list * arg_tags ,
void * handle ,
process_single_lv_fn_t process_single_lv )
{
struct volume_group * vg ;
2014-10-07 01:02:00 +04:00
struct vgnameid_list * vgnl ;
2014-10-04 02:37:49 +04:00
struct dm_str_list * sl ;
struct dm_list * tags_arg ;
struct dm_list lvnames ;
const char * vg_name ;
const char * vg_uuid ;
const char * vgn ;
const char * lvn ;
int ret_max = ECMD_PROCESSED ;
int ret ;
2014-11-14 12:50:31 +03:00
int skip ;
2014-10-04 02:37:49 +04:00
2014-10-07 01:02:00 +04:00
dm_list_iterate_items ( vgnl , vgnameids_to_process ) {
2014-11-14 12:50:31 +03:00
if ( sigint_caught ( ) )
return_ECMD_FAILED ;
2014-10-07 01:02:00 +04:00
vg_name = vgnl - > vg_name ;
vg_uuid = vgnl - > vgid ;
2014-11-15 00:00:35 +03:00
skip = 0 ;
2014-10-04 02:37:49 +04:00
/*
* arg_lvnames contains some elements that are just " vgname "
* which means process all lvs in the vg . Other elements
* are " vgname/lvname " which means process only the select
* lvs in the vg .
*/
tags_arg = arg_tags ;
dm_list_init ( & lvnames ) ; /* LVs to be processed in this VG */
dm_list_iterate_items ( sl , arg_lvnames ) {
vgn = sl - > str ;
lvn = strchr ( vgn , ' / ' ) ;
if ( ! lvn & & ! strcmp ( vgn , vg_name ) ) {
/* Process all LVs in this VG */
tags_arg = NULL ;
dm_list_init ( & lvnames ) ;
break ;
}
if ( lvn & & ! strncmp ( vgn , vg_name , strlen ( vg_name ) ) & &
strlen ( vg_name ) = = ( size_t ) ( lvn - vgn ) ) {
if ( ! str_list_add ( cmd - > mem , & lvnames ,
dm_pool_strdup ( cmd - > mem , lvn + 1 ) ) ) {
2014-11-14 18:08:27 +03:00
log_error ( " strlist allocation failed. " ) ;
2014-10-04 02:37:49 +04:00
return ECMD_FAILED ;
}
}
}
vg = vg_read ( cmd , vg_name , vg_uuid , flags ) ;
2014-11-14 12:50:31 +03:00
if ( ignore_vg ( vg , vg_name , flags & READ_ALLOW_INCONSISTENT , & skip ) ) {
2014-10-04 02:37:49 +04:00
stack ;
2014-11-15 00:00:35 +03:00
ret_max = ECMD_FAILED ;
release_vg ( vg ) ;
continue ;
}
if ( skip ) {
release_vg ( vg ) ;
continue ;
2014-10-04 02:37:49 +04:00
}
2014-11-15 00:00:35 +03:00
ret = process_each_lv_in_vg ( cmd , vg , & lvnames , tags_arg , 0 ,
handle , process_single_lv ) ;
if ( ret ! = ECMD_PROCESSED )
stack ;
2014-10-04 02:37:49 +04:00
if ( ret > ret_max )
ret_max = ret ;
2014-11-15 00:00:35 +03:00
unlock_and_release_vg ( cmd , vg , vg_name ) ;
2014-10-04 02:37:49 +04:00
}
return ret_max ;
}
/*
* Call process_single_lv ( ) for each LV selected by the command line arguments .
*/
int process_each_lv ( struct cmd_context * cmd , int argc , char * * argv , uint32_t flags ,
void * handle , process_single_lv_fn_t process_single_lv )
{
struct dm_list arg_tags ; /* str_list */
struct dm_list arg_vgnames ; /* str_list */
struct dm_list arg_lvnames ; /* str_list */
struct dm_list vgnameids_on_system ; /* vgnameid_list */
struct dm_list vgnameids_to_process ; /* vgnameid_list */
int enable_all_vgs = ( cmd - > command - > flags & ALL_VGS_IS_DEFAULT ) ;
int ret ;
dm_list_init ( & arg_tags ) ;
dm_list_init ( & arg_vgnames ) ;
dm_list_init ( & arg_lvnames ) ;
dm_list_init ( & vgnameids_on_system ) ;
dm_list_init ( & vgnameids_to_process ) ;
/*
* Find any LVs , VGs or tags explicitly provided on the command line .
*/
if ( ( ret = _get_arg_lvnames ( cmd , argc , argv , & arg_vgnames , & arg_lvnames , & arg_tags ) ! = ECMD_PROCESSED ) ) {
stack ;
return ret ;
}
/*
* Obtain the complete list of VGs present on the system if it is needed because :
* any tags were supplied and need resolving ; or
* no VG names were given and the command defaults to processing all VGs .
*/
if ( ( ( dm_list_empty ( & arg_vgnames ) & & enable_all_vgs ) | | ! dm_list_empty ( & arg_tags ) ) & &
2014-10-07 03:53:56 +04:00
( ret = _get_vgnameids_on_system ( cmd , & vgnameids_on_system , NULL , 0 ) ! = ECMD_PROCESSED ) ) {
2014-10-04 02:37:49 +04:00
stack ;
return ret ;
}
if ( dm_list_empty ( & arg_vgnames ) & & dm_list_empty ( & vgnameids_on_system ) ) {
/* FIXME Should be log_print, but suppressed for reporting cmds */
2014-11-14 18:11:43 +03:00
log_verbose ( " No volume groups found. " ) ;
2014-10-04 02:37:49 +04:00
return ECMD_PROCESSED ;
}
/*
* If we obtained a full list of VGs on the system , we need to work through them all ;
* otherwise we can merely work through the VG names provided .
*/
if ( ! dm_list_empty ( & vgnameids_on_system ) )
dm_list_splice ( & vgnameids_to_process , & vgnameids_on_system ) ;
else if ( ( ret = _copy_str_to_vgnameid_list ( cmd , & arg_vgnames , & vgnameids_to_process ) ) ! = ECMD_PROCESSED ) {
stack ;
return ret ;
}
return _process_lv_vgnameid_list ( cmd , flags , & vgnameids_to_process , & arg_vgnames , & arg_lvnames ,
& arg_tags , handle , process_single_lv ) ;
}
2014-10-07 01:02:00 +04:00
2014-10-07 03:34:04 +04:00
static int _get_arg_pvnames ( struct cmd_context * cmd ,
int argc , char * * argv ,
struct dm_list * arg_pvnames ,
struct dm_list * arg_tags )
2014-10-07 01:02:00 +04:00
{
2014-10-07 03:34:04 +04:00
int opt = 0 ;
char * at_sign , * tagname ;
char * arg_name ;
2014-10-07 01:02:00 +04:00
int ret_max = ECMD_PROCESSED ;
2014-11-14 18:08:27 +03:00
log_verbose ( " Using physical volume(s) on command line. " ) ;
2014-10-07 03:34:04 +04:00
for ( ; opt < argc ; opt + + ) {
arg_name = argv [ opt ] ;
dm_unescape_colons_and_at_signs ( arg_name , NULL , & at_sign ) ;
if ( at_sign & & ( at_sign = = arg_name ) ) {
tagname = at_sign + 1 ;
if ( ! validate_tag ( tagname ) ) {
2014-11-14 18:08:27 +03:00
log_error ( " Skipping invalid tag %s. " , tagname ) ;
2014-10-07 03:34:04 +04:00
if ( ret_max < EINVALID_CMD_LINE )
ret_max = EINVALID_CMD_LINE ;
continue ;
}
if ( ! str_list_add ( cmd - > mem , arg_tags ,
dm_pool_strdup ( cmd - > mem , tagname ) ) ) {
2014-11-14 18:08:27 +03:00
log_error ( " strlist allocation failed. " ) ;
2014-10-07 03:34:04 +04:00
return ECMD_FAILED ;
}
2014-10-07 01:02:00 +04:00
continue ;
}
2014-10-07 03:34:04 +04:00
if ( ! str_list_add ( cmd - > mem , arg_pvnames ,
dm_pool_strdup ( cmd - > mem , arg_name ) ) ) {
2014-11-14 18:08:27 +03:00
log_error ( " strlist allocation failed. " ) ;
2014-10-07 03:34:04 +04:00
return ECMD_FAILED ;
}
2014-10-07 01:02:00 +04:00
}
return ret_max ;
}
2014-10-07 03:34:04 +04:00
static int _get_all_devices ( struct cmd_context * cmd , struct dm_list * all_devices )
2014-10-07 01:02:00 +04:00
{
struct dev_iter * iter ;
struct device * dev ;
2014-10-07 03:34:04 +04:00
struct device_list * devl ;
2014-11-12 11:18:55 +03:00
int r = ECMD_FAILED ;
2014-10-07 01:02:00 +04:00
lvmcache_seed_infos_from_lvmetad ( cmd ) ;
if ( ! ( iter = dev_iter_create ( cmd - > filter , 1 ) ) ) {
2014-11-14 18:08:27 +03:00
log_error ( " dev_iter creation failed. " ) ;
2014-10-07 01:02:00 +04:00
return ECMD_FAILED ;
}
2014-10-07 03:34:04 +04:00
while ( ( dev = dev_iter_get ( iter ) ) ) {
if ( ! ( devl = dm_pool_alloc ( cmd - > mem , sizeof ( * devl ) ) ) ) {
2014-11-14 18:08:27 +03:00
log_error ( " device_list alloc failed. " ) ;
2014-11-12 11:18:55 +03:00
goto out ;
2014-10-07 01:02:00 +04:00
}
2014-10-07 03:34:04 +04:00
devl - > dev = dev ;
dm_list_add ( all_devices , & devl - > list ) ;
}
2014-11-12 11:18:55 +03:00
r = ECMD_PROCESSED ;
out :
2014-10-07 03:34:04 +04:00
dev_iter_destroy ( iter ) ;
2014-11-12 11:18:55 +03:00
return r ;
2014-10-07 03:34:04 +04:00
}
static int _device_list_remove ( struct dm_list * all_devices , struct device * dev )
{
struct device_list * devl ;
dm_list_iterate_items ( devl , all_devices ) {
if ( devl - > dev = = dev ) {
dm_list_del ( & devl - > list ) ;
return 1 ;
}
}
return 0 ;
}
static int _process_device_list ( struct cmd_context * cmd , struct dm_list * all_devices ,
void * handle , process_single_pv_fn_t process_single_pv )
{
struct physical_volume pv_dummy ;
struct physical_volume * pv ;
struct device_list * devl ;
int ret_max = ECMD_PROCESSED ;
int ret = 0 ;
/*
* Pretend that each device is a PV with dummy values .
* FIXME Formalise this extension or find an alternative .
*/
dm_list_iterate_items ( devl , all_devices ) {
2014-11-14 12:50:31 +03:00
if ( sigint_caught ( ) )
return_ECMD_FAILED ;
2014-10-07 01:02:00 +04:00
memset ( & pv_dummy , 0 , sizeof ( pv_dummy ) ) ;
dm_list_init ( & pv_dummy . tags ) ;
dm_list_init ( & pv_dummy . segments ) ;
2014-10-07 03:34:04 +04:00
pv_dummy . dev = devl - > dev ;
2014-10-07 01:02:00 +04:00
pv = & pv_dummy ;
2014-11-14 18:08:27 +03:00
log_very_verbose ( " Processing device %s. " , dev_name ( devl - > dev ) ) ;
2014-10-07 01:02:00 +04:00
ret = process_single_pv ( cmd , NULL , pv , handle ) ;
if ( ret > ret_max )
ret_max = ret ;
}
2014-10-07 03:34:04 +04:00
return ECMD_PROCESSED ;
}
static int _process_pvs_in_vg ( struct cmd_context * cmd ,
struct volume_group * vg ,
struct dm_list * all_devices ,
struct dm_list * arg_pvnames ,
struct dm_list * arg_tags ,
int process_all ,
int skip ,
void * handle ,
process_single_pv_fn_t process_single_pv )
{
struct physical_volume * pv ;
struct pv_list * pvl ;
const char * pv_name ;
int process_pv ;
int dev_found ;
int ret_max = ECMD_PROCESSED ;
int ret = 0 ;
dm_list_iterate_items ( pvl , & vg - > pvs ) {
2014-11-14 12:50:31 +03:00
if ( sigint_caught ( ) )
return_ECMD_FAILED ;
2014-10-07 03:34:04 +04:00
pv = pvl - > pv ;
pv_name = pv_dev_name ( pv ) ;
process_pv = process_all ;
/* Remove each pvname as it is processed. */
if ( ! process_pv & & ! dm_list_empty ( arg_pvnames ) & &
str_list_match_item ( arg_pvnames , pv_name ) ) {
process_pv = 1 ;
str_list_del ( arg_pvnames , pv_name ) ;
}
if ( ! process_pv & & ! dm_list_empty ( arg_tags ) & &
str_list_match_list ( arg_tags , & pv - > tags , NULL ) )
process_pv = 1 ;
if ( process_pv ) {
if ( skip )
2014-11-14 18:08:27 +03:00
log_verbose ( " Skipping PV %s in VG %s. " , pv_name , vg - > name ) ;
2014-10-07 03:34:04 +04:00
else
2014-11-14 18:08:27 +03:00
log_very_verbose ( " Processing PV %s in VG %s. " , pv_name , vg - > name ) ;
2014-10-07 03:34:04 +04:00
dev_found = _device_list_remove ( all_devices , pv - > dev ) ;
/*
* FIXME PVs with no mdas may turn up in an orphan VG when
* not using lvmetad as well as their correct VG . They
* will be missing from all_devices the second time
* around but must not be processed twice or trigger a message .
*
* Missing PVs will also need processing even though they are
* not present in all_devices .
*/
if ( ! dev_found & & ! is_missing_pv ( pv ) ) {
2014-11-14 18:08:27 +03:00
log_verbose ( " Skipping PV %s in VG %s: not in device list. " , pv_name , vg - > name ) ;
2014-10-07 03:34:04 +04:00
continue ;
}
2014-11-14 12:50:31 +03:00
if ( ! skip ) {
2014-11-15 00:00:35 +03:00
ret = process_single_pv ( cmd , vg , pv , handle ) ;
if ( ret ! = ECMD_PROCESSED )
2014-11-14 12:50:31 +03:00
stack ;
if ( ret > ret_max )
ret_max = ret ;
}
2014-10-07 03:34:04 +04:00
}
/*
* When processing only specific PV names , we can quit
* once they ' ve all been found .
*/
if ( ! process_all & & dm_list_empty ( arg_tags ) & & dm_list_empty ( arg_pvnames ) )
break ;
}
2014-10-07 01:02:00 +04:00
return ret_max ;
}
/*
2014-10-07 03:34:04 +04:00
* Iterate through all PVs in each listed VG . Process a PV if
* the name or tag matches arg_pvnames or arg_tags . If both
* arg_pvnames and arg_tags are empty , then process all PVs .
* No PV should be processed more than once .
*
* Each PV is removed from arg_pvnames and all_devices when it is
* processed . Any names remaining in arg_pvnames were not found , and
* should produce an error . Any devices remaining in all_devices were
* not found and should be processed by process_all_devices ( ) .
2014-10-07 01:02:00 +04:00
*/
2014-10-07 03:34:04 +04:00
static int _process_pvs_in_vgs ( struct cmd_context * cmd , uint32_t flags ,
struct dm_list * all_vgnameids ,
struct dm_list * all_devices ,
struct dm_list * arg_pvnames ,
struct dm_list * arg_tags ,
int process_all ,
void * handle ,
process_single_pv_fn_t process_single_pv )
2014-10-07 01:02:00 +04:00
{
2014-10-07 03:34:04 +04:00
struct volume_group * vg ;
struct vgnameid_list * vgnl ;
struct dm_str_list * sl ;
const char * vg_name ;
const char * vg_uuid ;
2014-10-07 01:02:00 +04:00
int ret_max = ECMD_PROCESSED ;
int ret ;
2014-11-15 00:00:35 +03:00
int skip ;
2014-10-07 01:02:00 +04:00
2014-10-07 03:34:04 +04:00
dm_list_iterate_items ( vgnl , all_vgnameids ) {
2014-11-14 12:50:31 +03:00
if ( sigint_caught ( ) )
return_ECMD_FAILED ;
2014-10-07 03:34:04 +04:00
vg_name = vgnl - > vg_name ;
vg_uuid = vgnl - > vgid ;
2014-11-15 00:00:35 +03:00
skip = 0 ;
2014-10-07 01:02:00 +04:00
2014-10-07 04:04:09 +04:00
vg = vg_read ( cmd , vg_name , vg_uuid , flags | READ_WARN_INCONSISTENT ) ;
2014-11-14 12:50:31 +03:00
if ( ignore_vg ( vg , vg_name , flags & READ_ALLOW_INCONSISTENT , & skip ) ) {
stack ;
2014-11-18 18:22:37 +03:00
ret_max = ECMD_FAILED ;
2014-11-20 10:52:44 +03:00
release_vg ( vg ) ;
2014-11-18 18:22:37 +03:00
continue ;
2014-11-15 00:00:35 +03:00
}
2014-11-18 18:22:37 +03:00
/*
* Don ' t continue when skip is set , because we need to remove
* vg - > pvs entries from devices list .
*/
2014-11-15 00:00:35 +03:00
ret = _process_pvs_in_vg ( cmd , vg , all_devices , arg_pvnames , arg_tags ,
process_all , skip , handle , process_single_pv ) ;
if ( ret ! = ECMD_PROCESSED )
stack ;
2014-11-18 18:22:37 +03:00
if ( ret > ret_max )
2014-10-07 03:34:04 +04:00
ret_max = ret ;
2014-11-18 18:22:37 +03:00
if ( skip )
release_vg ( vg ) ;
else
unlock_and_release_vg ( cmd , vg , vg - > name ) ;
2014-11-15 00:00:35 +03:00
2014-10-07 03:34:04 +04:00
/* Quit early when possible. */
if ( ! process_all & & dm_list_empty ( arg_tags ) & & dm_list_empty ( arg_pvnames ) )
return ret_max ;
2014-10-07 01:02:00 +04:00
}
2014-10-07 03:34:04 +04:00
/* Return an error if a pvname arg was not found. */
dm_list_iterate_items ( sl , arg_pvnames ) {
2014-11-14 18:08:27 +03:00
log_error ( " Failed to find physical volume \" %s \" . " , sl - > str ) ;
2014-10-07 03:34:04 +04:00
ret_max = ECMD_FAILED ;
}
2014-10-07 01:02:00 +04:00
2014-10-07 03:34:04 +04:00
return ret_max ;
}
2014-10-07 01:02:00 +04:00
2014-10-07 03:34:04 +04:00
int process_each_pv ( struct cmd_context * cmd ,
int argc , char * * argv ,
2014-10-07 03:53:56 +04:00
const char * only_this_vgname ,
2014-10-07 03:34:04 +04:00
uint32_t flags ,
void * handle ,
process_single_pv_fn_t process_single_pv )
{
2014-10-07 03:53:56 +04:00
struct dm_list arg_tags ; /* str_list */
struct dm_list arg_pvnames ; /* str_list */
struct dm_list all_vgnameids ; /* vgnameid_list */
struct dm_list all_devices ; /* device_list */
2014-10-07 03:34:04 +04:00
int process_all_pvs ;
int process_all_devices ;
2014-11-15 00:00:35 +03:00
int ret_max = ECMD_PROCESSED ;
2014-10-07 03:34:04 +04:00
int ret ;
2014-10-07 01:02:00 +04:00
2014-10-07 03:34:04 +04:00
dm_list_init ( & arg_tags ) ;
dm_list_init ( & arg_pvnames ) ;
dm_list_init ( & all_vgnameids ) ;
dm_list_init ( & all_devices ) ;
2014-10-07 01:02:00 +04:00
2014-10-07 03:34:04 +04:00
/*
* Create two lists from argv :
* arg_pvnames : pvs explicitly named in argv
* arg_tags : tags explicitly named in argv
*/
if ( ( ret = _get_arg_pvnames ( cmd , argc , argv , & arg_pvnames , & arg_tags ) ) ! = ECMD_PROCESSED )
return ret ;
2014-10-07 01:02:00 +04:00
2014-10-07 03:34:04 +04:00
process_all_pvs = dm_list_empty ( & arg_pvnames ) & & dm_list_empty ( & arg_tags ) ;
2014-10-07 01:02:00 +04:00
2014-10-07 03:34:04 +04:00
process_all_devices = process_all_pvs & &
( cmd - > command - > flags & ENABLE_ALL_DEVS ) & &
arg_count ( cmd , all_ARG ) ;
2014-10-07 01:02:00 +04:00
2014-10-07 03:34:04 +04:00
/*
* If the caller wants to process all devices ( not just PVs ) , then all PVs
* from all VGs are processed first , removing them from all_devices . Then
* any devs remaining in all_devices are processed .
*/
if ( ( ret = _get_all_devices ( cmd , & all_devices ) ! = ECMD_PROCESSED ) ) {
stack ;
return ret ;
}
2014-10-07 01:02:00 +04:00
2014-10-07 03:53:56 +04:00
if ( ( ret = _get_vgnameids_on_system ( cmd , & all_vgnameids , only_this_vgname , 1 ) ! = ECMD_PROCESSED ) ) {
2014-10-07 03:34:04 +04:00
stack ;
return ret ;
2014-10-07 01:02:00 +04:00
}
2014-11-15 00:00:35 +03:00
ret = _process_pvs_in_vgs ( cmd , flags , & all_vgnameids , & all_devices ,
& arg_pvnames , & arg_tags , process_all_pvs ,
handle , process_single_pv ) ;
if ( ret ! = ECMD_PROCESSED )
2014-11-14 12:50:31 +03:00
stack ;
2014-11-15 00:00:35 +03:00
if ( ret > ret_max )
ret_max = ret ;
2014-10-07 03:34:04 +04:00
2014-11-15 00:00:35 +03:00
if ( ! process_all_devices )
goto out ;
2014-10-07 03:34:04 +04:00
2014-11-15 00:00:35 +03:00
ret = _process_device_list ( cmd , & all_devices , handle , process_single_pv ) ;
if ( ret ! = ECMD_PROCESSED )
stack ;
if ( ret > ret_max )
ret_max = ret ;
out :
2014-10-07 01:02:00 +04:00
return ret_max ;
2014-10-07 03:34:04 +04:00
}
int process_each_pv_in_vg ( struct cmd_context * cmd , struct volume_group * vg ,
void * handle , process_single_pv_fn_t process_single_pv )
{
int ret_max = ECMD_PROCESSED ;
int ret ;
struct pv_list * pvl ;
2014-10-07 01:02:00 +04:00
2014-10-07 03:34:04 +04:00
dm_list_iterate_items ( pvl , & vg - > pvs ) {
if ( sigint_caught ( ) )
return_ECMD_FAILED ;
2014-11-14 21:32:03 +03:00
2014-11-15 00:00:35 +03:00
ret = process_single_pv ( cmd , vg , pvl - > pv , handle ) ;
if ( ret ! = ECMD_PROCESSED )
stack ;
2014-11-14 21:32:03 +03:00
if ( ret > ret_max )
2014-10-07 03:34:04 +04:00
ret_max = ret ;
}
return ret_max ;
2014-10-07 01:02:00 +04:00
}
2014-10-07 19:45:45 +04:00
int lvremove_single ( struct cmd_context * cmd , struct logical_volume * lv ,
void * handle __attribute__ ( ( unused ) ) )
{
/*
* Single force is equivalent to single - - yes
* Even multiple - - yes are equivalent to single - - force
* When we require - ff it cannot be replaced with - f - y
*/
force_t force = ( force_t ) arg_count ( cmd , force_ARG )
? : ( arg_is_set ( cmd , yes_ARG ) ? DONT_PROMPT : PROMPT ) ;
if ( ! lv_remove_with_dependencies ( cmd , lv , force , 0 ) )
return_ECMD_FAILED ;
return ECMD_PROCESSED ;
}