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 .
2015-04-29 17:25:50 +03:00
* Copyright ( C ) 2004 - 2015 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>
2014-10-24 21:29:04 +04:00
# include <sys/utsname.h>
2002-01-01 00:27:39 +03:00
2015-01-09 23:55:16 +03:00
struct device_id_list {
struct dm_list list ;
struct device * dev ;
char pvid [ ID_LEN + 1 ] ;
} ;
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 ) ) ;
2015-04-13 17:29:15 +03:00
lvmetad_disconnect ( ) ;
2013-09-03 18:06:16 +04:00
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 */
2014-11-26 19:09:47 +03:00
if ( ! strncmp ( vg_name , dmdir , dmdir_len ) & & vg_name [ dmdir_len ] = = ' / ' ) {
vg_name + = dmdir_len + 1 ;
2014-09-28 14:54:20 +04:00
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 .
2015-03-19 02:31:46 +03:00
* If * skip is 1 , it ' s OK for the caller to read the list of PVs in the VG .
2013-10-02 00:20:10 +04:00
*/
2015-02-13 20:01:55 +03:00
static int _ignore_vg ( struct volume_group * vg , const char * vg_name ,
struct dm_list * arg_vgnames , 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-10-24 21:29:04 +04:00
/*
* Commands that operate on " all vgs " shouldn ' t be bothered by
* skipping a foreign VG , and the command shouldn ' t fail when
* one is skipped . But , if the command explicitly asked to
* operate on a foreign VG and it ' s skipped , then the command
* would expect to fail .
*/
if ( read_error & FAILED_SYSTEMID ) {
if ( arg_vgnames & & str_list_match_item ( arg_vgnames , vg - > name ) ) {
2015-03-04 04:00:51 +03:00
log_error ( " Cannot access VG %s with system ID %s with %slocal system ID%s%s. " ,
vg - > name , vg - > system_id , vg - > cmd - > system_id ? " " : " unknown " ,
vg - > cmd - > system_id ? " " : " " , vg - > cmd - > system_id ? vg - > cmd - > system_id : " " ) ;
2014-10-24 21:29:04 +04:00
return 1 ;
} else {
read_error & = ~ FAILED_SYSTEMID ; /* Check for other errors */
2015-02-24 02:19:36 +03:00
log_verbose ( " Skipping foreign volume group %s " , vg_name ) ;
2014-10-24 21:29:04 +04:00
* skip = 1 ;
}
}
2015-05-08 23:58:00 +03:00
if ( read_error = = FAILED_CLUSTERED ) {
2015-03-19 02:31:46 +03:00
* skip = 1 ;
stack ; /* Error already logged */
return 1 ;
}
2014-11-14 12:50:31 +03:00
if ( read_error ! = SUCCESS ) {
2015-03-19 02:31:46 +03:00
* skip = 0 ;
2014-11-14 12:50:31 +03:00
log_error ( " Cannot process volume group %s " , vg_name ) ;
return 1 ;
}
return 0 ;
2013-10-02 00:20:10 +04:00
}
2014-12-03 16:20:00 +03:00
/*
* This functiona updates the " selected " arg only if last item processed
* is selected so this implements the " whole structure is selected if
* at least one of its items is selected " .
*/
static void _update_selection_result ( struct processing_handle * handle , int * selected )
{
if ( ! handle | | ! handle - > selection_handle )
return ;
if ( handle - > selection_handle - > selected )
* selected = 1 ;
}
static void _set_final_selection_result ( struct processing_handle * handle , int selected )
{
if ( ! handle | | ! handle - > selection_handle )
return ;
handle - > selection_handle - > selected = selected ;
}
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 ,
2014-11-27 17:02:13 +03:00
struct processing_handle * 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 ;
2014-12-03 16:20:00 +03:00
int whole_selected = 0 ;
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 ) ;
2014-12-03 16:20:00 +03:00
_update_selection_result ( handle , & whole_selected ) ;
2014-11-15 00:00:35 +03:00
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
2014-12-03 16:20:00 +03:00
/* the PV is selected if at least one PV segment is selected */
_set_final_selection_result ( handle , whole_selected ) ;
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 ,
2014-11-27 17:02:13 +03:00
struct processing_handle * 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 ;
2014-12-03 16:20:00 +03:00
int whole_selected = 0 ;
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 ) ;
2014-12-03 16:20:00 +03:00
_update_selection_result ( handle , & whole_selected ) ;
2014-11-15 00:00:35 +03:00
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 ;
}
2014-12-03 16:20:00 +03:00
/* the LV is selected if at least one LV segment is selected */
_set_final_selection_result ( handle , whole_selected ) ;
2002-12-12 23:55:49 +03:00
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 ;
2015-02-24 02:19:36 +03:00
/* Only vgsplit sets vg */
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 ;
2015-02-24 02:19:36 +03:00
vp_def - > system_id = vg - > system_id ; /* No need to clone this */
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 ;
2015-02-24 02:19:36 +03:00
vp_def - > system_id = cmd - > system_id ;
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
{
2015-02-24 02:19:36 +03:00
const char * system_id_arg_str ;
2014-10-24 21:29:04 +04: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
}
2015-02-24 02:19:36 +03: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 ) ;
2015-02-24 02:19:36 +03:00
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 ) ;
2015-02-24 02:19:36 +03:00
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
2015-02-24 02:19:36 +03:00
/* A clustered VG has no system ID. */
if ( vp_new - > clustered ) {
if ( arg_is_set ( cmd , systemid_ARG ) ) {
2015-02-27 22:32:00 +03:00
log_error ( " system ID cannot be set on clustered Volume Groups. " ) ;
2015-02-24 02:19:36 +03:00
return 0 ;
}
vp_new - > system_id = NULL ;
} else if ( ! ( system_id_arg_str = arg_str_value ( cmd , systemid_ARG , NULL ) ) )
2014-10-24 21:29:04 +04:00
vp_new - > system_id = vp_def - > system_id ;
2015-02-24 02:19:36 +03:00
else {
if ( ! ( vp_new - > system_id = system_id_from_string ( cmd , system_id_arg_str ) ) )
return_0 ;
2014-10-24 21:29:04 +04:00
2015-02-24 02:19:36 +03:00
/* FIXME Take local/extra_system_ids into account */
2014-10-24 21:29:04 +04:00
if ( vp_new - > system_id & & cmd - > system_id & &
2015-02-25 17:12:24 +03:00
strcmp ( vp_new - > system_id , cmd - > system_id ) ) {
if ( * vp_new - > system_id )
2015-02-27 22:32:00 +03:00
log_warn ( " VG with system ID %s might become inaccessible as local system ID is %s " ,
2015-02-25 17:12:24 +03:00
vp_new - > system_id , cmd - > system_id ) ;
else
2015-02-25 17:17:35 +03:00
log_warn ( " WARNING: A VG without a system ID allows unsafe access from other hosts. " ) ;
2015-02-25 17:12:24 +03:00
}
2014-10-24 21:29:04 +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
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 ;
2015-04-29 17:25:50 +03:00
const struct logical_volume * lv_mirr = NULL ;
2009-09-30 00:22:35 +04:00
2015-04-29 17:25:50 +03:00
if ( lv_is_pvmove ( lv ) )
lv_mirr = lv ;
else if ( lv_is_locked ( lv ) )
lv_mirr = find_pvmove_lv_in_lv ( lv ) ;
if ( lv_mirr & &
( pvname = get_pvmove_pvname_from_lv_mirr ( lv_mirr ) ) ) {
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 ) ;
2015-04-10 15:08:19 +03:00
pvmove_poll ( cmd , pvname , lv_mirr - > lvid . s , lv_mirr - > vg - > name , lv_mirr - > name , 1 ) ;
2009-09-30 00:22:35 +04:00
}
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. " ,
2015-04-29 17:25:50 +03:00
lv - > name ) ;
2009-09-30 00:22:35 +04:00
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
*/
2015-02-13 17:58:51 +03:00
int pvcreate_params_validate ( struct cmd_context * cmd , int argc ,
2009-10-06 00:03:54 +04:00
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
}
2014-11-23 00:39:56 +03:00
if ( ! ( result = dm_config_flatten ( current ) ) )
goto_out ;
2014-11-20 13:30:19 +03:00
2015-02-24 13:36:30 +03:00
if ( result - > root ) {
if ( ! ( cn = dm_config_create_node ( result , " policy_settings " ) ) )
goto_out ;
2014-11-20 13:30:19 +03:00
2015-02-24 13:36:30 +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 ;
2015-02-24 13:36:30 +03:00
cn - > sib = result - > root ;
result - > root = cn ;
2014-11-20 13:30:19 +03:00
if ( ! ( cn - > v = dm_config_create_value ( result ) ) )
goto_out ;
2014-11-27 22:19:28 +03:00
cn - > v - > type = DM_CFG_STRING ;
2014-11-20 13:30:19 +03:00
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 :
2014-11-26 13:46:13 +03:00
if ( ! ok & & result ) {
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
2014-11-27 17:02:13 +03:00
int process_each_label ( struct cmd_context * cmd , int argc , char * * argv ,
struct processing_handle * handle ,
2013-07-29 20:51:27 +04:00
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
/*
* 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 ,
2015-02-13 17:58:51 +03:00
unsigned one_vgname_arg ,
2014-10-03 23:47:19 +04:00
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 ] ;
2015-02-13 17:58:51 +03:00
2014-10-03 23:47:19 +04:00
if ( * vg_name = = ' @ ' ) {
2015-02-13 17:58:51 +03:00
if ( one_vgname_arg ) {
log_error ( " This command does not yet support a tag to identify a Volume Group. " ) ;
return EINVALID_CMD_LINE ;
}
2014-10-03 23:47:19 +04:00
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 ;
}
2015-02-13 17:58:51 +03:00
2014-10-03 23:47:19 +04:00
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 ;
}
2015-02-13 17:58:51 +03:00
2014-10-03 23:47:19 +04:00
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 ;
2015-02-13 17:58:51 +03:00
if ( one_vgname_arg )
break ;
2014-10-03 23:47:19 +04:00
continue ;
}
2015-02-13 17:58:51 +03:00
2014-10-03 23:47:19 +04:00
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 ;
}
2015-02-13 17:58:51 +03:00
if ( one_vgname_arg )
break ;
2014-10-03 23:47:19 +04:00
}
return ret_max ;
}
2014-11-28 16:46:18 +03:00
struct processing_handle * init_processing_handle ( struct cmd_context * cmd )
{
struct processing_handle * handle ;
if ( ! ( handle = dm_pool_zalloc ( cmd - > mem , sizeof ( struct processing_handle ) ) ) ) {
log_error ( " _init_processing_handle: failed to allocate memory for processing handle " ) ;
return NULL ;
}
/*
* For any reporting tool , the internal_report_for_select is reset to 0
* automatically because the internal reporting / selection is simply not
* needed - the reporting / selection is already a part of the code path
* used there .
*
* * The internal report for select is only needed for non - reporting tools ! *
*/
handle - > internal_report_for_select = arg_is_set ( cmd , select_ARG ) ;
return handle ;
}
2015-02-10 15:46:37 +03:00
int init_selection_handle ( struct cmd_context * cmd , struct processing_handle * handle ,
report_type_t initial_report_type )
2014-11-28 16:46:18 +03:00
{
struct selection_handle * sh ;
if ( ! ( sh = dm_pool_zalloc ( cmd - > mem , sizeof ( struct selection_handle ) ) ) ) {
log_error ( " _init_selection_handle: failed to allocate memory for selection handle " ) ;
return 0 ;
}
2015-02-10 15:46:37 +03:00
sh - > report_type = initial_report_type ;
2014-11-28 16:46:18 +03:00
if ( ! ( sh - > selection_rh = report_init_for_selection ( cmd , & sh - > report_type ,
arg_str_value ( cmd , select_ARG , NULL ) ) ) ) {
dm_pool_free ( cmd - > mem , sh ) ;
return_0 ;
}
handle - > selection_handle = sh ;
return 1 ;
}
2015-02-13 12:42:21 +03:00
void destroy_processing_handle ( struct cmd_context * cmd , struct processing_handle * handle )
2014-11-28 16:46:18 +03:00
{
if ( handle ) {
if ( handle - > selection_handle & & handle - > selection_handle - > selection_rh )
dm_report_free ( handle - > selection_handle - > selection_rh ) ;
2015-02-13 12:42:21 +03:00
dm_pool_free ( cmd - > mem , handle ) ;
2014-11-28 16:46:18 +03:00
}
}
2014-11-28 16:34:56 +03:00
int select_match_vg ( struct cmd_context * cmd , struct processing_handle * handle ,
struct volume_group * vg , int * selected )
2014-11-24 13:08:41 +03:00
{
2014-12-01 16:19:30 +03:00
struct selection_handle * sh = handle - > selection_handle ;
2014-11-28 16:34:56 +03:00
if ( ! handle - > internal_report_for_select ) {
* selected = 1 ;
return 1 ;
}
2014-12-01 16:19:30 +03:00
sh - > orig_report_type = VGS ;
2015-02-13 12:36:06 +03:00
if ( ! report_for_selection ( cmd , sh , NULL , vg , NULL ) ) {
2015-02-11 11:36:09 +03:00
log_error ( " Selection failed for VG %s. " , vg - > name ) ;
return 0 ;
}
2014-12-01 16:19:30 +03:00
sh - > orig_report_type = 0 ;
* selected = sh - > selected ;
2014-11-24 13:08:41 +03:00
return 1 ;
}
2014-11-28 16:34:56 +03:00
int select_match_lv ( struct cmd_context * cmd , struct processing_handle * handle ,
struct volume_group * vg , struct logical_volume * lv , int * selected )
2014-11-24 13:08:41 +03:00
{
2014-12-01 16:19:30 +03:00
struct selection_handle * sh = handle - > selection_handle ;
2014-11-28 16:34:56 +03:00
if ( ! handle - > internal_report_for_select ) {
* selected = 1 ;
return 1 ;
}
2014-12-01 16:19:30 +03:00
sh - > orig_report_type = LVS ;
2015-02-13 12:36:06 +03:00
if ( ! report_for_selection ( cmd , sh , NULL , vg , lv ) ) {
2015-02-11 11:36:09 +03:00
log_error ( " Selection failed for LV %s. " , lv - > name ) ;
return 0 ;
}
2014-12-01 16:19:30 +03:00
sh - > orig_report_type = 0 ;
* selected = sh - > selected ;
2014-11-24 13:08:41 +03:00
return 1 ;
}
2014-11-28 16:34:56 +03:00
int select_match_pv ( struct cmd_context * cmd , struct processing_handle * handle ,
struct volume_group * vg , struct physical_volume * pv , int * selected )
2014-11-24 13:08:41 +03:00
{
2014-12-01 16:19:30 +03:00
struct selection_handle * sh = handle - > selection_handle ;
2014-11-28 16:34:56 +03:00
if ( ! handle - > internal_report_for_select ) {
* selected = 1 ;
return 1 ;
}
2014-12-01 16:19:30 +03:00
sh - > orig_report_type = PVS ;
2015-02-13 12:36:06 +03:00
if ( ! report_for_selection ( cmd , sh , pv , vg , NULL ) ) {
2015-02-11 11:36:09 +03:00
log_error ( " Selection failed for PV %s. " , dev_name ( pv - > dev ) ) ;
return 0 ;
}
2014-12-01 16:19:30 +03:00
sh - > orig_report_type = 0 ;
* selected = sh - > selected ;
2014-11-24 13:08:41 +03:00
return 1 ;
}
2014-10-03 23:47:19 +04:00
static int _process_vgnameid_list ( struct cmd_context * cmd , uint32_t flags ,
struct dm_list * vgnameids_to_process ,
struct dm_list * arg_vgnames ,
2014-11-27 17:02:13 +03:00
struct dm_list * arg_tags ,
struct processing_handle * handle ,
2014-10-03 23:47:19 +04:00
process_single_vg_fn_t process_single_vg )
{
struct volume_group * vg ;
struct vgnameid_list * vgnl ;
const char * vg_name ;
const char * vg_uuid ;
2014-11-24 13:08:41 +03:00
int selected ;
2014-12-03 16:20:00 +03:00
int whole_selected = 0 ;
2014-10-03 23:47:19 +04:00
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 ;
2015-02-13 17:58:51 +03:00
/*
* FIXME If one_vgname_arg , only proceed if exactly one VG matches tags or selection .
*/
2014-10-03 23:47:19 +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-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 ) ;
2015-02-13 20:01:55 +03:00
if ( _ignore_vg ( vg , vg_name , arg_vgnames , 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? */
2014-11-24 13:08:41 +03:00
if ( ( process_all | |
2014-11-15 00:00:35 +03:00
( ! dm_list_empty ( arg_vgnames ) & & str_list_match_item ( arg_vgnames , vg_name ) ) | |
2014-11-24 13:08:41 +03:00
( ! dm_list_empty ( arg_tags ) & & str_list_match_list ( arg_tags , & vg - > tags , NULL ) ) ) & &
2014-11-28 16:34:56 +03:00
select_match_vg ( cmd , handle , vg , & selected ) & & selected ) {
2014-11-15 00:00:35 +03:00
ret = process_single_vg ( cmd , vg_name , vg , handle ) ;
2014-12-03 16:20:00 +03:00
_update_selection_result ( handle , & whole_selected ) ;
2014-11-15 00:00:35 +03:00
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
}
2014-12-03 16:20:00 +03:00
/* the VG is selected if at least one LV is selected */
_set_final_selection_result ( handle , whole_selected ) ;
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 ,
2014-11-27 17:02:13 +03:00
uint32_t flags , struct processing_handle * handle ,
2014-10-03 23:47:19 +04:00
process_single_vg_fn_t process_single_vg )
{
2014-11-28 17:04:25 +03:00
int handle_supplied = handle ! = NULL ;
2014-10-03 23:47:19 +04:00
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 ) ;
2015-02-13 17:58:51 +03:00
unsigned one_vgname_arg = ( flags & ONE_VGNAME_ARG ) ;
2014-10-03 23:47:19 +04:00
int ret ;
2015-02-27 01:06:32 +03:00
cmd - > error_foreign_vgs = 0 ;
2014-10-03 23:47:19 +04:00
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 .
*/
2015-02-13 17:58:51 +03:00
if ( ( ret = _get_arg_vgnames ( cmd , argc , argv , one_vgname_arg , & arg_vgnames , & arg_tags ) ) ! = ECMD_PROCESSED )
2014-11-28 17:04:25 +03:00
goto_out ;
2014-10-03 23:47:19 +04:00
/*
* 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 ) ) & &
2015-05-06 00:24:50 +03:00
! get_vgnameids ( cmd , & vgnameids_on_system , NULL , 0 ) )
2014-11-28 17:04:25 +03:00
goto_out ;
2014-10-03 23:47:19 +04:00
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-11-28 17:04:25 +03:00
ret = ECMD_PROCESSED ;
goto out ;
2014-10-03 23:47:19 +04:00
}
/*
* 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-11-28 17:04:25 +03:00
else if ( ( ret = _copy_str_to_vgnameid_list ( cmd , & arg_vgnames , & vgnameids_to_process ) ) ! = ECMD_PROCESSED )
goto_out ;
if ( ! handle & & ! ( handle = init_processing_handle ( cmd ) ) )
goto_out ;
if ( handle - > internal_report_for_select & & ! handle - > selection_handle & &
2015-02-10 15:46:37 +03:00
! init_selection_handle ( cmd , handle , VGS ) )
2014-11-28 17:04:25 +03:00
goto_out ;
2014-10-03 23:47:19 +04:00
2014-11-28 17:04:25 +03:00
ret = _process_vgnameid_list ( cmd , flags , & vgnameids_to_process ,
& arg_vgnames , & arg_tags , handle , process_single_vg ) ;
out :
if ( ! handle_supplied )
2015-02-13 12:42:21 +03:00
destroy_processing_handle ( cmd , handle ) ;
2015-02-13 17:58:51 +03:00
2014-11-28 17:04:25 +03:00
return ret ;
2014-10-03 23:47:19 +04:00
}
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-11-27 17:02:13 +03:00
struct processing_handle * handle ,
process_single_lv_fn_t process_single_lv )
2014-10-04 02:37:49 +04:00
{
int ret_max = ECMD_PROCESSED ;
int ret = 0 ;
2014-11-24 13:08:41 +03:00
int selected ;
2014-12-03 16:20:00 +03:00
int whole_selected = 0 ;
2014-11-28 17:04:25 +03:00
int handle_supplied = handle ! = NULL ;
2014-11-24 13:08:41 +03:00
unsigned process_lv ;
2014-10-04 02:37:49 +04:00
unsigned process_all = 0 ;
unsigned tags_supplied = 0 ;
unsigned lvargs_supplied = 0 ;
struct lv_list * lvl ;
struct dm_str_list * sl ;
metadata: process_each_lv_in_vg: get the list of LVs to process first, then do the processing
This avoids a problem in which we're using selection on LV list - we
need to do the selection on initial state and not on any intermediary
state as we process LVs one by one - some of the relations among LVs
can be gone during this processing.
For example, processing one LV can cause the other LVs to lose the
relation to this LV and hence they're not selectable anymore with
the original selection criteria as it would be if we did selection
on inital state. A perfect example is with thin snapshots:
$ lvs -o lv_name,origin,layout,role vg
LV Origin Layout Role
lvol1 thin,sparse public,origin,thinorigin,multithinorigin
lvol2 lvol1 thin,sparse public,snapshot,thinsnapshot
lvol3 lvol1 thin,sparse public,snapshot,thinsnapshot
pool thin,pool private
$ lvremove -ff -S 'lv_name=lvol1 || origin=lvol1'
Logical volume "lvol1" successfully removed
The lvremove command above was supposed to remove lvol1 as well as
all its snapshots which have origin=lvol1. It failed to do so, because
once we removed the origin lvol1, the lvol2 and lvol3 which were
snapshots before are not snapshots anymore - the relations change
as we're processing these LVs one by one.
If we do the selection first and then execute any concrete actions on
these LVs (which is what this patch does), the behaviour is correct
then - the selection is done on the *initial state*:
$ lvremove -ff -S 'lv_name=lvol1 || origin=lvol1'
Logical volume "lvol1" successfully removed
Logical volume "lvol2" successfully removed
Logical volume "lvol3" successfully removed
Similarly for all the other situations in which relations among
LVs are being changed by processing the LVs one by one.
This patch also introduces LV_REMOVED internal LV status flag
to mark removed LVs so they're not processed further when we
iterate over collected list of LVs to be processed.
Previously, when we iterated directly over vg->lvs list to
process the LVs, we relied on the fact that once the LV is removed,
it is also removed from the vg->lvs list we're iterating over.
But that was incorrect as we shouldn't remove LVs from the list
during one iteration while we're iterating over that exact list
(dm_list_iterate_items safe can handle only one removal at
one iteration anyway, so it can't be used here).
2015-03-16 19:10:21 +03:00
struct dm_list final_lvs ;
struct lv_list * final_lvl ;
dm_list_init ( & final_lvs ) ;
2014-10-04 02:37:49 +04:00
2014-11-28 17:04:25 +03:00
if ( ! vg_check_status ( vg , EXPORTED_VG ) ) {
ret_max = ECMD_FAILED ;
goto_out ;
}
2014-10-04 02:37:49 +04:00
if ( tags_in & & ! dm_list_empty ( tags_in ) )
tags_supplied = 1 ;
if ( arg_lvnames & & ! dm_list_empty ( arg_lvnames ) )
lvargs_supplied = 1 ;
2014-11-28 17:04:25 +03:00
if ( ! handle & & ! ( handle = init_processing_handle ( cmd ) ) ) {
ret_max = ECMD_FAILED ;
goto_out ;
}
if ( handle - > internal_report_for_select & & ! handle - > selection_handle & &
2015-02-10 15:46:37 +03:00
! init_selection_handle ( cmd , handle , LVS ) ) {
2014-11-28 17:04:25 +03:00
ret_max = ECMD_FAILED ;
goto_out ;
}
2014-10-04 02:37:49 +04:00
/* 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 ;
dm_list_iterate_items ( lvl , & vg - > lvs ) {
2014-11-28 17:04:25 +03:00
if ( sigint_caught ( ) ) {
ret_max = ECMD_FAILED ;
goto_out ;
}
2014-11-14 12:50:31 +03:00
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 ;
2014-11-24 13:08:41 +03:00
/*
* process the LV if one of the following :
* - process_all is set
* - LV name matches a supplied LV name
* - LV tag matches a supplied LV tag
* - LV matches the selection
*/
process_lv = process_all ;
if ( lvargs_supplied & & str_list_match_item ( arg_lvnames , lvl - > lv - > name ) ) {
2014-10-04 02:37:49 +04:00
/* Remove LV from list of unprocessed LV names */
str_list_del ( arg_lvnames , lvl - > lv - > name ) ;
2014-11-24 13:08:41 +03:00
process_lv = 1 ;
}
if ( ! process_lv & & tags_supplied & & str_list_match_list ( tags_in , & lvl - > lv - > tags , NULL ) )
process_lv = 1 ;
2014-11-28 16:34:56 +03:00
process_lv = process_lv & & select_match_lv ( cmd , handle , vg , lvl - > lv , & selected ) & & selected ;
2014-11-24 13:08:41 +03:00
2014-11-28 17:04:25 +03:00
if ( sigint_caught ( ) ) {
ret_max = ECMD_FAILED ;
goto_out ;
}
2014-11-24 13:08:41 +03:00
if ( ! process_lv )
2014-10-04 02:37:49 +04:00
continue ;
metadata: process_each_lv_in_vg: get the list of LVs to process first, then do the processing
This avoids a problem in which we're using selection on LV list - we
need to do the selection on initial state and not on any intermediary
state as we process LVs one by one - some of the relations among LVs
can be gone during this processing.
For example, processing one LV can cause the other LVs to lose the
relation to this LV and hence they're not selectable anymore with
the original selection criteria as it would be if we did selection
on inital state. A perfect example is with thin snapshots:
$ lvs -o lv_name,origin,layout,role vg
LV Origin Layout Role
lvol1 thin,sparse public,origin,thinorigin,multithinorigin
lvol2 lvol1 thin,sparse public,snapshot,thinsnapshot
lvol3 lvol1 thin,sparse public,snapshot,thinsnapshot
pool thin,pool private
$ lvremove -ff -S 'lv_name=lvol1 || origin=lvol1'
Logical volume "lvol1" successfully removed
The lvremove command above was supposed to remove lvol1 as well as
all its snapshots which have origin=lvol1. It failed to do so, because
once we removed the origin lvol1, the lvol2 and lvol3 which were
snapshots before are not snapshots anymore - the relations change
as we're processing these LVs one by one.
If we do the selection first and then execute any concrete actions on
these LVs (which is what this patch does), the behaviour is correct
then - the selection is done on the *initial state*:
$ lvremove -ff -S 'lv_name=lvol1 || origin=lvol1'
Logical volume "lvol1" successfully removed
Logical volume "lvol2" successfully removed
Logical volume "lvol3" successfully removed
Similarly for all the other situations in which relations among
LVs are being changed by processing the LVs one by one.
This patch also introduces LV_REMOVED internal LV status flag
to mark removed LVs so they're not processed further when we
iterate over collected list of LVs to be processed.
Previously, when we iterated directly over vg->lvs list to
process the LVs, we relied on the fact that once the LV is removed,
it is also removed from the vg->lvs list we're iterating over.
But that was incorrect as we shouldn't remove LVs from the list
during one iteration while we're iterating over that exact list
(dm_list_iterate_items safe can handle only one removal at
one iteration anyway, so it can't be used here).
2015-03-16 19:10:21 +03:00
log_very_verbose ( " Adding %s/%s to the list of LVs to be processed. " , vg - > name , lvl - > lv - > name ) ;
if ( ! ( final_lvl = dm_pool_zalloc ( vg - > vgmem , sizeof ( struct lv_list ) ) ) ) {
log_error ( " Failed to allocate final LV list item. " ) ;
ret_max = ECMD_FAILED ;
goto_out ;
}
final_lvl - > lv = lvl - > lv ;
dm_list_add ( & final_lvs , & final_lvl - > list ) ;
}
dm_list_iterate_items ( lvl , & final_lvs ) {
2015-03-23 15:32:00 +03:00
/*
* FIXME : Once we have index over vg - > removed_lvs , check directly
* LV presence there and remove LV_REMOVE flag / lv_is_removed fn
* as they won ' t be needed anymore .
*/
metadata: process_each_lv_in_vg: get the list of LVs to process first, then do the processing
This avoids a problem in which we're using selection on LV list - we
need to do the selection on initial state and not on any intermediary
state as we process LVs one by one - some of the relations among LVs
can be gone during this processing.
For example, processing one LV can cause the other LVs to lose the
relation to this LV and hence they're not selectable anymore with
the original selection criteria as it would be if we did selection
on inital state. A perfect example is with thin snapshots:
$ lvs -o lv_name,origin,layout,role vg
LV Origin Layout Role
lvol1 thin,sparse public,origin,thinorigin,multithinorigin
lvol2 lvol1 thin,sparse public,snapshot,thinsnapshot
lvol3 lvol1 thin,sparse public,snapshot,thinsnapshot
pool thin,pool private
$ lvremove -ff -S 'lv_name=lvol1 || origin=lvol1'
Logical volume "lvol1" successfully removed
The lvremove command above was supposed to remove lvol1 as well as
all its snapshots which have origin=lvol1. It failed to do so, because
once we removed the origin lvol1, the lvol2 and lvol3 which were
snapshots before are not snapshots anymore - the relations change
as we're processing these LVs one by one.
If we do the selection first and then execute any concrete actions on
these LVs (which is what this patch does), the behaviour is correct
then - the selection is done on the *initial state*:
$ lvremove -ff -S 'lv_name=lvol1 || origin=lvol1'
Logical volume "lvol1" successfully removed
Logical volume "lvol2" successfully removed
Logical volume "lvol3" successfully removed
Similarly for all the other situations in which relations among
LVs are being changed by processing the LVs one by one.
This patch also introduces LV_REMOVED internal LV status flag
to mark removed LVs so they're not processed further when we
iterate over collected list of LVs to be processed.
Previously, when we iterated directly over vg->lvs list to
process the LVs, we relied on the fact that once the LV is removed,
it is also removed from the vg->lvs list we're iterating over.
But that was incorrect as we shouldn't remove LVs from the list
during one iteration while we're iterating over that exact list
(dm_list_iterate_items safe can handle only one removal at
one iteration anyway, so it can't be used here).
2015-03-16 19:10:21 +03:00
if ( lv_is_removed ( lvl - > lv ) )
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 ) ;
2014-12-03 16:20:00 +03:00
if ( handle_supplied )
_update_selection_result ( handle , & whole_selected ) ;
2014-11-15 00:00:35 +03:00
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 )
2014-11-28 17:04:25 +03:00
goto_out ;
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 ;
}
}
2014-11-28 17:04:25 +03:00
out :
if ( ! handle_supplied )
2015-02-13 12:42:21 +03:00
destroy_processing_handle ( cmd , handle ) ;
2014-12-03 16:20:00 +03:00
else
_set_final_selection_result ( handle , whole_selected ) ;
2014-10-04 02:37:49 +04:00
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 ,
2014-11-27 17:02:13 +03:00
struct processing_handle * handle ,
2014-10-04 02:37:49 +04:00
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 ) ;
2015-02-13 20:01:55 +03:00
if ( _ignore_vg ( vg , vg_name , arg_vgnames , 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 ,
2014-11-27 17:02:13 +03:00
struct processing_handle * handle , process_single_lv_fn_t process_single_lv )
2014-10-04 02:37:49 +04:00
{
2014-11-28 17:04:25 +03:00
int handle_supplied = handle ! = NULL ;
2014-10-04 02:37:49 +04:00
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 ) ;
2015-05-06 00:24:50 +03:00
int need_vgnameids = 0 ;
2014-10-04 02:37:49 +04:00
int ret ;
2015-02-27 01:06:32 +03:00
cmd - > error_foreign_vgs = 0 ;
2014-10-04 02:37:49 +04:00
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 .
*/
2014-11-28 17:04:25 +03:00
if ( ( ret = _get_arg_lvnames ( cmd , argc , argv , & arg_vgnames , & arg_lvnames , & arg_tags ) ! = ECMD_PROCESSED ) )
goto_out ;
if ( ! handle & & ! ( handle = init_processing_handle ( cmd ) ) )
goto_out ;
if ( handle - > internal_report_for_select & & ! handle - > selection_handle & &
2015-02-10 15:46:37 +03:00
! init_selection_handle ( cmd , handle , LVS ) )
2014-11-28 17:04:25 +03:00
goto_out ;
2014-10-04 02:37:49 +04:00
/*
* Obtain the complete list of VGs present on the system if it is needed because :
* any tags were supplied and need resolving ; or
2015-05-06 00:24:50 +03:00
* no VG names were given and the select option needs resolving ; or
2014-10-04 02:37:49 +04:00
* no VG names were given and the command defaults to processing all VGs .
*/
2015-05-06 00:24:50 +03:00
if ( ! dm_list_empty ( & arg_tags ) )
need_vgnameids = 1 ;
else if ( dm_list_empty ( & arg_vgnames ) & & enable_all_vgs )
need_vgnameids = 1 ;
else if ( dm_list_empty ( & arg_vgnames ) & & handle - > internal_report_for_select )
need_vgnameids = 1 ;
if ( need_vgnameids & & ! get_vgnameids ( cmd , & vgnameids_on_system , NULL , 0 ) )
2014-11-28 17:04:25 +03:00
goto_out ;
2014-10-04 02:37:49 +04:00
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-11-28 17:04:25 +03:00
ret = ECMD_PROCESSED ;
goto out ;
2014-10-04 02:37:49 +04:00
}
/*
* 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-11-28 17:04:25 +03:00
else if ( ( ret = _copy_str_to_vgnameid_list ( cmd , & arg_vgnames , & vgnameids_to_process ) ) ! = ECMD_PROCESSED )
goto_out ;
2014-10-04 02:37:49 +04:00
2014-11-28 17:04:25 +03:00
ret = _process_lv_vgnameid_list ( cmd , flags , & vgnameids_to_process , & arg_vgnames , & arg_lvnames ,
& arg_tags , handle , process_single_lv ) ;
out :
if ( ! handle_supplied )
2015-02-13 12:42:21 +03:00
destroy_processing_handle ( cmd , handle ) ;
2014-11-28 17:04:25 +03:00
return ret ;
2014-10-04 02:37:49 +04:00
}
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 ;
}
2015-01-07 23:04:12 +03:00
static int _get_arg_devices ( struct cmd_context * cmd ,
struct dm_list * arg_pvnames ,
struct dm_list * arg_devices )
{
struct dm_str_list * sl ;
2015-01-09 23:55:16 +03:00
struct device_id_list * dil ;
2015-01-07 23:04:12 +03:00
int ret_max = ECMD_PROCESSED ;
dm_list_iterate_items ( sl , arg_pvnames ) {
2015-01-09 23:55:16 +03:00
if ( ! ( dil = dm_pool_alloc ( cmd - > mem , sizeof ( * dil ) ) ) ) {
log_error ( " device_id_list alloc failed. " ) ;
2015-01-07 23:04:12 +03:00
return ECMD_FAILED ;
}
2015-01-09 23:55:16 +03:00
if ( ! ( dil - > dev = dev_cache_get ( sl - > str , cmd - > filter ) ) ) {
log_error ( " Failed to find device for physical volume \" %s \" . " , sl - > str ) ;
2015-01-07 23:04:12 +03:00
ret_max = ECMD_FAILED ;
} else {
2015-01-09 23:55:16 +03:00
strncpy ( dil - > pvid , dil - > dev - > pvid , ID_LEN ) ;
dm_list_add ( arg_devices , & dil - > list ) ;
2015-01-07 23:04:12 +03:00
}
}
return ret_max ;
}
tolllib: process_each_pv: always use full_filter unconditionally when getting all devices
(This reverts patch #d95c6154)
Filter complete device list through full_filter unconditionally when
we're getting the list of *all* devices even in case we're interested
only in fraction of those devices - the PVs, not the other devices
which are not PVs yet (e.g. pvs vs. pvs -a).
We need to do this full filtering whenever we're handling *complete*
list of devices, we need to be safe here, mainly if there are any
future changes and we'd forgot to change to use proper filtering then.
Also properly preventing duplicates if there are any block subsystem
components used (mpath, MD ...).
Thing here is that (under use_lvmetad=1), cmd->filter can be used
only if we're sure that the list of devices we're filtering contains
only PVs. We have to use cmd->full_filter otherwise (like it is in
case of _get_all_devices fn which acquires complete list of devices,
no matter if it is a PV or not).
Of course, cmd->full_filter is more extensive than cmd->filter
which is only a subset of full_filter.
We could optimize this in a way that if we're interested in PVs only
during process_each_pv processing (e.g. using pvs in contrast to pvs -a),
we'd get the list of PV devices directly from lvmetad from the
lvmcache_seed_infos_from_lvmetad fn call which currently updates
lvmcache only. We'd add an additional output arg for this fn to get
the list of PV devices directly in addition, without a need to iterate
over all devices which include non-PVs which we're not interested in
anyway, hence we could use only cmd->filter, not the cmd->full_filter.
So the code would look something like this:
static int _get_all_devices(....)
{
struct device_id_list *dil;
if (interested_in_pvs_only)
lvmcache_seed_infos_from_lvmetad(cmd, &dil); /* new "dil" arg */
/* the "dil" list would be filtered through cmd->filter inside lvmcache_seed_infos_from_lvmetad */
else {
lvmcache_seed_infos_from_lvmetad(cmd, NULL);
dev_iter_create(cmd->full_filter)
while (dev = dev_iter_get ...) {
dm_list_add(all_devices, &dil->list);
}
}
}
2015-02-13 12:59:19 +03: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 ;
2015-01-09 23:55:16 +03:00
struct device_id_list * dil ;
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 ) ;
tolllib: process_each_pv: always use full_filter unconditionally when getting all devices
(This reverts patch #d95c6154)
Filter complete device list through full_filter unconditionally when
we're getting the list of *all* devices even in case we're interested
only in fraction of those devices - the PVs, not the other devices
which are not PVs yet (e.g. pvs vs. pvs -a).
We need to do this full filtering whenever we're handling *complete*
list of devices, we need to be safe here, mainly if there are any
future changes and we'd forgot to change to use proper filtering then.
Also properly preventing duplicates if there are any block subsystem
components used (mpath, MD ...).
Thing here is that (under use_lvmetad=1), cmd->filter can be used
only if we're sure that the list of devices we're filtering contains
only PVs. We have to use cmd->full_filter otherwise (like it is in
case of _get_all_devices fn which acquires complete list of devices,
no matter if it is a PV or not).
Of course, cmd->full_filter is more extensive than cmd->filter
which is only a subset of full_filter.
We could optimize this in a way that if we're interested in PVs only
during process_each_pv processing (e.g. using pvs in contrast to pvs -a),
we'd get the list of PV devices directly from lvmetad from the
lvmcache_seed_infos_from_lvmetad fn call which currently updates
lvmcache only. We'd add an additional output arg for this fn to get
the list of PV devices directly in addition, without a need to iterate
over all devices which include non-PVs which we're not interested in
anyway, hence we could use only cmd->filter, not the cmd->full_filter.
So the code would look something like this:
static int _get_all_devices(....)
{
struct device_id_list *dil;
if (interested_in_pvs_only)
lvmcache_seed_infos_from_lvmetad(cmd, &dil); /* new "dil" arg */
/* the "dil" list would be filtered through cmd->filter inside lvmcache_seed_infos_from_lvmetad */
else {
lvmcache_seed_infos_from_lvmetad(cmd, NULL);
dev_iter_create(cmd->full_filter)
while (dev = dev_iter_get ...) {
dm_list_add(all_devices, &dil->list);
}
}
}
2015-02-13 12:59:19 +03:00
if ( ! ( iter = dev_iter_create ( cmd - > full_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 ) ) ) {
2015-01-09 23:55:16 +03:00
if ( ! ( dil = dm_pool_alloc ( cmd - > mem , sizeof ( * dil ) ) ) ) {
log_error ( " device_id_list alloc failed. " ) ;
2014-11-12 11:18:55 +03:00
goto out ;
2014-10-07 01:02:00 +04:00
}
2015-01-14 23:16:03 +03:00
strncpy ( dil - > pvid , dev - > pvid , ID_LEN ) ;
2015-01-09 23:55:16 +03:00
dil - > dev = dev ;
dm_list_add ( all_devices , & dil - > list ) ;
2014-10-07 03:34:04 +04:00
}
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
}
2015-01-09 23:55:16 +03:00
static int _device_list_remove ( struct dm_list * devices , struct device * dev )
2014-10-07 03:34:04 +04:00
{
2015-01-09 23:55:16 +03:00
struct device_id_list * dil ;
2014-10-07 03:34:04 +04:00
2015-01-09 23:55:16 +03:00
dm_list_iterate_items ( dil , devices ) {
if ( dil - > dev = = dev ) {
dm_list_del ( & dil - > list ) ;
2014-10-07 03:34:04 +04:00
return 1 ;
}
}
return 0 ;
}
2015-01-09 23:55:16 +03:00
static struct device_id_list * _device_list_find_dev ( struct dm_list * devices , struct device * dev )
2015-01-07 23:04:12 +03:00
{
2015-01-09 23:55:16 +03:00
struct device_id_list * dil ;
2015-01-07 23:04:12 +03:00
2015-01-09 23:55:16 +03:00
dm_list_iterate_items ( dil , devices ) {
if ( dil - > dev = = dev )
return dil ;
2015-01-07 23:04:12 +03:00
}
2015-01-09 23:55:16 +03:00
return NULL ;
}
static struct device_id_list * _device_list_find_pvid ( struct dm_list * devices , struct physical_volume * pv )
{
struct device_id_list * dil ;
dm_list_iterate_items ( dil , devices ) {
if ( id_equal ( ( struct id * ) dil - > pvid , & pv - > id ) )
return dil ;
}
return NULL ;
2015-01-07 23:04:12 +03:00
}
2014-10-07 03:34:04 +04:00
static int _process_device_list ( struct cmd_context * cmd , struct dm_list * all_devices ,
2014-11-27 17:02:13 +03:00
struct processing_handle * handle ,
process_single_pv_fn_t process_single_pv )
2014-10-07 03:34:04 +04:00
{
struct physical_volume pv_dummy ;
struct physical_volume * pv ;
2015-01-09 23:55:16 +03:00
struct device_id_list * dil ;
2014-10-07 03:34:04 +04:00
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 .
*/
2015-01-09 23:55:16 +03:00
dm_list_iterate_items ( dil , 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 ) ;
2015-01-09 23:55:16 +03:00
pv_dummy . dev = dil - > dev ;
2014-10-07 01:02:00 +04:00
pv = & pv_dummy ;
2015-01-09 23:55:16 +03:00
log_very_verbose ( " Processing device %s. " , dev_name ( dil - > 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 ,
2015-01-07 23:04:12 +03:00
struct dm_list * arg_devices ,
2014-10-07 03:34:04 +04:00
struct dm_list * arg_tags ,
2015-01-14 23:16:03 +03:00
int process_all_pvs ,
int process_all_devices ,
2014-10-07 03:34:04 +04:00
int skip ,
2014-11-27 17:02:13 +03:00
struct processing_handle * handle ,
2014-10-07 03:34:04 +04:00
process_single_pv_fn_t process_single_pv )
{
2014-11-28 17:04:25 +03:00
int handle_supplied = handle ! = NULL ;
2014-10-07 03:34:04 +04:00
struct physical_volume * pv ;
struct pv_list * pvl ;
2015-01-09 23:55:16 +03:00
struct device_id_list * dil ;
toollib: override the PV device with duplicates
When multiple duplicate devices are specified on the
command line, the PV is processed once for each of them,
but pv->dev is the device used each time.
This overrides the PV device to reflect the duplicate
device that was specified on the command line. This is
done by hacking the lvmcache to replace pv->dev with the
device of the duplicate being processed. (It would be
preferable to override pv->dev without munging the content
of the cache, and without sprinkling special cases throughout
the code.)
This override only applies when multiple duplicate devices are
specified on the command line. When only a single duplicate
device of pv->dev is specified, the priority is to display the
cached pv->dev, so pv->dev is not overridden by the named
duplicate device.
In the examples below, loop3 is the cached device referenced
by pv->dev, and is given priority for processing. Only after
loop3 is processed/displayed, will other duplicate devices
loop0/loop1 appear (when requested on the command line.)
With two duplicate devices, loop0 and loop3:
# pvs
Found duplicate PV XhLbpVo0hmuwrMQLjfxuAvPFUFZqD4vr: using /dev/loop3 not /dev/loop0
PV VG Fmt Attr PSize PFree
/dev/loop3 loopa lvm2 a-- 12.00m 12.00m
# pvs /dev/loop3
Found duplicate PV XhLbpVo0hmuwrMQLjfxuAvPFUFZqD4vr: using /dev/loop3 not /dev/loop0
PV VG Fmt Attr PSize PFree
/dev/loop3 loopa lvm2 a-- 12.00m 12.00m
# pvs /dev/loop0
Found duplicate PV XhLbpVo0hmuwrMQLjfxuAvPFUFZqD4vr: using /dev/loop3 not /dev/loop0
PV VG Fmt Attr PSize PFree
/dev/loop3 loopa lvm2 a-- 12.00m 12.00m
# pvs -o+dev_size /dev/loop0 /dev/loop3
Found duplicate PV XhLbpVo0hmuwrMQLjfxuAvPFUFZqD4vr: using /dev/loop3 not /dev/loop0
PV VG Fmt Attr PSize PFree DevSize
/dev/loop0 loopa lvm2 a-- 12.00m 12.00m 16.00m
/dev/loop3 loopa lvm2 a-- 12.00m 12.00m 32.00m
With three duplicate devices, loop0, loop1, loop3:
# pvs -o+dev_size
Found duplicate PV XhLbpVo0hmuwrMQLjfxuAvPFUFZqD4vr: using /dev/loop1 not /dev/loop0
Found duplicate PV XhLbpVo0hmuwrMQLjfxuAvPFUFZqD4vr: using /dev/loop3 not /dev/loop1
PV VG Fmt Attr PSize PFree DevSize
/dev/loop3 loopa lvm2 a-- 12.00m 12.00m 32.00m
# pvs -o+dev_size /dev/loop3
Found duplicate PV XhLbpVo0hmuwrMQLjfxuAvPFUFZqD4vr: using /dev/loop1 not /dev/loop0
Found duplicate PV XhLbpVo0hmuwrMQLjfxuAvPFUFZqD4vr: using /dev/loop3 not /dev/loop1
PV VG Fmt Attr PSize PFree DevSize
/dev/loop3 loopa lvm2 a-- 12.00m 12.00m 32.00m
# pvs -o+dev_size /dev/loop0
Found duplicate PV XhLbpVo0hmuwrMQLjfxuAvPFUFZqD4vr: using /dev/loop1 not /dev/loop0
Found duplicate PV XhLbpVo0hmuwrMQLjfxuAvPFUFZqD4vr: using /dev/loop3 not /dev/loop1
PV VG Fmt Attr PSize PFree DevSize
/dev/loop3 loopa lvm2 a-- 12.00m 12.00m 32.00m
# pvs -o+dev_size /dev/loop1
Found duplicate PV XhLbpVo0hmuwrMQLjfxuAvPFUFZqD4vr: using /dev/loop1 not /dev/loop0
Found duplicate PV XhLbpVo0hmuwrMQLjfxuAvPFUFZqD4vr: using /dev/loop3 not /dev/loop1
PV VG Fmt Attr PSize PFree DevSize
/dev/loop3 loopa lvm2 a-- 12.00m 12.00m 32.00m
# pvs -o+dev_size /dev/loop3 /dev/loop0
Found duplicate PV XhLbpVo0hmuwrMQLjfxuAvPFUFZqD4vr: using /dev/loop1 not /dev/loop0
Found duplicate PV XhLbpVo0hmuwrMQLjfxuAvPFUFZqD4vr: using /dev/loop3 not /dev/loop1
PV VG Fmt Attr PSize PFree DevSize
/dev/loop0 loopa lvm2 a-- 12.00m 12.00m 16.00m
/dev/loop3 loopa lvm2 a-- 12.00m 12.00m 32.00m
# pvs -o+dev_size /dev/loop3 /dev/loop1
Found duplicate PV XhLbpVo0hmuwrMQLjfxuAvPFUFZqD4vr: using /dev/loop1 not /dev/loop0
Found duplicate PV XhLbpVo0hmuwrMQLjfxuAvPFUFZqD4vr: using /dev/loop3 not /dev/loop1
PV VG Fmt Attr PSize PFree DevSize
/dev/loop1 loopa lvm2 a-- 12.00m 12.00m 32.00m
/dev/loop3 loopa lvm2 a-- 12.00m 12.00m 32.00m
# pvs -o+dev_size /dev/loop0 /dev/loop1
Found duplicate PV XhLbpVo0hmuwrMQLjfxuAvPFUFZqD4vr: using /dev/loop1 not /dev/loop0
Found duplicate PV XhLbpVo0hmuwrMQLjfxuAvPFUFZqD4vr: using /dev/loop3 not /dev/loop1
PV VG Fmt Attr PSize PFree DevSize
/dev/loop1 loopa lvm2 a-- 12.00m 12.00m 32.00m
/dev/loop3 loopa lvm2 a-- 12.00m 12.00m 32.00m
# pvs -o+dev_size /dev/loop0 /dev/loop1 /dev/loop3
Found duplicate PV XhLbpVo0hmuwrMQLjfxuAvPFUFZqD4vr: using /dev/loop1 not /dev/loop0
Found duplicate PV XhLbpVo0hmuwrMQLjfxuAvPFUFZqD4vr: using /dev/loop3 not /dev/loop1
PV VG Fmt Attr PSize PFree DevSize
/dev/loop0 loopa lvm2 a-- 12.00m 12.00m 16.00m
/dev/loop1 loopa lvm2 a-- 12.00m 12.00m 32.00m
/dev/loop3 loopa lvm2 a-- 12.00m 12.00m 32.00m
2015-01-14 01:16:22 +03:00
struct device * dev_orig ;
2014-10-07 03:34:04 +04:00
const char * pv_name ;
2014-11-24 13:08:41 +03:00
int selected ;
2014-10-07 03:34:04 +04:00
int process_pv ;
int dev_found ;
int ret_max = ECMD_PROCESSED ;
int ret = 0 ;
2014-11-28 17:04:25 +03:00
if ( ! handle & & ( ! ( handle = init_processing_handle ( cmd ) ) ) ) {
ret_max = ECMD_FAILED ;
goto_out ;
}
if ( handle - > internal_report_for_select & & ! handle - > selection_handle & &
2015-02-10 15:46:37 +03:00
! init_selection_handle ( cmd , handle , PVS ) ) {
2014-11-28 17:04:25 +03:00
ret_max = ECMD_FAILED ;
goto_out ;
}
2014-10-07 03:34:04 +04:00
dm_list_iterate_items ( pvl , & vg - > pvs ) {
2014-11-28 17:04:25 +03:00
if ( sigint_caught ( ) ) {
ret_max = ECMD_FAILED ;
goto_out ;
}
2014-11-14 12:50:31 +03:00
2014-10-07 03:34:04 +04:00
pv = pvl - > pv ;
pv_name = pv_dev_name ( pv ) ;
2015-01-14 23:16:03 +03:00
process_pv = process_all_pvs ;
2014-10-07 03:34:04 +04:00
2015-01-07 23:04:12 +03:00
/* Remove each arg_devices entry as it is processed. */
if ( ! process_pv & & ! dm_list_empty ( arg_devices ) & &
2015-01-09 23:55:16 +03:00
( dil = _device_list_find_dev ( arg_devices , pv - > dev ) ) ) {
2014-10-07 03:34:04 +04:00
process_pv = 1 ;
2015-01-09 23:55:16 +03:00
_device_list_remove ( arg_devices , dil - > dev ) ;
}
/* Select the PV if the device arg has the same pvid. */
if ( ! process_pv & & ! dm_list_empty ( arg_devices ) & &
( dil = _device_list_find_pvid ( arg_devices , pv ) ) ) {
process_pv = 1 ;
_device_list_remove ( arg_devices , dil - > dev ) ;
2014-10-07 03:34:04 +04:00
}
if ( ! process_pv & & ! dm_list_empty ( arg_tags ) & &
str_list_match_list ( arg_tags , & pv - > tags , NULL ) )
process_pv = 1 ;
2014-11-28 16:34:56 +03:00
process_pv = process_pv & & select_match_pv ( cmd , handle , vg , pv , & selected ) & & selected ;
2014-11-24 13:08:41 +03:00
2014-10-07 03:34:04 +04:00
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 ;
}
2015-01-09 23:55:16 +03:00
/*
* This is a very rare and obscure case where multiple
* duplicate devices are specified on the command line
* referring to this PV . In this case we want to
* process this PV once for each specified device .
*/
if ( ! skip & & ! dm_list_empty ( arg_devices ) ) {
while ( ( dil = _device_list_find_pvid ( arg_devices , pv ) ) ) {
_device_list_remove ( arg_devices , dil - > dev ) ;
/*
toollib: override the PV device with duplicates
When multiple duplicate devices are specified on the
command line, the PV is processed once for each of them,
but pv->dev is the device used each time.
This overrides the PV device to reflect the duplicate
device that was specified on the command line. This is
done by hacking the lvmcache to replace pv->dev with the
device of the duplicate being processed. (It would be
preferable to override pv->dev without munging the content
of the cache, and without sprinkling special cases throughout
the code.)
This override only applies when multiple duplicate devices are
specified on the command line. When only a single duplicate
device of pv->dev is specified, the priority is to display the
cached pv->dev, so pv->dev is not overridden by the named
duplicate device.
In the examples below, loop3 is the cached device referenced
by pv->dev, and is given priority for processing. Only after
loop3 is processed/displayed, will other duplicate devices
loop0/loop1 appear (when requested on the command line.)
With two duplicate devices, loop0 and loop3:
# pvs
Found duplicate PV XhLbpVo0hmuwrMQLjfxuAvPFUFZqD4vr: using /dev/loop3 not /dev/loop0
PV VG Fmt Attr PSize PFree
/dev/loop3 loopa lvm2 a-- 12.00m 12.00m
# pvs /dev/loop3
Found duplicate PV XhLbpVo0hmuwrMQLjfxuAvPFUFZqD4vr: using /dev/loop3 not /dev/loop0
PV VG Fmt Attr PSize PFree
/dev/loop3 loopa lvm2 a-- 12.00m 12.00m
# pvs /dev/loop0
Found duplicate PV XhLbpVo0hmuwrMQLjfxuAvPFUFZqD4vr: using /dev/loop3 not /dev/loop0
PV VG Fmt Attr PSize PFree
/dev/loop3 loopa lvm2 a-- 12.00m 12.00m
# pvs -o+dev_size /dev/loop0 /dev/loop3
Found duplicate PV XhLbpVo0hmuwrMQLjfxuAvPFUFZqD4vr: using /dev/loop3 not /dev/loop0
PV VG Fmt Attr PSize PFree DevSize
/dev/loop0 loopa lvm2 a-- 12.00m 12.00m 16.00m
/dev/loop3 loopa lvm2 a-- 12.00m 12.00m 32.00m
With three duplicate devices, loop0, loop1, loop3:
# pvs -o+dev_size
Found duplicate PV XhLbpVo0hmuwrMQLjfxuAvPFUFZqD4vr: using /dev/loop1 not /dev/loop0
Found duplicate PV XhLbpVo0hmuwrMQLjfxuAvPFUFZqD4vr: using /dev/loop3 not /dev/loop1
PV VG Fmt Attr PSize PFree DevSize
/dev/loop3 loopa lvm2 a-- 12.00m 12.00m 32.00m
# pvs -o+dev_size /dev/loop3
Found duplicate PV XhLbpVo0hmuwrMQLjfxuAvPFUFZqD4vr: using /dev/loop1 not /dev/loop0
Found duplicate PV XhLbpVo0hmuwrMQLjfxuAvPFUFZqD4vr: using /dev/loop3 not /dev/loop1
PV VG Fmt Attr PSize PFree DevSize
/dev/loop3 loopa lvm2 a-- 12.00m 12.00m 32.00m
# pvs -o+dev_size /dev/loop0
Found duplicate PV XhLbpVo0hmuwrMQLjfxuAvPFUFZqD4vr: using /dev/loop1 not /dev/loop0
Found duplicate PV XhLbpVo0hmuwrMQLjfxuAvPFUFZqD4vr: using /dev/loop3 not /dev/loop1
PV VG Fmt Attr PSize PFree DevSize
/dev/loop3 loopa lvm2 a-- 12.00m 12.00m 32.00m
# pvs -o+dev_size /dev/loop1
Found duplicate PV XhLbpVo0hmuwrMQLjfxuAvPFUFZqD4vr: using /dev/loop1 not /dev/loop0
Found duplicate PV XhLbpVo0hmuwrMQLjfxuAvPFUFZqD4vr: using /dev/loop3 not /dev/loop1
PV VG Fmt Attr PSize PFree DevSize
/dev/loop3 loopa lvm2 a-- 12.00m 12.00m 32.00m
# pvs -o+dev_size /dev/loop3 /dev/loop0
Found duplicate PV XhLbpVo0hmuwrMQLjfxuAvPFUFZqD4vr: using /dev/loop1 not /dev/loop0
Found duplicate PV XhLbpVo0hmuwrMQLjfxuAvPFUFZqD4vr: using /dev/loop3 not /dev/loop1
PV VG Fmt Attr PSize PFree DevSize
/dev/loop0 loopa lvm2 a-- 12.00m 12.00m 16.00m
/dev/loop3 loopa lvm2 a-- 12.00m 12.00m 32.00m
# pvs -o+dev_size /dev/loop3 /dev/loop1
Found duplicate PV XhLbpVo0hmuwrMQLjfxuAvPFUFZqD4vr: using /dev/loop1 not /dev/loop0
Found duplicate PV XhLbpVo0hmuwrMQLjfxuAvPFUFZqD4vr: using /dev/loop3 not /dev/loop1
PV VG Fmt Attr PSize PFree DevSize
/dev/loop1 loopa lvm2 a-- 12.00m 12.00m 32.00m
/dev/loop3 loopa lvm2 a-- 12.00m 12.00m 32.00m
# pvs -o+dev_size /dev/loop0 /dev/loop1
Found duplicate PV XhLbpVo0hmuwrMQLjfxuAvPFUFZqD4vr: using /dev/loop1 not /dev/loop0
Found duplicate PV XhLbpVo0hmuwrMQLjfxuAvPFUFZqD4vr: using /dev/loop3 not /dev/loop1
PV VG Fmt Attr PSize PFree DevSize
/dev/loop1 loopa lvm2 a-- 12.00m 12.00m 32.00m
/dev/loop3 loopa lvm2 a-- 12.00m 12.00m 32.00m
# pvs -o+dev_size /dev/loop0 /dev/loop1 /dev/loop3
Found duplicate PV XhLbpVo0hmuwrMQLjfxuAvPFUFZqD4vr: using /dev/loop1 not /dev/loop0
Found duplicate PV XhLbpVo0hmuwrMQLjfxuAvPFUFZqD4vr: using /dev/loop3 not /dev/loop1
PV VG Fmt Attr PSize PFree DevSize
/dev/loop0 loopa lvm2 a-- 12.00m 12.00m 16.00m
/dev/loop1 loopa lvm2 a-- 12.00m 12.00m 32.00m
/dev/loop3 loopa lvm2 a-- 12.00m 12.00m 32.00m
2015-01-14 01:16:22 +03:00
* Replace pv - > dev with this dil - > dev
* in lvmcache so the duplicate dev
* info will be reported . FIXME : it
* would be nicer to override pv - > dev
* without munging lvmcache content .
2015-01-09 23:55:16 +03:00
*/
toollib: override the PV device with duplicates
When multiple duplicate devices are specified on the
command line, the PV is processed once for each of them,
but pv->dev is the device used each time.
This overrides the PV device to reflect the duplicate
device that was specified on the command line. This is
done by hacking the lvmcache to replace pv->dev with the
device of the duplicate being processed. (It would be
preferable to override pv->dev without munging the content
of the cache, and without sprinkling special cases throughout
the code.)
This override only applies when multiple duplicate devices are
specified on the command line. When only a single duplicate
device of pv->dev is specified, the priority is to display the
cached pv->dev, so pv->dev is not overridden by the named
duplicate device.
In the examples below, loop3 is the cached device referenced
by pv->dev, and is given priority for processing. Only after
loop3 is processed/displayed, will other duplicate devices
loop0/loop1 appear (when requested on the command line.)
With two duplicate devices, loop0 and loop3:
# pvs
Found duplicate PV XhLbpVo0hmuwrMQLjfxuAvPFUFZqD4vr: using /dev/loop3 not /dev/loop0
PV VG Fmt Attr PSize PFree
/dev/loop3 loopa lvm2 a-- 12.00m 12.00m
# pvs /dev/loop3
Found duplicate PV XhLbpVo0hmuwrMQLjfxuAvPFUFZqD4vr: using /dev/loop3 not /dev/loop0
PV VG Fmt Attr PSize PFree
/dev/loop3 loopa lvm2 a-- 12.00m 12.00m
# pvs /dev/loop0
Found duplicate PV XhLbpVo0hmuwrMQLjfxuAvPFUFZqD4vr: using /dev/loop3 not /dev/loop0
PV VG Fmt Attr PSize PFree
/dev/loop3 loopa lvm2 a-- 12.00m 12.00m
# pvs -o+dev_size /dev/loop0 /dev/loop3
Found duplicate PV XhLbpVo0hmuwrMQLjfxuAvPFUFZqD4vr: using /dev/loop3 not /dev/loop0
PV VG Fmt Attr PSize PFree DevSize
/dev/loop0 loopa lvm2 a-- 12.00m 12.00m 16.00m
/dev/loop3 loopa lvm2 a-- 12.00m 12.00m 32.00m
With three duplicate devices, loop0, loop1, loop3:
# pvs -o+dev_size
Found duplicate PV XhLbpVo0hmuwrMQLjfxuAvPFUFZqD4vr: using /dev/loop1 not /dev/loop0
Found duplicate PV XhLbpVo0hmuwrMQLjfxuAvPFUFZqD4vr: using /dev/loop3 not /dev/loop1
PV VG Fmt Attr PSize PFree DevSize
/dev/loop3 loopa lvm2 a-- 12.00m 12.00m 32.00m
# pvs -o+dev_size /dev/loop3
Found duplicate PV XhLbpVo0hmuwrMQLjfxuAvPFUFZqD4vr: using /dev/loop1 not /dev/loop0
Found duplicate PV XhLbpVo0hmuwrMQLjfxuAvPFUFZqD4vr: using /dev/loop3 not /dev/loop1
PV VG Fmt Attr PSize PFree DevSize
/dev/loop3 loopa lvm2 a-- 12.00m 12.00m 32.00m
# pvs -o+dev_size /dev/loop0
Found duplicate PV XhLbpVo0hmuwrMQLjfxuAvPFUFZqD4vr: using /dev/loop1 not /dev/loop0
Found duplicate PV XhLbpVo0hmuwrMQLjfxuAvPFUFZqD4vr: using /dev/loop3 not /dev/loop1
PV VG Fmt Attr PSize PFree DevSize
/dev/loop3 loopa lvm2 a-- 12.00m 12.00m 32.00m
# pvs -o+dev_size /dev/loop1
Found duplicate PV XhLbpVo0hmuwrMQLjfxuAvPFUFZqD4vr: using /dev/loop1 not /dev/loop0
Found duplicate PV XhLbpVo0hmuwrMQLjfxuAvPFUFZqD4vr: using /dev/loop3 not /dev/loop1
PV VG Fmt Attr PSize PFree DevSize
/dev/loop3 loopa lvm2 a-- 12.00m 12.00m 32.00m
# pvs -o+dev_size /dev/loop3 /dev/loop0
Found duplicate PV XhLbpVo0hmuwrMQLjfxuAvPFUFZqD4vr: using /dev/loop1 not /dev/loop0
Found duplicate PV XhLbpVo0hmuwrMQLjfxuAvPFUFZqD4vr: using /dev/loop3 not /dev/loop1
PV VG Fmt Attr PSize PFree DevSize
/dev/loop0 loopa lvm2 a-- 12.00m 12.00m 16.00m
/dev/loop3 loopa lvm2 a-- 12.00m 12.00m 32.00m
# pvs -o+dev_size /dev/loop3 /dev/loop1
Found duplicate PV XhLbpVo0hmuwrMQLjfxuAvPFUFZqD4vr: using /dev/loop1 not /dev/loop0
Found duplicate PV XhLbpVo0hmuwrMQLjfxuAvPFUFZqD4vr: using /dev/loop3 not /dev/loop1
PV VG Fmt Attr PSize PFree DevSize
/dev/loop1 loopa lvm2 a-- 12.00m 12.00m 32.00m
/dev/loop3 loopa lvm2 a-- 12.00m 12.00m 32.00m
# pvs -o+dev_size /dev/loop0 /dev/loop1
Found duplicate PV XhLbpVo0hmuwrMQLjfxuAvPFUFZqD4vr: using /dev/loop1 not /dev/loop0
Found duplicate PV XhLbpVo0hmuwrMQLjfxuAvPFUFZqD4vr: using /dev/loop3 not /dev/loop1
PV VG Fmt Attr PSize PFree DevSize
/dev/loop1 loopa lvm2 a-- 12.00m 12.00m 32.00m
/dev/loop3 loopa lvm2 a-- 12.00m 12.00m 32.00m
# pvs -o+dev_size /dev/loop0 /dev/loop1 /dev/loop3
Found duplicate PV XhLbpVo0hmuwrMQLjfxuAvPFUFZqD4vr: using /dev/loop1 not /dev/loop0
Found duplicate PV XhLbpVo0hmuwrMQLjfxuAvPFUFZqD4vr: using /dev/loop3 not /dev/loop1
PV VG Fmt Attr PSize PFree DevSize
/dev/loop0 loopa lvm2 a-- 12.00m 12.00m 16.00m
/dev/loop1 loopa lvm2 a-- 12.00m 12.00m 32.00m
/dev/loop3 loopa lvm2 a-- 12.00m 12.00m 32.00m
2015-01-14 01:16:22 +03:00
dev_orig = pv - > dev ;
lvmcache_replace_dev ( cmd , pv , dil - > dev ) ;
2015-01-09 23:55:16 +03:00
log_very_verbose ( " Processing PV %s device %s in VG %s. " ,
pv_name , dev_name ( dil - > dev ) , vg - > name ) ;
ret = process_single_pv ( cmd , vg , pv , handle ) ;
if ( ret ! = ECMD_PROCESSED )
stack ;
if ( ret > ret_max )
ret_max = ret ;
toollib: override the PV device with duplicates
When multiple duplicate devices are specified on the
command line, the PV is processed once for each of them,
but pv->dev is the device used each time.
This overrides the PV device to reflect the duplicate
device that was specified on the command line. This is
done by hacking the lvmcache to replace pv->dev with the
device of the duplicate being processed. (It would be
preferable to override pv->dev without munging the content
of the cache, and without sprinkling special cases throughout
the code.)
This override only applies when multiple duplicate devices are
specified on the command line. When only a single duplicate
device of pv->dev is specified, the priority is to display the
cached pv->dev, so pv->dev is not overridden by the named
duplicate device.
In the examples below, loop3 is the cached device referenced
by pv->dev, and is given priority for processing. Only after
loop3 is processed/displayed, will other duplicate devices
loop0/loop1 appear (when requested on the command line.)
With two duplicate devices, loop0 and loop3:
# pvs
Found duplicate PV XhLbpVo0hmuwrMQLjfxuAvPFUFZqD4vr: using /dev/loop3 not /dev/loop0
PV VG Fmt Attr PSize PFree
/dev/loop3 loopa lvm2 a-- 12.00m 12.00m
# pvs /dev/loop3
Found duplicate PV XhLbpVo0hmuwrMQLjfxuAvPFUFZqD4vr: using /dev/loop3 not /dev/loop0
PV VG Fmt Attr PSize PFree
/dev/loop3 loopa lvm2 a-- 12.00m 12.00m
# pvs /dev/loop0
Found duplicate PV XhLbpVo0hmuwrMQLjfxuAvPFUFZqD4vr: using /dev/loop3 not /dev/loop0
PV VG Fmt Attr PSize PFree
/dev/loop3 loopa lvm2 a-- 12.00m 12.00m
# pvs -o+dev_size /dev/loop0 /dev/loop3
Found duplicate PV XhLbpVo0hmuwrMQLjfxuAvPFUFZqD4vr: using /dev/loop3 not /dev/loop0
PV VG Fmt Attr PSize PFree DevSize
/dev/loop0 loopa lvm2 a-- 12.00m 12.00m 16.00m
/dev/loop3 loopa lvm2 a-- 12.00m 12.00m 32.00m
With three duplicate devices, loop0, loop1, loop3:
# pvs -o+dev_size
Found duplicate PV XhLbpVo0hmuwrMQLjfxuAvPFUFZqD4vr: using /dev/loop1 not /dev/loop0
Found duplicate PV XhLbpVo0hmuwrMQLjfxuAvPFUFZqD4vr: using /dev/loop3 not /dev/loop1
PV VG Fmt Attr PSize PFree DevSize
/dev/loop3 loopa lvm2 a-- 12.00m 12.00m 32.00m
# pvs -o+dev_size /dev/loop3
Found duplicate PV XhLbpVo0hmuwrMQLjfxuAvPFUFZqD4vr: using /dev/loop1 not /dev/loop0
Found duplicate PV XhLbpVo0hmuwrMQLjfxuAvPFUFZqD4vr: using /dev/loop3 not /dev/loop1
PV VG Fmt Attr PSize PFree DevSize
/dev/loop3 loopa lvm2 a-- 12.00m 12.00m 32.00m
# pvs -o+dev_size /dev/loop0
Found duplicate PV XhLbpVo0hmuwrMQLjfxuAvPFUFZqD4vr: using /dev/loop1 not /dev/loop0
Found duplicate PV XhLbpVo0hmuwrMQLjfxuAvPFUFZqD4vr: using /dev/loop3 not /dev/loop1
PV VG Fmt Attr PSize PFree DevSize
/dev/loop3 loopa lvm2 a-- 12.00m 12.00m 32.00m
# pvs -o+dev_size /dev/loop1
Found duplicate PV XhLbpVo0hmuwrMQLjfxuAvPFUFZqD4vr: using /dev/loop1 not /dev/loop0
Found duplicate PV XhLbpVo0hmuwrMQLjfxuAvPFUFZqD4vr: using /dev/loop3 not /dev/loop1
PV VG Fmt Attr PSize PFree DevSize
/dev/loop3 loopa lvm2 a-- 12.00m 12.00m 32.00m
# pvs -o+dev_size /dev/loop3 /dev/loop0
Found duplicate PV XhLbpVo0hmuwrMQLjfxuAvPFUFZqD4vr: using /dev/loop1 not /dev/loop0
Found duplicate PV XhLbpVo0hmuwrMQLjfxuAvPFUFZqD4vr: using /dev/loop3 not /dev/loop1
PV VG Fmt Attr PSize PFree DevSize
/dev/loop0 loopa lvm2 a-- 12.00m 12.00m 16.00m
/dev/loop3 loopa lvm2 a-- 12.00m 12.00m 32.00m
# pvs -o+dev_size /dev/loop3 /dev/loop1
Found duplicate PV XhLbpVo0hmuwrMQLjfxuAvPFUFZqD4vr: using /dev/loop1 not /dev/loop0
Found duplicate PV XhLbpVo0hmuwrMQLjfxuAvPFUFZqD4vr: using /dev/loop3 not /dev/loop1
PV VG Fmt Attr PSize PFree DevSize
/dev/loop1 loopa lvm2 a-- 12.00m 12.00m 32.00m
/dev/loop3 loopa lvm2 a-- 12.00m 12.00m 32.00m
# pvs -o+dev_size /dev/loop0 /dev/loop1
Found duplicate PV XhLbpVo0hmuwrMQLjfxuAvPFUFZqD4vr: using /dev/loop1 not /dev/loop0
Found duplicate PV XhLbpVo0hmuwrMQLjfxuAvPFUFZqD4vr: using /dev/loop3 not /dev/loop1
PV VG Fmt Attr PSize PFree DevSize
/dev/loop1 loopa lvm2 a-- 12.00m 12.00m 32.00m
/dev/loop3 loopa lvm2 a-- 12.00m 12.00m 32.00m
# pvs -o+dev_size /dev/loop0 /dev/loop1 /dev/loop3
Found duplicate PV XhLbpVo0hmuwrMQLjfxuAvPFUFZqD4vr: using /dev/loop1 not /dev/loop0
Found duplicate PV XhLbpVo0hmuwrMQLjfxuAvPFUFZqD4vr: using /dev/loop3 not /dev/loop1
PV VG Fmt Attr PSize PFree DevSize
/dev/loop0 loopa lvm2 a-- 12.00m 12.00m 16.00m
/dev/loop1 loopa lvm2 a-- 12.00m 12.00m 32.00m
/dev/loop3 loopa lvm2 a-- 12.00m 12.00m 32.00m
2015-01-14 01:16:22 +03:00
/* Put the cache state back as it was. */
lvmcache_replace_dev ( cmd , pv , dev_orig ) ;
2015-01-09 23:55:16 +03:00
}
}
2015-01-14 23:16:03 +03:00
/*
* This is another rare and obscure case where multiple
* duplicate devices are being displayed by pvs - a , and
* we want each of them to be displayed in the context
* of this VG , so that this VG name appears next to it .
*/
2015-01-14 23:38:05 +03:00
if ( process_all_devices & & lvmcache_found_duplicate_pvs ( ) ) {
2015-01-14 23:16:03 +03:00
while ( ( dil = _device_list_find_pvid ( all_devices , pv ) ) ) {
_device_list_remove ( all_devices , dil - > dev ) ;
dev_orig = pv - > dev ;
lvmcache_replace_dev ( cmd , pv , dil - > dev ) ;
ret = process_single_pv ( cmd , vg , pv , handle ) ;
if ( ret ! = ECMD_PROCESSED )
stack ;
if ( ret > ret_max )
ret_max = ret ;
lvmcache_replace_dev ( cmd , pv , dev_orig ) ;
}
}
2014-10-07 03:34:04 +04:00
}
/*
2015-01-07 23:04:12 +03:00
* When processing only specific PVs , we can quit once they ' ve all been found .
2014-10-07 03:34:04 +04:00
*/
2015-01-14 23:16:03 +03:00
if ( ! process_all_pvs & & dm_list_empty ( arg_tags ) & & dm_list_empty ( arg_devices ) )
2014-10-07 03:34:04 +04:00
break ;
}
2014-11-28 17:04:25 +03:00
out :
if ( ! handle_supplied )
2015-02-13 12:42:21 +03:00
destroy_processing_handle ( cmd , handle ) ;
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
2015-01-07 23:04:12 +03:00
* its dev or tag matches arg_devices or arg_tags . If both
* arg_devices and arg_tags are empty , then process all PVs .
2014-10-07 03:34:04 +04:00
* No PV should be processed more than once .
*
2015-01-07 23:04:12 +03:00
* Each PV is removed from arg_devices and all_devices when it is
* processed . Any names remaining in arg_devices were not found , and
2014-10-07 03:34:04 +04:00
* should produce an error . Any devices remaining in all_devices were
2015-01-09 23:55:16 +03:00
* not found and should be processed by process_device_list ( ) .
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 ,
2015-01-07 23:04:12 +03:00
struct dm_list * arg_devices ,
2014-10-07 03:34:04 +04:00
struct dm_list * arg_tags ,
2015-01-14 23:16:03 +03:00
int process_all_pvs ,
int process_all_devices ,
2014-11-27 17:02:13 +03:00
struct processing_handle * handle ,
2014-10-07 03:34:04 +04:00
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 ;
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 ) ;
2015-02-13 20:01:55 +03:00
if ( _ignore_vg ( vg , vg_name , NULL , flags & READ_ALLOW_INCONSISTENT , & skip ) ) {
2014-11-14 12:50:31 +03:00
stack ;
2014-11-18 18:22:37 +03:00
ret_max = ECMD_FAILED ;
2015-03-19 02:31:46 +03:00
if ( ! skip ) {
release_vg ( vg ) ;
continue ;
}
/* Drop through to eliminate a clustered VG's PVs from the devices list */
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 .
*/
2015-01-07 23:04:12 +03:00
ret = _process_pvs_in_vg ( cmd , vg , all_devices , arg_devices , arg_tags ,
2015-01-14 23:16:03 +03:00
process_all_pvs , process_all_devices , skip ,
handle , process_single_pv ) ;
2014-11-15 00:00:35 +03:00
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. */
2015-01-14 23:16:03 +03:00
if ( ! process_all_pvs & & dm_list_empty ( arg_tags ) & & dm_list_empty ( arg_devices ) )
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
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 ,
2014-11-27 17:02:13 +03:00
struct processing_handle * handle ,
2014-10-07 03:34:04 +04:00
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 */
2015-01-09 23:55:16 +03:00
struct dm_list arg_devices ; /* device_id_list */
2014-10-07 03:53:56 +04:00
struct dm_list all_vgnameids ; /* vgnameid_list */
2015-01-09 23:55:16 +03:00
struct dm_list all_devices ; /* device_id_list */
struct device_id_list * dil ;
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
2015-02-27 01:06:32 +03:00
cmd - > error_foreign_vgs = 0 ;
2014-10-07 03:34:04 +04:00
dm_list_init ( & arg_tags ) ;
dm_list_init ( & arg_pvnames ) ;
2015-01-07 23:04:12 +03:00
dm_list_init ( & arg_devices ) ;
2014-10-07 03:34:04 +04:00
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
2015-01-07 23:04:12 +03:00
*
* Then convert arg_pvnames , which are free - form , user - specified ,
* names / paths into arg_devices which can be used to match below .
2014-10-07 03:34:04 +04:00
*/
2015-01-07 23:04:12 +03:00
if ( ( ret = _get_arg_pvnames ( cmd , argc , argv , & arg_pvnames , & arg_tags ) ) ! = ECMD_PROCESSED ) {
stack ;
2014-10-07 03:34:04 +04:00
return ret ;
2015-01-07 23:04:12 +03:00
}
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
2015-03-19 02:34:46 +03:00
process_all_devices = process_all_pvs & & ( cmd - > command - > flags & ENABLE_ALL_DEVS ) & &
arg_count ( cmd , all_ARG ) ;
2015-01-07 23:04:12 +03:00
toollib: fix duplicate handling in process_each_pv
With use_lvmetad=0, duplicate PVs /dev/loop0 and /dev/loop1,
where in this example, /dev/loop1 is the cached device
referenced by pv->dev, the command 'pvs /dev/loop0' reports:
Failed to find physical volume "/dev/loop0".
This is because the duplicate PV detection by pvid is
not working because _get_all_devices() is not setting
any dev->pvid for any entries. This is because the
pvid information has not yet been saved in lvmcache.
This is fixed by calling _get_vgnameids_on_system()
before _get_all_devices(), which has the effect of
caching the necessary pvid information.
With this fix, running pvs /dev/loop0, or pvs /dev/loop1,
produces no error and one line of output for the PV (the
device printed is the one cached in pv->dev, in this
example /dev/loop1.)
Running 'pvs /dev/loop0 /dev/loop1' produces no error
and two lines of output, with each device displayed
on one of the lines.
Running 'pvs -a' shows two PVs, one with loop0 and one
with loop1, and both shown as a member of the same VG.
Running 'pvs' shows only one of the duplicate PVs,
and that shows the device cached in pv->dev (loop1).
The above output is what the duplicate handling code
was previously designed to output in commits:
b64da4d8b521 toollib: search for duplicate PVs only when needed
3a7c47af0e88 toollib: pvs -a should display VG name for each duplicate PV
57d74a45a05e toollib: override the PV device with duplicates
c1f246fedfc3 toollib: handle duplicate pvs in process_in_pv
As a further step after this, we may choose to change
some of those.
For all of these commands, a warning is printed about
the existence of the duplicate PVs:
Found duplicate PV ...: using /dev/loop1 not /dev/loop0
2015-04-20 22:35:35 +03:00
/*
2015-05-06 00:24:50 +03:00
* Need pvid ' s set on all PVs before processing so that pvid ' s
* can be compared to find duplicates while processing .
toollib: fix duplicate handling in process_each_pv
With use_lvmetad=0, duplicate PVs /dev/loop0 and /dev/loop1,
where in this example, /dev/loop1 is the cached device
referenced by pv->dev, the command 'pvs /dev/loop0' reports:
Failed to find physical volume "/dev/loop0".
This is because the duplicate PV detection by pvid is
not working because _get_all_devices() is not setting
any dev->pvid for any entries. This is because the
pvid information has not yet been saved in lvmcache.
This is fixed by calling _get_vgnameids_on_system()
before _get_all_devices(), which has the effect of
caching the necessary pvid information.
With this fix, running pvs /dev/loop0, or pvs /dev/loop1,
produces no error and one line of output for the PV (the
device printed is the one cached in pv->dev, in this
example /dev/loop1.)
Running 'pvs /dev/loop0 /dev/loop1' produces no error
and two lines of output, with each device displayed
on one of the lines.
Running 'pvs -a' shows two PVs, one with loop0 and one
with loop1, and both shown as a member of the same VG.
Running 'pvs' shows only one of the duplicate PVs,
and that shows the device cached in pv->dev (loop1).
The above output is what the duplicate handling code
was previously designed to output in commits:
b64da4d8b521 toollib: search for duplicate PVs only when needed
3a7c47af0e88 toollib: pvs -a should display VG name for each duplicate PV
57d74a45a05e toollib: override the PV device with duplicates
c1f246fedfc3 toollib: handle duplicate pvs in process_in_pv
As a further step after this, we may choose to change
some of those.
For all of these commands, a warning is printed about
the existence of the duplicate PVs:
Found duplicate PV ...: using /dev/loop1 not /dev/loop0
2015-04-20 22:35:35 +03:00
*/
2015-05-06 00:24:50 +03:00
lvmcache_seed_infos_from_lvmetad ( cmd ) ;
if ( ! get_vgnameids ( cmd , & all_vgnameids , only_this_vgname , 1 ) ) {
toollib: fix duplicate handling in process_each_pv
With use_lvmetad=0, duplicate PVs /dev/loop0 and /dev/loop1,
where in this example, /dev/loop1 is the cached device
referenced by pv->dev, the command 'pvs /dev/loop0' reports:
Failed to find physical volume "/dev/loop0".
This is because the duplicate PV detection by pvid is
not working because _get_all_devices() is not setting
any dev->pvid for any entries. This is because the
pvid information has not yet been saved in lvmcache.
This is fixed by calling _get_vgnameids_on_system()
before _get_all_devices(), which has the effect of
caching the necessary pvid information.
With this fix, running pvs /dev/loop0, or pvs /dev/loop1,
produces no error and one line of output for the PV (the
device printed is the one cached in pv->dev, in this
example /dev/loop1.)
Running 'pvs /dev/loop0 /dev/loop1' produces no error
and two lines of output, with each device displayed
on one of the lines.
Running 'pvs -a' shows two PVs, one with loop0 and one
with loop1, and both shown as a member of the same VG.
Running 'pvs' shows only one of the duplicate PVs,
and that shows the device cached in pv->dev (loop1).
The above output is what the duplicate handling code
was previously designed to output in commits:
b64da4d8b521 toollib: search for duplicate PVs only when needed
3a7c47af0e88 toollib: pvs -a should display VG name for each duplicate PV
57d74a45a05e toollib: override the PV device with duplicates
c1f246fedfc3 toollib: handle duplicate pvs in process_in_pv
As a further step after this, we may choose to change
some of those.
For all of these commands, a warning is printed about
the existence of the duplicate PVs:
Found duplicate PV ...: using /dev/loop1 not /dev/loop0
2015-04-20 22:35:35 +03:00
stack ;
return ret ;
}
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 .
*/
tolllib: process_each_pv: always use full_filter unconditionally when getting all devices
(This reverts patch #d95c6154)
Filter complete device list through full_filter unconditionally when
we're getting the list of *all* devices even in case we're interested
only in fraction of those devices - the PVs, not the other devices
which are not PVs yet (e.g. pvs vs. pvs -a).
We need to do this full filtering whenever we're handling *complete*
list of devices, we need to be safe here, mainly if there are any
future changes and we'd forgot to change to use proper filtering then.
Also properly preventing duplicates if there are any block subsystem
components used (mpath, MD ...).
Thing here is that (under use_lvmetad=1), cmd->filter can be used
only if we're sure that the list of devices we're filtering contains
only PVs. We have to use cmd->full_filter otherwise (like it is in
case of _get_all_devices fn which acquires complete list of devices,
no matter if it is a PV or not).
Of course, cmd->full_filter is more extensive than cmd->filter
which is only a subset of full_filter.
We could optimize this in a way that if we're interested in PVs only
during process_each_pv processing (e.g. using pvs in contrast to pvs -a),
we'd get the list of PV devices directly from lvmetad from the
lvmcache_seed_infos_from_lvmetad fn call which currently updates
lvmcache only. We'd add an additional output arg for this fn to get
the list of PV devices directly in addition, without a need to iterate
over all devices which include non-PVs which we're not interested in
anyway, hence we could use only cmd->filter, not the cmd->full_filter.
So the code would look something like this:
static int _get_all_devices(....)
{
struct device_id_list *dil;
if (interested_in_pvs_only)
lvmcache_seed_infos_from_lvmetad(cmd, &dil); /* new "dil" arg */
/* the "dil" list would be filtered through cmd->filter inside lvmcache_seed_infos_from_lvmetad */
else {
lvmcache_seed_infos_from_lvmetad(cmd, NULL);
dev_iter_create(cmd->full_filter)
while (dev = dev_iter_get ...) {
dm_list_add(all_devices, &dil->list);
}
}
}
2015-02-13 12:59:19 +03:00
if ( ( ret = _get_all_devices ( cmd , & all_devices ) ! = ECMD_PROCESSED ) ) {
2014-10-07 03:34:04 +04:00
stack ;
return ret ;
}
2014-10-07 01:02:00 +04:00
2015-03-19 02:34:46 +03:00
if ( ( ret = _get_arg_devices ( cmd , & arg_pvnames , & arg_devices ) ! = ECMD_PROCESSED ) )
/* get_arg_devices reports the error for any PV names not found. */
ret_max = ECMD_FAILED ;
2014-11-15 00:00:35 +03:00
ret = _process_pvs_in_vgs ( cmd , flags , & all_vgnameids , & all_devices ,
2015-01-14 23:16:03 +03:00
& arg_devices , & arg_tags ,
process_all_pvs , process_all_devices ,
2014-11-15 00:00:35 +03:00
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
2015-01-09 23:55:16 +03:00
dm_list_iterate_items ( dil , & arg_devices ) {
log_error ( " Failed to find physical volume \" %s \" . " , dev_name ( dil - > dev ) ) ;
2015-01-07 23:04:12 +03:00
ret_max = ECMD_FAILED ;
}
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 ,
2014-11-27 17:02:13 +03:00
struct processing_handle * handle ,
process_single_pv_fn_t process_single_pv )
2014-10-07 03:34:04 +04:00
{
2014-12-03 16:20:00 +03:00
int whole_selected = 0 ;
2014-10-07 03:34:04 +04:00
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 ) ;
2014-12-03 16:20:00 +03:00
_update_selection_result ( handle , & whole_selected ) ;
2014-11-15 00:00:35 +03:00
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 ;
}
2014-12-03 16:20:00 +03:00
_set_final_selection_result ( handle , whole_selected ) ;
2014-10-07 03:34:04 +04:00
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 ,
2014-11-27 17:02:13 +03:00
struct processing_handle * handle __attribute__ ( ( unused ) ) )
2014-10-07 19:45:45 +04:00
{
/*
* 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 ;
}