2005-06-06 21:12:08 +04:00
/*
2014-07-11 14:15:23 +04:00
* Copyright ( C ) 2005 - 2014 Red Hat , Inc . All rights reserved .
2005-06-06 21:12:08 +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 .
2005-06-06 21:12:08 +04:00
*
2007-08-21 00:55:30 +04:00
* You should have received a copy of the GNU Lesser General Public License
2005-06-06 21:12:08 +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
*/
# include "tools.h"
2007-12-22 15:13:29 +03:00
# include "polldaemon.h"
2005-11-29 21:20:23 +03:00
# include "lv_alloc.h"
2005-06-06 21:12:08 +04:00
struct lvconvert_params {
2014-07-11 14:15:23 +04:00
int cache ;
2013-03-11 15:40:05 +04:00
int force ;
2006-04-06 00:43:23 +04:00
int snapshot ;
2013-12-04 06:09:37 +04:00
int splitsnapshot ;
2010-01-13 04:45:15 +03:00
int merge ;
2011-08-18 23:43:08 +04:00
int merge_mirror ;
2013-06-25 15:35:12 +04:00
int poolmetadataspare ;
2013-03-11 15:40:05 +04:00
int thin ;
int yes ;
2006-04-06 00:43:23 +04:00
int zero ;
2005-08-15 18:10:28 +04:00
const char * lv_name ;
This patch adds the capability to split off a mirror legs.
It is pretty much the same as reducing the number of
mirror legs, but we just don't delete them afterwards.
The following command line interface is enforced:
prompt> lvconvert --splitmirror <n> -n <name> <VG>/<LV>
where 'n' is the number of images to split off, and
where 'name' is the name of the newly split off logical volume.
If more than one leg is split off, a new mirror will be the
result. The newly split off mirror will have a 'core' log.
Example:
[root@bp-01 LVM2]# !lvs
lvs -a -o name,copy_percent,devices
LV Copy% Devices
lv 100.00 lv_mimage_0(0),lv_mimage_1(0),lv_mimage_2(0),lv_mimage_3(0)
[lv_mimage_0] /dev/sdb1(0)
[lv_mimage_1] /dev/sdc1(0)
[lv_mimage_2] /dev/sdd1(0)
[lv_mimage_3] /dev/sde1(0)
[lv_mlog] /dev/sdi1(0)
[root@bp-01 LVM2]# lvconvert --splitmirrors 2 --name split vg/lv /dev/sd[ce]1
Logical volume lv converted.
[root@bp-01 LVM2]# !lvs
lvs -a -o name,copy_percent,devices
LV Copy% Devices
lv 100.00 lv_mimage_0(0),lv_mimage_2(0)
[lv_mimage_0] /dev/sdb1(0)
[lv_mimage_2] /dev/sdd1(0)
[lv_mlog] /dev/sdi1(0)
split 100.00 split_mimage_0(0),split_mimage_1(0)
[split_mimage_0] /dev/sde1(0)
[split_mimage_1] /dev/sdc1(0)
It can be seen that '--splitmirror <n>' is exactly the same
as '--mirrors -<n>' (note the minus sign), except there is the
additional notion to keep the image being detached from the
mirror instead of just throwing it away.
Signed-off-by: Jonathan Brassow <jbrassow@redhat.com>
2010-01-09 01:00:31 +03:00
const char * lv_split_name ;
2007-12-22 15:13:29 +03:00
const char * lv_name_full ;
2006-04-06 00:43:23 +04:00
const char * vg_name ;
2008-01-15 00:11:47 +03:00
int wait_completion ;
int need_polling ;
2006-04-06 00:43:23 +04:00
2013-10-04 17:32:23 +04:00
int thin_chunk_size_calc_policy ;
2006-04-06 00:43:23 +04:00
uint32_t chunk_size ;
uint32_t region_size ;
2005-08-15 18:10:28 +04:00
uint32_t mirrors ;
2005-11-29 21:20:23 +03:00
sign_t mirrors_sign ;
This patch adds the capability to split off a mirror legs.
It is pretty much the same as reducing the number of
mirror legs, but we just don't delete them afterwards.
The following command line interface is enforced:
prompt> lvconvert --splitmirror <n> -n <name> <VG>/<LV>
where 'n' is the number of images to split off, and
where 'name' is the name of the newly split off logical volume.
If more than one leg is split off, a new mirror will be the
result. The newly split off mirror will have a 'core' log.
Example:
[root@bp-01 LVM2]# !lvs
lvs -a -o name,copy_percent,devices
LV Copy% Devices
lv 100.00 lv_mimage_0(0),lv_mimage_1(0),lv_mimage_2(0),lv_mimage_3(0)
[lv_mimage_0] /dev/sdb1(0)
[lv_mimage_1] /dev/sdc1(0)
[lv_mimage_2] /dev/sdd1(0)
[lv_mimage_3] /dev/sde1(0)
[lv_mlog] /dev/sdi1(0)
[root@bp-01 LVM2]# lvconvert --splitmirrors 2 --name split vg/lv /dev/sd[ce]1
Logical volume lv converted.
[root@bp-01 LVM2]# !lvs
lvs -a -o name,copy_percent,devices
LV Copy% Devices
lv 100.00 lv_mimage_0(0),lv_mimage_2(0)
[lv_mimage_0] /dev/sdb1(0)
[lv_mimage_2] /dev/sdd1(0)
[lv_mlog] /dev/sdi1(0)
split 100.00 split_mimage_0(0),split_mimage_1(0)
[split_mimage_0] /dev/sde1(0)
[split_mimage_1] /dev/sdc1(0)
It can be seen that '--splitmirror <n>' is exactly the same
as '--mirrors -<n>' (note the minus sign), except there is the
additional notion to keep the image being detached from the
mirror instead of just throwing it away.
Signed-off-by: Jonathan Brassow <jbrassow@redhat.com>
2010-01-09 01:00:31 +03:00
uint32_t keep_mimages ;
2010-04-13 05:54:32 +04:00
uint32_t stripes ;
uint32_t stripe_size ;
2012-11-19 16:37:57 +04:00
uint32_t read_ahead ;
2014-02-12 19:51:42 +04:00
uint32_t feature_flags ; /* cache_pool */
2006-04-06 00:43:23 +04:00
2011-08-11 22:24:40 +04:00
const struct segment_type * segtype ;
2012-11-15 13:32:13 +04:00
unsigned target_attr ;
2005-08-15 18:10:28 +04:00
alloc_policy_t alloc ;
int pv_count ;
char * * pvs ;
2008-11-04 01:14:30 +03:00
struct dm_list * pvh ;
2010-01-13 04:49:52 +03:00
2011-11-30 06:02:10 +04:00
int replace_pv_count ;
char * * replace_pvs ;
struct dm_list * replace_pvh ;
2010-01-13 04:49:52 +03:00
struct logical_volume * lv_to_poll ;
2012-05-09 16:17:06 +04:00
2013-03-06 14:58:09 +04:00
int passed_args ;
2014-07-11 14:15:23 +04:00
uint64_t pool_metadata_size ;
2013-02-05 14:26:27 +04:00
const char * origin_lv_name ;
2012-05-09 16:17:06 +04:00
const char * pool_data_lv_name ;
2014-07-11 14:15:23 +04:00
struct logical_volume * pool_data_lv ;
2012-05-14 15:57:30 +04:00
const char * pool_metadata_lv_name ;
2014-07-11 14:15:23 +04:00
struct logical_volume * pool_metadata_lv ;
2012-05-14 15:57:30 +04:00
thin_discards_t discards ;
2005-06-06 21:12:08 +04:00
} ;
2014-07-11 14:15:23 +04:00
static int _lvconvert_vg_name ( struct lvconvert_params * lp ,
struct cmd_context * cmd ,
const char * * lv_name )
{
const char * vg_name ;
const char * tmp_str ;
if ( ! lv_name | | ! * lv_name )
return 1 ;
/* If contains VG name, extract it. */
if ( ( tmp_str = strchr ( * lv_name , ( int ) ' / ' ) ) ) {
if ( ! ( vg_name = extract_vgname ( cmd , * lv_name ) ) )
return_0 ;
if ( ! lp - > vg_name )
lp - > vg_name = vg_name ;
else if ( strcmp ( vg_name , lp - > vg_name ) ) {
log_error ( " Please use a single volume group name "
" ( \" %s \" or \" %s \" ) " , vg_name , lp - > vg_name ) ;
return 0 ;
}
/* Strip VG from lv_name */
* lv_name = tmp_str + 1 ;
}
if ( ! apply_lvname_restrictions ( * lv_name ) )
return_0 ;
return 1 ;
}
2006-04-19 19:33:07 +04:00
static int _lvconvert_name_params ( struct lvconvert_params * lp ,
struct cmd_context * cmd ,
int * pargc , char * * * pargv )
2006-04-06 00:43:23 +04:00
{
char * ptr ;
2006-04-07 18:14:31 +04:00
const char * vg_name = NULL ;
2006-04-06 00:43:23 +04:00
2014-08-13 16:19:13 +04:00
if ( lp - > merge ) {
if ( ! * pargc ) {
log_error ( " Please specify a logical volume path. " ) ;
return 0 ;
}
2010-02-06 01:44:37 +03:00
return 1 ;
2014-08-13 16:19:13 +04:00
}
2010-02-06 01:44:37 +03:00
2014-07-11 14:15:23 +04:00
if ( ! * pargc ) {
if ( lp - > cache ) {
log_error ( " Logical volume name for caching is missing. " ) ;
return 0 ;
}
if ( lp - > thin ) {
2006-04-06 00:43:23 +04:00
log_error ( " Please specify a logical volume to act as "
2014-07-11 14:15:23 +04:00
" the external origin. " ) ;
2006-04-06 00:43:23 +04:00
return 0 ;
}
2014-07-11 14:15:23 +04:00
if ( lp - > snapshot ) {
log_error ( " Please specify a logical volume to act as "
" the snapshot exception store. " ) ;
2006-04-06 00:43:23 +04:00
return 0 ;
}
2014-07-11 14:15:23 +04:00
if ( ! lp - > lv_name_full ) {
log_error ( " Please provide logical volume path. " ) ;
return 0 ;
2013-02-04 16:56:54 +04:00
}
2014-07-11 14:15:23 +04:00
} else if ( ! lp - > lv_name_full ) {
lp - > lv_name_full = ( * pargv ) [ 0 ] ;
( * pargv ) + + , ( * pargc ) - - ;
2013-02-05 14:26:27 +04:00
}
2013-02-04 16:56:54 +04:00
2014-07-11 14:15:23 +04:00
if ( ! _lvconvert_vg_name ( lp , cmd , & lp - > pool_metadata_lv_name ) )
return_0 ;
2012-05-09 16:17:06 +04:00
2014-07-11 14:15:23 +04:00
if ( ! _lvconvert_vg_name ( lp , cmd , & lp - > pool_data_lv_name ) )
return_0 ;
2006-04-06 00:43:23 +04:00
2014-07-11 14:15:23 +04:00
if ( ! _lvconvert_vg_name ( lp , cmd , & lp - > origin_lv_name ) )
return_0 ;
2006-04-06 00:43:23 +04:00
2014-07-17 14:19:48 +04:00
if ( ! _lvconvert_vg_name ( lp , cmd , & lp - > lv_split_name ) )
return_0 ;
2007-12-22 15:13:29 +03:00
if ( strchr ( lp - > lv_name_full , ' / ' ) & &
( vg_name = extract_vgname ( cmd , lp - > lv_name_full ) ) & &
2006-04-06 00:43:23 +04:00
lp - > vg_name & & strcmp ( vg_name , lp - > vg_name ) ) {
log_error ( " Please use a single volume group name "
" ( \" %s \" or \" %s \" ) " , vg_name , lp - > vg_name ) ;
return 0 ;
}
if ( ! lp - > vg_name )
lp - > vg_name = vg_name ;
if ( ! validate_name ( lp - > vg_name ) ) {
log_error ( " Please provide a valid volume group name " ) ;
return 0 ;
}
2007-12-22 15:13:29 +03:00
if ( ( ptr = strrchr ( lp - > lv_name_full , ' / ' ) ) )
2006-04-06 00:43:23 +04:00
lp - > lv_name = ptr + 1 ;
2014-07-11 14:15:23 +04:00
else
2014-07-11 15:54:54 +04:00
lp - > lv_name = lp - > lv_name_full ;
2006-04-06 00:43:23 +04:00
2012-05-14 15:57:30 +04:00
if ( ! lp - > merge_mirror & &
! strstr ( lp - > lv_name , " _tdata " ) & &
! strstr ( lp - > lv_name , " _tmeta " ) & &
! apply_lvname_restrictions ( lp - > lv_name ) )
2006-04-06 00:43:23 +04:00
return_0 ;
2014-07-11 14:15:23 +04:00
if ( * pargc ) {
if ( lp - > snapshot ) {
log_error ( " Too many arguments provided for snapshots. " ) ;
return 0 ;
}
if ( lp - > splitsnapshot ) {
log_error ( " Too many arguments provided with --splitsnapshot. " ) ;
return 0 ;
}
if ( lp - > pool_data_lv_name & & lp - > pool_metadata_lv_name ) {
log_error ( " Too many arguments provided for pool. " ) ;
return 0 ;
}
2012-05-09 16:17:06 +04:00
}
2006-04-06 00:43:23 +04:00
return 1 ;
}
2013-07-23 19:04:43 +04:00
static int _check_conversion_type ( struct cmd_context * cmd , const char * type_str )
{
if ( ! type_str | | ! * type_str )
return 1 ;
if ( ! strcmp ( type_str , " mirror " ) ) {
if ( ! arg_count ( cmd , mirrors_ARG ) ) {
log_error ( " --type mirror requires -m/--mirrors " ) ;
return 0 ;
}
return 1 ;
}
/* FIXME: Check thin-pool and thin more thoroughly! */
2014-02-12 19:51:42 +04:00
if ( ! strcmp ( type_str , " snapshot " ) | |
! strncmp ( type_str , " raid " , 4 ) | |
2014-02-19 19:26:03 +04:00
! strcmp ( type_str , " cache-pool " ) | | ! strcmp ( type_str , " cache " ) | |
2013-07-23 19:04:43 +04:00
! strcmp ( type_str , " thin-pool " ) | | ! strcmp ( type_str , " thin " ) )
return 1 ;
log_error ( " Conversion using --type %s is not supported. " , type_str ) ;
return 0 ;
}
/* -s/--snapshot and --type snapshot are synonyms */
2014-07-02 17:09:06 +04:00
static int _snapshot_type_requested ( struct cmd_context * cmd , const char * type_str ) {
2014-07-01 12:13:10 +04:00
return ( arg_count ( cmd , snapshot_ARG ) | | ! strcmp ( type_str , " snapshot " ) ) ;
}
2013-07-23 19:04:43 +04:00
/* mirror/raid* (1,10,4,5,6 and their variants) reshape */
2014-07-02 17:09:06 +04:00
static int _mirror_or_raid_type_requested ( struct cmd_context * cmd , const char * type_str ) {
2014-07-01 12:13:10 +04:00
return ( arg_count ( cmd , mirrors_ARG ) | | ! strncmp ( type_str , " raid " , 4 ) | | ! strcmp ( type_str , " mirror " ) ) ;
}
2013-07-23 19:04:43 +04:00
2014-07-11 14:15:23 +04:00
static int _read_pool_params ( struct lvconvert_params * lp , struct cmd_context * cmd ,
const char * type_str , int * pargc , char * * * pargv )
{
const char * tmp_str ;
int cachepool = 0 ;
int thinpool = 0 ;
2014-07-18 14:19:40 +04:00
if ( ( lp - > pool_data_lv_name = arg_str_value ( cmd , cachepool_ARG , NULL ) ) ) {
2014-07-11 14:15:23 +04:00
if ( type_str [ 0 ] & &
strcmp ( type_str , " cache " ) & &
strcmp ( type_str , " cache-pool " ) ) {
log_error ( " --cachepool argument is only valid with "
" the cache or cache-pool segment type. " ) ;
return 0 ;
}
cachepool = 1 ;
type_str = " cache-pool " ;
} else if ( ! strcmp ( type_str , " cache-pool " ) )
cachepool = 1 ;
2014-07-18 14:19:40 +04:00
else if ( ( lp - > pool_data_lv_name = arg_str_value ( cmd , thinpool_ARG , NULL ) ) ) {
2014-07-11 14:15:23 +04:00
if ( type_str [ 0 ] & &
strcmp ( type_str , " thin " ) & &
strcmp ( type_str , " thin-pool " ) ) {
log_error ( " --thinpool argument is only valid with "
" the thin or thin-pool segment type. " ) ;
return 0 ;
}
thinpool = 1 ;
type_str = " thin-pool " ;
} else if ( ! strcmp ( type_str , " thin-pool " ) )
thinpool = 1 ;
if ( cachepool ) {
2014-07-17 17:12:21 +04:00
if ( ( tmp_str = arg_str_value ( cmd , cachemode_ARG , NULL ) ) & &
! get_cache_mode ( tmp_str , & lp - > feature_flags ) )
return_0 ;
2014-07-11 14:15:23 +04:00
} else {
2014-07-18 23:56:37 +04:00
if ( arg_from_list_is_set ( cmd , " is valid only with cache pools " ,
2014-07-18 14:19:40 +04:00
cachepool_ARG , cachemode_ARG , - 1 ) )
2014-07-11 14:15:23 +04:00
return_0 ;
if ( lp - > cache ) {
log_error ( " --cache requires --cachepool. " ) ;
return 0 ;
}
}
2014-07-18 14:19:40 +04:00
if ( thinpool ) {
lp - > discards = ( thin_discards_t ) arg_uint_value ( cmd , discards_ARG , THIN_DISCARDS_PASSDOWN ) ;
lp - > origin_lv_name = arg_str_value ( cmd , originname_ARG , NULL ) ;
} else {
if ( arg_from_list_is_set ( cmd , " is valid only with thin pools " ,
discards_ARG , originname_ARG , thinpool_ARG ,
zero_ARG , - 1 ) )
return_0 ;
if ( lp - > thin ) {
log_error ( " --thin requires --thinpool. " ) ;
return 0 ;
}
}
2014-07-11 14:15:23 +04:00
if ( thinpool | | cachepool ) {
2014-07-18 23:56:37 +04:00
if ( arg_from_list_is_set ( cmd , " is invalid with pools " ,
merge_ARG , mirrors_ARG , repair_ARG , snapshot_ARG ,
2014-07-23 00:20:18 +04:00
splitmirrors_ARG , splitsnapshot_ARG , - 1 ) )
2014-07-11 14:15:23 +04:00
return_0 ;
2014-07-23 00:20:18 +04:00
if ( ! ( lp - > segtype = get_segtype_from_string ( cmd , type_str ) ) )
return_0 ;
2014-07-11 14:15:23 +04:00
2014-07-23 00:20:18 +04:00
if ( ! get_pool_params ( cmd , lp - > segtype , & lp - > passed_args ,
& lp - > pool_metadata_size ,
& lp - > poolmetadataspare ,
& lp - > chunk_size , & lp - > discards ,
& lp - > zero ) )
return_0 ;
2014-07-11 14:15:23 +04:00
2014-07-23 00:20:18 +04:00
if ( ( lp - > pool_metadata_lv_name = arg_str_value ( cmd , poolmetadata_ARG , NULL ) ) & &
arg_from_list_is_set ( cmd , " is invalid with --poolmetadata " ,
stripesize_ARG , stripes_long_ARG ,
readahead_ARG , - 1 ) )
return_0 ;
2014-07-11 14:15:23 +04:00
2014-07-18 14:19:40 +04:00
if ( ! lp - > pool_data_lv_name ) {
2014-07-11 14:15:23 +04:00
if ( ! * pargc ) {
log_error ( " Please specify the pool data LV. " ) ;
return 0 ;
}
lp - > pool_data_lv_name = ( * pargv ) [ 0 ] ;
2014-07-18 14:19:40 +04:00
( * pargv ) + + , ( * pargc ) - - ;
2014-07-11 14:15:23 +04:00
}
if ( ! lp - > thin & & ! lp - > cache )
lp - > lv_name_full = lp - > pool_data_lv_name ;
2014-07-23 00:20:18 +04:00
2014-07-11 14:15:23 +04:00
/* Hmm _read_activation_params */
lp - > read_ahead = arg_uint_value ( cmd , readahead_ARG ,
cmd - > default_settings . read_ahead ) ;
2014-07-18 23:56:37 +04:00
} else if ( arg_from_list_is_set ( cmd , " is valid only with pools " ,
poolmetadatasize_ARG , poolmetadataspare_ARG ,
- 1 ) )
2014-07-11 14:15:23 +04:00
return_0 ;
return 1 ;
}
2005-08-15 18:10:28 +04:00
static int _read_params ( struct lvconvert_params * lp , struct cmd_context * cmd ,
int argc , char * * argv )
{
2011-11-30 06:02:10 +04:00
int i ;
const char * tmp_str ;
struct arg_value_group_list * group ;
2006-04-28 19:01:39 +04:00
int region_size ;
2006-08-17 22:23:44 +04:00
int pagesize = lvm_getpagesize ( ) ;
2013-07-23 19:04:43 +04:00
const char * type_str = arg_str_value ( cmd , type_ARG , " " ) ;
2006-04-28 19:01:39 +04:00
2013-07-23 19:04:43 +04:00
if ( ! _check_conversion_type ( cmd , type_str ) )
return_0 ;
2014-07-11 00:02:54 +04:00
if ( arg_count ( cmd , repair_ARG ) & &
2014-07-18 23:56:37 +04:00
arg_outside_list_is_set ( cmd , " cannot be used with --repair " ,
repair_ARG ,
alloc_ARG , use_policies_ARG ,
stripes_long_ARG , stripesize_ARG ,
force_ARG , noudevsync_ARG , test_ARG ,
- 1 ) )
2014-07-11 00:02:54 +04:00
return_0 ;
if ( arg_is_set ( cmd , mirrorlog_ARG ) & & arg_is_set ( cmd , corelog_ARG ) ) {
log_error ( " --mirrorlog and --corelog are incompatible. " ) ;
return 0 ;
}
2014-07-17 17:36:07 +04:00
if ( arg_is_set ( cmd , splitsnapshot_ARG ) ) {
2014-07-18 23:56:37 +04:00
if ( arg_outside_list_is_set ( cmd , " cannot be used with --splitsnapshot " ,
splitsnapshot_ARG ,
force_ARG , noudevsync_ARG , test_ARG ,
- 1 ) )
2014-07-17 17:36:07 +04:00
return_0 ;
2013-12-04 06:09:37 +04:00
lp - > splitsnapshot = 1 ;
2014-07-17 17:36:07 +04:00
}
2013-12-04 06:09:37 +04:00
2014-07-02 17:09:06 +04:00
if ( ( _snapshot_type_requested ( cmd , type_str ) | | arg_count ( cmd , merge_ARG ) ) & &
( arg_count ( cmd , mirrorlog_ARG ) | | _mirror_or_raid_type_requested ( cmd , type_str ) | |
2013-03-11 13:44:05 +04:00
arg_count ( cmd , repair_ARG ) | | arg_count ( cmd , thinpool_ARG ) ) ) {
2013-07-23 19:04:43 +04:00
log_error ( " --snapshot/--type snapshot or --merge argument "
" cannot be mixed with --mirrors/--type mirror/--type raid*, "
" --mirrorlog, --repair or --thinpool. " ) ;
2006-04-06 00:43:23 +04:00
return 0 ;
}
2012-12-11 18:50:25 +04:00
if ( ( arg_count ( cmd , stripes_long_ARG ) | | arg_count ( cmd , stripesize_ARG ) ) & &
2014-07-02 17:09:06 +04:00
! ( _mirror_or_raid_type_requested ( cmd , type_str ) | |
2013-07-23 19:04:43 +04:00
arg_count ( cmd , repair_ARG ) | |
arg_count ( cmd , thinpool_ARG ) ) ) {
2012-12-11 18:50:25 +04:00
log_error ( " --stripes or --stripesize argument is only valid "
2013-07-23 19:04:43 +04:00
" with --mirrors/--type mirror/--type raid*, --repair and --thinpool " ) ;
2012-12-11 18:50:25 +04:00
return 0 ;
}
2014-07-11 14:15:23 +04:00
if ( arg_count ( cmd , cache_ARG ) )
lp - > cache = 1 ;
2010-01-13 04:45:15 +03:00
2014-07-11 14:15:23 +04:00
if ( ! strcmp ( type_str , " cache " ) )
lp - > cache = 1 ;
else if ( lp - > cache ) {
if ( type_str [ 0 ] ) {
log_error ( " --cache is incompatible with --type %s " , type_str ) ;
return 0 ;
}
type_str = " cache " ;
This patch adds the capability to split off a mirror legs.
It is pretty much the same as reducing the number of
mirror legs, but we just don't delete them afterwards.
The following command line interface is enforced:
prompt> lvconvert --splitmirror <n> -n <name> <VG>/<LV>
where 'n' is the number of images to split off, and
where 'name' is the name of the newly split off logical volume.
If more than one leg is split off, a new mirror will be the
result. The newly split off mirror will have a 'core' log.
Example:
[root@bp-01 LVM2]# !lvs
lvs -a -o name,copy_percent,devices
LV Copy% Devices
lv 100.00 lv_mimage_0(0),lv_mimage_1(0),lv_mimage_2(0),lv_mimage_3(0)
[lv_mimage_0] /dev/sdb1(0)
[lv_mimage_1] /dev/sdc1(0)
[lv_mimage_2] /dev/sdd1(0)
[lv_mimage_3] /dev/sde1(0)
[lv_mlog] /dev/sdi1(0)
[root@bp-01 LVM2]# lvconvert --splitmirrors 2 --name split vg/lv /dev/sd[ce]1
Logical volume lv converted.
[root@bp-01 LVM2]# !lvs
lvs -a -o name,copy_percent,devices
LV Copy% Devices
lv 100.00 lv_mimage_0(0),lv_mimage_2(0)
[lv_mimage_0] /dev/sdb1(0)
[lv_mimage_2] /dev/sdd1(0)
[lv_mlog] /dev/sdi1(0)
split 100.00 split_mimage_0(0),split_mimage_1(0)
[split_mimage_0] /dev/sde1(0)
[split_mimage_1] /dev/sdc1(0)
It can be seen that '--splitmirror <n>' is exactly the same
as '--mirrors -<n>' (note the minus sign), except there is the
additional notion to keep the image being detached from the
mirror instead of just throwing it away.
Signed-off-by: Jonathan Brassow <jbrassow@redhat.com>
2010-01-09 01:00:31 +03:00
}
2013-03-11 15:40:05 +04:00
if ( arg_count ( cmd , thin_ARG ) )
lp - > thin = 1 ;
2014-07-11 14:15:23 +04:00
if ( ! strcmp ( type_str , " thin " ) )
lp - > thin = 1 ;
else if ( lp - > thin ) {
if ( type_str [ 0 ] ) {
log_error ( " --thin is incompatible with --type %s " , type_str ) ;
2014-02-12 19:55:35 +04:00
return 0 ;
}
2014-07-11 14:15:23 +04:00
type_str = " thin " ;
}
if ( ! _read_pool_params ( lp , cmd , type_str , & argc , & argv ) )
return_0 ;
if ( ! arg_count ( cmd , background_ARG ) )
lp - > wait_completion = 1 ;
if ( _snapshot_type_requested ( cmd , type_str ) ) {
2012-05-09 16:17:06 +04:00
if ( arg_count ( cmd , merge_ARG ) ) {
2014-07-11 14:15:23 +04:00
log_error ( " --snapshot and --merge are mutually exclusive. " ) ;
2012-05-09 16:17:06 +04:00
return 0 ;
}
2014-07-11 14:15:23 +04:00
lp - > snapshot = 1 ;
2012-05-09 16:17:06 +04:00
}
This patch adds the capability to split off a mirror legs.
It is pretty much the same as reducing the number of
mirror legs, but we just don't delete them afterwards.
The following command line interface is enforced:
prompt> lvconvert --splitmirror <n> -n <name> <VG>/<LV>
where 'n' is the number of images to split off, and
where 'name' is the name of the newly split off logical volume.
If more than one leg is split off, a new mirror will be the
result. The newly split off mirror will have a 'core' log.
Example:
[root@bp-01 LVM2]# !lvs
lvs -a -o name,copy_percent,devices
LV Copy% Devices
lv 100.00 lv_mimage_0(0),lv_mimage_1(0),lv_mimage_2(0),lv_mimage_3(0)
[lv_mimage_0] /dev/sdb1(0)
[lv_mimage_1] /dev/sdc1(0)
[lv_mimage_2] /dev/sdd1(0)
[lv_mimage_3] /dev/sde1(0)
[lv_mlog] /dev/sdi1(0)
[root@bp-01 LVM2]# lvconvert --splitmirrors 2 --name split vg/lv /dev/sd[ce]1
Logical volume lv converted.
[root@bp-01 LVM2]# !lvs
lvs -a -o name,copy_percent,devices
LV Copy% Devices
lv 100.00 lv_mimage_0(0),lv_mimage_2(0)
[lv_mimage_0] /dev/sdb1(0)
[lv_mimage_2] /dev/sdd1(0)
[lv_mlog] /dev/sdi1(0)
split 100.00 split_mimage_0(0),split_mimage_1(0)
[split_mimage_0] /dev/sde1(0)
[split_mimage_1] /dev/sdc1(0)
It can be seen that '--splitmirror <n>' is exactly the same
as '--mirrors -<n>' (note the minus sign), except there is the
additional notion to keep the image being detached from the
mirror instead of just throwing it away.
Signed-off-by: Jonathan Brassow <jbrassow@redhat.com>
2010-01-09 01:00:31 +03:00
/*
* The ' - - splitmirrors n ' argument is equivalent to ' - - mirrors - n '
* ( note the minus sign ) , except that it signifies the additional
* intent to keep the mimage that is detached , rather than
* discarding it .
*/
if ( arg_count ( cmd , splitmirrors_ARG ) ) {
2014-07-11 14:15:23 +04:00
if ( _mirror_or_raid_type_requested ( cmd , type_str ) ) {
log_error ( " --mirrors/--type mirror/--type raid* and --splitmirrors are "
" mutually exclusive. " ) ;
return 0 ;
}
2011-08-18 23:38:26 +04:00
if ( ! arg_count ( cmd , name_ARG ) & &
! arg_count ( cmd , trackchanges_ARG ) ) {
This patch adds the capability to split off a mirror legs.
It is pretty much the same as reducing the number of
mirror legs, but we just don't delete them afterwards.
The following command line interface is enforced:
prompt> lvconvert --splitmirror <n> -n <name> <VG>/<LV>
where 'n' is the number of images to split off, and
where 'name' is the name of the newly split off logical volume.
If more than one leg is split off, a new mirror will be the
result. The newly split off mirror will have a 'core' log.
Example:
[root@bp-01 LVM2]# !lvs
lvs -a -o name,copy_percent,devices
LV Copy% Devices
lv 100.00 lv_mimage_0(0),lv_mimage_1(0),lv_mimage_2(0),lv_mimage_3(0)
[lv_mimage_0] /dev/sdb1(0)
[lv_mimage_1] /dev/sdc1(0)
[lv_mimage_2] /dev/sdd1(0)
[lv_mimage_3] /dev/sde1(0)
[lv_mlog] /dev/sdi1(0)
[root@bp-01 LVM2]# lvconvert --splitmirrors 2 --name split vg/lv /dev/sd[ce]1
Logical volume lv converted.
[root@bp-01 LVM2]# !lvs
lvs -a -o name,copy_percent,devices
LV Copy% Devices
lv 100.00 lv_mimage_0(0),lv_mimage_2(0)
[lv_mimage_0] /dev/sdb1(0)
[lv_mimage_2] /dev/sdd1(0)
[lv_mlog] /dev/sdi1(0)
split 100.00 split_mimage_0(0),split_mimage_1(0)
[split_mimage_0] /dev/sde1(0)
[split_mimage_1] /dev/sdc1(0)
It can be seen that '--splitmirror <n>' is exactly the same
as '--mirrors -<n>' (note the minus sign), except there is the
additional notion to keep the image being detached from the
mirror instead of just throwing it away.
Signed-off-by: Jonathan Brassow <jbrassow@redhat.com>
2010-01-09 01:00:31 +03:00
log_error ( " Please name the new logical volume using '--name' " ) ;
return 0 ;
}
2014-07-17 14:19:48 +04:00
lp - > lv_split_name = arg_str_value ( cmd , name_ARG , NULL ) ;
This patch adds the capability to split off a mirror legs.
It is pretty much the same as reducing the number of
mirror legs, but we just don't delete them afterwards.
The following command line interface is enforced:
prompt> lvconvert --splitmirror <n> -n <name> <VG>/<LV>
where 'n' is the number of images to split off, and
where 'name' is the name of the newly split off logical volume.
If more than one leg is split off, a new mirror will be the
result. The newly split off mirror will have a 'core' log.
Example:
[root@bp-01 LVM2]# !lvs
lvs -a -o name,copy_percent,devices
LV Copy% Devices
lv 100.00 lv_mimage_0(0),lv_mimage_1(0),lv_mimage_2(0),lv_mimage_3(0)
[lv_mimage_0] /dev/sdb1(0)
[lv_mimage_1] /dev/sdc1(0)
[lv_mimage_2] /dev/sdd1(0)
[lv_mimage_3] /dev/sde1(0)
[lv_mlog] /dev/sdi1(0)
[root@bp-01 LVM2]# lvconvert --splitmirrors 2 --name split vg/lv /dev/sd[ce]1
Logical volume lv converted.
[root@bp-01 LVM2]# !lvs
lvs -a -o name,copy_percent,devices
LV Copy% Devices
lv 100.00 lv_mimage_0(0),lv_mimage_2(0)
[lv_mimage_0] /dev/sdb1(0)
[lv_mimage_2] /dev/sdd1(0)
[lv_mlog] /dev/sdi1(0)
split 100.00 split_mimage_0(0),split_mimage_1(0)
[split_mimage_0] /dev/sde1(0)
[split_mimage_1] /dev/sdc1(0)
It can be seen that '--splitmirror <n>' is exactly the same
as '--mirrors -<n>' (note the minus sign), except there is the
additional notion to keep the image being detached from the
mirror instead of just throwing it away.
Signed-off-by: Jonathan Brassow <jbrassow@redhat.com>
2010-01-09 01:00:31 +03:00
lp - > keep_mimages = 1 ;
lp - > mirrors = arg_uint_value ( cmd , splitmirrors_ARG , 0 ) ;
lp - > mirrors_sign = SIGN_MINUS ;
} else if ( arg_count ( cmd , name_ARG ) ) {
log_error ( " The 'name' argument is only valid "
" with --splitmirrors " ) ;
return 0 ;
}
2011-08-18 23:43:08 +04:00
if ( arg_count ( cmd , merge_ARG ) ) {
if ( ( argc = = 1 ) & & strstr ( argv [ 0 ] , " _rimage_ " ) )
lp - > merge_mirror = 1 ;
else
lp - > merge = 1 ;
}
2010-01-13 04:45:15 +03:00
2006-04-06 00:43:23 +04:00
if ( arg_count ( cmd , mirrors_ARG ) ) {
This patch adds the capability to split off a mirror legs.
It is pretty much the same as reducing the number of
mirror legs, but we just don't delete them afterwards.
The following command line interface is enforced:
prompt> lvconvert --splitmirror <n> -n <name> <VG>/<LV>
where 'n' is the number of images to split off, and
where 'name' is the name of the newly split off logical volume.
If more than one leg is split off, a new mirror will be the
result. The newly split off mirror will have a 'core' log.
Example:
[root@bp-01 LVM2]# !lvs
lvs -a -o name,copy_percent,devices
LV Copy% Devices
lv 100.00 lv_mimage_0(0),lv_mimage_1(0),lv_mimage_2(0),lv_mimage_3(0)
[lv_mimage_0] /dev/sdb1(0)
[lv_mimage_1] /dev/sdc1(0)
[lv_mimage_2] /dev/sdd1(0)
[lv_mimage_3] /dev/sde1(0)
[lv_mlog] /dev/sdi1(0)
[root@bp-01 LVM2]# lvconvert --splitmirrors 2 --name split vg/lv /dev/sd[ce]1
Logical volume lv converted.
[root@bp-01 LVM2]# !lvs
lvs -a -o name,copy_percent,devices
LV Copy% Devices
lv 100.00 lv_mimage_0(0),lv_mimage_2(0)
[lv_mimage_0] /dev/sdb1(0)
[lv_mimage_2] /dev/sdd1(0)
[lv_mlog] /dev/sdi1(0)
split 100.00 split_mimage_0(0),split_mimage_1(0)
[split_mimage_0] /dev/sde1(0)
[split_mimage_1] /dev/sdc1(0)
It can be seen that '--splitmirror <n>' is exactly the same
as '--mirrors -<n>' (note the minus sign), except there is the
additional notion to keep the image being detached from the
mirror instead of just throwing it away.
Signed-off-by: Jonathan Brassow <jbrassow@redhat.com>
2010-01-09 01:00:31 +03:00
/*
* - - splitmirrors has been chosen as the mechanism for
* specifying the intent of detaching and keeping a mimage
* versus an additional qualifying argument being added here .
*/
2006-04-06 00:43:23 +04:00
lp - > mirrors = arg_uint_value ( cmd , mirrors_ARG , 0 ) ;
2012-02-28 18:24:57 +04:00
lp - > mirrors_sign = arg_sign_value ( cmd , mirrors_ARG , SIGN_NONE ) ;
2006-04-06 00:43:23 +04:00
}
2012-03-02 01:14:43 +04:00
lp - > alloc = ( alloc_policy_t ) arg_uint_value ( cmd , alloc_ARG , ALLOC_INHERIT ) ;
2005-08-15 18:10:28 +04:00
2013-12-04 06:09:37 +04:00
/* There are six types of lvconvert. */
2010-04-13 05:54:32 +04:00
if ( lp - > merge ) { /* Snapshot merge */
2014-07-18 23:56:37 +04:00
if ( arg_outside_list_is_set ( cmd , " cannot be used with --merge " ,
merge_ARG ,
background_ARG , interval_ARG ,
force_ARG , noudevsync_ARG , test_ARG ,
- 1 ) )
2014-07-17 17:38:13 +04:00
return_0 ;
2010-01-13 04:45:15 +03:00
if ( ! ( lp - > segtype = get_segtype_from_string ( cmd , " snapshot " ) ) )
return_0 ;
2013-12-04 06:09:37 +04:00
} else if ( lp - > splitsnapshot ) /* Destroy snapshot retaining cow as separate LV */
;
else if ( lp - > snapshot ) { /* Snapshot creation from pre-existing cow */
2014-07-11 14:15:23 +04:00
if ( ! argc ) {
2014-07-17 16:46:38 +04:00
log_error ( " Please provide logical volume path for snapshot origin. " ) ;
2014-07-11 14:15:23 +04:00
return 0 ;
}
lp - > origin_lv_name = argv [ 0 ] ;
argv + + , argc - - ;
2006-04-06 00:43:23 +04:00
if ( arg_count ( cmd , regionsize_ARG ) ) {
log_error ( " --regionsize is only available with mirrors " ) ;
return 0 ;
}
2010-04-13 05:54:32 +04:00
if ( arg_count ( cmd , stripesize_ARG ) | | arg_count ( cmd , stripes_long_ARG ) ) {
log_error ( " --stripes and --stripesize are only available with striped mirrors " ) ;
return 0 ;
}
2014-07-08 00:40:36 +04:00
if ( arg_count ( cmd , chunksize_ARG ) & &
( arg_sign_value ( cmd , chunksize_ARG , SIGN_NONE ) = = SIGN_MINUS ) ) {
log_error ( " Negative chunk size is invalid. " ) ;
2006-04-06 00:43:23 +04:00
return 0 ;
}
2014-07-08 00:40:36 +04:00
2007-11-14 03:08:25 +03:00
lp - > chunk_size = arg_uint_value ( cmd , chunksize_ARG , 8 ) ;
2006-04-06 00:43:23 +04:00
if ( lp - > chunk_size < 8 | | lp - > chunk_size > 1024 | |
( lp - > chunk_size & ( lp - > chunk_size - 1 ) ) ) {
log_error ( " Chunk size must be a power of 2 in the "
" range 4K to 512K " ) ;
return 0 ;
}
2014-07-01 13:03:31 +04:00
log_verbose ( " Setting chunk size to %s. " , display_size ( cmd , lp - > chunk_size ) ) ;
2005-08-15 18:10:28 +04:00
2006-04-06 00:43:23 +04:00
if ( ! ( lp - > segtype = get_segtype_from_string ( cmd , " snapshot " ) ) )
return_0 ;
2005-11-29 21:20:23 +03:00
2006-04-06 00:43:23 +04:00
lp - > zero = strcmp ( arg_str_value ( cmd , zero_ARG ,
( lp - > segtype - > flags &
SEG_CANNOT_BE_ZEROED ) ?
" n " : " y " ) , " n " ) ;
2011-11-30 06:02:10 +04:00
} else if ( arg_count ( cmd , replace_ARG ) ) { /* RAID device replacement */
lp - > replace_pv_count = arg_count ( cmd , replace_ARG ) ;
lp - > replace_pvs = dm_pool_alloc ( cmd - > mem , sizeof ( char * ) * lp - > replace_pv_count ) ;
if ( ! lp - > replace_pvs )
return_0 ;
i = 0 ;
dm_list_iterate_items ( group , & cmd - > arg_value_groups ) {
if ( ! grouped_arg_is_set ( group - > arg_values , replace_ARG ) )
continue ;
if ( ! ( tmp_str = grouped_arg_str_value ( group - > arg_values ,
replace_ARG ,
NULL ) ) ) {
log_error ( " Failed to get '--replace' argument " ) ;
return 0 ;
}
if ( ! ( lp - > replace_pvs [ i + + ] = dm_pool_strdup ( cmd - > mem ,
tmp_str ) ) )
return_0 ;
}
2014-07-11 16:09:32 +04:00
} else if ( _mirror_or_raid_type_requested ( cmd , type_str ) | |
2014-07-11 16:40:51 +04:00
arg_is_set ( cmd , repair_ARG ) | |
2014-07-11 16:09:32 +04:00
arg_is_set ( cmd , mirrorlog_ARG ) | |
arg_is_set ( cmd , corelog_ARG ) ) { /* Mirrors (and some RAID functions) */
2006-04-06 00:43:23 +04:00
if ( arg_count ( cmd , chunksize_ARG ) ) {
2014-07-08 00:40:36 +04:00
log_error ( " --chunksize is only available with snapshots or pools. " ) ;
2005-11-29 21:20:23 +03:00
return 0 ;
}
2006-04-06 00:43:23 +04:00
if ( arg_count ( cmd , zero_ARG ) ) {
2012-05-14 15:57:30 +04:00
log_error ( " --zero is only available with snapshots or thin pools. " ) ;
2006-04-06 00:43:23 +04:00
return 0 ;
}
/*
2014-07-11 14:25:18 +04:00
* - - regionsize is only valid if converting an LV into a mirror .
* Checked when we know the state of the LV being converted .
*/
2006-04-28 19:01:39 +04:00
2006-04-06 00:43:23 +04:00
if ( arg_count ( cmd , regionsize_ARG ) ) {
2012-02-28 18:24:57 +04:00
if ( arg_sign_value ( cmd , regionsize_ARG , SIGN_NONE ) = =
2006-04-06 00:43:23 +04:00
SIGN_MINUS ) {
log_error ( " Negative regionsize is invalid " ) ;
return 0 ;
}
2007-11-14 03:08:25 +03:00
lp - > region_size = arg_uint_value ( cmd , regionsize_ARG , 0 ) ;
2006-04-28 19:01:39 +04:00
} else {
2013-02-21 00:40:17 +04:00
region_size = get_default_region_size ( cmd ) ;
2006-04-28 19:01:39 +04:00
if ( region_size < 0 ) {
log_error ( " Negative regionsize in "
" configuration file is invalid " ) ;
return 0 ;
}
lp - > region_size = region_size ;
}
2006-04-28 21:25:54 +04:00
if ( lp - > region_size % ( pagesize > > SECTOR_SHIFT ) ) {
log_error ( " Region size (% " PRIu32 " ) must be "
" a multiple of machine memory "
" page size (%d) " ,
lp - > region_size , pagesize > > SECTOR_SHIFT ) ;
return 0 ;
}
2006-04-06 00:43:23 +04:00
if ( lp - > region_size & ( lp - > region_size - 1 ) ) {
log_error ( " Region size (% " PRIu32
" ) must be a power of 2 " , lp - > region_size ) ;
return 0 ;
}
2006-04-28 17:11:05 +04:00
if ( ! lp - > region_size ) {
log_error ( " Non-zero region size must be supplied. " ) ;
return 0 ;
}
2010-04-13 05:54:32 +04:00
/* Default is never striped, regardless of existing LV configuration. */
2013-07-01 13:27:11 +04:00
if ( ! get_stripe_params ( cmd , & lp - > stripes , & lp - > stripe_size ) )
return_0 ;
2010-04-13 05:54:32 +04:00
2013-08-08 01:01:45 +04:00
if ( arg_count ( cmd , mirrors_ARG ) & & ! lp - > mirrors ) {
/* down-converting to linear/stripe? */
if ( ! ( lp - > segtype =
get_segtype_from_string ( cmd , " striped " ) ) )
return_0 ;
} else if ( arg_count ( cmd , type_ARG ) ) {
/* changing mirror type? */
if ( ! ( lp - > segtype = get_segtype_from_string ( cmd , arg_str_value ( cmd , type_ARG , find_config_tree_str ( cmd , global_mirror_segtype_default_CFG , NULL ) ) ) ) )
return_0 ;
} /* else segtype will default to current type */
2005-11-29 21:20:23 +03:00
}
2005-08-15 18:10:28 +04:00
2013-03-11 15:40:05 +04:00
lp - > force = arg_count ( cmd , force_ARG ) ;
lp - > yes = arg_count ( cmd , yes_ARG ) ;
2011-11-30 06:02:10 +04:00
if ( activation ( ) & & lp - > segtype & & lp - > segtype - > ops - > target_present & &
2012-11-15 13:32:13 +04:00
! lp - > segtype - > ops - > target_present ( cmd , NULL , & lp - > target_attr ) ) {
2006-04-06 00:43:23 +04:00
log_error ( " %s: Required device-mapper target(s) not "
" detected in your kernel " , lp - > segtype - > name ) ;
2005-08-15 18:10:28 +04:00
return 0 ;
}
2006-04-19 19:33:07 +04:00
if ( ! _lvconvert_name_params ( lp , cmd , & argc , & argv ) )
2006-04-06 00:43:23 +04:00
return_0 ;
2005-08-15 18:10:28 +04:00
lp - > pv_count = argc ;
lp - > pvs = argv ;
return 1 ;
}
2007-12-22 15:13:29 +03:00
static struct volume_group * _get_lvconvert_vg ( struct cmd_context * cmd ,
2010-02-06 01:40:49 +03:00
const char * name ,
2010-07-09 19:34:40 +04:00
const char * uuid __attribute__ ( ( unused ) ) )
2007-12-22 15:13:29 +03:00
{
2008-01-30 17:00:02 +03:00
dev_close_all ( ) ;
2007-12-22 15:13:29 +03:00
2010-02-06 01:40:49 +03:00
if ( name & & ! strchr ( name , ' / ' ) )
return vg_read_for_update ( cmd , name , NULL , 0 ) ;
/* 'name' is the full LV name; must extract_vgname() */
return vg_read_for_update ( cmd , extract_vgname ( cmd , name ) ,
2009-07-01 20:59:37 +04:00
NULL , 0 ) ;
2007-12-22 15:13:29 +03:00
}
2010-07-09 19:34:40 +04:00
static struct logical_volume * _get_lvconvert_lv ( struct cmd_context * cmd __attribute__ ( ( unused ) ) ,
2007-12-22 15:13:29 +03:00
struct volume_group * vg ,
const char * name ,
2009-06-01 18:43:27 +04:00
const char * uuid ,
2011-09-06 22:49:31 +04:00
uint64_t lv_type __attribute__ ( ( unused ) ) )
2007-12-22 15:13:29 +03:00
{
2009-06-01 18:43:27 +04:00
struct logical_volume * lv = find_lv ( vg , name ) ;
if ( ! lv | | ( uuid & & strcmp ( uuid , ( char * ) & lv - > lvid ) ) )
return NULL ;
return lv ;
2007-12-22 15:13:29 +03:00
}
2012-08-02 13:38:07 +04:00
static int _reload_lv ( struct cmd_context * cmd ,
struct volume_group * vg ,
struct logical_volume * lv )
2012-08-01 17:34:45 +04:00
{
2012-08-02 13:38:07 +04:00
int r = 0 ;
2012-08-01 17:34:45 +04:00
log_very_verbose ( " Updating logical volume \" %s \" on disk(s) " , lv - > name ) ;
2012-08-02 13:38:07 +04:00
if ( ! vg_write ( vg ) )
2012-08-01 17:34:45 +04:00
return_0 ;
if ( ! suspend_lv ( cmd , lv ) ) {
log_error ( " Failed to lock %s " , lv - > name ) ;
2012-08-02 13:38:07 +04:00
vg_revert ( vg ) ;
2013-02-05 14:21:21 +04:00
if ( ! resume_lv ( cmd , lv ) )
stack ;
2012-08-02 13:38:07 +04:00
goto out ;
2012-08-01 17:34:45 +04:00
}
2012-08-02 13:38:07 +04:00
if ( ! vg_commit ( vg ) ) {
2013-02-05 14:21:21 +04:00
vg_revert ( vg ) ;
2012-08-01 17:34:45 +04:00
if ( ! resume_lv ( cmd , lv ) )
stack ;
2012-08-02 13:38:07 +04:00
goto_out ;
2012-08-01 17:34:45 +04:00
}
log_very_verbose ( " Updating \" %s \" in kernel " , lv - > name ) ;
if ( ! resume_lv ( cmd , lv ) ) {
log_error ( " Problem reactivating %s " , lv - > name ) ;
2012-08-02 13:38:07 +04:00
goto out ;
2012-08-01 17:34:45 +04:00
}
2012-08-02 13:38:07 +04:00
r = 1 ;
backup ( vg ) ;
2013-02-05 14:21:21 +04:00
out :
2012-08-02 13:38:07 +04:00
return r ;
2012-08-01 17:34:45 +04:00
}
2007-12-22 15:13:29 +03:00
static int _finish_lvconvert_mirror ( struct cmd_context * cmd ,
struct volume_group * vg ,
struct logical_volume * lv ,
2010-07-09 19:34:40 +04:00
struct dm_list * lvs_changed __attribute__ ( ( unused ) ) )
2007-12-22 15:13:29 +03:00
{
2010-02-06 00:49:16 +03:00
if ( ! ( lv - > status & CONVERTING ) )
return 1 ;
2007-12-22 15:13:29 +03:00
if ( ! collapse_mirrored_lv ( lv ) ) {
log_error ( " Failed to remove temporary sync layer. " ) ;
return 0 ;
}
2008-01-10 21:35:51 +03:00
lv - > status & = ~ CONVERTING ;
2007-12-22 15:13:29 +03:00
log_very_verbose ( " Updating logical volume \" %s \" on disk(s) " , lv - > name ) ;
2014-07-11 14:25:18 +04:00
if ( ! _reload_lv ( cmd , vg , lv ) )
2007-12-22 15:13:29 +03:00
return_0 ;
config: add silent mode
Accept -q as the short form of --quiet.
Suppress non-essential standard output if -q is given twice.
Treat log/silent in lvm.conf as equivalent to -qq.
Review all log_print messages and change some to
log_print_unless_silent.
When silent, the following commands still produce output:
dumpconfig, lvdisplay, lvmdiskscan, lvs, pvck, pvdisplay,
pvs, version, vgcfgrestore -l, vgdisplay, vgs.
[Needs checking.]
Non-essential messages are shifted from log level 4 to log level 5
for syslog and lvm2_log_fn purposes.
2012-08-25 23:35:48 +04:00
log_print_unless_silent ( " Logical volume %s converted. " , lv - > name ) ;
2012-08-02 13:38:07 +04:00
return 1 ;
2007-12-22 15:13:29 +03:00
}
2013-11-29 20:20:56 +04:00
/* Swap lvid and LV names */
static int _swap_lv_identifiers ( struct cmd_context * cmd ,
struct logical_volume * a , struct logical_volume * b )
{
union lvid lvid ;
const char * name ;
lvid = a - > lvid ;
a - > lvid = b - > lvid ;
b - > lvid = lvid ;
name = a - > name ;
a - > name = b - > name ;
if ( ! lv_rename_update ( cmd , b , name , 0 ) )
return_0 ;
return 1 ;
}
2013-11-30 00:28:18 +04:00
static void _move_lv_attributes ( struct logical_volume * to , struct logical_volume * from )
{
/* Maybe move this code into _finish_thin_merge() */
to - > status = from - > status ; // FIXME maybe some masking ?
to - > alloc = from - > alloc ;
to - > profile = from - > profile ;
to - > read_ahead = from - > read_ahead ;
to - > major = from - > major ;
to - > minor = from - > minor ;
to - > timestamp = from - > timestamp ;
to - > hostname = from - > hostname ;
/* Move tags */
dm_list_init ( & to - > tags ) ;
dm_list_splice ( & to - > tags , & from - > tags ) ;
/* Anything else to preserve? */
}
/* Finalise merging of lv into merge_lv */
static int _finish_thin_merge ( struct cmd_context * cmd ,
struct logical_volume * merge_lv ,
struct logical_volume * lv )
{
if ( ! _swap_lv_identifiers ( cmd , merge_lv , lv ) ) {
log_error ( " Failed to swap %s with merging %s. " ,
lv - > name , merge_lv - > name ) ;
return 0 ;
}
/* Preserve origins' attributes */
_move_lv_attributes ( lv , merge_lv ) ;
/* Removed LV has to be visible */
if ( ! lv_remove_single ( cmd , merge_lv , DONT_PROMPT , 1 ) )
return_0 ;
return 1 ;
}
2010-01-13 04:49:52 +03:00
static int _finish_lvconvert_merge ( struct cmd_context * cmd ,
struct volume_group * vg ,
struct logical_volume * lv ,
2010-07-09 19:34:40 +04:00
struct dm_list * lvs_changed __attribute__ ( ( unused ) ) )
2010-01-13 04:49:52 +03:00
{
2013-11-28 14:39:38 +04:00
struct lv_segment * snap_seg = find_snapshot ( lv ) ;
if ( ! lv_is_merging_origin ( lv ) ) {
2010-01-13 04:49:52 +03:00
log_error ( " Logical volume %s has no merging snapshot. " , lv - > name ) ;
return 0 ;
}
config: add silent mode
Accept -q as the short form of --quiet.
Suppress non-essential standard output if -q is given twice.
Treat log/silent in lvm.conf as equivalent to -qq.
Review all log_print messages and change some to
log_print_unless_silent.
When silent, the following commands still produce output:
dumpconfig, lvdisplay, lvmdiskscan, lvs, pvck, pvdisplay,
pvs, version, vgcfgrestore -l, vgdisplay, vgs.
[Needs checking.]
Non-essential messages are shifted from log level 4 to log level 5
for syslog and lvm2_log_fn purposes.
2012-08-25 23:35:48 +04:00
log_print_unless_silent ( " Merge of snapshot into logical volume %s has finished. " , lv - > name ) ;
2013-11-30 00:28:18 +04:00
if ( seg_is_thin_volume ( snap_seg ) ) {
clear_snapshot_merge ( lv ) ;
if ( ! _finish_thin_merge ( cmd , lv , snap_seg - > lv ) )
return_0 ;
} else if ( ! lv_remove_single ( cmd , snap_seg - > cow , DONT_PROMPT , 0 ) ) {
2010-01-13 04:49:52 +03:00
log_error ( " Could not remove snapshot %s merged into %s. " ,
snap_seg - > cow - > name , lv - > name ) ;
return 0 ;
}
return 1 ;
}
static progress_t _poll_merge_progress ( struct cmd_context * cmd ,
struct logical_volume * lv ,
2010-07-09 19:34:40 +04:00
const char * name __attribute__ ( ( unused ) ) ,
2010-01-13 04:49:52 +03:00
struct daemon_parms * parms )
{
2014-06-09 14:08:27 +04:00
dm_percent_t percent = DM_PERCENT_0 ;
2010-01-13 04:49:52 +03:00
2014-06-16 15:38:35 +04:00
if ( ! lv_is_merging_origin ( lv ) | |
! lv_snapshot_percent ( lv , & percent ) ) {
2010-01-16 01:58:25 +03:00
log_error ( " %s: Failed query for merging percentage. Aborting merge. " , lv - > name ) ;
2010-01-13 04:49:52 +03:00
return PROGRESS_CHECK_FAILED ;
2014-06-09 14:08:27 +04:00
} else if ( percent = = DM_PERCENT_INVALID ) {
2010-01-13 04:49:52 +03:00
log_error ( " %s: Merging snapshot invalidated. Aborting merge. " , lv - > name ) ;
return PROGRESS_CHECK_FAILED ;
2014-06-09 14:08:27 +04:00
} else if ( percent = = LVM_PERCENT_MERGE_FAILED ) {
2012-01-21 02:02:04 +04:00
log_error ( " %s: Merge failed. Retry merge or inspect manually. " , lv - > name ) ;
return PROGRESS_CHECK_FAILED ;
2010-01-13 04:49:52 +03:00
}
if ( parms - > progress_display )
config: add silent mode
Accept -q as the short form of --quiet.
Suppress non-essential standard output if -q is given twice.
Treat log/silent in lvm.conf as equivalent to -qq.
Review all log_print messages and change some to
log_print_unless_silent.
When silent, the following commands still produce output:
dumpconfig, lvdisplay, lvmdiskscan, lvs, pvck, pvdisplay,
pvs, version, vgcfgrestore -l, vgdisplay, vgs.
[Needs checking.]
Non-essential messages are shifted from log level 4 to log level 5
for syslog and lvm2_log_fn purposes.
2012-08-25 23:35:48 +04:00
log_print_unless_silent ( " %s: %s: %.1f%% " , lv - > name , parms - > progress_title ,
2014-06-09 14:08:27 +04:00
100.0 - dm_percent_to_float ( percent ) ) ;
2010-01-13 04:49:52 +03:00
else
2010-11-30 14:53:31 +03:00
log_verbose ( " %s: %s: %.1f%% " , lv - > name , parms - > progress_title ,
2014-06-09 14:08:27 +04:00
100.0 - dm_percent_to_float ( percent ) ) ;
2010-01-13 04:49:52 +03:00
2014-06-09 14:08:27 +04:00
if ( percent = = DM_PERCENT_0 )
2010-01-13 04:49:52 +03:00
return PROGRESS_FINISHED_ALL ;
return PROGRESS_UNFINISHED ;
}
2013-11-30 00:28:18 +04:00
static progress_t _poll_thin_merge_progress ( struct cmd_context * cmd ,
struct logical_volume * lv ,
const char * name __attribute__ ( ( unused ) ) ,
struct daemon_parms * parms )
{
uint32_t device_id ;
if ( ! lv_thin_device_id ( lv , & device_id ) ) {
stack ;
return PROGRESS_CHECK_FAILED ;
}
/*
* There is no need to poll more than once ,
* a thin snapshot merge is immediate .
*/
if ( device_id ! = find_snapshot ( lv ) - > device_id ) {
log_error ( " LV %s is not merged. " , lv - > name ) ;
return PROGRESS_CHECK_FAILED ;
}
return PROGRESS_FINISHED_ALL ; /* Merging happend */
}
2007-12-22 15:13:29 +03:00
static struct poll_functions _lvconvert_mirror_fns = {
. get_copy_vg = _get_lvconvert_vg ,
. get_copy_lv = _get_lvconvert_lv ,
2009-09-30 22:15:06 +04:00
. poll_progress = poll_mirror_progress ,
2007-12-22 15:13:29 +03:00
. finish_copy = _finish_lvconvert_mirror ,
} ;
2010-01-13 04:49:52 +03:00
static struct poll_functions _lvconvert_merge_fns = {
. get_copy_vg = _get_lvconvert_vg ,
. get_copy_lv = _get_lvconvert_lv ,
. poll_progress = _poll_merge_progress ,
. finish_copy = _finish_lvconvert_merge ,
} ;
2013-11-30 00:28:18 +04:00
static struct poll_functions _lvconvert_thin_merge_fns = {
. get_copy_vg = _get_lvconvert_vg ,
. get_copy_lv = _get_lvconvert_lv ,
. poll_progress = _poll_thin_merge_progress ,
. finish_copy = _finish_lvconvert_merge ,
} ;
2009-06-01 18:43:27 +04:00
int lvconvert_poll ( struct cmd_context * cmd , struct logical_volume * lv ,
2008-01-10 21:35:51 +03:00
unsigned background )
2007-12-22 15:13:29 +03:00
{
2010-02-06 01:40:49 +03:00
/*
* FIXME allocate an " object key " structure with split
* out members ( vg_name , lv_name , uuid , etc ) and pass that
* around the lvconvert and polldaemon code
* - will avoid needless work , e . g . extract_vgname ( )
* - unfortunately there are enough overloaded " name " dragons in
* the polldaemon , lvconvert , pvmove code that a comprehensive
* audit / rework is needed
*/
2014-06-16 14:39:32 +04:00
char uuid [ sizeof ( lv - > lvid ) ] ;
char lv_full_name [ NAME_LEN ] ;
2009-06-01 18:43:27 +04:00
2014-06-16 14:39:32 +04:00
if ( dm_snprintf ( lv_full_name , sizeof ( lv_full_name ) , " %s/%s " , lv - > vg - > name , lv - > name ) < 0 ) {
log_error ( INTERNAL_ERROR " Name \" %s/%s \" is too long. " , lv - > vg - > name , lv - > name ) ;
2014-07-11 14:24:32 +04:00
return ECMD_FAILED ;
2014-06-16 14:39:32 +04:00
}
2009-06-01 18:43:27 +04:00
memcpy ( uuid , & lv - > lvid , sizeof ( lv - > lvid ) ) ;
2013-11-29 23:29:38 +04:00
if ( lv_is_merging_origin ( lv ) )
2010-01-13 04:49:52 +03:00
return poll_daemon ( cmd , lv_full_name , uuid , background , 0 ,
2014-02-18 00:48:27 +04:00
seg_is_thin_volume ( find_snapshot ( lv ) ) ?
2013-11-30 00:28:18 +04:00
& _lvconvert_thin_merge_fns : & _lvconvert_merge_fns ,
" Merged " ) ;
2013-11-29 23:29:38 +04:00
return poll_daemon ( cmd , lv_full_name , uuid , background , 0 ,
& _lvconvert_mirror_fns , " Converted " ) ;
2007-12-22 15:13:29 +03:00
}
2007-12-22 05:13:00 +03:00
static int _insert_lvconvert_layer ( struct cmd_context * cmd ,
struct logical_volume * lv )
{
char * format , * layer_name ;
size_t len ;
int i ;
/*
* We would like to give the same number for this layer
* and the newly added mimage .
* However , LV name of newly added mimage is determined * after *
* the LV name of this layer is determined .
*
* So , use generate_lv_name ( ) to generate mimage name first
* and take the number from it .
*/
len = strlen ( lv - > name ) + 32 ;
if ( ! ( format = alloca ( len ) ) | |
! ( layer_name = alloca ( len ) ) | |
dm_snprintf ( format , len , " %s_mimage_%%d " , lv - > name ) < 0 ) {
log_error ( " lvconvert: layer name allocation failed. " ) ;
return 0 ;
}
if ( ! generate_lv_name ( lv - > vg , format , layer_name , len ) | |
sscanf ( layer_name , format , & i ) ! = 1 ) {
log_error ( " lvconvert: layer name generation failed. " ) ;
return 0 ;
}
if ( dm_snprintf ( layer_name , len , MIRROR_SYNC_LAYER " _%d " , i ) < 0 ) {
log_error ( " layer name allocation failed. " ) ;
return 0 ;
}
if ( ! insert_layer_for_lv ( cmd , lv , 0 , layer_name ) ) {
log_error ( " Failed to insert resync layer " ) ;
return 0 ;
}
return 1 ;
}
2009-05-21 07:04:52 +04:00
static int _failed_mirrors_count ( struct logical_volume * lv )
2009-04-23 20:56:21 +04:00
{
struct lv_segment * lvseg ;
int ret = 0 ;
2011-04-08 18:40:18 +04:00
unsigned s ;
2009-05-21 07:04:52 +04:00
2009-04-23 20:56:21 +04:00
dm_list_iterate_items ( lvseg , & lv - > segments ) {
if ( ! seg_is_mirrored ( lvseg ) )
return - 1 ;
2011-05-07 17:56:13 +04:00
for ( s = 0 ; s < lvseg - > area_count ; s + + ) {
if ( seg_type ( lvseg , s ) = = AREA_LV ) {
if ( is_temporary_mirror_layer ( seg_lv ( lvseg , s ) ) )
ret + = _failed_mirrors_count ( seg_lv ( lvseg , s ) ) ;
else if ( seg_lv ( lvseg , s ) - > status & PARTIAL_LV )
+ + ret ;
else if ( seg_type ( lvseg , s ) = = AREA_PV & &
is_missing_pv ( seg_pv ( lvseg , s ) ) )
+ + ret ;
}
}
2009-04-23 20:56:21 +04:00
}
2009-05-21 07:04:52 +04:00
2009-04-23 20:56:21 +04:00
return ret ;
}
2011-05-07 17:56:13 +04:00
static int _failed_logs_count ( struct logical_volume * lv )
{
2012-02-24 02:36:56 +04:00
int ret = 0 ;
unsigned s ;
2011-05-07 17:56:13 +04:00
struct logical_volume * log_lv = first_seg ( lv ) - > log_lv ;
if ( log_lv & & ( log_lv - > status & PARTIAL_LV ) ) {
if ( log_lv - > status & MIRRORED )
ret + = _failed_mirrors_count ( log_lv ) ;
else
ret + = 1 ;
}
for ( s = 0 ; s < first_seg ( lv ) - > area_count ; s + + ) {
if ( seg_type ( first_seg ( lv ) , s ) = = AREA_LV & &
is_temporary_mirror_layer ( seg_lv ( first_seg ( lv ) , s ) ) )
ret + = _failed_logs_count ( seg_lv ( first_seg ( lv ) , s ) ) ;
}
return ret ;
}
2009-04-23 20:56:21 +04:00
static struct dm_list * _failed_pv_list ( struct volume_group * vg )
{
2009-05-21 07:04:52 +04:00
struct dm_list * failed_pvs ;
2009-04-23 20:56:21 +04:00
struct pv_list * pvl , * new_pvl ;
2009-05-21 07:04:52 +04:00
if ( ! ( failed_pvs = dm_pool_alloc ( vg - > vgmem , sizeof ( * failed_pvs ) ) ) ) {
log_error ( " Allocation of list of failed_pvs failed. " ) ;
2014-05-20 14:53:51 +04:00
return NULL ;
2009-04-23 20:56:21 +04:00
}
2009-05-21 07:04:52 +04:00
dm_list_init ( failed_pvs ) ;
2009-04-23 20:56:21 +04:00
dm_list_iterate_items ( pvl , & vg - > pvs ) {
2010-03-16 17:37:38 +03:00
if ( ! is_missing_pv ( pvl - > pv ) )
2009-04-23 20:56:21 +04:00
continue ;
2014-07-11 14:25:18 +04:00
/*
2010-01-06 16:26:21 +03:00
* Finally , - - repair will remove empty PVs .
* But we only want remove these which are output of repair ,
* Do not count these which are already empty here .
* FIXME : code should traverse PV in LV not in whole VG .
* FIXME : layer violation ? should it depend on vgreduce - - removemising ?
*/
if ( pvl - > pv - > pe_alloc_count = = 0 )
continue ;
2009-04-23 20:56:21 +04:00
if ( ! ( new_pvl = dm_pool_alloc ( vg - > vgmem , sizeof ( * new_pvl ) ) ) ) {
2009-05-21 07:04:52 +04:00
log_error ( " Allocation of failed_pvs list entry failed. " ) ;
2014-05-20 14:53:51 +04:00
return NULL ;
2009-04-23 20:56:21 +04:00
}
new_pvl - > pv = pvl - > pv ;
2009-05-21 07:04:52 +04:00
dm_list_add ( failed_pvs , & new_pvl - > list ) ;
2009-04-23 20:56:21 +04:00
}
2009-05-21 07:04:52 +04:00
return failed_pvs ;
2009-04-23 20:56:21 +04:00
}
2010-05-24 19:32:20 +04:00
static int _is_partial_lv ( struct logical_volume * lv ,
2010-07-09 19:34:40 +04:00
void * baton __attribute__ ( ( unused ) ) )
2010-05-24 19:32:20 +04:00
{
return lv - > status & PARTIAL_LV ;
}
2009-05-21 07:04:52 +04:00
/*
* Walk down the stacked mirror LV to the original mirror LV .
*/
2008-01-16 22:16:48 +03:00
static struct logical_volume * _original_lv ( struct logical_volume * lv )
{
struct logical_volume * next_lv = lv , * tmp_lv ;
while ( ( tmp_lv = find_temporary_mirror ( next_lv ) ) )
next_lv = tmp_lv ;
return next_lv ;
}
2009-06-04 16:01:15 +04:00
static void _lvconvert_mirrors_repair_ask ( struct cmd_context * cmd ,
int failed_log , int failed_mirrors ,
int * replace_log , int * replace_mirrors )
{
2014-05-20 22:10:29 +04:00
const char * leg_policy , * log_policy ;
2009-06-04 16:01:15 +04:00
int force = arg_count ( cmd , force_ARG ) ;
int yes = arg_count ( cmd , yes_ARG ) ;
if ( arg_count ( cmd , use_policies_ARG ) ) {
2013-06-25 14:29:54 +04:00
leg_policy = find_config_tree_str ( cmd , activation_mirror_image_fault_policy_CFG , NULL ) ;
log_policy = find_config_tree_str ( cmd , activation_mirror_log_fault_policy_CFG , NULL ) ;
2009-06-04 16:01:15 +04:00
* replace_mirrors = strcmp ( leg_policy , " remove " ) ;
* replace_log = strcmp ( log_policy , " remove " ) ;
return ;
}
if ( force ! = PROMPT ) {
* replace_log = * replace_mirrors = 0 ;
return ;
}
2014-05-20 22:10:29 +04:00
* replace_log = * replace_mirrors = 1 ;
2012-12-11 12:52:54 +04:00
if ( yes )
return ;
2009-06-04 16:01:15 +04:00
if ( failed_log & &
2014-05-20 22:10:55 +04:00
yes_no_prompt ( " Attempt to replace failed mirror log? [y/n]: " ) = = ' n ' )
2009-06-04 16:01:15 +04:00
* replace_log = 0 ;
if ( failed_mirrors & &
yes_no_prompt ( " Attempt to replace failed mirror images "
2014-05-20 22:10:55 +04:00
" (requires full device resync)? [y/n]: " ) = = ' n ' )
2009-06-04 16:01:15 +04:00
* replace_mirrors = 0 ;
}
2010-03-27 01:15:43 +03:00
/*
* _get_log_count
* @ lv : the mirror LV
*
* Get the number of on - disk copies of the log .
* 0 = ' core '
* 1 = ' disk '
* 2 + = ' mirrored '
*/
2013-11-25 16:42:30 +04:00
static uint32_t _get_log_count ( struct logical_volume * lv )
2009-08-03 01:56:29 +04:00
{
2010-03-27 01:15:43 +03:00
struct logical_volume * log_lv ;
log_lv = first_seg ( _original_lv ( lv ) ) - > log_lv ;
2011-05-07 17:56:13 +04:00
if ( log_lv )
return lv_mirror_count ( log_lv ) ;
2010-03-27 01:15:43 +03:00
2011-05-07 17:56:13 +04:00
return 0 ;
2009-08-03 01:56:29 +04:00
}
2010-06-24 00:32:29 +04:00
static int _lv_update_mirrored_log ( struct logical_volume * lv ,
struct dm_list * operable_pvs ,
int log_count )
{
int old_log_count ;
struct logical_volume * log_lv ;
2010-08-03 01:07:40 +04:00
/*
* When log_count is 0 , mirrored log doesn ' t need to be
* updated here but it will be removed later .
*/
if ( ! log_count )
return 1 ;
2010-06-24 00:32:29 +04:00
log_lv = first_seg ( _original_lv ( lv ) ) - > log_lv ;
if ( ! log_lv | | ! ( log_lv - > status & MIRRORED ) )
return 1 ;
old_log_count = _get_log_count ( lv ) ;
if ( old_log_count = = log_count )
return 1 ;
/* Reducing redundancy of the log */
2010-08-03 01:07:40 +04:00
return remove_mirror_images ( log_lv , log_count ,
is_mirror_image_removable ,
operable_pvs , 0U ) ;
2010-06-24 00:32:29 +04:00
}
2009-08-03 01:56:29 +04:00
static int _lv_update_log_type ( struct cmd_context * cmd ,
struct lvconvert_params * lp ,
struct logical_volume * lv ,
2010-03-27 01:15:43 +03:00
struct dm_list * operable_pvs ,
2010-01-09 01:32:35 +03:00
int log_count )
2009-08-03 01:56:29 +04:00
{
2010-03-27 01:15:43 +03:00
int old_log_count ;
2012-02-13 22:36:55 +04:00
uint32_t region_size = ( lp ) ? lp - > region_size :
first_seg ( lv ) - > region_size ;
alloc_policy_t alloc = ( lp ) ? lp - > alloc : lv - > alloc ;
2010-03-27 01:15:43 +03:00
struct logical_volume * original_lv ;
struct logical_volume * log_lv ;
old_log_count = _get_log_count ( lv ) ;
if ( old_log_count = = log_count )
return 1 ;
original_lv = _original_lv ( lv ) ;
/* Remove an existing log completely */
if ( ! log_count ) {
2010-10-12 20:41:17 +04:00
if ( ! remove_mirror_log ( cmd , original_lv , operable_pvs ,
arg_count ( cmd , yes_ARG ) | |
arg_count ( cmd , force_ARG ) ) )
2009-08-03 01:56:29 +04:00
return_0 ;
2010-03-27 01:15:43 +03:00
return 1 ;
2009-08-03 01:56:29 +04:00
}
2010-03-27 01:15:43 +03:00
log_lv = first_seg ( original_lv ) - > log_lv ;
/* Adding redundancy to the log */
if ( old_log_count < log_count ) {
2011-05-07 17:56:13 +04:00
region_size = adjusted_mirror_region_size ( lv - > vg - > extent_size ,
lv - > le_count ,
2012-02-13 22:36:55 +04:00
region_size ) ;
2011-05-07 17:56:13 +04:00
2011-01-11 20:05:08 +03:00
if ( ! add_mirror_log ( cmd , original_lv , log_count ,
2012-02-13 22:36:55 +04:00
region_size , operable_pvs , alloc ) )
2011-01-11 20:05:08 +03:00
return_0 ;
/*
* FIXME : This simple approach won ' t work in cluster mirrors ,
* but it doesn ' t matter because we don ' t support
* mirrored logs in cluster mirrors .
*/
2012-08-02 13:38:07 +04:00
if ( old_log_count & &
! _reload_lv ( cmd , log_lv - > vg , log_lv ) )
return_0 ;
2011-01-11 20:05:08 +03:00
return 1 ;
2010-03-27 01:15:43 +03:00
}
/* Reducing redundancy of the log */
2012-02-13 22:36:55 +04:00
return remove_mirror_images ( log_lv , log_count ,
is_mirror_image_removable , operable_pvs , 1U ) ;
2009-08-03 01:56:29 +04:00
}
2010-01-06 16:26:21 +03:00
/*
* Reomove missing and empty PVs from VG , if are also in provided list
*/
static void _remove_missing_empty_pv ( struct volume_group * vg , struct dm_list * remove_pvs )
{
struct pv_list * pvl , * pvl_vg , * pvlt ;
int removed = 0 ;
if ( ! remove_pvs )
return ;
dm_list_iterate_items ( pvl , remove_pvs ) {
dm_list_iterate_items_safe ( pvl_vg , pvlt , & vg - > pvs ) {
if ( ! id_equal ( & pvl - > pv - > id , & pvl_vg - > pv - > id ) | |
2010-03-16 17:37:38 +03:00
! is_missing_pv ( pvl_vg - > pv ) | |
2010-01-06 16:26:21 +03:00
pvl_vg - > pv - > pe_alloc_count ! = 0 )
continue ;
/* FIXME: duplication of vgreduce code, move this to library */
vg - > free_count - = pvl_vg - > pv - > pe_count ;
vg - > extent_count - = pvl_vg - > pv - > pe_count ;
2010-04-13 21:26:03 +04:00
del_pvl_from_vgs ( vg , pvl_vg ) ;
2011-03-11 17:56:56 +03:00
free_pv_fid ( pvl_vg - > pv ) ;
2010-01-06 16:26:21 +03:00
removed + + ;
}
}
if ( removed ) {
if ( ! vg_write ( vg ) | | ! vg_commit ( vg ) ) {
stack ;
return ;
}
log_warn ( " %d missing and now unallocated Physical Volumes removed from VG. " , removed ) ;
}
}
2010-03-27 01:15:43 +03:00
/*
* _lvconvert_mirrors_parse_params
*
* This function performs the following :
* 1 ) Gets the old values of mimage and log counts
* 2 ) Parses the CLI args to find the new desired values
* 3 ) Adjusts ' lp - > mirrors ' to the appropriate absolute value .
* ( Remember , ' lp - > mirrors ' is specified in terms of the number of " copies "
* vs . the number of mimages . It can also be a relative value . )
* 4 ) Sets ' lp - > need_polling ' if collapsing
* 5 ) Validates other mirror params
*
* Returns : 1 on success , 0 on error
*/
static int _lvconvert_mirrors_parse_params ( struct cmd_context * cmd ,
struct logical_volume * lv ,
struct lvconvert_params * lp ,
uint32_t * old_mimage_count ,
uint32_t * old_log_count ,
uint32_t * new_mimage_count ,
uint32_t * new_log_count )
2005-06-06 21:12:08 +04:00
{
2009-06-04 16:01:15 +04:00
int repair = arg_count ( cmd , repair_ARG ) ;
2010-03-27 01:15:43 +03:00
const char * mirrorlog ;
* old_mimage_count = lv_mirror_count ( lv ) ;
* old_log_count = _get_log_count ( lv ) ;
2007-12-21 04:08:18 +03:00
2010-03-27 01:15:43 +03:00
/*
* Collapsing a stack of mirrors :
*
* If called with no argument , try collapsing the resync layers
*/
2008-01-10 21:35:51 +03:00
if ( ! arg_count ( cmd , mirrors_ARG ) & & ! arg_count ( cmd , mirrorlog_ARG ) & &
2009-04-23 20:56:21 +04:00
! arg_count ( cmd , corelog_ARG ) & & ! arg_count ( cmd , regionsize_ARG ) & &
This patch adds the capability to split off a mirror legs.
It is pretty much the same as reducing the number of
mirror legs, but we just don't delete them afterwards.
The following command line interface is enforced:
prompt> lvconvert --splitmirror <n> -n <name> <VG>/<LV>
where 'n' is the number of images to split off, and
where 'name' is the name of the newly split off logical volume.
If more than one leg is split off, a new mirror will be the
result. The newly split off mirror will have a 'core' log.
Example:
[root@bp-01 LVM2]# !lvs
lvs -a -o name,copy_percent,devices
LV Copy% Devices
lv 100.00 lv_mimage_0(0),lv_mimage_1(0),lv_mimage_2(0),lv_mimage_3(0)
[lv_mimage_0] /dev/sdb1(0)
[lv_mimage_1] /dev/sdc1(0)
[lv_mimage_2] /dev/sdd1(0)
[lv_mimage_3] /dev/sde1(0)
[lv_mlog] /dev/sdi1(0)
[root@bp-01 LVM2]# lvconvert --splitmirrors 2 --name split vg/lv /dev/sd[ce]1
Logical volume lv converted.
[root@bp-01 LVM2]# !lvs
lvs -a -o name,copy_percent,devices
LV Copy% Devices
lv 100.00 lv_mimage_0(0),lv_mimage_2(0)
[lv_mimage_0] /dev/sdb1(0)
[lv_mimage_2] /dev/sdd1(0)
[lv_mlog] /dev/sdi1(0)
split 100.00 split_mimage_0(0),split_mimage_1(0)
[split_mimage_0] /dev/sde1(0)
[split_mimage_1] /dev/sdc1(0)
It can be seen that '--splitmirror <n>' is exactly the same
as '--mirrors -<n>' (note the minus sign), except there is the
additional notion to keep the image being detached from the
mirror instead of just throwing it away.
Signed-off-by: Jonathan Brassow <jbrassow@redhat.com>
2010-01-09 01:00:31 +03:00
! arg_count ( cmd , splitmirrors_ARG ) & & ! repair ) {
2010-03-27 01:15:43 +03:00
* new_mimage_count = * old_mimage_count ;
* new_log_count = * old_log_count ;
2009-06-15 16:08:59 +04:00
if ( find_temporary_mirror ( lv ) | | ( lv - > status & CONVERTING ) )
lp - > need_polling = 1 ;
2007-12-22 15:13:29 +03:00
return 1 ;
2007-12-21 04:08:18 +03:00
}
2005-11-29 21:20:23 +03:00
2007-08-02 00:54:28 +04:00
/*
2010-03-27 01:15:43 +03:00
* Adjusting mimage count ?
2007-08-02 00:54:28 +04:00
*/
This patch adds the capability to split off a mirror legs.
It is pretty much the same as reducing the number of
mirror legs, but we just don't delete them afterwards.
The following command line interface is enforced:
prompt> lvconvert --splitmirror <n> -n <name> <VG>/<LV>
where 'n' is the number of images to split off, and
where 'name' is the name of the newly split off logical volume.
If more than one leg is split off, a new mirror will be the
result. The newly split off mirror will have a 'core' log.
Example:
[root@bp-01 LVM2]# !lvs
lvs -a -o name,copy_percent,devices
LV Copy% Devices
lv 100.00 lv_mimage_0(0),lv_mimage_1(0),lv_mimage_2(0),lv_mimage_3(0)
[lv_mimage_0] /dev/sdb1(0)
[lv_mimage_1] /dev/sdc1(0)
[lv_mimage_2] /dev/sdd1(0)
[lv_mimage_3] /dev/sde1(0)
[lv_mlog] /dev/sdi1(0)
[root@bp-01 LVM2]# lvconvert --splitmirrors 2 --name split vg/lv /dev/sd[ce]1
Logical volume lv converted.
[root@bp-01 LVM2]# !lvs
lvs -a -o name,copy_percent,devices
LV Copy% Devices
lv 100.00 lv_mimage_0(0),lv_mimage_2(0)
[lv_mimage_0] /dev/sdb1(0)
[lv_mimage_2] /dev/sdd1(0)
[lv_mlog] /dev/sdi1(0)
split 100.00 split_mimage_0(0),split_mimage_1(0)
[split_mimage_0] /dev/sde1(0)
[split_mimage_1] /dev/sdc1(0)
It can be seen that '--splitmirror <n>' is exactly the same
as '--mirrors -<n>' (note the minus sign), except there is the
additional notion to keep the image being detached from the
mirror instead of just throwing it away.
Signed-off-by: Jonathan Brassow <jbrassow@redhat.com>
2010-01-09 01:00:31 +03:00
if ( ! arg_count ( cmd , mirrors_ARG ) & & ! arg_count ( cmd , splitmirrors_ARG ) )
2010-03-27 01:15:43 +03:00
lp - > mirrors = * old_mimage_count ;
2007-08-02 00:54:28 +04:00
else if ( lp - > mirrors_sign = = SIGN_PLUS )
2010-03-27 01:15:43 +03:00
lp - > mirrors = * old_mimage_count + lp - > mirrors ;
2007-08-02 00:54:28 +04:00
else if ( lp - > mirrors_sign = = SIGN_MINUS )
2010-07-14 01:53:07 +04:00
lp - > mirrors = ( * old_mimage_count > lp - > mirrors ) ?
* old_mimage_count - lp - > mirrors : 0 ;
2007-08-02 00:54:28 +04:00
else
2005-11-29 21:20:23 +03:00
lp - > mirrors + = 1 ;
2010-03-27 01:15:43 +03:00
* new_mimage_count = lp - > mirrors ;
/* Too many mimages? */
2009-11-27 17:35:38 +03:00
if ( lp - > mirrors > DEFAULT_MIRROR_MAX_IMAGES ) {
log_error ( " Only up to %d images in mirror supported currently. " ,
DEFAULT_MIRROR_MAX_IMAGES ) ;
return 0 ;
}
2010-03-27 01:15:43 +03:00
/* Did the user try to subtract more legs than available? */
if ( lp - > mirrors < 1 ) {
2010-07-14 01:53:07 +04:00
log_error ( " Unable to reduce images by specified amount - only %d in %s " ,
* old_mimage_count , lv - > name ) ;
2010-03-27 01:15:43 +03:00
return 0 ;
2010-01-07 23:42:55 +03:00
}
2010-03-27 01:15:43 +03:00
/*
* FIXME : It would be nice to say what we are adjusting to , but
* I really don ' t know whether to specify the # of copies or mimages .
*/
if ( * old_mimage_count ! = * new_mimage_count )
log_verbose ( " Adjusting mirror image count of %s " , lv - > name ) ;
2009-04-30 00:11:46 +04:00
2010-03-27 01:15:43 +03:00
/*
* Adjust log type
*
* If we are converting from a mirror to another mirror or simply
* changing the log type , we start by assuming they want the log
* type the same and then parse the given args . OTOH , If we are
* converting from linear to mirror , then we start from the default
* position that the user would like a ' disk ' log .
*/
* new_log_count = ( * old_mimage_count > 1 ) ? * old_log_count : 1 ;
if ( ! arg_count ( cmd , corelog_ARG ) & & ! arg_count ( cmd , mirrorlog_ARG ) )
return 1 ;
2010-01-09 01:32:35 +03:00
2010-03-27 01:15:43 +03:00
if ( arg_count ( cmd , corelog_ARG ) )
* new_log_count = 0 ;
2010-01-09 01:32:35 +03:00
2010-03-27 01:15:43 +03:00
mirrorlog = arg_str_value ( cmd , mirrorlog_ARG ,
! * new_log_count ? " core " : DEFAULT_MIRRORLOG ) ;
2007-08-02 01:01:06 +04:00
2010-03-27 01:15:43 +03:00
if ( ! strcmp ( " mirrored " , mirrorlog ) )
* new_log_count = 2 ;
else if ( ! strcmp ( " disk " , mirrorlog ) )
* new_log_count = 1 ;
else if ( ! strcmp ( " core " , mirrorlog ) )
* new_log_count = 0 ;
else {
log_error ( " Unknown mirrorlog type: %s " , mirrorlog ) ;
return 0 ;
2009-04-23 20:56:21 +04:00
}
2007-08-21 23:46:36 +04:00
2010-08-02 23:03:45 +04:00
/*
* No mirrored logs for cluster mirrors until
* log daemon is multi - threaded .
*/
if ( ( * new_log_count = = 2 ) & & vg_is_clustered ( lv - > vg ) ) {
log_error ( " Log type, \" mirrored \" , is unavailable to cluster mirrors " ) ;
return 0 ;
}
2010-03-27 01:15:43 +03:00
log_verbose ( " Setting logging type to %s " , mirrorlog ) ;
2007-08-02 01:01:06 +04:00
/*
* Region size must not change on existing mirrors
*/
2005-11-29 21:20:23 +03:00
if ( arg_count ( cmd , regionsize_ARG ) & & ( lv - > status & MIRRORED ) & &
2010-03-27 01:15:43 +03:00
( lp - > region_size ! = first_seg ( lv ) - > region_size ) ) {
2005-11-29 21:20:23 +03:00
log_error ( " Mirror log region size cannot be changed on "
" an existing mirror. " ) ;
return 0 ;
}
2005-06-06 21:12:08 +04:00
2009-04-23 20:56:21 +04:00
/*
2009-05-19 14:27:47 +04:00
* For the most part , we cannot handle multi - segment mirrors . Bail out
* early if we have encountered one .
2009-04-23 20:56:21 +04:00
*/
2009-05-19 14:27:47 +04:00
if ( ( lv - > status & MIRRORED ) & & dm_list_size ( & lv - > segments ) ! = 1 ) {
2009-04-23 20:56:21 +04:00
log_error ( " Logical volume %s has multiple "
" mirror segments. " , lv - > name ) ;
return 0 ;
}
2009-04-30 00:11:46 +04:00
2010-03-27 01:15:43 +03:00
return 1 ;
}
2009-06-04 16:01:15 +04:00
2010-05-24 19:32:20 +04:00
2010-03-27 01:15:43 +03:00
/*
* _lvconvert_mirrors_aux
*
* Add / remove mirror images and adjust log type . ' operable_pvs '
* are the set of PVs open to removal or allocation - depending
* on the operation being performed .
*/
static int _lvconvert_mirrors_aux ( struct cmd_context * cmd ,
struct logical_volume * lv ,
struct lvconvert_params * lp ,
struct dm_list * operable_pvs ,
uint32_t new_mimage_count ,
2010-04-14 17:51:58 +04:00
uint32_t new_log_count )
2010-03-27 01:15:43 +03:00
{
uint32_t region_size ;
struct lv_segment * seg ;
struct logical_volume * layer_lv ;
uint32_t old_mimage_count = lv_mirror_count ( lv ) ;
uint32_t old_log_count = _get_log_count ( lv ) ;
if ( ( lp - > mirrors = = 1 ) & & ! ( lv - > status & MIRRORED ) ) {
2012-10-16 12:14:41 +04:00
log_warn ( " Logical volume %s is already not mirrored. " ,
lv - > name ) ;
2010-03-27 01:15:43 +03:00
return 1 ;
2007-08-02 00:54:28 +04:00
}
2010-03-27 01:15:43 +03:00
region_size = adjusted_mirror_region_size ( lv - > vg - > extent_size ,
lv - > le_count ,
lp - > region_size ) ;
This patch adds the capability to split off a mirror legs.
It is pretty much the same as reducing the number of
mirror legs, but we just don't delete them afterwards.
The following command line interface is enforced:
prompt> lvconvert --splitmirror <n> -n <name> <VG>/<LV>
where 'n' is the number of images to split off, and
where 'name' is the name of the newly split off logical volume.
If more than one leg is split off, a new mirror will be the
result. The newly split off mirror will have a 'core' log.
Example:
[root@bp-01 LVM2]# !lvs
lvs -a -o name,copy_percent,devices
LV Copy% Devices
lv 100.00 lv_mimage_0(0),lv_mimage_1(0),lv_mimage_2(0),lv_mimage_3(0)
[lv_mimage_0] /dev/sdb1(0)
[lv_mimage_1] /dev/sdc1(0)
[lv_mimage_2] /dev/sdd1(0)
[lv_mimage_3] /dev/sde1(0)
[lv_mlog] /dev/sdi1(0)
[root@bp-01 LVM2]# lvconvert --splitmirrors 2 --name split vg/lv /dev/sd[ce]1
Logical volume lv converted.
[root@bp-01 LVM2]# !lvs
lvs -a -o name,copy_percent,devices
LV Copy% Devices
lv 100.00 lv_mimage_0(0),lv_mimage_2(0)
[lv_mimage_0] /dev/sdb1(0)
[lv_mimage_2] /dev/sdd1(0)
[lv_mlog] /dev/sdi1(0)
split 100.00 split_mimage_0(0),split_mimage_1(0)
[split_mimage_0] /dev/sde1(0)
[split_mimage_1] /dev/sdc1(0)
It can be seen that '--splitmirror <n>' is exactly the same
as '--mirrors -<n>' (note the minus sign), except there is the
additional notion to keep the image being detached from the
mirror instead of just throwing it away.
Signed-off-by: Jonathan Brassow <jbrassow@redhat.com>
2010-01-09 01:00:31 +03:00
2010-08-06 19:38:32 +04:00
if ( ! operable_pvs )
2010-03-27 01:15:43 +03:00
operable_pvs = lp - > pvh ;
This patch adds the capability to split off a mirror legs.
It is pretty much the same as reducing the number of
mirror legs, but we just don't delete them afterwards.
The following command line interface is enforced:
prompt> lvconvert --splitmirror <n> -n <name> <VG>/<LV>
where 'n' is the number of images to split off, and
where 'name' is the name of the newly split off logical volume.
If more than one leg is split off, a new mirror will be the
result. The newly split off mirror will have a 'core' log.
Example:
[root@bp-01 LVM2]# !lvs
lvs -a -o name,copy_percent,devices
LV Copy% Devices
lv 100.00 lv_mimage_0(0),lv_mimage_1(0),lv_mimage_2(0),lv_mimage_3(0)
[lv_mimage_0] /dev/sdb1(0)
[lv_mimage_1] /dev/sdc1(0)
[lv_mimage_2] /dev/sdd1(0)
[lv_mimage_3] /dev/sde1(0)
[lv_mlog] /dev/sdi1(0)
[root@bp-01 LVM2]# lvconvert --splitmirrors 2 --name split vg/lv /dev/sd[ce]1
Logical volume lv converted.
[root@bp-01 LVM2]# !lvs
lvs -a -o name,copy_percent,devices
LV Copy% Devices
lv 100.00 lv_mimage_0(0),lv_mimage_2(0)
[lv_mimage_0] /dev/sdb1(0)
[lv_mimage_2] /dev/sdd1(0)
[lv_mlog] /dev/sdi1(0)
split 100.00 split_mimage_0(0),split_mimage_1(0)
[split_mimage_0] /dev/sde1(0)
[split_mimage_1] /dev/sdc1(0)
It can be seen that '--splitmirror <n>' is exactly the same
as '--mirrors -<n>' (note the minus sign), except there is the
additional notion to keep the image being detached from the
mirror instead of just throwing it away.
Signed-off-by: Jonathan Brassow <jbrassow@redhat.com>
2010-01-09 01:00:31 +03:00
2010-03-27 01:15:43 +03:00
seg = first_seg ( lv ) ;
2009-04-30 00:11:46 +04:00
2010-03-27 01:15:43 +03:00
/*
* Up - convert from linear to mirror
*/
if ( ! ( lv - > status & MIRRORED ) ) {
2007-08-02 00:54:28 +04:00
/* FIXME Share code with lvcreate */
2009-04-23 20:56:21 +04:00
/*
* FIXME should we give not only lp - > pvh , but also all PVs
* currently taken by the mirror ? Would make more sense from
* user perspective .
*/
2010-04-13 05:54:32 +04:00
if ( ! lv_add_mirrors ( cmd , lv , new_mimage_count - 1 , lp - > stripes ,
lp - > stripe_size , region_size , new_log_count , operable_pvs ,
2012-01-26 02:38:40 +04:00
lp - > alloc , MIRROR_BY_LV ) )
return_0 ;
2008-01-15 00:11:47 +03:00
if ( lp - > wait_completion )
lp - > need_polling = 1 ;
2010-03-27 01:15:43 +03:00
goto out ;
}
/*
* Up - convert m - way mirror to n - way mirror
*/
if ( new_mimage_count > old_mimage_count ) {
2011-03-29 16:51:57 +04:00
if ( lv - > status & LV_NOTSYNCED ) {
2009-06-15 17:43:15 +04:00
log_error ( " Can't add mirror to out-of-sync mirrored "
" LV: use lvchange --resync first. " ) ;
2007-12-22 05:13:00 +03:00
return 0 ;
}
2009-10-26 13:01:56 +03:00
/*
* We allow snapshots of mirrors , but for now , we
* do not allow up converting mirrors that are under
* snapshots . The layering logic is somewhat complex ,
* and preliminary test show that the conversion can ' t
* seem to get the correct % ' age of completion .
*/
if ( lv_is_origin ( lv ) ) {
log_error ( " Can't add additional mirror images to "
" mirrors that are under snapshots " ) ;
2010-04-14 17:51:58 +04:00
return 0 ;
2009-10-26 13:01:56 +03:00
}
2010-04-21 18:04:24 +04:00
/*
* Is there already a convert in progress ? We do not
* currently allow more than one .
*/
if ( find_temporary_mirror ( lv ) | | ( lv - > status & CONVERTING ) ) {
log_error ( " %s is already being converted. Unable to start another conversion. " ,
lv - > name ) ;
return 0 ;
}
2008-01-10 21:35:51 +03:00
/*
* Log addition / removal should be done before the layer
* insertion to make the end result consistent with
* linear - to - mirror conversion .
*/
2010-03-27 01:15:43 +03:00
if ( ! _lv_update_log_type ( cmd , lp , lv ,
2013-07-01 13:27:11 +04:00
operable_pvs , new_log_count ) )
return_0 ;
2010-03-27 01:15:43 +03:00
2008-01-10 21:35:51 +03:00
/* Insert a temporary layer for syncing,
* only if the original lv is using disk log . */
if ( seg - > log_lv & & ! _insert_lvconvert_layer ( cmd , lv ) ) {
2007-12-20 21:55:46 +03:00
log_error ( " Failed to insert resync layer " ) ;
return 0 ;
}
2010-03-27 01:15:43 +03:00
2008-01-10 21:35:51 +03:00
/* FIXME: can't have multiple mlogs. force corelog. */
2010-03-27 01:15:43 +03:00
if ( ! lv_add_mirrors ( cmd , lv ,
2011-01-11 20:05:08 +03:00
new_mimage_count - old_mimage_count ,
lp - > stripes , lp - > stripe_size ,
2010-03-27 01:15:43 +03:00
region_size , 0U , operable_pvs , lp - > alloc ,
2009-10-23 05:24:17 +04:00
MIRROR_BY_LV ) ) {
layer_lv = seg_lv ( first_seg ( lv ) , 0 ) ;
if ( ! remove_layer_from_lv ( lv , layer_lv ) | |
2013-04-11 01:47:04 +04:00
( lv_is_active ( layer_lv ) & &
! deactivate_lv ( cmd , layer_lv ) ) | |
2009-10-23 05:24:17 +04:00
! lv_remove ( layer_lv ) | | ! vg_write ( lv - > vg ) | |
! vg_commit ( lv - > vg ) ) {
log_error ( " ABORTING: Failed to remove "
" temporary mirror layer %s. " ,
layer_lv - > name ) ;
log_error ( " Manual cleanup with vgcfgrestore "
" and dmsetup may be required. " ) ;
return 0 ;
}
2013-07-01 13:27:11 +04:00
return_0 ;
2009-10-23 05:24:17 +04:00
}
2010-02-06 00:49:16 +03:00
if ( seg - > log_lv )
lv - > status | = CONVERTING ;
2008-01-15 00:11:47 +03:00
lp - > need_polling = 1 ;
2010-03-27 01:15:43 +03:00
goto out_skip_log_convert ;
2005-06-06 21:12:08 +04:00
}
2010-03-27 01:15:43 +03:00
/*
* Down - convert ( reduce # of mimages ) .
*/
if ( new_mimage_count < old_mimage_count ) {
uint32_t nmc = old_mimage_count - new_mimage_count ;
uint32_t nlc = ( ! new_log_count | | lp - > mirrors = = 1 ) ? 1U : 0U ;
2010-04-20 16:18:31 +04:00
/* FIXME: Why did nlc used to be calculated that way? */
2010-03-27 01:15:43 +03:00
/* Reduce number of mirrors */
if ( lp - > keep_mimages ) {
2011-08-18 23:38:26 +04:00
if ( arg_count ( cmd , trackchanges_ARG ) ) {
log_error ( " --trackchanges is not available "
" to 'mirror' segment type " ) ;
return 0 ;
}
2010-03-27 01:15:43 +03:00
if ( ! lv_split_mirror_images ( lv , lp - > lv_split_name ,
nmc , operable_pvs ) )
2014-05-20 14:53:51 +04:00
return_0 ;
2010-03-27 01:15:43 +03:00
} else if ( ! lv_remove_mirrors ( cmd , lv , nmc , nlc ,
2010-05-24 19:32:20 +04:00
is_mirror_image_removable , operable_pvs , 0 ) )
2010-03-27 01:15:43 +03:00
return_0 ;
goto out ; /* Just in case someone puts code between */
}
out :
/*
* Converting the log type
*/
2010-04-28 21:41:30 +04:00
if ( ( lv - > status & MIRRORED ) & & ( old_log_count ! = new_log_count ) ) {
2010-03-27 01:15:43 +03:00
if ( ! _lv_update_log_type ( cmd , lp , lv ,
2013-07-01 13:27:11 +04:00
operable_pvs , new_log_count ) )
return_0 ;
2009-04-23 20:56:21 +04:00
}
2010-03-27 01:15:43 +03:00
out_skip_log_convert :
2012-08-02 13:38:07 +04:00
if ( ! _reload_lv ( cmd , lv - > vg , lv ) )
return_0 ;
2005-06-06 21:12:08 +04:00
2010-03-27 01:15:43 +03:00
return 1 ;
}
2011-05-07 17:56:13 +04:00
int mirror_remove_missing ( struct cmd_context * cmd ,
struct logical_volume * lv , int force )
{
struct dm_list * failed_pvs ;
int log_count = _get_log_count ( lv ) - _failed_logs_count ( lv ) ;
if ( ! ( failed_pvs = _failed_pv_list ( lv - > vg ) ) )
return_0 ;
2013-11-25 16:42:30 +04:00
if ( force & & _failed_mirrors_count ( lv ) = = ( int ) lv_mirror_count ( lv ) ) {
2011-05-07 17:56:13 +04:00
log_error ( " No usable images left in %s. " , lv - > name ) ;
2012-03-02 01:14:43 +04:00
return lv_remove_with_dependencies ( cmd , lv , DONT_PROMPT , 0 ) ;
2011-05-07 17:56:13 +04:00
}
/*
* We must adjust the log first , or the entire mirror
* will get stuck during a suspend .
*/
if ( ! _lv_update_mirrored_log ( lv , failed_pvs , log_count ) )
2014-05-20 14:53:51 +04:00
return_0 ;
2011-05-07 17:56:13 +04:00
if ( _failed_mirrors_count ( lv ) > 0 & &
! lv_remove_mirrors ( cmd , lv , _failed_mirrors_count ( lv ) ,
log_count ? 0U : 1U ,
_is_partial_lv , NULL , 0 ) )
2014-05-20 14:53:51 +04:00
return_0 ;
2011-05-07 17:56:13 +04:00
2012-11-15 00:58:47 +04:00
if ( lv_is_mirrored ( lv ) & &
! _lv_update_log_type ( cmd , NULL , lv , failed_pvs , log_count ) )
2014-05-20 14:53:51 +04:00
return_0 ;
2011-05-07 17:56:13 +04:00
2012-08-02 13:38:07 +04:00
if ( ! _reload_lv ( cmd , lv - > vg , lv ) )
return_0 ;
2011-05-07 17:56:13 +04:00
return 1 ;
}
2010-03-27 01:15:43 +03:00
/*
* _lvconvert_mirrors_repair
*
* This function operates in two phases . First , all of the bad
* devices are removed from the mirror . Then , if desired by the
* user , the devices are replaced .
*
* ' old_mimage_count ' and ' old_log_count ' are there so we know
* what to convert to after the removal of devices .
*/
static int _lvconvert_mirrors_repair ( struct cmd_context * cmd ,
struct logical_volume * lv ,
2011-05-07 17:56:13 +04:00
struct lvconvert_params * lp )
2010-03-27 01:15:43 +03:00
{
2014-05-20 22:10:29 +04:00
int failed_logs ;
int failed_mimages ;
2011-05-07 17:56:13 +04:00
int replace_logs = 0 ;
int replace_mimages = 0 ;
uint32_t log_count ;
uint32_t original_mimages = lv_mirror_count ( lv ) ;
uint32_t original_logs = _get_log_count ( lv ) ;
2010-03-27 01:15:43 +03:00
cmd - > handles_missing_pvs = 1 ;
cmd - > partial_activation = 1 ;
lp - > need_polling = 0 ;
2010-05-24 19:32:20 +04:00
lv_check_transient ( lv ) ; /* TODO check this in lib for all commands? */
2010-03-27 01:15:43 +03:00
if ( ! ( lv - > status & PARTIAL_LV ) ) {
2014-05-20 14:56:49 +04:00
log_print_unless_silent ( " %s is consistent. Nothing to repair. " , lv - > name ) ;
2010-03-27 01:15:43 +03:00
return 1 ;
}
2011-05-07 17:56:13 +04:00
failed_mimages = _failed_mirrors_count ( lv ) ;
failed_logs = _failed_logs_count ( lv ) ;
2010-03-27 01:15:43 +03:00
2014-05-20 14:57:42 +04:00
if ( ! mirror_remove_missing ( cmd , lv , 0 ) )
return_0 ;
2010-03-27 01:15:43 +03:00
2011-05-07 17:56:13 +04:00
if ( failed_mimages )
2014-05-20 14:56:49 +04:00
log_print_unless_silent ( " Mirror status: %d of %d images failed. " ,
failed_mimages , original_mimages ) ;
2010-03-27 01:15:43 +03:00
/*
* Count the failed log devices
*/
2011-05-07 17:56:13 +04:00
if ( failed_logs )
2014-05-20 14:56:49 +04:00
log_print_unless_silent ( " Mirror log status: %d of %d images failed. " ,
failed_logs , original_logs ) ;
2010-03-27 01:15:43 +03:00
/*
* Find out our policies
*/
2011-05-07 17:56:13 +04:00
_lvconvert_mirrors_repair_ask ( cmd , failed_logs , failed_mimages ,
& replace_logs , & replace_mimages ) ;
2010-03-27 01:15:43 +03:00
/*
* Second phase - replace faulty devices
*/
2011-05-07 17:56:13 +04:00
lp - > mirrors = replace_mimages ? original_mimages : ( original_mimages - failed_mimages ) ;
2010-03-27 01:15:43 +03:00
2010-05-24 19:32:20 +04:00
/*
* It does not make sense to replace the log if the volume is no longer
* a mirror .
*/
2011-05-07 17:56:13 +04:00
if ( lp - > mirrors = = 1 )
replace_logs = 0 ;
2010-05-24 19:32:20 +04:00
2011-05-07 17:56:13 +04:00
log_count = replace_logs ? original_logs : ( original_logs - failed_logs ) ;
2010-04-14 17:51:58 +04:00
2011-05-07 17:56:13 +04:00
while ( replace_mimages | | replace_logs ) {
2010-04-14 17:51:58 +04:00
log_warn ( " Trying to up-convert to %d images, %d logs. " , lp - > mirrors , log_count ) ;
if ( _lvconvert_mirrors_aux ( cmd , lv , lp , NULL ,
lp - > mirrors , log_count ) )
break ;
2014-05-20 22:10:55 +04:00
if ( lp - > mirrors > 2 )
- - lp - > mirrors ;
else if ( log_count > 0 )
- - log_count ;
else
break ; /* nowhere to go, anymore... */
2009-04-23 20:56:21 +04:00
}
2011-05-07 17:56:13 +04:00
if ( replace_mimages & & lv_mirror_count ( lv ) ! = original_mimages )
2010-04-14 17:51:58 +04:00
log_warn ( " WARNING: Failed to replace %d of %d images in volume %s " ,
2011-05-07 17:56:13 +04:00
original_mimages - lv_mirror_count ( lv ) , original_mimages , lv - > name ) ;
if ( replace_logs & & _get_log_count ( lv ) ! = original_logs )
2010-04-14 17:51:58 +04:00
log_warn ( " WARNING: Failed to replace %d of %d logs in volume %s " ,
2011-05-07 17:56:13 +04:00
original_logs - _get_log_count ( lv ) , original_logs , lv - > name ) ;
2010-04-14 17:51:58 +04:00
/* if (!arg_count(cmd, use_policies_ARG) && (lp->mirrors != old_mimage_count
| | log_count ! = old_log_count ) )
return 0 ; */
2010-03-27 01:15:43 +03:00
return 1 ;
}
2013-07-24 17:25:22 +04:00
static int _lvconvert_validate_thin ( struct logical_volume * lv ,
struct lvconvert_params * lp )
{
if ( ! lv_is_thin_pool ( lv ) & & ! lv_is_thin_volume ( lv ) )
return 1 ;
log_error ( " Converting thin%s segment type for \" %s/%s \" to %s is not supported. " ,
lv_is_thin_pool ( lv ) ? " pool " : " " ,
lv - > vg - > name , lv - > name , lp - > segtype - > name ) ;
if ( lv_is_thin_volume ( lv ) )
return 0 ;
/* Give advice for thin pool conversion */
log_error ( " For pool data volume conversion use \" %s/%s \" . " ,
lv - > vg - > name , seg_lv ( first_seg ( lv ) , 0 ) - > name ) ;
log_error ( " For pool metadata volume conversion use \" %s/%s \" . " ,
lv - > vg - > name , first_seg ( lv ) - > metadata_lv - > name ) ;
return 0 ;
}
2010-03-27 01:15:43 +03:00
/*
* _lvconvert_mirrors
*
* Determine what is being done . Are we doing a conversion , repair , or
* collapsing a stack ? Once determined , call helper functions .
*/
static int _lvconvert_mirrors ( struct cmd_context * cmd ,
struct logical_volume * lv ,
struct lvconvert_params * lp )
{
int repair = arg_count ( cmd , repair_ARG ) ;
uint32_t old_mimage_count ;
uint32_t old_log_count ;
uint32_t new_mimage_count ;
uint32_t new_log_count ;
2011-08-18 23:43:08 +04:00
if ( lp - > merge_mirror ) {
log_error ( " Unable to merge mirror images "
" of segment type 'mirror' " ) ;
return 0 ;
}
2013-07-24 17:25:22 +04:00
if ( ! _lvconvert_validate_thin ( lv , lp ) )
return_0 ;
Mirror/Thin: Disallow thinpools on mirror logical volumes
The same corner cases that exist for snapshots on mirrors exist for
any logical volume layered on top of mirror. (One example is when
a mirror image fails and a non-repair LVM command is the first to
detect it via label reading. In this case, the LVM command will hang
and prevent the necessary LVM repair command from running.) When
a better alternative exists, it makes no sense to allow a new target
to stack on mirrors as a new feature. Since, RAID is now capable of
running EX in a cluster and thin is not active-active aware, it makes
sense to pair these two rather than mirror+thinpool.
As further background, here are some additional comments that I made
when addressing a bug related to mirror+thinpool:
(https://bugzilla.redhat.com/show_bug.cgi?id=919604#c9)
I am going to disallow thin* on top of mirror logical volumes.
Users will have to use the "raid1" segment type if they want this.
This bug has come down to a choice between:
1) Disallowing thin-LVs from being used as PVs.
2) Disallowing thinpools on top of mirrors.
The problem is that the code in dev_manager.c:device_is_usable() is unable
to tell whether there is a mirror device lower in the stack from the device
being checked. Pretty much anything layered on top of a mirror will suffer
from this problem. (Snapshots are a good example of this; and option #1
above has been chosen to deal with them. This can also be seen in
dev_manager.c:device_is_usable().) When a mirror failure occurs, the
kernel blocks all I/O to it. If there is an LVM command that comes along
to do the repair (or a different operation that requires label reading), it
would normally avoid the mirror when it sees that it is blocked. However,
if there is a snapshot or a thin-LV that is on a mirror, the above code
will not detect the mirror underneath and will issue label reading I/O.
This causes the command to hang.
Choosing #1 would mean that thin-LVs could never be used as PVs - even if
they are stacked on something other than mirrors.
Choosing #2 means that thinpools can never be placed on mirrors. This is
probably better than we think, since it is preferred that people use the
"raid1" segment type in the first place. However, RAID* cannot currently
be used in a cluster volume group - even in EX-only mode. Thus, a complete
solution for option #2 must include the ability to activate RAID logical
volumes (and perform RAID operations) in a cluster volume group. I've
already begun working on this.
2013-09-12 00:58:44 +04:00
if ( lv_is_thin_type ( lv ) ) {
log_error ( " Mirror segment type cannot be used for thinpool%s. \n "
" Try \" raid1 \" segment type instead. " ,
lv_is_thin_pool_data ( lv ) ? " s " : " metadata " ) ;
return 0 ;
}
2010-03-27 01:15:43 +03:00
/* Adjust mimage and/or log count */
if ( ! _lvconvert_mirrors_parse_params ( cmd , lv , lp ,
& old_mimage_count , & old_log_count ,
& new_mimage_count , & new_log_count ) )
return 0 ;
2010-11-25 20:15:46 +03:00
if ( ( ( old_mimage_count < new_mimage_count & & old_log_count > new_log_count ) | |
( old_mimage_count > new_mimage_count & & old_log_count < new_log_count ) ) & &
lp - > pv_count ) {
2011-01-06 02:18:46 +03:00
log_error ( " Cannot both allocate and free extents when "
" specifying physical volumes to use. " ) ;
2010-11-25 20:15:46 +03:00
log_error ( " Please specify the operation in two steps. " ) ;
return 0 ;
}
2010-03-27 01:15:43 +03:00
/* Nothing to do? (Probably finishing collapse.) */
if ( ( old_mimage_count = = new_mimage_count ) & &
( old_log_count = = new_log_count ) & & ! repair )
return 1 ;
if ( repair )
2011-05-07 17:56:13 +04:00
return _lvconvert_mirrors_repair ( cmd , lv , lp ) ;
2010-03-27 01:15:43 +03:00
if ( ! _lvconvert_mirrors_aux ( cmd , lv , lp , NULL ,
2010-04-14 17:51:58 +04:00
new_mimage_count , new_log_count ) )
2010-03-27 01:15:43 +03:00
return 0 ;
2008-01-15 00:11:47 +03:00
if ( ! lp - > need_polling )
config: add silent mode
Accept -q as the short form of --quiet.
Suppress non-essential standard output if -q is given twice.
Treat log/silent in lvm.conf as equivalent to -qq.
Review all log_print messages and change some to
log_print_unless_silent.
When silent, the following commands still produce output:
dumpconfig, lvdisplay, lvmdiskscan, lvs, pvck, pvdisplay,
pvs, version, vgcfgrestore -l, vgdisplay, vgs.
[Needs checking.]
Non-essential messages are shifted from log level 4 to log level 5
for syslog and lvm2_log_fn purposes.
2012-08-25 23:35:48 +04:00
log_print_unless_silent ( " Logical volume %s converted. " , lv - > name ) ;
2005-06-06 21:12:08 +04:00
2009-04-21 18:31:57 +04:00
backup ( lv - > vg ) ;
2010-03-27 01:15:43 +03:00
return 1 ;
2005-06-06 21:12:08 +04:00
}
2013-12-04 06:09:37 +04:00
static int _is_valid_raid_conversion ( const struct segment_type * from_segtype ,
2011-08-11 22:24:40 +04:00
const struct segment_type * to_segtype )
{
if ( from_segtype = = to_segtype )
return 1 ;
if ( ! segtype_is_raid ( from_segtype ) & & ! segtype_is_raid ( to_segtype ) )
return_0 ; /* Not converting to or from RAID? */
2011-10-07 18:52:26 +04:00
return 1 ;
2011-08-11 22:24:40 +04:00
}
2014-07-01 11:55:04 +04:00
static void _lvconvert_raid_repair_ask ( struct cmd_context * cmd ,
struct lvconvert_params * lp ,
int * replace_dev )
2011-12-06 23:30:15 +04:00
{
2014-07-01 11:55:04 +04:00
const char * dev_policy ;
2011-12-06 23:30:15 +04:00
2012-12-11 12:52:54 +04:00
* replace_dev = 1 ;
2011-12-06 23:30:15 +04:00
if ( arg_count ( cmd , use_policies_ARG ) ) {
2013-06-25 14:29:54 +04:00
dev_policy = find_config_tree_str ( cmd , activation_raid_fault_policy_CFG , NULL ) ;
2011-12-06 23:30:15 +04:00
if ( ! strcmp ( dev_policy , " allocate " ) | |
! strcmp ( dev_policy , " replace " ) )
2012-12-11 12:52:54 +04:00
return ;
/* else if (!strcmp(dev_policy, "anything_else")) -- no replace */
* replace_dev = 0 ;
2011-12-06 23:30:15 +04:00
return ;
}
2014-07-01 11:55:04 +04:00
if ( ! lp - > yes & &
yes_no_prompt ( " Attempt to replace failed RAID images "
2012-12-11 12:52:54 +04:00
" (requires full device resync)? [y/n]: " ) = = ' n ' ) {
* replace_dev = 0 ;
2011-12-06 23:30:15 +04:00
}
}
2013-12-04 06:09:37 +04:00
static int _lvconvert_raid ( struct logical_volume * lv , struct lvconvert_params * lp )
2011-08-11 22:24:40 +04:00
{
2013-12-05 12:41:03 +04:00
int replace = 0 , image_count = 0 ;
2011-12-06 23:30:15 +04:00
struct dm_list * failed_pvs ;
2011-08-11 22:24:40 +04:00
struct cmd_context * cmd = lv - > vg - > cmd ;
struct lv_segment * seg = first_seg ( lv ) ;
2014-06-09 14:08:27 +04:00
dm_percent_t sync_percent ;
2011-08-11 22:24:40 +04:00
if ( ! arg_count ( cmd , type_ARG ) )
lp - > segtype = seg - > segtype ;
2011-10-07 18:52:26 +04:00
/* Can only change image count for raid1 and linear */
if ( arg_count ( cmd , mirrors_ARG ) & &
! seg_is_mirrored ( seg ) & & ! seg_is_linear ( seg ) ) {
2011-08-11 22:24:40 +04:00
log_error ( " '--mirrors/-m' is not compatible with %s " ,
2012-09-05 20:35:54 +04:00
seg - > segtype - > ops - > name ( seg ) ) ;
2011-08-11 22:24:40 +04:00
return 0 ;
}
2013-07-24 17:25:22 +04:00
if ( ! _lvconvert_validate_thin ( lv , lp ) )
return_0 ;
2013-12-04 06:09:37 +04:00
if ( ! _is_valid_raid_conversion ( seg - > segtype , lp - > segtype ) ) {
2011-08-11 22:24:40 +04:00
log_error ( " Unable to convert %s/%s from %s to %s " ,
lv - > vg - > name , lv - > name ,
2012-09-05 20:35:54 +04:00
seg - > segtype - > ops - > name ( seg ) , lp - > segtype - > name ) ;
2011-08-11 22:24:40 +04:00
return 0 ;
}
/* Change number of RAID1 images */
2011-08-18 23:34:18 +04:00
if ( arg_count ( cmd , mirrors_ARG ) | | arg_count ( cmd , splitmirrors_ARG ) ) {
2011-08-11 22:24:40 +04:00
image_count = lv_raid_image_count ( lv ) ;
if ( lp - > mirrors_sign = = SIGN_PLUS )
image_count + = lp - > mirrors ;
else if ( lp - > mirrors_sign = = SIGN_MINUS )
image_count - = lp - > mirrors ;
else
image_count = lp - > mirrors + 1 ;
if ( image_count < 1 ) {
2011-08-18 23:34:18 +04:00
log_error ( " Unable to %s images by specified amount " ,
arg_count ( cmd , splitmirrors_ARG ) ?
" split " : " reduce " ) ;
2011-08-11 22:24:40 +04:00
return 0 ;
}
}
2011-08-18 23:43:08 +04:00
if ( lp - > merge_mirror )
return lv_raid_merge ( lv ) ;
if ( arg_count ( cmd , trackchanges_ARG ) )
return lv_raid_split_and_track ( lv , lp - > pvh ) ;
if ( arg_count ( cmd , splitmirrors_ARG ) )
return lv_raid_split ( lv , lp - > lv_split_name ,
image_count , lp - > pvh ) ;
if ( arg_count ( cmd , mirrors_ARG ) )
return lv_raid_change_image_count ( lv , image_count , lp - > pvh ) ;
2011-10-07 18:56:01 +04:00
if ( arg_count ( cmd , type_ARG ) )
return lv_raid_reshape ( lv , lp - > segtype ) ;
2011-11-30 06:02:10 +04:00
if ( arg_count ( cmd , replace_ARG ) )
return lv_raid_replace ( lv , lp - > replace_pvh , lp - > pvh ) ;
2011-12-06 23:30:15 +04:00
if ( arg_count ( cmd , repair_ARG ) ) {
2013-09-11 01:33:22 +04:00
if ( ! lv_is_active_exclusive_locally ( lv ) ) {
log_error ( " %s/%s must be active %sto perform this "
" operation. " , lv - > vg - > name , lv - > name ,
vg_is_clustered ( lv - > vg ) ?
" exclusive locally " : " " ) ;
2012-12-19 00:40:42 +04:00
return 0 ;
}
if ( ! lv_raid_percent ( lv , & sync_percent ) ) {
log_error ( " Unable to determine sync status of %s/%s. " ,
lv - > vg - > name , lv - > name ) ;
return 0 ;
}
2014-06-09 14:08:27 +04:00
if ( sync_percent ! = DM_PERCENT_100 ) {
2014-07-01 11:53:58 +04:00
log_warn ( " WARNING: %s/%s is not in-sync. " ,
lv - > vg - > name , lv - > name ) ;
log_warn ( " WARNING: Portions of the array may be unrecoverable. " ) ;
2012-12-19 00:40:42 +04:00
/*
* The kernel will not allow a device to be replaced
* in an array that is not in - sync unless we override
* by forcing the array to be considered " in-sync " .
*/
init_mirror_in_sync ( 1 ) ;
}
2014-07-01 11:55:04 +04:00
_lvconvert_raid_repair_ask ( cmd , lp , & replace ) ;
2011-12-06 23:30:15 +04:00
if ( replace ) {
2012-02-22 19:20:50 +04:00
if ( ! ( failed_pvs = _failed_pv_list ( lv - > vg ) ) )
return_0 ;
2012-02-22 20:03:55 +04:00
if ( ! lv_raid_replace ( lv , failed_pvs , lp - > pvh ) ) {
log_error ( " Failed to replace faulty devices in "
" %s/%s. " , lv - > vg - > name , lv - > name ) ;
return 0 ;
}
config: add silent mode
Accept -q as the short form of --quiet.
Suppress non-essential standard output if -q is given twice.
Treat log/silent in lvm.conf as equivalent to -qq.
Review all log_print messages and change some to
log_print_unless_silent.
When silent, the following commands still produce output:
dumpconfig, lvdisplay, lvmdiskscan, lvs, pvck, pvdisplay,
pvs, version, vgcfgrestore -l, vgdisplay, vgs.
[Needs checking.]
Non-essential messages are shifted from log level 4 to log level 5
for syslog and lvm2_log_fn purposes.
2012-08-25 23:35:48 +04:00
log_print_unless_silent ( " Faulty devices in %s/%s successfully "
" replaced. " , lv - > vg - > name , lv - > name ) ;
2012-02-22 20:03:55 +04:00
return 1 ;
2011-12-06 23:30:15 +04:00
}
/* "warn" if policy not set to replace */
if ( arg_count ( cmd , use_policies_ARG ) )
2012-10-16 12:14:41 +04:00
log_warn ( " Use 'lvconvert --repair %s/%s' to replace "
" failed device. " , lv - > vg - > name , lv - > name ) ;
2011-12-06 23:30:15 +04:00
return 1 ;
}
2011-08-11 22:24:40 +04:00
log_error ( " Conversion operation not yet supported. " ) ;
return 0 ;
}
2013-12-04 06:09:37 +04:00
static int _lvconvert_splitsnapshot ( struct cmd_context * cmd , struct logical_volume * cow ,
struct lvconvert_params * lp )
{
struct lvinfo info ;
struct volume_group * vg = cow - > vg ;
if ( ! lv_is_cow ( cow ) ) {
log_error ( " %s/%s is not a snapshot. " , vg - > name , cow - > name ) ;
return ECMD_FAILED ;
}
if ( lv_is_origin ( cow ) | | lv_is_external_origin ( cow ) ) {
log_error ( " Unable to split LV %s/%s that is a snapshot origin. " , vg - > name , cow - > name ) ;
return ECMD_FAILED ;
}
if ( lv_is_merging_cow ( cow ) ) {
log_error ( " Unable to split off snapshot %s/%s being merged into its origin. " , vg - > name , cow - > name ) ;
return ECMD_FAILED ;
}
if ( lv_is_virtual_origin ( origin_from_cow ( cow ) ) ) {
log_error ( " Unable to split off snapshot %s/%s with virtual origin. " , vg - > name , cow - > name ) ;
return ECMD_FAILED ;
}
if ( lv_is_thin_pool ( cow ) | | lv_is_pool_metadata_spare ( cow ) ) {
log_error ( " Unable to split off LV %s/%s needed by thin volume(s). " , vg - > name , cow - > name ) ;
return ECMD_FAILED ;
}
if ( ! ( vg - > fid - > fmt - > features & FMT_MDAS ) ) {
log_error ( " Unable to split off snapshot %s/%s using old LVM1-style metadata. " , vg - > name , cow - > name ) ;
return ECMD_FAILED ;
}
if ( ! vg_check_status ( vg , LVM_WRITE ) )
return_ECMD_FAILED ;
if ( lv_is_mirror_type ( cow ) | | lv_is_raid_type ( cow ) | | lv_is_thin_type ( cow ) ) {
log_error ( " LV %s/%s type is unsupported with --splitsnapshot. " , vg - > name , cow - > name ) ;
return ECMD_FAILED ;
}
2014-07-11 14:25:18 +04:00
if ( lv_info ( cmd , cow , 0 , & info , 1 , 0 ) ) {
if ( ! lv_check_not_in_use ( cmd , cow , & info ) )
2014-07-11 14:24:32 +04:00
return_ECMD_FAILED ;
2013-12-04 06:09:37 +04:00
2014-07-11 14:25:18 +04:00
if ( ( lp - > force = = PROMPT ) & &
lv_is_visible ( cow ) & &
lv_is_active ( cow ) ) {
if ( yes_no_prompt ( " Do you really want to split off active "
" logical volume %s? [y/n]: " , cow - > name ) = = ' n ' ) {
log_error ( " Logical volume %s not split. " , cow - > name ) ;
return ECMD_FAILED ;
}
}
}
2013-12-04 06:09:37 +04:00
if ( ! archive ( vg ) )
return_ECMD_FAILED ;
log_verbose ( " Splitting snapshot %s/%s from its origin. " , vg - > name , cow - > name ) ;
if ( ! vg_remove_snapshot ( cow ) )
return_ECMD_FAILED ;
backup ( vg ) ;
log_print_unless_silent ( " Logical Volume %s/%s split from its origin. " , vg - > name , cow - > name ) ;
return ECMD_PROCESSED ;
}
static int _lvconvert_snapshot ( struct cmd_context * cmd ,
struct logical_volume * lv ,
struct lvconvert_params * lp )
2006-04-06 00:43:23 +04:00
{
struct logical_volume * org ;
2014-08-26 19:07:37 +04:00
if ( lv - > status & MIRRORED ) {
2014-03-17 17:05:17 +04:00
log_error ( " Unable to convert mirrored LV \" %s \" into a snapshot. " , lv - > name ) ;
return 0 ;
}
2014-03-17 12:41:36 +04:00
if ( lv_is_origin ( lv ) ) {
/* Unsupported stack */
log_error ( " Unable to convert origin \" %s \" into a snapshot. " , lv - > name ) ;
return 0 ;
}
2014-07-11 14:15:23 +04:00
if ( ! ( org = find_lv ( lv - > vg , lp - > origin_lv_name ) ) ) {
log_error ( " Couldn't find origin volume %s. " , lp - > origin_lv_name ) ;
2006-04-06 00:43:23 +04:00
return 0 ;
}
2007-11-07 19:33:12 +03:00
if ( org = = lv ) {
2014-07-11 14:15:23 +04:00
log_error ( " Unable to use %s as both snapshot and origin. " ,
display_lvname ( lv ) ) ;
2007-11-07 19:33:12 +03:00
return 0 ;
}
2014-03-17 16:06:00 +04:00
if ( ! cow_has_min_chunks ( lv - > vg , lv - > le_count , lp - > chunk_size ) )
return_0 ;
2014-08-26 19:07:37 +04:00
if ( org - > status & ( LOCKED | PVMOVE | MIRRORED ) | | lv_is_cow ( org ) ) {
2011-06-01 16:24:15 +04:00
log_error ( " Unable to convert an LV into a snapshot of a %s LV. " ,
2006-04-06 00:43:23 +04:00
org - > status & LOCKED ? " locked " :
2008-06-27 01:38:58 +04:00
org - > status & PVMOVE ? " pvmove " :
org - > status & MIRRORED ? " mirrored " :
" snapshot " ) ;
2006-04-06 00:43:23 +04:00
return 0 ;
}
2014-07-08 00:33:31 +04:00
log_warn ( " WARNING: Converting logical volume %s to snapshot exception store. " ,
display_lvname ( lv ) ) ;
log_warn ( " THIS WILL DESTROY CONTENT OF LOGICAL VOLUME (filesystem etc.) " ) ;
if ( ! lp - > yes & &
yes_no_prompt ( " Do you really want to convert %s? [y/n]: " ,
display_lvname ( lv ) ) = = ' n ' ) {
log_error ( " Conversion aborted. " ) ;
2007-08-02 00:54:28 +04:00
return 0 ;
2006-04-06 00:43:23 +04:00
}
if ( ! deactivate_lv ( cmd , lv ) ) {
log_error ( " Couldn't deactivate LV %s. " , lv - > name ) ;
return 0 ;
}
2014-07-08 00:33:31 +04:00
if ( ! lp - > zero | | ! ( lv - > status & LVM_WRITE ) )
log_warn ( " WARNING: \" %s \" not zeroed " , lv - > name ) ;
else {
lv - > status | = LV_TEMPORARY ;
if ( ! activate_lv_local ( cmd , lv ) | |
! wipe_lv ( lv , ( struct wipe_params ) { . do_zero = 1 } ) ) {
log_error ( " Aborting. Failed to wipe snapshot exception store. " ) ;
return 0 ;
}
lv - > status & = ~ LV_TEMPORARY ;
/* Deactivates cleared metadata LV */
if ( ! deactivate_lv_local ( lv - > vg - > cmd , lv ) ) {
log_error ( " Failed to deactivate zeroed snapshot exception store. " ) ;
return 0 ;
}
}
2014-03-17 16:07:08 +04:00
if ( ! archive ( lv - > vg ) )
return_0 ;
2009-05-14 01:21:58 +04:00
if ( ! vg_add_snapshot ( org , lv , NULL , org - > le_count , lp - > chunk_size ) ) {
2006-04-06 00:43:23 +04:00
log_error ( " Couldn't create snapshot. " ) ;
return 0 ;
}
/* store vg on disk(s) */
2013-12-04 06:04:29 +04:00
if ( ! _reload_lv ( cmd , lv - > vg , org ) )
2006-04-06 00:43:23 +04:00
return_0 ;
config: add silent mode
Accept -q as the short form of --quiet.
Suppress non-essential standard output if -q is given twice.
Treat log/silent in lvm.conf as equivalent to -qq.
Review all log_print messages and change some to
log_print_unless_silent.
When silent, the following commands still produce output:
dumpconfig, lvdisplay, lvmdiskscan, lvs, pvck, pvdisplay,
pvs, version, vgcfgrestore -l, vgdisplay, vgs.
[Needs checking.]
Non-essential messages are shifted from log level 4 to log level 5
for syslog and lvm2_log_fn purposes.
2012-08-25 23:35:48 +04:00
log_print_unless_silent ( " Logical volume %s converted to snapshot. " , lv - > name ) ;
2012-08-02 13:38:07 +04:00
return 1 ;
2006-04-06 00:43:23 +04:00
}
2013-11-26 15:09:41 +04:00
static int _lvconvert_merge_old_snapshot ( struct cmd_context * cmd ,
struct logical_volume * lv ,
struct lvconvert_params * lp )
2010-01-13 04:45:15 +03:00
{
int r = 0 ;
2010-01-13 04:54:34 +03:00
int merge_on_activate = 0 ;
2010-01-13 04:45:15 +03:00
struct logical_volume * origin = origin_from_cow ( lv ) ;
2013-07-03 00:26:03 +04:00
struct lv_segment * snap_seg = find_snapshot ( lv ) ;
2010-01-13 04:47:18 +03:00
struct lvinfo info ;
2014-06-09 14:08:27 +04:00
dm_percent_t snap_percent ;
2010-01-13 04:45:15 +03:00
/* Check if merge is possible */
2013-11-26 15:09:41 +04:00
if ( ! lv_is_cow ( lv ) ) {
log_error ( " \" %s \" is not a mergeable logical volume. " ,
lv - > name ) ;
return 0 ;
}
2010-01-13 04:55:43 +03:00
if ( lv_is_merging_cow ( lv ) ) {
2013-11-26 15:09:41 +04:00
log_error ( " Snapshot %s is already merging. " , lv - > name ) ;
2010-01-13 04:45:15 +03:00
return 0 ;
}
2013-11-26 15:09:41 +04:00
2010-01-13 04:55:43 +03:00
if ( lv_is_merging_origin ( origin ) ) {
2013-11-28 14:39:38 +04:00
log_error ( " Snapshot %s is already merging into the origin. " ,
find_snapshot ( origin ) - > cow - > name ) ;
2010-01-13 04:45:15 +03:00
return 0 ;
}
2013-11-26 15:09:41 +04:00
2013-10-12 00:47:45 +04:00
if ( lv_is_virtual_origin ( origin ) ) {
log_error ( " Snapshot %s has virtual origin. " , lv - > name ) ;
return 0 ;
}
2010-01-13 04:45:15 +03:00
2013-11-26 15:09:41 +04:00
if ( lv_is_external_origin ( origin_from_cow ( lv ) ) ) {
log_error ( " Cannot merge snapshot \" %s \" into "
" the read-only external origin \" %s \" . " ,
lv - > name , origin_from_cow ( lv ) - > name ) ;
return 0 ;
}
if ( lv_info ( lv - > vg - > cmd , lv , 0 , & info , 1 , 0 )
& & info . exists & & info . live_table & &
( ! lv_snapshot_percent ( lv , & snap_percent ) | |
2014-06-09 14:08:27 +04:00
snap_percent = = DM_PERCENT_INVALID ) ) {
2013-11-26 15:09:41 +04:00
log_error ( " Unable to merge invalidated snapshot LV \" %s \" . " ,
lv - > name ) ;
return 0 ;
}
if ( ! archive ( lv - > vg ) )
return_0 ;
2010-01-13 04:47:18 +03:00
/*
* Prevent merge with open device ( s ) as it would likely lead
2010-01-13 04:54:34 +03:00
* to application / filesystem failure . Merge on origin ' s next
* activation if either the origin or snapshot LV are currently
* open .
2010-01-13 04:47:18 +03:00
*
* FIXME testing open_count is racey ; snapshot - merge target ' s
* constructor and DM should prevent appropriate devices from
* being open .
*/
2013-11-22 18:27:47 +04:00
if ( lv_info ( cmd , origin , 0 , & info , 1 , 0 ) & &
! lv_check_not_in_use ( cmd , origin , & info ) ) {
log_print_unless_silent ( " Can't merge over open origin volume. " ) ;
merge_on_activate = 1 ;
} else if ( lv_info ( cmd , lv , 0 , & info , 1 , 0 ) & &
! lv_check_not_in_use ( cmd , lv , & info ) ) {
log_print_unless_silent ( " Can't merge when snapshot is open. " ) ;
merge_on_activate = 1 ;
2010-01-13 04:47:18 +03:00
}
2013-11-22 17:52:35 +04:00
init_snapshot_merge ( snap_seg , origin ) ;
if ( snap_seg - > segtype - > ops - > target_present & &
! snap_seg - > segtype - > ops - > target_present ( snap_seg - > lv - > vg - > cmd ,
snap_seg , NULL ) ) {
2013-05-16 10:21:57 +04:00
log_error ( " Can't initialize snapshot merge. "
" Missing support in kernel? " ) ;
2013-11-22 17:52:35 +04:00
return 0 ;
2013-05-16 10:21:57 +04:00
}
2010-01-13 04:45:15 +03:00
/* store vg on disk(s) */
if ( ! vg_write ( lv - > vg ) )
return_0 ;
2010-01-13 04:54:34 +03:00
if ( merge_on_activate ) {
/* commit vg but skip starting the merge */
if ( ! vg_commit ( lv - > vg ) )
return_0 ;
r = 1 ;
config: add silent mode
Accept -q as the short form of --quiet.
Suppress non-essential standard output if -q is given twice.
Treat log/silent in lvm.conf as equivalent to -qq.
Review all log_print messages and change some to
log_print_unless_silent.
When silent, the following commands still produce output:
dumpconfig, lvdisplay, lvmdiskscan, lvs, pvck, pvdisplay,
pvs, version, vgcfgrestore -l, vgdisplay, vgs.
[Needs checking.]
Non-essential messages are shifted from log level 4 to log level 5
for syslog and lvm2_log_fn purposes.
2012-08-25 23:35:48 +04:00
log_print_unless_silent ( " Merging of snapshot %s will start "
2014-08-14 13:12:02 +04:00
" next activation of %s. " ,
display_lvname ( lv ) , display_lvname ( origin ) ) ;
2010-01-13 04:54:34 +03:00
goto out ;
}
2010-01-13 04:45:15 +03:00
/* Perform merge */
if ( ! suspend_lv ( cmd , origin ) ) {
2013-11-26 15:09:41 +04:00
log_error ( " Failed to suspend origin %s. " , origin - > name ) ;
2010-01-13 04:45:15 +03:00
vg_revert ( lv - > vg ) ;
goto out ;
}
if ( ! vg_commit ( lv - > vg ) ) {
if ( ! resume_lv ( cmd , origin ) )
stack ;
goto_out ;
}
if ( ! resume_lv ( cmd , origin ) ) {
2013-11-26 15:09:41 +04:00
log_error ( " Failed to reactivate origin %s. " , origin - > name ) ;
2010-01-13 04:45:15 +03:00
goto out ;
}
2010-01-13 04:49:52 +03:00
lp - > need_polling = 1 ;
lp - > lv_to_poll = origin ;
2010-01-13 04:45:15 +03:00
r = 1 ;
config: add silent mode
Accept -q as the short form of --quiet.
Suppress non-essential standard output if -q is given twice.
Treat log/silent in lvm.conf as equivalent to -qq.
Review all log_print messages and change some to
log_print_unless_silent.
When silent, the following commands still produce output:
dumpconfig, lvdisplay, lvmdiskscan, lvs, pvck, pvdisplay,
pvs, version, vgcfgrestore -l, vgdisplay, vgs.
[Needs checking.]
Non-essential messages are shifted from log level 4 to log level 5
for syslog and lvm2_log_fn purposes.
2012-08-25 23:35:48 +04:00
log_print_unless_silent ( " Merging of volume %s started. " , lv - > name ) ;
2010-01-13 04:45:15 +03:00
out :
backup ( lv - > vg ) ;
2013-11-26 15:09:41 +04:00
2010-01-13 04:45:15 +03:00
return r ;
}
2013-11-30 00:28:18 +04:00
static int _lvconvert_merge_thin_snapshot ( struct cmd_context * cmd ,
struct logical_volume * lv ,
struct lvconvert_params * lp )
{
int origin_is_active = 0 , r = 0 ;
struct lv_segment * snap_seg = first_seg ( lv ) ;
struct logical_volume * origin = snap_seg - > origin ;
if ( ! origin ) {
log_error ( " \" %s \" is not a mergeable logical volume. " ,
lv - > name ) ;
return 0 ;
}
/* Check if merge is possible */
if ( lv_is_merging_origin ( origin ) ) {
log_error ( " Snapshot %s is already merging into the origin. " ,
find_snapshot ( origin ) - > lv - > name ) ;
return 0 ;
}
if ( lv_is_external_origin ( origin ) ) {
log_error ( " \" %s \" is read-only external origin \" %s \" . " ,
lv - > name , origin_from_cow ( lv ) - > name ) ;
return 0 ;
}
if ( lv_is_origin ( origin ) ) {
log_error ( " Merging into the old snapshot origin %s is not supported. " ,
origin - > name ) ;
return 0 ;
}
if ( ! archive ( lv - > vg ) )
return_0 ;
// FIXME: allow origin to be specified
// FIXME: verify snapshot is descendant of specified origin
/*
* Prevent merge with open device ( s ) as it would likely lead
* to application / filesystem failure . Merge on origin ' s next
* activation if either the origin or snapshot LV can ' t be
* deactivated .
*/
if ( ! deactivate_lv ( cmd , lv ) )
log_print_unless_silent ( " Delaying merge since snapshot is open. " ) ;
else if ( ( origin_is_active = lv_is_active ( origin ) ) & &
! deactivate_lv ( cmd , origin ) )
log_print_unless_silent ( " Delaying merge since origin volume is open. " ) ;
else {
/*
* Both thin snapshot and origin are inactive ,
* replace the origin LV with its snapshot LV .
*/
if ( ! _finish_thin_merge ( cmd , origin , lv ) )
goto_out ;
if ( origin_is_active & & ! activate_lv ( cmd , lv ) ) {
log_error ( " Failed to reactivate origin %s. " , lv - > name ) ;
goto out ;
}
r = 1 ;
goto out ;
}
init_snapshot_merge ( snap_seg , origin ) ;
/* Commit vg, merge will start with next activation */
if ( ! vg_write ( lv - > vg ) | | ! vg_commit ( lv - > vg ) )
return_0 ;
log_print_unless_silent ( " Merging of thin snapshot %s will occur on "
2014-08-14 13:12:02 +04:00
" next activation of %s. " ,
display_lvname ( lv ) , display_lvname ( origin ) ) ;
2013-11-30 00:28:18 +04:00
r = 1 ;
out :
backup ( lv - > vg ) ;
return r ;
}
2014-07-11 14:15:23 +04:00
static int _lvconvert_pool_repair ( struct cmd_context * cmd ,
struct logical_volume * pool_lv ,
struct lvconvert_params * lp )
2013-07-24 17:25:34 +04:00
{
const char * dmdir = dm_dir ( ) ;
const char * thin_dump =
find_config_tree_str_allow_empty ( cmd , global_thin_dump_executable_CFG , NULL ) ;
const char * thin_repair =
find_config_tree_str_allow_empty ( cmd , global_thin_repair_executable_CFG , NULL ) ;
const struct dm_config_node * cn ;
const struct dm_config_value * cv ;
int ret = 0 , status ;
int args = 0 ;
const char * argv [ 19 ] ; /* Max supported 10 args */
char * split , * dm_name , * trans_id_str ;
char meta_path [ PATH_MAX ] ;
char pms_path [ PATH_MAX ] ;
uint64_t trans_id ;
struct logical_volume * pmslv ;
struct logical_volume * mlv = first_seg ( pool_lv ) - > metadata_lv ;
2013-08-06 17:21:42 +04:00
struct pipe_data pdata ;
2013-07-24 17:25:34 +04:00
FILE * f ;
if ( ! thin_repair [ 0 ] ) {
log_error ( " Thin repair commnand is not configured. Repair is disabled. " ) ;
return 0 ; /* Checking disabled */
}
2013-08-06 17:21:42 +04:00
pmslv = pool_lv - > vg - > pool_metadata_spare_lv ;
2013-07-24 17:25:34 +04:00
/* Check we have pool metadata spare LV */
if ( ! handle_pool_metadata_spare ( pool_lv - > vg , 0 , NULL , 1 ) )
return_0 ;
2013-08-06 17:21:42 +04:00
if ( pmslv ! = pool_lv - > vg - > pool_metadata_spare_lv ) {
if ( ! vg_write ( pool_lv - > vg ) | | ! vg_commit ( pool_lv - > vg ) )
return_0 ;
pmslv = pool_lv - > vg - > pool_metadata_spare_lv ;
}
2013-07-24 17:25:34 +04:00
if ( ! ( dm_name = dm_build_dm_name ( cmd - > mem , mlv - > vg - > name ,
mlv - > name , NULL ) ) | |
( dm_snprintf ( meta_path , sizeof ( meta_path ) , " %s/%s " , dmdir , dm_name ) < 0 ) ) {
log_error ( " Failed to build thin metadata path. " ) ;
return 0 ;
}
if ( ! ( dm_name = dm_build_dm_name ( cmd - > mem , pmslv - > vg - > name ,
pmslv - > name , NULL ) ) | |
( dm_snprintf ( pms_path , sizeof ( pms_path ) , " %s/%s " , dmdir , dm_name ) < 0 ) ) {
log_error ( " Failed to build pool metadata spare path. " ) ;
return 0 ;
}
if ( ( cn = find_config_tree_node ( cmd , global_thin_repair_options_CFG , NULL ) ) ) {
for ( cv = cn - > v ; cv & & args < 16 ; cv = cv - > next ) {
if ( cv - > type ! = DM_CFG_STRING ) {
log_error ( " Invalid string in config file: "
" global/thin_repair_options " ) ;
return 0 ;
}
argv [ + + args ] = cv - > v . str ;
}
} else {
/* Use default options (no support for options with spaces) */
if ( ! ( split = dm_pool_strdup ( cmd - > mem , DEFAULT_THIN_REPAIR_OPTIONS ) ) ) {
log_error ( " Failed to duplicate thin repair string. " ) ;
return 0 ;
}
args = dm_split_words ( split , 16 , 0 , ( char * * ) argv + 1 ) ;
}
if ( args = = 10 ) {
log_error ( " Too many options for thin repair command. " ) ;
return 0 ;
}
argv [ 0 ] = thin_repair ;
argv [ + + args ] = " -i " ;
argv [ + + args ] = meta_path ;
argv [ + + args ] = " -o " ;
argv [ + + args ] = pms_path ;
argv [ + + args ] = NULL ;
if ( pool_is_active ( pool_lv ) ) {
log_error ( " Only inactive pool can be repaired. " ) ;
return 0 ;
}
if ( ! activate_lv_local ( cmd , pmslv ) ) {
log_error ( " Cannot activate pool metadata spare volume %s. " ,
pmslv - > name ) ;
return 0 ;
}
if ( ! activate_lv_local ( cmd , mlv ) ) {
log_error ( " Cannot activate thin pool metadata volume %s. " ,
mlv - > name ) ;
goto deactivate_pmslv ;
}
if ( ! ( ret = exec_cmd ( cmd , ( const char * const * ) argv , & status , 1 ) ) ) {
log_error ( " Repair of thin metadata volume of thin pool %s/%s failed (status:%d). "
" Manual repair required! " ,
pool_lv - > vg - > name , pool_lv - > name , status ) ;
goto deactivate_mlv ;
}
if ( thin_dump [ 0 ] ) {
2013-08-06 17:21:42 +04:00
argv [ 0 ] = thin_dump ;
argv [ 1 ] = pms_path ;
argv [ 2 ] = NULL ;
2013-07-24 17:25:34 +04:00
2013-08-06 17:21:42 +04:00
if ( ! ( f = pipe_open ( cmd , argv , 0 , & pdata ) ) )
log_warn ( " WARNING: Cannot read output from %s %s. " , thin_dump , pms_path ) ;
2013-07-24 17:25:34 +04:00
else {
/*
* Scan only the 1 st . line for transation id .
* Watch out , if the thin_dump format changes
*/
if ( ( fgets ( meta_path , sizeof ( meta_path ) , f ) > 0 ) & &
( trans_id_str = strstr ( meta_path , " transaction= \" " ) ) & &
( sscanf ( trans_id_str + 13 , " % " PRIu64 , & trans_id ) = = 1 ) & &
( trans_id ! = first_seg ( pool_lv ) - > transaction_id ) & &
( ( trans_id - 1 ) ! = first_seg ( pool_lv ) - > transaction_id ) )
log_error ( " Transaction id % " PRIu64 " from pool \" %s/%s \" "
" does not match repaired transaction id "
" % " PRIu64 " from %s. " ,
first_seg ( pool_lv ) - > transaction_id ,
pool_lv - > vg - > name , pool_lv - > name , trans_id ,
pms_path ) ;
2013-08-06 17:21:42 +04:00
( void ) pipe_close ( & pdata ) ; /* killing pipe */
2013-07-24 17:25:34 +04:00
}
}
deactivate_mlv :
if ( ! deactivate_lv ( cmd , mlv ) ) {
log_error ( " Cannot deactivate thin pool metadata volume %s. " ,
mlv - > name ) ;
return 0 ;
}
deactivate_pmslv :
if ( ! deactivate_lv ( cmd , pmslv ) ) {
log_error ( " Cannot deactivate thin pool metadata volume %s. " ,
mlv - > name ) ;
return 0 ;
}
if ( ! ret )
return 0 ;
if ( pmslv = = pool_lv - > vg - > pool_metadata_spare_lv ) {
pool_lv - > vg - > pool_metadata_spare_lv = NULL ;
pmslv - > status & = ~ POOL_METADATA_SPARE ;
lv_set_visible ( pmslv ) ;
}
/* Try to allocate new pool metadata spare LV */
if ( ! handle_pool_metadata_spare ( pool_lv - > vg , 0 , NULL , 1 ) )
stack ;
2014-06-30 13:01:04 +04:00
if ( dm_snprintf ( meta_path , sizeof ( meta_path ) , " %s_meta%%d " , pool_lv - > name ) < 0 ) {
log_error ( " Can't prepare new metadata name for %s. " , pool_lv - > name ) ;
2013-07-24 17:25:34 +04:00
return 0 ;
}
if ( ! generate_lv_name ( pool_lv - > vg , meta_path , pms_path , sizeof ( pms_path ) ) ) {
log_error ( " Can't generate new name for %s. " , meta_path ) ;
return 0 ;
}
if ( ! detach_pool_metadata_lv ( first_seg ( pool_lv ) , & mlv ) )
return_0 ;
if ( ! _swap_lv_identifiers ( cmd , mlv , pmslv ) )
return_0 ;
/* Used _pmspare will become _tmeta */
if ( ! attach_pool_metadata_lv ( first_seg ( pool_lv ) , pmslv ) )
return_0 ;
2014-06-30 13:01:04 +04:00
/* Used _tmeta will become visible _meta%d */
2013-07-24 17:25:34 +04:00
if ( ! lv_rename_update ( cmd , mlv , pms_path , 0 ) )
return_0 ;
if ( ! vg_write ( pool_lv - > vg ) | | ! vg_commit ( pool_lv - > vg ) )
return_0 ;
log_warn ( " WARNING: If everything works, remove \" %s/%s \" . " ,
mlv - > vg - > name , mlv - > name ) ;
log_warn ( " WARNING: Use pvmove command to move \" %s/%s \" on the best fitting PV. " ,
2014-06-30 13:01:04 +04:00
pool_lv - > vg - > name , first_seg ( pool_lv ) - > metadata_lv - > name ) ;
2013-07-24 17:25:34 +04:00
return 1 ;
}
2014-07-11 14:15:23 +04:00
/* Currently converts only to thin volume with external origin */
static int _lvconvert_thin ( struct cmd_context * cmd ,
struct logical_volume * lv ,
struct lvconvert_params * lp )
2013-02-05 14:26:27 +04:00
{
2014-07-11 14:15:23 +04:00
struct logical_volume * torigin_lv , * pool_lv = lp - > pool_data_lv ;
2013-02-05 14:26:27 +04:00
struct volume_group * vg = pool_lv - > vg ;
2013-03-08 17:12:56 +04:00
struct lvcreate_params lvc = {
. activate = CHANGE_AE ,
. alloc = ALLOC_INHERIT ,
. lv_name = lp - > origin_lv_name ,
. major = - 1 ,
. minor = - 1 ,
. permission = LVM_READ ,
. pool = pool_lv - > name ,
. pvh = & vg - > pvs ,
. read_ahead = DM_READ_AHEAD_AUTO ,
. stripes = 1 ,
2014-07-11 14:15:23 +04:00
. voriginextents = lv - > le_count ,
. voriginsize = lv - > size ,
2013-03-08 17:12:56 +04:00
} ;
2013-02-05 14:26:27 +04:00
2014-07-11 14:15:23 +04:00
if ( lv = = pool_lv ) {
log_error ( " Can't use same LV %s for thin pool and thin volume. " ,
display_lvname ( pool_lv ) ) ;
return 0 ;
}
if ( lv_is_thin_pool ( lv ) ) {
log_error ( " Can't use pool %s as external origin. " ,
display_lvname ( lv ) ) ;
return 0 ;
}
2013-02-05 14:26:27 +04:00
dm_list_init ( & lvc . tags ) ;
2014-07-11 14:15:23 +04:00
if ( ! pool_supports_external_origin ( first_seg ( pool_lv ) , lv ) )
2014-01-29 17:27:13 +04:00
return_0 ;
2013-02-05 14:26:27 +04:00
if ( ! ( lvc . segtype = get_segtype_from_string ( cmd , " thin " ) ) )
return_0 ;
2014-07-11 14:15:23 +04:00
if ( ! archive ( vg ) )
return_0 ;
2013-02-05 14:26:27 +04:00
/* New thin LV needs to be created (all messages sent to pool) */
if ( ! ( torigin_lv = lv_create_single ( vg , & lvc ) ) )
return_0 ;
2013-03-08 17:12:56 +04:00
/* Deactivate prepared Thin LV */
2013-02-05 14:26:27 +04:00
if ( ! deactivate_lv ( cmd , torigin_lv ) ) {
log_error ( " Aborting. Unable to deactivate new LV. "
" Manual intervention required. " ) ;
return 0 ;
}
/*
* Crashing till this point will leave plain thin volume
* which could be easily removed by the user after i . e . power - off
*/
2014-07-11 14:15:23 +04:00
if ( ! _swap_lv_identifiers ( cmd , torigin_lv , lv ) ) {
2013-02-05 14:26:27 +04:00
stack ;
goto revert_new_lv ;
}
/* Preserve read-write status of original LV here */
2014-07-11 14:15:23 +04:00
torigin_lv - > status | = ( lv - > status & LVM_WRITE ) ;
2013-02-05 14:26:27 +04:00
2014-07-11 14:15:23 +04:00
if ( ! attach_thin_external_origin ( first_seg ( torigin_lv ) , lv ) ) {
2013-02-05 14:26:27 +04:00
stack ;
goto revert_new_lv ;
}
if ( ! _reload_lv ( cmd , vg , torigin_lv ) ) {
stack ;
goto deactivate_and_revert_new_lv ;
}
2014-07-11 14:15:23 +04:00
log_print_unless_silent ( " Converted %s to thin volume with "
" external origin %s. " ,
display_lvname ( torigin_lv ) ,
display_lvname ( lv ) ) ;
backup ( vg ) ;
2013-02-05 14:26:27 +04:00
return 1 ;
deactivate_and_revert_new_lv :
2014-07-11 14:15:23 +04:00
if ( ! _swap_lv_identifiers ( cmd , torigin_lv , lv ) )
2013-02-05 14:26:27 +04:00
stack ;
if ( ! deactivate_lv ( cmd , torigin_lv ) ) {
log_error ( " Unable to deactivate failed new LV. "
" Manual intervention required. " ) ;
return 0 ;
}
if ( ! detach_thin_external_origin ( first_seg ( torigin_lv ) ) )
return_0 ;
revert_new_lv :
/* FIXME Better to revert to backup of metadata? */
if ( ! lv_remove ( torigin_lv ) | | ! vg_write ( vg ) | | ! vg_commit ( vg ) )
log_error ( " Manual intervention may be required to remove "
" abandoned LV(s) before retrying. " ) ;
else
backup ( vg ) ;
return 0 ;
}
2014-02-12 19:51:42 +04:00
static int _lvconvert_update_pool_params ( struct logical_volume * pool_lv ,
struct lvconvert_params * lp )
{
2014-07-23 00:20:18 +04:00
return update_pool_params ( lp - > segtype ,
pool_lv - > vg ,
lp - > target_attr ,
lp - > passed_args ,
pool_lv - > le_count ,
& lp - > pool_metadata_size ,
& lp - > thin_chunk_size_calc_policy ,
& lp - > chunk_size ,
& lp - > discards ,
& lp - > zero ) ;
2014-02-12 19:51:42 +04:00
}
2012-05-14 15:57:30 +04:00
/*
* Thin lvconvert version which
* rename metadata
* convert / layers thinpool over data
* attach metadata
*/
2014-07-11 14:15:23 +04:00
static int _lvconvert_pool ( struct cmd_context * cmd ,
struct logical_volume * pool_lv ,
struct lvconvert_params * lp )
2012-05-09 16:17:06 +04:00
{
int r = 0 ;
2012-12-02 19:40:07 +04:00
const char * old_name ;
2012-05-09 16:17:06 +04:00
struct lv_segment * seg ;
2014-07-11 14:15:23 +04:00
struct volume_group * vg = pool_lv - > vg ;
2013-10-08 15:24:22 +04:00
struct logical_volume * data_lv ;
2014-07-11 14:15:23 +04:00
struct logical_volume * metadata_lv = NULL ;
2012-12-02 19:40:07 +04:00
struct logical_volume * pool_metadata_lv ;
2013-07-04 13:25:41 +04:00
char metadata_name [ NAME_LEN ] , data_name [ NAME_LEN ] ;
2013-10-16 12:11:37 +04:00
int activate_pool ;
2012-05-14 15:57:30 +04:00
2014-07-11 14:15:23 +04:00
if ( lp - > pool_data_lv_name & &
! ( pool_lv = find_lv ( vg , lp - > pool_data_lv_name ) ) ) {
log_error ( " Unknown pool data LV %s. " , lp - > pool_data_lv_name ) ;
2012-11-19 16:37:57 +04:00
return 0 ;
}
2014-07-11 14:15:23 +04:00
if ( lp - > pool_metadata_lv_name ) {
if ( ! ( lp - > pool_metadata_lv = find_lv ( vg , lp - > pool_metadata_lv_name ) ) ) {
log_error ( " Unknown pool metadata LV %s. " , lp - > pool_metadata_lv_name ) ;
2014-01-28 16:21:39 +04:00
return 0 ;
}
2014-07-11 14:15:23 +04:00
lp - > pool_metadata_size = lp - > pool_metadata_lv - > size ;
metadata_lv = lp - > pool_metadata_lv ;
2014-01-28 16:21:39 +04:00
2014-07-11 14:15:23 +04:00
if ( ! lv_is_visible ( metadata_lv ) ) {
log_error ( " Can't convert internal LV %s. " ,
display_lvname ( metadata_lv ) ) ;
2013-02-05 14:26:27 +04:00
return 0 ;
}
2014-07-11 14:15:23 +04:00
if ( lv_is_mirrored ( metadata_lv ) & & ! lv_is_raid_type ( metadata_lv ) ) {
log_error ( " Mirror logical volumes cannot be used "
" for pool metadata. " ) ;
log_error ( " Try \" raid1 \" segment type instead. " ) ;
return 0 ;
}
if ( metadata_lv - > status & LOCKED ) {
log_error ( " Can't convert locked LV %s. " ,
display_lvname ( metadata_lv ) ) ;
return 0 ;
}
if ( metadata_lv = = pool_lv ) {
log_error ( " Can't use same LV for pool data and metadata LV %s. " ,
display_lvname ( metadata_lv ) ) ;
return 0 ;
}
if ( lv_is_thin_type ( metadata_lv ) | |
lv_is_cache_type ( metadata_lv ) ) {
2014-08-19 16:16:39 +04:00
log_error ( " Can't use thin or cache type LV %s for pool metadata. " ,
display_lvname ( metadata_lv ) ) ;
2013-08-10 01:04:30 +04:00
return 0 ;
}
2014-07-11 14:15:23 +04:00
if ( ! lv_is_pool ( pool_lv ) ) {
if ( ! _lvconvert_update_pool_params ( pool_lv , lp ) )
return_0 ;
if ( lp - > pool_metadata_size > metadata_lv - > size ) {
log_error ( " Logical volume %s is too small for metadata. " ,
display_lvname ( metadata_lv ) ) ;
return 0 ;
}
2013-02-05 14:26:27 +04:00
}
}
2014-07-11 14:15:23 +04:00
if ( ! lv_is_visible ( pool_lv ) ) {
log_error ( " Can't convert internal LV %s. " , display_lvname ( pool_lv ) ) ;
2012-05-14 15:57:30 +04:00
return 0 ;
}
2012-05-09 16:17:06 +04:00
2014-07-11 14:15:23 +04:00
if ( lv_is_mirrored ( pool_lv ) & & ! lv_is_raid_type ( pool_lv ) ) {
log_error ( " Mirror logical volumes cannot be used as pools. \n "
" Try \" raid1 \" segment type instead. " ) ;
2012-06-05 16:55:00 +04:00
return 0 ;
2012-05-09 16:17:06 +04:00
}
2014-02-12 19:51:42 +04:00
if ( ( dm_snprintf ( metadata_name , sizeof ( metadata_name ) , " %s%s " ,
pool_lv - > name ,
( segtype_is_cache_pool ( lp - > segtype ) ) ?
" _cmeta " : " _tmeta " ) < 0 ) | |
( dm_snprintf ( data_name , sizeof ( data_name ) , " %s%s " ,
pool_lv - > name ,
( segtype_is_cache_pool ( lp - > segtype ) ) ?
" _cdata " : " _tdata " ) < 0 ) ) {
2013-07-04 13:25:41 +04:00
log_error ( " Failed to create internal lv names, "
2014-02-12 19:51:42 +04:00
" pool name is too long. " ) ;
2012-12-02 19:23:44 +04:00
return 0 ;
}
2012-11-19 16:37:57 +04:00
2014-07-11 14:15:23 +04:00
if ( lv_is_pool ( pool_lv ) ) {
lp - > pool_data_lv = pool_lv ;
2013-07-04 13:25:41 +04:00
2014-07-11 14:15:23 +04:00
if ( ! metadata_lv ) {
2014-07-18 23:56:37 +04:00
if ( arg_from_list_is_set ( cmd , " is invalid with existing pool " ,
cachemode_ARG , chunksize_ARG , discards_ARG ,
zero_ARG , poolmetadatasize_ARG , - 1 ) )
2014-07-11 14:15:23 +04:00
return_0 ;
return 1 ;
2012-05-09 16:17:06 +04:00
}
2014-07-11 14:15:23 +04:00
if ( lp - > thin | | lp - > cache ) {
log_error ( " --%s and pool metadata swap is not supported. " ,
lp - > thin ? " thin " : " cache " ) ;
2012-05-14 15:57:30 +04:00
return 0 ;
2012-05-09 16:17:06 +04:00
}
2014-07-11 14:15:23 +04:00
/* FIXME cache pool */
if ( lv_is_thin_pool ( pool_lv ) & & pool_is_active ( pool_lv ) ) {
/* If any volume referencing pool active - abort here */
log_error ( " Cannot convert pool %s with active volumes. " ,
display_lvname ( pool_lv ) ) ;
2012-05-14 15:57:30 +04:00
return 0 ;
2012-05-09 16:17:06 +04:00
}
2012-12-02 19:40:07 +04:00
2014-07-11 14:15:23 +04:00
seg = first_seg ( pool_lv ) ;
2014-07-01 13:06:36 +04:00
2014-07-11 14:15:23 +04:00
/* Normally do NOT change chunk size when swapping */
if ( arg_count ( cmd , chunksize_ARG ) & &
( lp - > chunk_size ! = seg - > chunk_size ) ) {
if ( lp - > force = = PROMPT ) {
log_error ( " Chunk size can be only changed with --force. Conversion aborted. " ) ;
return 0 ;
2012-12-02 19:40:07 +04:00
}
2014-07-11 14:15:23 +04:00
log_warn ( " WARNING: Changing chunk size %s to "
" %s for %s pool volume. " ,
display_size ( cmd , seg - > chunk_size ) ,
display_size ( cmd , lp - > chunk_size ) ,
display_lvname ( pool_lv ) ) ;
/* Ok, user has likely some serious reason for this */
2014-07-01 13:06:36 +04:00
if ( ! lp - > yes & &
2014-07-11 14:15:23 +04:00
yes_no_prompt ( " Do you really want to change chunk size "
" for %s pool volume? [y/n]: " ,
display_lvname ( pool_lv ) ) = = ' n ' ) {
2014-07-01 13:06:36 +04:00
log_error ( " Conversion aborted. " ) ;
return 0 ;
}
2014-07-11 14:15:23 +04:00
} else
lp - > chunk_size = seg - > chunk_size ;
2014-07-01 13:06:36 +04:00
2014-07-11 14:15:23 +04:00
if ( ! _lvconvert_update_pool_params ( pool_lv , lp ) )
return_0 ;
2014-07-01 13:06:36 +04:00
2014-07-11 14:15:23 +04:00
if ( metadata_lv - > size < lp - > pool_metadata_size )
log_print_unless_silent ( " Continuing with swap... " ) ;
2012-12-02 19:40:07 +04:00
2014-07-11 14:15:23 +04:00
if ( ! arg_count ( cmd , discards_ARG ) )
lp - > discards = seg - > discards ;
if ( ! arg_count ( cmd , zero_ARG ) )
lp - > zero = seg - > zero_new_blocks ;
2012-12-02 19:40:07 +04:00
2014-07-11 14:15:23 +04:00
if ( ! lp - > yes & &
yes_no_prompt ( " Do you want to swap metadata of %s "
2014-08-19 16:16:39 +04:00
" pool with metadata volume %s? [y/n]: " ,
2014-07-11 14:15:23 +04:00
display_lvname ( pool_lv ) ,
display_lvname ( metadata_lv ) ) = = ' n ' ) {
log_error ( " Conversion aborted. " ) ;
2014-05-20 18:21:14 +04:00
return 0 ;
}
2014-07-11 14:15:23 +04:00
} else if ( lv_is_thin_type ( pool_lv ) ) {
2014-08-19 16:16:39 +04:00
log_error ( " Can't use thin type logical volume %s for thin pool data. " ,
display_lvname ( pool_lv ) ) ;
2014-07-11 14:15:23 +04:00
return 0 ;
} else {
log_warn ( " WARNING: Converting logical volume %s%s%s to pool's data%s. " ,
display_lvname ( pool_lv ) ,
metadata_lv ? " and " : " " ,
metadata_lv ? display_lvname ( metadata_lv ) : " " ,
metadata_lv ? " and metadata volumes " : " volume " ) ;
log_warn ( " THIS WILL DESTROY CONTENT OF LOGICAL VOLUME (filesystem etc.) " ) ;
2014-05-20 18:21:14 +04:00
2014-07-11 14:15:23 +04:00
if ( ! lp - > yes & &
yes_no_prompt ( " Do you really want to convert %s%s%s? [y/n]: " ,
display_lvname ( pool_lv ) ,
metadata_lv ? " and " : " " ,
metadata_lv ? display_lvname ( metadata_lv ) : " " ) = = ' n ' ) {
log_error ( " Conversion aborted. " ) ;
2012-05-14 15:57:30 +04:00
return 0 ;
2012-05-09 16:17:06 +04:00
}
2014-07-11 14:15:23 +04:00
}
2014-07-01 13:06:36 +04:00
2014-07-11 14:15:23 +04:00
if ( segtype_is_cache_pool ( lp - > segtype ) )
activate_pool = 0 ; /* Cannot activate cache pool */
else
/* Allow to have only thinpool active and restore it's active state */
activate_pool = lv_is_active ( pool_lv ) ;
if ( ! metadata_lv ) {
2014-02-12 19:51:42 +04:00
if ( ! _lvconvert_update_pool_params ( pool_lv , lp ) )
2012-11-19 16:37:57 +04:00
return_0 ;
2013-10-29 16:18:14 +04:00
2014-07-11 14:15:23 +04:00
if ( ! get_stripe_params ( cmd , & lp - > stripes , & lp - > stripe_size ) )
return_0 ;
2014-07-01 13:06:36 +04:00
2014-07-11 14:15:23 +04:00
if ( ! archive ( vg ) )
return_0 ;
if ( ! ( metadata_lv = alloc_pool_metadata ( pool_lv , metadata_name ,
lp - > read_ahead , lp - > stripes ,
lp - > stripe_size ,
lp - > pool_metadata_size ,
lp - > alloc , lp - > pvh ) ) )
return_0 ;
} else {
if ( ! deactivate_lv ( cmd , metadata_lv ) ) {
log_error ( " Aborting. Failed to deactivate %s. " ,
display_lvname ( metadata_lv ) ) ;
2014-07-01 13:06:36 +04:00
return 0 ;
}
2014-07-11 14:15:23 +04:00
if ( ! archive ( vg ) )
return_0 ;
/* Swap normal LV with pool's metadata LV ? */
if ( lv_is_pool ( pool_lv ) ) {
/* Swap names between old and new metadata LV */
2014-07-11 16:19:22 +04:00
seg = first_seg ( pool_lv ) ;
if ( ! detach_pool_metadata_lv ( seg , & pool_metadata_lv ) )
2014-07-11 14:15:23 +04:00
return_0 ;
old_name = metadata_lv - > name ;
if ( ! lv_rename_update ( cmd , metadata_lv , " pvmove_tmeta " , 0 ) )
return_0 ;
if ( ! lv_rename_update ( cmd , pool_metadata_lv , old_name , 0 ) )
return_0 ;
goto mda_write ;
}
2013-10-29 16:18:14 +04:00
metadata_lv - > status | = LV_TEMPORARY ;
if ( ! activate_lv_local ( cmd , metadata_lv ) ) {
2014-02-12 19:51:42 +04:00
log_error ( " Aborting. Failed to activate metadata lv. " ) ;
2013-10-29 16:18:14 +04:00
return 0 ;
}
2013-11-06 19:16:34 +04:00
2013-11-28 14:22:24 +04:00
if ( ! wipe_lv ( metadata_lv , ( struct wipe_params ) { . do_zero = 1 } ) ) {
2014-02-12 19:51:42 +04:00
log_error ( " Aborting. Failed to wipe metadata lv. " ) ;
2013-10-29 16:18:14 +04:00
return 0 ;
}
2012-05-14 15:57:30 +04:00
}
2014-07-11 14:15:23 +04:00
/* We are changing target type, so deactivate first */
2012-05-14 15:57:30 +04:00
if ( ! deactivate_lv ( cmd , metadata_lv ) ) {
2014-02-12 19:51:42 +04:00
log_error ( " Aborting. Failed to deactivate metadata lv. "
2012-05-14 15:57:30 +04:00
" Manual intervention required. " ) ;
return 0 ;
}
2014-07-11 14:15:23 +04:00
if ( ! deactivate_lv ( cmd , pool_lv ) ) {
log_error ( " Aborting. Failed to deactivate logical volume %s. " ,
display_lvname ( pool_lv ) ) ;
return 0 ;
2014-07-01 13:06:36 +04:00
}
data_lv = pool_lv ;
2013-03-11 12:49:10 +04:00
old_name = data_lv - > name ; /* Use for pool name */
2012-05-14 15:57:30 +04:00
/*
2014-02-12 19:51:42 +04:00
* Since we wish to have underlaying devs to match _ [ ct ] data
2013-03-11 12:49:10 +04:00
* rename data LV to match pool LV subtree first ,
* also checks for visible LV .
2012-05-14 15:57:30 +04:00
*/
/* FIXME: any more types prohibited here? */
2013-03-11 12:49:10 +04:00
if ( ! lv_rename_update ( cmd , data_lv , data_name , 0 ) )
return_0 ;
2012-05-14 15:57:30 +04:00
2013-03-11 12:49:10 +04:00
if ( ! ( pool_lv = lv_create_empty ( old_name , NULL ,
2014-02-12 19:51:42 +04:00
( ( segtype_is_cache_pool ( lp - > segtype ) ) ?
CACHE_POOL : THIN_POOL ) |
VISIBLE_LV | LVM_READ | LVM_WRITE ,
2014-07-11 14:15:23 +04:00
ALLOC_INHERIT , vg ) ) ) {
2013-03-11 12:49:10 +04:00
log_error ( " Creation of pool LV failed. " ) ;
return 0 ;
}
2014-07-11 14:15:23 +04:00
/* Allocate a new pool segment */
2013-03-11 12:49:10 +04:00
if ( ! ( seg = alloc_lv_segment ( lp - > segtype , pool_lv , 0 , data_lv - > le_count ,
2014-02-12 19:51:42 +04:00
pool_lv - > status , 0 , NULL , NULL , 1 ,
data_lv - > le_count , 0 , 0 , 0 , NULL ) ) )
2012-05-09 16:17:06 +04:00
return_0 ;
2013-03-11 12:49:10 +04:00
/* Add the new segment to the layer LV */
dm_list_add ( & pool_lv - > segments , & seg - > list ) ;
pool_lv - > le_count = data_lv - > le_count ;
pool_lv - > size = data_lv - > size ;
2012-05-09 16:17:06 +04:00
2012-12-02 19:27:39 +04:00
if ( ! attach_pool_data_lv ( seg , data_lv ) )
return_0 ;
2013-03-11 12:49:10 +04:00
/* FIXME: revert renamed LVs in fail path? */
/* FIXME: any common code with metadata/thin_manip.c extend_pool() ? */
2012-05-09 16:17:06 +04:00
seg - > low_water_mark = 0 ;
2012-05-14 15:57:30 +04:00
seg - > transaction_id = 0 ;
2012-12-02 19:40:07 +04:00
mda_write :
2012-12-02 19:27:39 +04:00
seg - > chunk_size = lp - > chunk_size ;
seg - > discards = lp - > discards ;
seg - > zero_new_blocks = lp - > zero ? 1 : 0 ;
2012-05-09 16:17:06 +04:00
2012-12-02 19:27:39 +04:00
/* Rename deactivated metadata LV to have _tmeta suffix */
/* Implicit checks if metadata_lv is visible */
2013-07-04 16:02:27 +04:00
if ( lp - > pool_metadata_lv_name & &
2013-03-11 12:49:10 +04:00
! lv_rename_update ( cmd , metadata_lv , metadata_name , 0 ) )
2012-05-09 16:17:06 +04:00
return_0 ;
2012-12-02 19:27:39 +04:00
if ( ! attach_pool_metadata_lv ( seg , metadata_lv ) )
2012-05-09 16:17:06 +04:00
return_0 ;
2014-07-11 14:15:23 +04:00
if ( ! handle_pool_metadata_spare ( vg , metadata_lv - > le_count ,
lp - > pvh , lp - > poolmetadataspare ) )
2012-05-09 16:17:06 +04:00
return_0 ;
2014-07-11 14:15:23 +04:00
if ( ! vg_write ( vg ) | | ! vg_commit ( vg ) )
return_0 ;
if ( seg - > zero_new_blocks & &
seg - > chunk_size > = DEFAULT_THIN_POOL_CHUNK_SIZE_PERFORMANCE * 2 )
log_warn ( " WARNING: Pool zeroing and large %s chunk size slows down "
" provisioning. " , display_size ( cmd , seg - > chunk_size ) ) ;
2013-10-16 12:11:37 +04:00
if ( activate_pool & &
! activate_lv_excl ( cmd , pool_lv ) ) {
2014-07-11 14:15:23 +04:00
log_error ( " Failed to activate pool logical volume %s. " ,
display_lvname ( pool_lv ) ) ;
2012-12-02 19:31:27 +04:00
/* Deactivate subvolumes */
if ( ! deactivate_lv ( cmd , seg_lv ( seg , 0 ) ) )
log_error ( " Failed to deactivate pool data logical volume. " ) ;
if ( ! deactivate_lv ( cmd , seg - > metadata_lv ) )
log_error ( " Failed to deactivate pool metadata logical volume. " ) ;
2012-05-09 16:17:06 +04:00
goto out ;
}
2014-07-11 14:15:23 +04:00
log_print_unless_silent ( " Converted %s to %s pool. " ,
display_lvname ( pool_lv ) ,
2014-02-12 19:51:42 +04:00
( segtype_is_cache_pool ( lp - > segtype ) ) ?
" cache " : " thin " ) ;
2012-05-14 15:57:30 +04:00
2012-05-09 16:17:06 +04:00
r = 1 ;
2013-02-05 14:26:27 +04:00
2014-07-11 14:15:23 +04:00
lp - > pool_data_lv = pool_lv ;
out :
backup ( vg ) ;
2013-02-05 14:26:27 +04:00
2012-05-09 16:17:06 +04:00
return r ;
2014-07-11 14:15:23 +04:00
#if 0
revert_new_lv :
/* TBD */
if ( ! lp - > pool_metadata_lv_name ) {
if ( ! deactivate_lv ( cmd , metadata_lv ) ) {
log_error ( " Failed to deactivate metadata lv. " ) ;
return 0 ;
}
if ( ! lv_remove ( metadata_lv ) | | ! vg_write ( vg ) | | ! vg_commit ( vg ) )
log_error ( " Manual intervention may be required to remove "
" abandoned LV(s) before retrying. " ) ;
else
backup ( vg ) ;
}
return 0 ;
# endif
2012-05-09 16:17:06 +04:00
}
2014-07-11 14:15:23 +04:00
static int _lvconvert_cache ( struct cmd_context * cmd ,
struct logical_volume * origin ,
2014-02-12 19:55:35 +04:00
struct lvconvert_params * lp )
{
2014-07-11 14:15:23 +04:00
struct logical_volume * pool_lv = lp - > pool_data_lv ;
2014-02-12 19:55:35 +04:00
struct logical_volume * cache_lv ;
2014-07-11 14:15:23 +04:00
if ( origin = = pool_lv ) {
log_error ( " Can't use same LV %s for cache pool and cache volume. " ,
display_lvname ( pool_lv ) ) ;
2014-02-12 19:55:35 +04:00
return 0 ;
}
2014-07-11 14:15:23 +04:00
if ( lv_is_pool ( origin ) | | lv_is_cache_type ( origin ) ) {
2014-08-19 16:16:39 +04:00
log_error ( " Can't cache pool or cache type volume %s. " ,
display_lvname ( origin ) ) ;
2014-02-12 19:55:35 +04:00
return 0 ;
}
2014-07-11 14:15:23 +04:00
if ( ! archive ( origin - > vg ) )
2014-02-12 19:55:35 +04:00
return_0 ;
2014-07-11 14:15:23 +04:00
if ( ! ( cache_lv = lv_cache_create ( pool_lv , origin ) ) )
2014-02-12 19:55:35 +04:00
return_0 ;
2014-07-11 14:15:23 +04:00
if ( ! _reload_lv ( cmd , cache_lv - > vg , cache_lv ) )
2014-02-12 19:55:35 +04:00
return_0 ;
2014-07-11 14:15:23 +04:00
log_print_unless_silent ( " Logical volume %s is now cached. " ,
display_lvname ( cache_lv ) ) ;
2014-02-12 19:55:35 +04:00
return 1 ;
}
2010-02-06 01:44:37 +03:00
static int _lvconvert_single ( struct cmd_context * cmd , struct logical_volume * lv ,
void * handle )
2005-06-06 21:12:08 +04:00
{
struct lvconvert_params * lp = handle ;
2011-05-07 17:56:13 +04:00
struct dm_list * failed_pvs ;
2005-06-06 21:12:08 +04:00
if ( lv - > status & LOCKED ) {
log_error ( " Cannot convert locked LV %s " , lv - > name ) ;
return ECMD_FAILED ;
}
2013-12-04 06:09:37 +04:00
if ( lv_is_cow ( lv ) & & ! lp - > merge & & ! lp - > splitsnapshot ) {
2005-06-06 21:12:08 +04:00
log_error ( " Can't convert snapshot logical volume \" %s \" " ,
lv - > name ) ;
return ECMD_FAILED ;
}
if ( lv - > status & PVMOVE ) {
log_error ( " Unable to convert pvmove LV %s " , lv - > name ) ;
return ECMD_FAILED ;
}
2013-12-04 06:09:37 +04:00
if ( lp - > splitsnapshot )
return _lvconvert_splitsnapshot ( cmd , lv , lp ) ;
2014-07-10 22:59:39 +04:00
if ( arg_count ( cmd , repair_ARG ) ) {
if ( lv_is_pool ( lv ) ) {
if ( ! _lvconvert_pool_repair ( cmd , lv , lp ) )
return_ECMD_FAILED ;
return ECMD_PROCESSED ;
}
if ( ! lv_is_mirrored ( lv ) & & ! lv_is_raid ( lv ) ) {
if ( arg_count ( cmd , use_policies_ARG ) )
return ECMD_PROCESSED ; /* nothing to be done here */
log_error ( " Can't repair LV \" %s \" of segtype %s. " ,
lv - > name ,
first_seg ( lv ) - > segtype - > ops - > name ( first_seg ( lv ) ) ) ;
return ECMD_FAILED ;
}
2009-06-10 19:27:57 +04:00
}
2013-09-26 07:25:43 +04:00
if ( ! lp - > segtype ) {
/* segtype not explicitly set in _read_params */
2011-11-30 06:02:10 +04:00
lp - > segtype = first_seg ( lv ) - > segtype ;
2013-09-26 07:25:43 +04:00
/*
* If we are converting to mirror / raid1 and
* the segtype was not specified , then we need
* to consult the default .
*/
if ( arg_count ( cmd , mirrors_ARG ) & & ! lv_is_mirrored ( lv ) ) {
2014-07-11 14:24:32 +04:00
if ( ! ( lp - > segtype = get_segtype_from_string ( cmd , find_config_tree_str ( cmd , global_mirror_segtype_default_CFG , NULL ) ) ) )
return_ECMD_FAILED ;
2013-09-26 07:25:43 +04:00
}
}
2010-01-13 04:45:15 +03:00
if ( lp - > merge ) {
2013-11-30 00:28:18 +04:00
if ( ( lv_is_thin_volume ( lv ) & & ! _lvconvert_merge_thin_snapshot ( cmd , lv , lp ) ) | |
( ! lv_is_thin_volume ( lv ) & & ! _lvconvert_merge_old_snapshot ( cmd , lv , lp ) ) ) {
2013-11-26 15:09:41 +04:00
log_print_unless_silent ( " Unable to merge LV \" %s \" into its origin. " , lv - > name ) ;
2010-01-13 04:45:15 +03:00
return ECMD_FAILED ;
}
} else if ( lp - > snapshot ) {
2013-12-04 06:09:37 +04:00
if ( ! _lvconvert_snapshot ( cmd , lv , lp ) )
2013-07-01 13:27:22 +04:00
return_ECMD_FAILED ;
2014-07-11 14:15:23 +04:00
} else if ( segtype_is_pool ( lp - > segtype ) | | lp - > thin | | lp - > cache ) {
if ( ! _lvconvert_pool ( cmd , lv , lp ) )
2014-02-12 19:55:35 +04:00
return_ECMD_FAILED ;
2014-07-11 14:15:23 +04:00
if ( ( lp - > thin & & ! _lvconvert_thin ( cmd , lv , lp ) ) | |
( lp - > cache & & ! _lvconvert_cache ( cmd , lv , lp ) ) )
2014-02-12 19:51:42 +04:00
return_ECMD_FAILED ;
2011-08-18 23:43:08 +04:00
} else if ( segtype_is_raid ( lp - > segtype ) | |
( lv - > status & RAID ) | | lp - > merge_mirror ) {
2013-07-01 13:27:22 +04:00
if ( ! archive ( lv - > vg ) )
return_ECMD_FAILED ;
2011-08-11 22:24:40 +04:00
2013-12-04 06:09:37 +04:00
if ( ! _lvconvert_raid ( lv , lp ) )
2013-07-01 13:27:22 +04:00
return_ECMD_FAILED ;
if ( ! ( failed_pvs = _failed_pv_list ( lv - > vg ) ) )
return_ECMD_FAILED ;
2011-08-11 22:24:40 +04:00
/* If repairing and using policies, remove missing PVs from VG */
if ( arg_count ( cmd , repair_ARG ) & & arg_count ( cmd , use_policies_ARG ) )
_remove_missing_empty_pv ( lv - > vg , failed_pvs ) ;
2010-07-14 01:53:07 +04:00
} else if ( arg_count ( cmd , mirrors_ARG ) | |
arg_count ( cmd , splitmirrors_ARG ) | |
( lv - > status & MIRRORED ) ) {
2013-07-01 13:27:22 +04:00
if ( ! archive ( lv - > vg ) )
return_ECMD_FAILED ;
2010-01-08 16:04:10 +03:00
2013-07-01 13:27:22 +04:00
if ( ! _lvconvert_mirrors ( cmd , lv , lp ) )
return_ECMD_FAILED ;
if ( ! ( failed_pvs = _failed_pv_list ( lv - > vg ) ) )
return_ECMD_FAILED ;
2011-05-07 17:56:13 +04:00
2010-01-08 16:04:10 +03:00
/* If repairing and using policies, remove missing PVs from VG */
if ( arg_count ( cmd , repair_ARG ) & & arg_count ( cmd , use_policies_ARG ) )
2011-05-07 17:56:13 +04:00
_remove_missing_empty_pv ( lv - > vg , failed_pvs ) ;
2005-06-06 21:12:08 +04:00
}
return ECMD_PROCESSED ;
}
2010-02-06 01:44:37 +03:00
/*
* FIXME move to toollib along with the rest of the drop / reacquire
2013-12-04 06:09:37 +04:00
* VG locking that is used by _lvconvert_merge_single ( )
2010-02-06 01:44:37 +03:00
*/
static struct logical_volume * get_vg_lock_and_logical_volume ( struct cmd_context * cmd ,
const char * vg_name ,
const char * lv_name )
2005-06-06 21:12:08 +04:00
{
2010-02-06 01:44:37 +03:00
/*
* Returns NULL if the requested LV doesn ' t exist ;
2011-08-11 00:25:29 +04:00
* otherwise the caller must release_vg ( lv - > vg )
2010-02-06 01:44:37 +03:00
* - it is also up to the caller to unlock_vg ( ) as needed
*/
2005-06-06 21:12:08 +04:00
struct volume_group * vg ;
2010-02-06 01:44:37 +03:00
struct logical_volume * lv = NULL ;
vg = _get_lvconvert_vg ( cmd , vg_name , NULL ) ;
if ( vg_read_error ( vg ) ) {
2011-08-11 00:25:29 +04:00
release_vg ( vg ) ;
2010-04-26 22:31:58 +04:00
return_NULL ;
2010-02-06 01:44:37 +03:00
}
if ( ! ( lv = _get_lvconvert_lv ( cmd , vg , lv_name , NULL , 0 ) ) ) {
2010-04-26 22:31:58 +04:00
log_error ( " Can't find LV %s in VG %s " , lv_name , vg_name ) ;
2011-08-11 00:25:29 +04:00
unlock_and_release_vg ( cmd , vg , vg_name ) ;
2010-02-06 01:44:37 +03:00
return NULL ;
}
return lv ;
}
2013-12-04 06:09:37 +04:00
static int _poll_logical_volume ( struct cmd_context * cmd , struct logical_volume * lv ,
2010-02-06 01:44:37 +03:00
int wait_completion )
{
2008-01-10 21:35:51 +03:00
struct lvinfo info ;
2005-06-06 21:12:08 +04:00
2011-02-03 04:24:46 +03:00
if ( ! lv_info ( cmd , lv , 0 , & info , 0 , 0 ) | | ! info . exists ) {
config: add silent mode
Accept -q as the short form of --quiet.
Suppress non-essential standard output if -q is given twice.
Treat log/silent in lvm.conf as equivalent to -qq.
Review all log_print messages and change some to
log_print_unless_silent.
When silent, the following commands still produce output:
dumpconfig, lvdisplay, lvmdiskscan, lvs, pvck, pvdisplay,
pvs, version, vgcfgrestore -l, vgdisplay, vgs.
[Needs checking.]
Non-essential messages are shifted from log level 4 to log level 5
for syslog and lvm2_log_fn purposes.
2012-08-25 23:35:48 +04:00
log_print_unless_silent ( " Conversion starts after activation. " ) ;
2010-02-06 01:44:37 +03:00
return ECMD_PROCESSED ;
2005-06-06 21:12:08 +04:00
}
2014-02-23 02:13:43 +04:00
2010-02-06 01:44:37 +03:00
return lvconvert_poll ( cmd , lv , wait_completion ? 0 : 1U ) ;
}
static int lvconvert_single ( struct cmd_context * cmd , struct lvconvert_params * lp )
{
2014-08-13 16:20:41 +04:00
struct logical_volume * lv ;
2010-02-06 01:44:37 +03:00
int ret = ECMD_FAILED ;
int saved_ignore_suspended_devices = ignore_suspended_devices ( ) ;
2005-06-06 21:12:08 +04:00
2009-07-15 09:47:55 +04:00
if ( arg_count ( cmd , repair_ARG ) ) {
2009-06-15 18:47:39 +04:00
init_ignore_suspended_devices ( 1 ) ;
2009-07-15 09:47:55 +04:00
cmd - > handles_missing_pvs = 1 ;
}
2009-06-15 18:47:39 +04:00
2014-07-11 14:15:23 +04:00
if ( ! ( lv = get_vg_lock_and_logical_volume ( cmd , lp - > vg_name , lp - > lv_name ) ) )
2010-02-06 01:47:22 +03:00
goto_out ;
2005-06-06 21:12:08 +04:00
2010-04-26 22:12:40 +04:00
/*
* lp - > pvh holds the list of PVs available for allocation or removal
*/
2010-02-06 01:44:37 +03:00
if ( lp - > pv_count ) {
2010-02-06 01:47:22 +03:00
if ( ! ( lp - > pvh = create_pv_list ( cmd - > mem , lv - > vg , lp - > pv_count ,
2010-02-06 01:44:37 +03:00
lp - > pvs , 0 ) ) )
2008-01-30 16:19:47 +03:00
goto_bad ;
2005-06-06 21:12:08 +04:00
} else
2010-02-06 01:47:22 +03:00
lp - > pvh = & lv - > vg - > pvs ;
2005-06-06 21:12:08 +04:00
2011-11-30 06:02:10 +04:00
if ( lp - > replace_pv_count & &
! ( lp - > replace_pvh = create_pv_list ( cmd - > mem , lv - > vg ,
lp - > replace_pv_count ,
lp - > replace_pvs , 0 ) ) )
goto_bad ;
2010-02-06 01:47:22 +03:00
lp - > lv_to_poll = lv ;
ret = _lvconvert_single ( cmd , lv , lp ) ;
2008-01-30 16:19:47 +03:00
bad :
2010-02-06 01:44:37 +03:00
unlock_vg ( cmd , lp - > vg_name ) ;
2007-12-22 15:13:29 +03:00
2010-02-06 01:44:37 +03:00
if ( ret = = ECMD_PROCESSED & & lp - > need_polling )
2013-12-04 06:09:37 +04:00
ret = _poll_logical_volume ( cmd , lp - > lv_to_poll ,
2010-02-06 01:44:37 +03:00
lp - > wait_completion ) ;
2010-02-06 01:47:22 +03:00
2011-08-11 00:25:29 +04:00
release_vg ( lv - > vg ) ;
2009-04-10 14:01:38 +04:00
out :
2009-06-15 18:47:39 +04:00
init_ignore_suspended_devices ( saved_ignore_suspended_devices ) ;
2005-06-06 21:12:08 +04:00
return ret ;
}
2010-02-06 01:44:37 +03:00
2013-12-04 06:09:37 +04:00
static int _lvconvert_merge_single ( struct cmd_context * cmd , struct logical_volume * lv ,
2010-02-06 01:44:37 +03:00
void * handle )
{
struct lvconvert_params * lp = handle ;
2014-08-13 16:20:41 +04:00
const char * vg_name ;
struct logical_volume * refreshed_lv ;
2010-02-06 01:44:37 +03:00
int ret ;
/*
* FIXME can ' t trust lv ' s VG to be current given that caller
2013-12-04 06:09:37 +04:00
* is process_each_lv ( ) - - _poll_logical_volume ( ) may have
2010-02-06 01:44:37 +03:00
* already updated the VG ' s metadata in an earlier iteration .
* - preemptively drop the VG lock , as is needed for
2013-12-04 06:09:37 +04:00
* _poll_logical_volume ( ) , refresh LV ( and VG in the process ) .
2010-02-06 01:44:37 +03:00
*/
vg_name = lv - > vg - > name ;
unlock_vg ( cmd , vg_name ) ;
refreshed_lv = get_vg_lock_and_logical_volume ( cmd , vg_name , lv - > name ) ;
2010-04-26 22:31:58 +04:00
if ( ! refreshed_lv ) {
log_error ( " ABORTING: Can't reread LV %s/%s " , vg_name , lv - > name ) ;
2010-02-06 01:44:37 +03:00
return ECMD_FAILED ;
2010-04-26 22:31:58 +04:00
}
2010-02-06 01:44:37 +03:00
lp - > lv_to_poll = refreshed_lv ;
ret = _lvconvert_single ( cmd , refreshed_lv , lp ) ;
if ( ret = = ECMD_PROCESSED & & lp - > need_polling ) {
/*
* Must drop VG lock , because lvconvert_poll ( ) needs it ,
* then reacquire it after polling completes
*/
unlock_vg ( cmd , vg_name ) ;
2013-12-04 06:09:37 +04:00
ret = _poll_logical_volume ( cmd , lp - > lv_to_poll ,
2010-02-06 01:44:37 +03:00
lp - > wait_completion ) ;
/* use LCK_VG_WRITE to match lvconvert()'s READ_FOR_UPDATE */
2013-03-18 00:29:58 +04:00
if ( ! lock_vol ( cmd , vg_name , LCK_VG_WRITE , NULL ) ) {
2010-02-06 01:44:37 +03:00
log_error ( " ABORTING: Can't relock VG for %s "
" after polling finished " , vg_name ) ;
ret = ECMD_FAILED ;
}
}
2011-08-11 00:25:29 +04:00
release_vg ( refreshed_lv - > vg ) ;
2010-02-06 01:44:37 +03:00
return ret ;
}
int lvconvert ( struct cmd_context * cmd , int argc , char * * argv )
{
2014-08-13 16:20:10 +04:00
struct lvconvert_params lp = {
. target_attr = ~ 0 ,
} ;
2010-02-06 01:44:37 +03:00
if ( ! _read_params ( & lp , cmd , argc , argv ) ) {
stack ;
return EINVALID_CMD_LINE ;
}
2014-08-13 16:19:13 +04:00
if ( lp . merge )
2010-02-06 01:44:37 +03:00
return process_each_lv ( cmd , argc , argv , READ_FOR_UPDATE , & lp ,
2013-12-04 06:09:37 +04:00
& _lvconvert_merge_single ) ;
2010-02-06 01:44:37 +03:00
return lvconvert_single ( cmd , & lp ) ;
}