2003-05-06 16:22:24 +04:00
/*
2008-01-30 17:00:02 +03:00
* Copyright ( C ) 2003 - 2004 Sistina Software , Inc . All rights reserved .
2008-06-13 16:15:55 +04:00
* Copyright ( C ) 2004 - 2008 Red Hat , Inc . All rights reserved .
2003-05-06 16:22:24 +04:00
*
2004-03-30 23:35:44 +04:00
* This file is part of LVM2 .
*
* This copyrighted material is made available to anyone wishing to use ,
* modify , copy , or redistribute it subject to the terms and conditions
2007-08-21 00:55:30 +04:00
* of the GNU Lesser General Public License v .2 .1 .
2004-03-30 23:35:44 +04:00
*
2007-08-21 00:55:30 +04:00
* You should have received a copy of the GNU Lesser General Public License
2004-03-30 23:35:44 +04:00
* along with this program ; if not , write to the Free Software Foundation ,
* Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
2003-05-06 16:22:24 +04:00
*/
# include "lib.h"
# include "metadata.h"
# include "toolcontext.h"
2004-09-16 22:40:56 +04:00
# include "segtype.h"
2004-05-05 01:25:57 +04:00
# include "display.h"
2007-12-20 18:42:55 +03:00
# include "archiver.h"
2004-05-25 00:51:56 +04:00
# include "activate.h"
2005-04-22 19:43:02 +04:00
# include "lv_alloc.h"
2005-06-03 18:49:51 +04:00
# include "lvm-string.h"
2007-03-26 20:10:10 +04:00
# include "str_list.h"
2005-11-29 21:20:23 +03:00
# include "locking.h" /* FIXME Should not be used in this file */
2009-11-19 15:09:53 +03:00
# include "memlock.h"
2005-06-03 18:49:51 +04:00
2006-05-11 23:45:53 +04:00
# include "defaults.h" /* FIXME: should this be defaults.h? */
2007-12-21 01:37:42 +03:00
/* These are necessary for _write_log_header() */
# include "xlate.h"
# define MIRROR_MAGIC 0x4D695272
# define MIRROR_DISK_VERSION 2
2006-05-11 23:45:53 +04:00
/* These are the flags that represent the mirror failure restoration policies */
2008-01-30 17:00:02 +03:00
# define MIRROR_REMOVE 0
# define MIRROR_ALLOCATE 1
2006-05-11 23:45:53 +04:00
# define MIRROR_ALLOCATE_ANYWHERE 2
2007-12-20 21:55:46 +03:00
/*
* Returns true if the lv is temporary mirror layer for resync
*/
int is_temporary_mirror_layer ( const struct logical_volume * lv )
{
if ( lv - > status & MIRROR_IMAGE
& & lv - > status & MIRRORED
& & ! ( lv - > status & LOCKED ) )
return 1 ;
return 0 ;
}
2008-01-16 22:09:35 +03:00
/*
* Return a temporary LV for resyncing added mirror image .
* Add other mirror legs to lvs list .
*/
2008-01-16 22:13:51 +03:00
struct logical_volume * find_temporary_mirror ( const struct logical_volume * lv )
2008-01-16 22:09:35 +03:00
{
struct lv_segment * seg ;
if ( ! ( lv - > status & MIRRORED ) )
return NULL ;
seg = first_seg ( lv ) ;
/* Temporary mirror is always area_num == 0 */
if ( seg_type ( seg , 0 ) = = AREA_LV & &
is_temporary_mirror_layer ( seg_lv ( seg , 0 ) ) )
return seg_lv ( seg , 0 ) ;
return NULL ;
}
2007-12-20 18:42:55 +03:00
/*
* Returns the number of mirrors of the LV
*/
2007-12-20 21:55:46 +03:00
uint32_t lv_mirror_count ( const struct logical_volume * lv )
2007-12-20 18:42:55 +03:00
{
2007-12-20 21:55:46 +03:00
struct lv_segment * seg ;
uint32_t s , mirrors ;
if ( ! ( lv - > status & MIRRORED ) )
return 1 ;
seg = first_seg ( lv ) ;
mirrors = seg - > area_count ;
for ( s = 0 ; s < seg - > area_count ; s + + ) {
if ( seg_type ( seg , s ) ! = AREA_LV )
continue ;
if ( is_temporary_mirror_layer ( seg_lv ( seg , s ) ) )
mirrors + = lv_mirror_count ( seg_lv ( seg , s ) ) - 1 ;
}
return mirrors ;
2007-12-20 18:42:55 +03:00
}
2005-10-27 23:58:22 +04:00
struct lv_segment * find_mirror_seg ( struct lv_segment * seg )
{
2008-01-16 22:00:59 +03:00
struct lv_segment * mirror_seg ;
mirror_seg = get_only_segment_using_this_lv ( seg - > lv ) ;
if ( ! mirror_seg ) {
log_error ( " Failed to find mirror_seg for %s " , seg - > lv - > name ) ;
return NULL ;
}
if ( ! seg_is_mirrored ( mirror_seg ) ) {
log_error ( " %s on %s is not a mirror segments " ,
mirror_seg - > lv - > name , seg - > lv - > name ) ;
return NULL ;
}
return mirror_seg ;
2005-10-27 23:58:22 +04:00
}
2005-08-12 23:23:08 +04:00
/*
2006-11-10 22:35:03 +03:00
* Reduce the region size if necessary to ensure
* the volume size is a multiple of the region size .
2005-08-12 23:23:08 +04:00
*/
uint32_t adjusted_mirror_region_size ( uint32_t extent_size , uint32_t extents ,
uint32_t region_size )
{
2006-11-10 22:35:03 +03:00
uint64_t region_max ;
2005-08-12 23:23:08 +04:00
2006-11-10 23:15:10 +03:00
region_max = ( 1 < < ( ffs ( ( int ) extents ) - 1 ) ) * ( uint64_t ) extent_size ;
2005-08-12 23:23:08 +04:00
2006-11-10 22:35:03 +03:00
if ( region_max < UINT32_MAX & & region_size > region_max ) {
region_size = ( uint32_t ) region_max ;
2005-08-12 23:23:08 +04:00
log_print ( " Using reduced mirror region size of % " PRIu32
2006-11-10 22:35:03 +03:00
" sectors " , region_size ) ;
2005-08-12 23:23:08 +04:00
}
return region_size ;
}
2008-09-18 23:56:50 +04:00
/*
* shift_mirror_images
* @ mirrored_seg
* @ mimage : The position ( index ) of the image to move to the end
*
* When dealing with removal of legs , we often move a ' removable leg '
* to the back of the ' areas ' array . It is critically important not
* to simply swap it for the last area in the array . This would have
* the affect of reordering the remaining legs - altering position of
* the primary . So , we must shuffle all of the areas in the array
* to maintain their relative position before moving the ' removable
* leg ' to the end .
*
* Short illustration of the problem :
* - Mirror consists of legs A , B , C and we want to remove A
* - We swap A and C and then remove A , leaving C , B
* This scenario is problematic in failure cases where A dies , because
* B becomes the primary . If the above happens , we effectively throw
* away any changes made between the time of failure and the time of
* restructuring the mirror .
*
* So , any time we want to move areas to the end to be removed , use
* this function .
*/
int shift_mirror_images ( struct lv_segment * mirrored_seg , unsigned mimage )
{
int i ;
struct lv_segment_area area ;
if ( mimage > = mirrored_seg - > area_count ) {
log_error ( " Invalid index (%u) of mirror image supplied "
" to shift_mirror_images() " , mimage ) ;
return 0 ;
}
area = mirrored_seg - > areas [ mimage ] ;
/* Shift remaining images down to fill the hole */
for ( i = mimage + 1 ; i < mirrored_seg - > area_count ; i + + )
mirrored_seg - > areas [ i - 1 ] = mirrored_seg - > areas [ i ] ;
/* Place this one at the end */
mirrored_seg - > areas [ i - 1 ] = area ;
2008-09-19 04:20:39 +04:00
return 1 ;
2008-09-18 23:56:50 +04:00
}
2008-01-16 22:09:35 +03:00
/*
* This function writes a new header to the mirror log header to the lv
*
* Returns : 1 on success , 0 on failure
*/
static int _write_log_header ( struct cmd_context * cmd , struct logical_volume * lv )
{
struct device * dev ;
char * name ;
struct { /* The mirror log header */
uint32_t magic ;
uint32_t version ;
uint64_t nr_regions ;
} log_header ;
log_header . magic = xlate32 ( MIRROR_MAGIC ) ;
log_header . version = xlate32 ( MIRROR_DISK_VERSION ) ;
log_header . nr_regions = xlate64 ( ( uint64_t ) - 1 ) ;
if ( ! ( name = dm_pool_alloc ( cmd - > mem , PATH_MAX ) ) ) {
log_error ( " Name allocation failed - log header not written (%s) " ,
lv - > name ) ;
return 0 ;
}
if ( dm_snprintf ( name , PATH_MAX , " %s%s/%s " , cmd - > dev_dir ,
lv - > vg - > name , lv - > name ) < 0 ) {
log_error ( " Name too long - log header not written (%s) " , lv - > name ) ;
return 0 ;
}
log_verbose ( " Writing log header to device, %s " , lv - > name ) ;
if ( ! ( dev = dev_cache_get ( name , NULL ) ) ) {
log_error ( " %s: not found: log header not written " , name ) ;
return 0 ;
}
if ( ! dev_open_quiet ( dev ) )
return 0 ;
if ( ! dev_write ( dev , UINT64_C ( 0 ) , sizeof ( log_header ) , & log_header ) ) {
log_error ( " Failed to write log header to %s " , name ) ;
dev_close_immediate ( dev ) ;
return 0 ;
}
dev_close_immediate ( dev ) ;
return 1 ;
}
/*
* Initialize mirror log contents
*/
static int _init_mirror_log ( struct cmd_context * cmd ,
struct logical_volume * log_lv , int in_sync ,
2008-11-04 01:14:30 +03:00
struct dm_list * tags , int remove_on_failure )
2008-01-16 22:09:35 +03:00
{
struct str_list * sl ;
2008-01-17 16:37:51 +03:00
struct lvinfo info ;
uint32_t orig_status = log_lv - > status ;
int was_active = 0 ;
2008-01-16 22:09:35 +03:00
if ( ! activation ( ) & & in_sync ) {
log_error ( " Aborting. Unable to create in-sync mirror log "
" while activation is disabled. " ) ;
return 0 ;
}
2008-01-17 16:37:51 +03:00
/* If the LV is active, deactivate it first. */
if ( lv_info ( cmd , log_lv , & info , 0 , 0 ) & & info . exists ) {
if ( ! deactivate_lv ( cmd , log_lv ) )
return_0 ;
was_active = 1 ;
}
/* Temporary make it visible for set_lv() */
2009-05-14 01:26:45 +04:00
lv_set_visible ( log_lv ) ;
2008-01-17 16:37:51 +03:00
2008-01-16 22:09:35 +03:00
/* Temporary tag mirror log for activation */
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( sl , tags )
2008-01-16 22:09:35 +03:00
if ( ! str_list_add ( cmd - > mem , & log_lv - > tags , sl - > str ) ) {
log_error ( " Aborting. Unable to tag mirror log. " ) ;
2008-01-17 16:37:51 +03:00
goto activate_lv ;
2008-01-16 22:09:35 +03:00
}
/* store mirror log on disk(s) */
2009-04-21 18:31:57 +04:00
if ( ! vg_write ( log_lv - > vg ) | | ! vg_commit ( log_lv - > vg ) )
2008-01-17 16:37:51 +03:00
goto activate_lv ;
2008-01-16 22:09:35 +03:00
backup ( log_lv - > vg ) ;
if ( ! activate_lv ( cmd , log_lv ) ) {
log_error ( " Aborting. Failed to activate mirror log. " ) ;
goto revert_new_lv ;
}
/* Remove the temporary tags */
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( sl , tags )
2008-01-16 22:09:35 +03:00
if ( ! str_list_del ( & log_lv - > tags , sl - > str ) )
log_error ( " Failed to remove tag %s from mirror log. " ,
sl - > str ) ;
if ( activation ( ) & & ! set_lv ( cmd , log_lv , log_lv - > size ,
in_sync ? - 1 : 0 ) ) {
log_error ( " Aborting. Failed to wipe mirror log. " ) ;
goto deactivate_and_revert_new_lv ;
}
if ( activation ( ) & & ! _write_log_header ( cmd , log_lv ) ) {
log_error ( " Aborting. Failed to write mirror log header. " ) ;
goto deactivate_and_revert_new_lv ;
}
if ( ! deactivate_lv ( cmd , log_lv ) ) {
log_error ( " Aborting. Failed to deactivate mirror log. "
" Manual intervention required. " ) ;
return 0 ;
}
2009-05-21 07:04:52 +04:00
lv_set_hidden ( log_lv ) ;
2008-01-16 22:09:35 +03:00
2008-01-17 16:37:51 +03:00
if ( was_active & & ! activate_lv ( cmd , log_lv ) )
return_0 ;
2008-01-16 22:09:35 +03:00
return 1 ;
deactivate_and_revert_new_lv :
if ( ! deactivate_lv ( cmd , log_lv ) ) {
log_error ( " Unable to deactivate mirror log LV. "
" Manual intervention required. " ) ;
return 0 ;
}
revert_new_lv :
2008-01-17 16:37:51 +03:00
log_lv - > status = orig_status ;
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( sl , tags )
2008-01-17 16:37:51 +03:00
if ( ! str_list_del ( & log_lv - > tags , sl - > str ) )
log_error ( " Failed to remove tag %s from mirror log. " ,
sl - > str ) ;
if ( remove_on_failure & & ! lv_remove ( log_lv ) ) {
2008-01-16 22:09:35 +03:00
log_error ( " Manual intervention may be required to remove "
" abandoned log LV before retrying. " ) ;
2008-01-17 16:37:51 +03:00
return 0 ;
}
2009-04-21 18:31:57 +04:00
if ( ! vg_write ( log_lv - > vg ) | | ! vg_commit ( log_lv - > vg ) )
2008-01-17 16:37:51 +03:00
log_error ( " Manual intervention may be required to "
" remove/restore abandoned log LV before retrying. " ) ;
2009-04-21 18:31:57 +04:00
else
backup ( log_lv - > vg ) ;
2008-01-17 16:37:51 +03:00
activate_lv :
if ( was_active & & ! remove_on_failure & & ! activate_lv ( cmd , log_lv ) )
return_0 ;
2008-01-16 22:09:35 +03:00
return 0 ;
}
2007-03-26 20:10:10 +04:00
/*
* Delete independent / orphan LV , it must acquire lock .
*/
2007-12-20 21:55:46 +03:00
static int _delete_lv ( struct logical_volume * mirror_lv , struct logical_volume * lv )
2007-03-26 20:10:10 +04:00
{
2007-12-20 21:55:46 +03:00
struct cmd_context * cmd = mirror_lv - > vg - > cmd ;
2007-03-26 20:10:10 +04:00
struct str_list * sl ;
/* Inherit tags - maybe needed for activation */
2007-12-20 21:55:46 +03:00
if ( ! str_list_match_list ( & mirror_lv - > tags , & lv - > tags ) ) {
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( sl , & mirror_lv - > tags )
2007-03-26 20:10:10 +04:00
if ( ! str_list_add ( cmd - > mem , & lv - > tags , sl - > str ) ) {
log_error ( " Aborting. Unable to tag. " ) ;
return 0 ;
}
2007-12-20 21:55:46 +03:00
if ( ! vg_write ( mirror_lv - > vg ) | |
! vg_commit ( mirror_lv - > vg ) ) {
2007-03-26 20:10:10 +04:00
log_error ( " Intermediate VG commit for orphan volume failed. " ) ;
return 0 ;
}
}
if ( ! activate_lv ( cmd , lv ) )
return_0 ;
if ( ! deactivate_lv ( cmd , lv ) )
return_0 ;
if ( ! lv_remove ( lv ) )
return_0 ;
return 1 ;
}
2008-01-10 21:35:51 +03:00
static int _merge_mirror_images ( struct logical_volume * lv ,
2008-11-04 01:14:30 +03:00
const struct dm_list * mimages )
2008-01-10 21:35:51 +03:00
{
2008-11-04 01:14:30 +03:00
uint32_t addition = dm_list_size ( mimages ) ;
2008-01-10 21:35:51 +03:00
struct logical_volume * * img_lvs ;
struct lv_list * lvl ;
int i = 0 ;
if ( ! addition )
return 1 ;
if ( ! ( img_lvs = alloca ( sizeof ( * img_lvs ) * addition ) ) )
return_0 ;
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( lvl , mimages )
2008-01-10 21:35:51 +03:00
img_lvs [ i + + ] = lvl - > lv ;
return lv_add_mirror_lvs ( lv , img_lvs , addition ,
MIRROR_IMAGE , first_seg ( lv ) - > region_size ) ;
}
2008-01-16 22:00:59 +03:00
/* Unlink the relationship between the segment and its log_lv */
2008-01-26 03:25:04 +03:00
struct logical_volume * detach_mirror_log ( struct lv_segment * mirrored_seg )
2008-01-16 22:00:59 +03:00
{
struct logical_volume * log_lv ;
if ( ! mirrored_seg - > log_lv )
2008-01-26 03:25:04 +03:00
return NULL ;
2008-01-16 22:00:59 +03:00
log_lv = mirrored_seg - > log_lv ;
mirrored_seg - > log_lv = NULL ;
2009-05-14 01:26:45 +04:00
lv_set_visible ( log_lv ) ;
2008-01-16 22:00:59 +03:00
log_lv - > status & = ~ MIRROR_LOG ;
remove_seg_from_segs_using_this_lv ( log_lv , mirrored_seg ) ;
2008-01-26 03:25:04 +03:00
return log_lv ;
2008-01-16 22:00:59 +03:00
}
2008-01-16 22:11:39 +03:00
/* Check if mirror image LV is removable with regard to given removable_pvs */
static int _is_mirror_image_removable ( struct logical_volume * mimage_lv ,
2008-11-04 01:14:30 +03:00
struct dm_list * removable_pvs )
2008-01-16 22:11:39 +03:00
{
struct physical_volume * pv ;
struct lv_segment * seg ;
int pv_found ;
struct pv_list * pvl ;
uint32_t s ;
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( seg , & mimage_lv - > segments ) {
2008-01-16 22:11:39 +03:00
for ( s = 0 ; s < seg - > area_count ; s + + ) {
2008-01-16 22:38:39 +03:00
if ( seg_type ( seg , s ) ! = AREA_PV ) {
/* FIXME Recurse for AREA_LV? */
/* Structure of seg_lv is unknown.
* Not removing this LV for safety . */
return 0 ;
}
2008-01-16 22:11:39 +03:00
pv = seg_pv ( seg , s ) ;
pv_found = 0 ;
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( pvl , removable_pvs ) {
2009-04-23 20:43:01 +04:00
if ( id_equal ( & pv - > id , & pvl - > pv - > id ) ) {
pv_found = 1 ;
break ;
}
if ( pvl - > pv - > dev & & pv - > dev & &
pv - > dev - > dev = = pvl - > pv - > dev - > dev ) {
2008-01-16 22:11:39 +03:00
pv_found = 1 ;
break ;
}
}
if ( ! pv_found )
return 0 ;
}
}
return 1 ;
}
2005-06-06 21:12:08 +04:00
/*
2007-12-20 21:55:46 +03:00
* Remove num_removed images from mirrored_seg
2008-01-17 16:13:54 +03:00
*
* Arguments :
* num_removed : the requested ( maximum ) number of mirrors to be removed
* removable_pvs : if not NULL , only mirrors using PVs in this list
* will be removed
* remove_log : if non - zero , log_lv will be removed
* ( even if it ' s 0 , log_lv will be removed if there is no
* mirror remaining after the removal )
* collapse : if non - zero , instead of removing , remove the temporary
* mirror layer and merge mirrors to the original LV .
* removable_pvs should be NULL and num_removed should be
* seg - > area_count - 1.
* removed : if non NULL , the number of removed mirror images is set
* as a result
*
* If collapse is non - zero , < removed > is guaranteed to be equal to num_removed .
*
* Return values :
* Failure ( 0 ) means something unexpected has happend and
* the caller should abort .
* Even if no mirror was removed ( e . g . no LV matches to ' removable_pvs ' ) ,
* returns success ( 1 ) .
2005-06-06 21:12:08 +04:00
*/
2007-12-20 21:55:46 +03:00
static int _remove_mirror_images ( struct logical_volume * lv ,
uint32_t num_removed ,
2008-11-04 01:14:30 +03:00
struct dm_list * removable_pvs ,
2008-01-17 16:13:54 +03:00
unsigned remove_log , unsigned collapse ,
uint32_t * removed )
2005-06-06 21:12:08 +04:00
{
uint32_t m ;
2008-01-16 22:11:39 +03:00
uint32_t s ;
2005-11-29 21:20:23 +03:00
struct logical_volume * sub_lv ;
2008-01-26 03:25:04 +03:00
struct logical_volume * detached_log_lv = NULL ;
2005-11-29 21:20:23 +03:00
struct logical_volume * lv1 = NULL ;
2008-01-16 22:11:39 +03:00
struct lv_segment * mirrored_seg = first_seg ( lv ) ;
2005-11-29 21:20:23 +03:00
uint32_t old_area_count = mirrored_seg - > area_count ;
uint32_t new_area_count = mirrored_seg - > area_count ;
2007-12-20 21:55:46 +03:00
struct lv_list * lvl ;
2008-11-04 01:14:30 +03:00
struct dm_list tmp_orphan_lvs ;
2005-11-29 21:20:23 +03:00
2008-01-17 16:13:54 +03:00
if ( removed )
* removed = 0 ;
2005-11-29 21:20:23 +03:00
log_very_verbose ( " Reducing mirror set from % " PRIu32 " to % "
PRIu32 " image(s)%s. " ,
2007-12-20 21:55:46 +03:00
old_area_count , old_area_count - num_removed ,
2005-11-29 21:20:23 +03:00
remove_log ? " and no log volume " : " " ) ;
2008-01-10 21:35:51 +03:00
if ( collapse & &
( removable_pvs | | ( old_area_count - num_removed ! = 1 ) ) ) {
log_error ( " Incompatible parameters to _remove_mirror_images " ) ;
return 0 ;
}
2005-11-29 21:20:23 +03:00
/* Move removable_pvs to end of array */
if ( removable_pvs ) {
2008-01-10 21:35:51 +03:00
for ( s = 0 ; s < mirrored_seg - > area_count & &
old_area_count - new_area_count < num_removed ; s + + ) {
2005-11-29 21:20:23 +03:00
sub_lv = seg_lv ( mirrored_seg , s ) ;
2008-09-18 23:56:50 +04:00
2008-01-17 16:13:54 +03:00
if ( ! is_temporary_mirror_layer ( sub_lv ) & &
_is_mirror_image_removable ( sub_lv , removable_pvs ) ) {
2008-09-18 23:56:50 +04:00
if ( ! shift_mirror_images ( mirrored_seg , s ) )
return_0 ;
2005-11-29 21:20:23 +03:00
new_area_count - - ;
}
}
2008-01-17 16:13:54 +03:00
if ( num_removed & & old_area_count = = new_area_count )
return 1 ;
2007-12-20 21:55:46 +03:00
} else
new_area_count = old_area_count - num_removed ;
2005-06-06 21:12:08 +04:00
2007-12-20 21:55:46 +03:00
/* Remove mimage LVs from the segment */
2008-11-04 01:14:30 +03:00
dm_list_init ( & tmp_orphan_lvs ) ;
2007-12-20 21:55:46 +03:00
for ( m = new_area_count ; m < mirrored_seg - > area_count ; m + + ) {
2005-11-29 21:20:23 +03:00
seg_lv ( mirrored_seg , m ) - > status & = ~ MIRROR_IMAGE ;
2009-05-14 01:26:45 +04:00
lv_set_visible ( seg_lv ( mirrored_seg , m ) ) ;
2007-12-20 21:55:46 +03:00
if ( ! ( lvl = dm_pool_alloc ( lv - > vg - > cmd - > mem , sizeof ( * lvl ) ) ) ) {
log_error ( " lv_list alloc failed " ) ;
return 0 ;
}
lvl - > lv = seg_lv ( mirrored_seg , m ) ;
2008-11-04 01:14:30 +03:00
dm_list_add ( & tmp_orphan_lvs , & lvl - > list ) ;
2008-01-16 22:00:59 +03:00
release_lv_segment_area ( mirrored_seg , m , mirrored_seg - > area_len ) ;
2005-11-29 21:20:23 +03:00
}
2007-12-20 21:55:46 +03:00
mirrored_seg - > area_count = new_area_count ;
2005-11-29 21:20:23 +03:00
/* If no more mirrors, remove mirror layer */
2008-01-17 16:13:54 +03:00
/* As an exceptional case, if the lv is temporary layer,
* leave the LV as mirrored and let the lvconvert completion
* to remove the layer . */
if ( new_area_count = = 1 & & ! is_temporary_mirror_layer ( lv ) ) {
2005-11-29 21:20:23 +03:00
lv1 = seg_lv ( mirrored_seg , 0 ) ;
2008-02-22 16:28:29 +03:00
lv1 - > status & = ~ MIRROR_IMAGE ;
2009-05-14 01:26:45 +04:00
lv_set_visible ( lv1 ) ;
2008-01-26 03:25:04 +03:00
detached_log_lv = detach_mirror_log ( mirrored_seg ) ;
2007-12-20 21:55:46 +03:00
if ( ! remove_layer_from_lv ( lv , lv1 ) )
2006-11-30 20:52:47 +03:00
return_0 ;
2007-12-20 21:55:46 +03:00
lv - > status & = ~ MIRRORED ;
lv - > status & = ~ MIRROR_NOTSYNCED ;
2008-01-10 21:35:51 +03:00
if ( collapse & & ! _merge_mirror_images ( lv , & tmp_orphan_lvs ) ) {
log_error ( " Failed to add mirror images " ) ;
return 0 ;
}
2008-01-17 16:13:54 +03:00
} else if ( new_area_count = = 0 ) {
2008-01-19 01:00:46 +03:00
log_very_verbose ( " All mimages of %s are gone " , lv - > name ) ;
2008-01-17 16:13:54 +03:00
/* All mirror images are gone.
* It can happen for vgreduce - - removemissing . */
2008-01-26 03:25:04 +03:00
detached_log_lv = detach_mirror_log ( mirrored_seg ) ;
2008-01-17 16:13:54 +03:00
lv - > status & = ~ MIRRORED ;
lv - > status & = ~ MIRROR_NOTSYNCED ;
2008-01-17 16:54:05 +03:00
if ( ! replace_lv_with_error_segment ( lv ) )
2008-01-17 16:13:54 +03:00
return_0 ;
2008-01-10 21:35:51 +03:00
} else if ( remove_log )
2008-01-26 03:25:04 +03:00
detached_log_lv = detach_mirror_log ( mirrored_seg ) ;
2005-06-06 21:12:08 +04:00
2005-11-29 21:20:23 +03:00
/*
* To successfully remove these unwanted LVs we need to
* remove the LVs from the mirror set , commit that metadata
* then deactivate and remove them fully .
*/
2005-06-06 21:12:08 +04:00
2005-11-29 21:20:23 +03:00
if ( ! vg_write ( mirrored_seg - > lv - > vg ) ) {
log_error ( " intermediate VG write failed. " ) ;
2005-06-06 21:12:08 +04:00
return 0 ;
}
2005-11-29 21:20:23 +03:00
if ( ! suspend_lv ( mirrored_seg - > lv - > vg - > cmd , mirrored_seg - > lv ) ) {
log_error ( " Failed to lock %s " , mirrored_seg - > lv - > name ) ;
vg_revert ( mirrored_seg - > lv - > vg ) ;
2005-06-06 21:12:08 +04:00
return 0 ;
}
2005-11-29 21:20:23 +03:00
if ( ! vg_commit ( mirrored_seg - > lv - > vg ) ) {
resume_lv ( mirrored_seg - > lv - > vg - > cmd , mirrored_seg - > lv ) ;
return 0 ;
}
2005-06-06 21:12:08 +04:00
2005-11-29 21:20:23 +03:00
log_very_verbose ( " Updating \" %s \" in kernel " , mirrored_seg - > lv - > name ) ;
2005-06-06 21:12:08 +04:00
2008-09-18 23:09:47 +04:00
/*
2008-10-17 14:50:14 +04:00
* Avoid having same mirror target loaded twice simultaneously by first
* resuming the removed LV which now contains an error segment .
* As it ' s now detached from mirrored_seg - > lv we must resume it
2008-09-18 23:09:47 +04:00
* explicitly .
*/
2009-11-19 16:42:38 +03:00
if ( lv1 ) {
if ( ! resume_lv ( lv1 - > vg - > cmd , lv1 ) ) {
log_error ( " Problem resuming temporary LV, %s " , lv1 - > name ) ;
return 0 ;
}
2008-09-18 23:09:47 +04:00
2009-11-19 16:42:38 +03:00
/*
* The code above calls a suspend_lv once , however we now need
* to resume 2 LVs , due to image removal : the mirror image
* itself here , and now the remaining mirror LV . Since
* suspend_lv / resume_lv call memlock_inc / memlock_dec and these
* need to be balanced , we need to call an extra memlock_inc ( )
* here to balance for the this extra resume - - the following
* one could otherwise either deadlock due to suspended
* devices , or alternatively drop memlock_count below 0.
*/
memlock_inc ( ) ;
}
2009-11-18 21:23:46 +03:00
2005-11-29 21:20:23 +03:00
if ( ! resume_lv ( mirrored_seg - > lv - > vg - > cmd , mirrored_seg - > lv ) ) {
log_error ( " Problem reactivating %s " , mirrored_seg - > lv - > name ) ;
2005-06-06 21:12:08 +04:00
return 0 ;
}
2007-12-20 21:55:46 +03:00
/* Save or delete the 'orphan' LVs */
2008-01-10 21:35:51 +03:00
if ( ! collapse ) {
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( lvl , & tmp_orphan_lvs )
2007-12-20 21:55:46 +03:00
if ( ! _delete_lv ( lv , lvl - > lv ) )
2008-01-26 03:25:04 +03:00
return_0 ;
2007-12-20 21:55:46 +03:00
}
2006-07-21 00:37:10 +04:00
2007-12-20 21:55:46 +03:00
if ( lv1 & & ! _delete_lv ( lv , lv1 ) )
2008-01-26 03:25:04 +03:00
return_0 ;
2005-11-29 21:20:23 +03:00
2008-01-26 03:25:04 +03:00
if ( detached_log_lv & & ! _delete_lv ( lv , detached_log_lv ) )
return_0 ;
2005-11-29 21:20:23 +03:00
2008-01-17 16:13:54 +03:00
/* Mirror with only 1 area is 'in sync'. */
2008-01-26 03:25:04 +03:00
if ( new_area_count = = 1 & & is_temporary_mirror_layer ( lv ) ) {
if ( first_seg ( lv ) - > log_lv & &
! _init_mirror_log ( lv - > vg - > cmd , first_seg ( lv ) - > log_lv ,
1 , & lv - > tags , 0 ) ) {
2008-01-17 16:13:54 +03:00
/* As a result, unnecessary sync may run after
* collapsing . But safe . */
log_error ( " Failed to initialize log device " ) ;
return_0 ;
}
}
if ( removed )
* removed = old_area_count - new_area_count ;
2008-01-19 01:00:46 +03:00
log_very_verbose ( " % " PRIu32 " image(s) removed from %s " ,
old_area_count - num_removed , lv - > name ) ;
2005-11-29 21:20:23 +03:00
return 1 ;
2005-06-06 21:12:08 +04:00
}
2007-12-20 21:55:46 +03:00
/*
* Remove the number of mirror images from the LV
*/
int remove_mirror_images ( struct logical_volume * lv , uint32_t num_mirrors ,
2008-11-04 01:14:30 +03:00
struct dm_list * removable_pvs , unsigned remove_log )
2007-12-20 21:55:46 +03:00
{
2008-01-17 16:13:54 +03:00
uint32_t num_removed , removed_once , r ;
2007-12-20 21:55:46 +03:00
uint32_t existing_mirrors = lv_mirror_count ( lv ) ;
2008-01-17 16:13:54 +03:00
struct logical_volume * next_lv = lv ;
2007-12-20 21:55:46 +03:00
num_removed = existing_mirrors - num_mirrors ;
2008-01-10 21:35:51 +03:00
/* num_removed can be 0 if the function is called just to remove log */
do {
2008-01-17 16:13:54 +03:00
if ( num_removed < first_seg ( next_lv ) - > area_count )
2007-12-20 21:55:46 +03:00
removed_once = num_removed ;
else
2008-01-17 16:13:54 +03:00
removed_once = first_seg ( next_lv ) - > area_count - 1 ;
2007-12-20 21:55:46 +03:00
2008-01-17 16:13:54 +03:00
if ( ! _remove_mirror_images ( next_lv , removed_once ,
removable_pvs , remove_log , 0 , & r ) )
2007-12-20 21:55:46 +03:00
return_0 ;
2008-01-17 16:13:54 +03:00
if ( r < removed_once ) {
/* Some mirrors are removed from the temporary mirror,
* but the temporary layer still exists .
* Down the stack and retry for remainder . */
2008-01-17 16:54:05 +03:00
next_lv = find_temporary_mirror ( next_lv ) ;
2008-01-17 16:13:54 +03:00
}
num_removed - = r ;
} while ( next_lv & & num_removed ) ;
if ( num_removed ) {
if ( num_removed = = existing_mirrors - num_mirrors )
log_error ( " No mirror images found using specified PVs. " ) ;
else {
log_error ( " %u images are removed out of requested %u. " ,
existing_mirrors - lv_mirror_count ( lv ) ,
existing_mirrors - num_mirrors ) ;
}
return 0 ;
}
2007-12-20 21:55:46 +03:00
return 1 ;
}
static int _mirrored_lv_in_sync ( struct logical_volume * lv )
{
float sync_percent ;
2009-10-01 04:35:29 +04:00
percent_range_t percent_range ;
2007-12-20 21:55:46 +03:00
2009-10-01 04:35:29 +04:00
if ( ! lv_mirror_percent ( lv - > vg - > cmd , lv , 0 , & sync_percent ,
& percent_range , NULL ) ) {
2007-12-20 21:55:46 +03:00
log_error ( " Unable to determine mirror sync status of %s/%s. " ,
lv - > vg - > name , lv - > name ) ;
return 0 ;
}
2009-10-01 04:35:29 +04:00
return ( percent_range = = PERCENT_100 ) ? 1 : 0 ;
2007-12-20 21:55:46 +03:00
}
/*
* Collapsing temporary mirror layers .
*
* When mirrors are added to already - mirrored LV , a temporary mirror layer
* is inserted at the top of the stack to reduce resync work .
* The function will remove the intermediate layer and collapse the stack
* as far as mirrors are in - sync .
*
* The function is destructive : to remove intermediate mirror layers ,
* VG metadata commits and suspend / resume are necessary .
*/
int collapse_mirrored_lv ( struct logical_volume * lv )
{
2008-01-16 22:00:59 +03:00
struct logical_volume * tmp_lv ;
struct lv_segment * mirror_seg ;
2007-12-20 21:55:46 +03:00
2008-01-16 22:13:51 +03:00
while ( ( tmp_lv = find_temporary_mirror ( lv ) ) ) {
2008-01-16 22:00:59 +03:00
mirror_seg = find_mirror_seg ( first_seg ( tmp_lv ) ) ;
if ( ! mirror_seg ) {
log_error ( " Failed to find mirrored LV for %s " ,
tmp_lv - > name ) ;
return 0 ;
}
if ( ! _mirrored_lv_in_sync ( mirror_seg - > lv ) ) {
2007-12-20 21:55:46 +03:00
log_verbose ( " Not collapsing %s: out-of-sync " ,
2008-01-16 22:00:59 +03:00
mirror_seg - > lv - > name ) ;
2007-12-20 21:55:46 +03:00
return 1 ;
}
2008-01-16 22:00:59 +03:00
if ( ! _remove_mirror_images ( mirror_seg - > lv ,
mirror_seg - > area_count - 1 ,
2008-01-17 16:13:54 +03:00
NULL , 1 , 1 , NULL ) ) {
2007-12-20 21:55:46 +03:00
log_error ( " Failed to release mirror images " ) ;
return 0 ;
}
}
return 1 ;
}
2007-08-22 18:38:18 +04:00
static int get_mirror_fault_policy ( struct cmd_context * cmd __attribute ( ( unused ) ) ,
int log_policy )
2006-05-11 23:45:53 +04:00
{
const char * policy ;
if ( log_policy )
policy = find_config_str ( NULL , " activation/mirror_log_fault_policy " ,
DEFAULT_MIRROR_LOG_FAULT_POLICY ) ;
else
2006-05-12 23:47:40 +04:00
policy = find_config_str ( NULL , " activation/mirror_device_fault_policy " ,
2006-05-11 23:45:53 +04:00
DEFAULT_MIRROR_DEV_FAULT_POLICY ) ;
if ( ! strcmp ( policy , " remove " ) )
return MIRROR_REMOVE ;
else if ( ! strcmp ( policy , " allocate " ) )
return MIRROR_ALLOCATE ;
else if ( ! strcmp ( policy , " allocate_anywhere " ) )
return MIRROR_ALLOCATE_ANYWHERE ;
if ( log_policy )
log_error ( " Bad activation/mirror_log_fault_policy " ) ;
else
2006-05-12 23:47:40 +04:00
log_error ( " Bad activation/mirror_device_fault_policy " ) ;
2006-05-11 23:45:53 +04:00
return MIRROR_REMOVE ;
}
static int get_mirror_log_fault_policy ( struct cmd_context * cmd )
{
return get_mirror_fault_policy ( cmd , 1 ) ;
}
2006-05-12 23:47:40 +04:00
static int get_mirror_device_fault_policy ( struct cmd_context * cmd )
2006-05-11 23:45:53 +04:00
{
return get_mirror_fault_policy ( cmd , 0 ) ;
}
/*
* replace_mirror_images
* @ mirrored_seg : segment ( which may be linear now ) to restore
* @ num_mirrors : number of copies we should end up with
* @ replace_log : replace log if not present
* @ in_sync : was the original mirror in - sync ?
*
* in_sync will be set to 0 if new mirror devices are being added
* In other words , it is only useful if the log ( and only the log )
* is being restored .
*
* Returns : 0 on failure , 1 on reconfig , - 1 if no reconfig done
*/
static int replace_mirror_images ( struct lv_segment * mirrored_seg ,
uint32_t num_mirrors ,
int log_policy , int in_sync )
{
int r = - 1 ;
struct logical_volume * lv = mirrored_seg - > lv ;
/* FIXME: Use lvconvert rather than duplicating its code */
if ( mirrored_seg - > area_count < num_mirrors ) {
log_error ( " WARNING: Failed to replace mirror device in %s/%s " ,
mirrored_seg - > lv - > vg - > name , mirrored_seg - > lv - > name ) ;
if ( ( mirrored_seg - > area_count > 1 ) & & ! mirrored_seg - > log_lv )
log_error ( " WARNING: Use 'lvconvert -m %d %s/%s --corelog' to replace failed devices " ,
num_mirrors - 1 , lv - > vg - > name , lv - > name ) ;
else
log_error ( " WARNING: Use 'lvconvert -m %d %s/%s' to replace failed devices " ,
num_mirrors - 1 , lv - > vg - > name , lv - > name ) ;
r = 0 ;
/* REMEMBER/FIXME: set in_sync to 0 if a new mirror device was added */
in_sync = 0 ;
}
/*
* FIXME : right now , we ignore the allocation policy specified to
* allocate the new log .
*/
if ( ( mirrored_seg - > area_count > 1 ) & & ! mirrored_seg - > log_lv & &
( log_policy ! = MIRROR_REMOVE ) ) {
log_error ( " WARNING: Failed to replace mirror log device in %s/%s " ,
lv - > vg - > name , lv - > name ) ;
log_error ( " WARNING: Use 'lvconvert -m %d %s/%s' to replace failed devices " ,
mirrored_seg - > area_count - 1 , lv - > vg - > name , lv - > name ) ;
r = 0 ;
}
return r ;
}
2006-05-11 23:01:11 +04:00
int reconfigure_mirror_images ( struct lv_segment * mirrored_seg , uint32_t num_mirrors ,
2008-11-04 01:14:30 +03:00
struct dm_list * removable_pvs , unsigned remove_log )
2006-05-11 23:01:11 +04:00
{
int r ;
2007-12-20 21:55:46 +03:00
int in_sync ;
2006-05-11 23:45:53 +04:00
int log_policy , dev_policy ;
uint32_t old_num_mirrors = mirrored_seg - > area_count ;
int had_log = ( mirrored_seg - > log_lv ) ? 1 : 0 ;
2006-05-11 23:01:11 +04:00
/* was the mirror in-sync before problems? */
2007-12-20 21:55:46 +03:00
in_sync = _mirrored_lv_in_sync ( mirrored_seg - > lv ) ;
2006-05-11 23:01:11 +04:00
/*
* While we are only removing devices , we can have sync set .
* Setting this is only useful if we are moving to core log
* otherwise the disk log will contain the sync information
*/
2007-12-20 18:42:55 +03:00
init_mirror_in_sync ( in_sync ) ;
2006-05-11 23:01:11 +04:00
2008-01-17 16:13:54 +03:00
r = _remove_mirror_images ( mirrored_seg - > lv , old_num_mirrors - num_mirrors ,
removable_pvs , remove_log , 0 , NULL ) ;
2006-05-11 23:01:11 +04:00
if ( ! r )
/* Unable to remove bad devices */
return 0 ;
2007-06-28 21:33:44 +04:00
log_warn ( " WARNING: Bad device removed from mirror volume, %s/%s " ,
2006-05-11 23:45:53 +04:00
mirrored_seg - > lv - > vg - > name , mirrored_seg - > lv - > name ) ;
log_policy = get_mirror_log_fault_policy ( mirrored_seg - > lv - > vg - > cmd ) ;
2006-05-12 23:47:40 +04:00
dev_policy = get_mirror_device_fault_policy ( mirrored_seg - > lv - > vg - > cmd ) ;
2006-05-11 23:45:53 +04:00
r = replace_mirror_images ( mirrored_seg ,
( dev_policy ! = MIRROR_REMOVE ) ?
old_num_mirrors : num_mirrors ,
2007-12-20 18:42:55 +03:00
log_policy , in_sync ) ;
2006-05-11 23:45:53 +04:00
if ( ! r )
/* Failed to replace device(s) */
log_error ( " WARNING: Unable to find substitute device for mirror volume, %s/%s " ,
mirrored_seg - > lv - > vg - > name , mirrored_seg - > lv - > name ) ;
else if ( r > 0 )
/* Success in replacing device(s) */
2007-06-28 21:33:44 +04:00
log_warn ( " WARNING: Mirror volume, %s/%s restored - substitute for failed device found. " ,
2006-05-11 23:45:53 +04:00
mirrored_seg - > lv - > vg - > name , mirrored_seg - > lv - > name ) ;
else
/* Bad device removed, but not replaced because of policy */
if ( mirrored_seg - > area_count = = 1 ) {
2007-06-28 21:33:44 +04:00
log_warn ( " WARNING: Mirror volume, %s/%s converted to linear due to device failure. " ,
2006-05-11 23:45:53 +04:00
mirrored_seg - > lv - > vg - > name , mirrored_seg - > lv - > name ) ;
} else if ( had_log & & ! mirrored_seg - > log_lv ) {
2007-06-28 21:33:44 +04:00
log_warn ( " WARNING: Mirror volume, %s/%s disk log removed due to device failure. " ,
2006-05-11 23:45:53 +04:00
mirrored_seg - > lv - > vg - > name , mirrored_seg - > lv - > name ) ;
}
/*
* If we made it here , we at least removed the bad device .
* Consider this success .
*/
2006-05-11 23:01:11 +04:00
return 1 ;
}
2007-12-20 18:42:55 +03:00
static int _create_mimage_lvs ( struct alloc_handle * ah ,
uint32_t num_mirrors ,
struct logical_volume * lv ,
struct logical_volume * * img_lvs )
2005-06-03 18:49:51 +04:00
{
uint32_t m ;
char * img_name ;
size_t len ;
len = strlen ( lv - > name ) + 32 ;
if ( ! ( img_name = alloca ( len ) ) ) {
log_error ( " img_name allocation failed. "
" Remove new LV and retry. " ) ;
return 0 ;
}
2006-08-21 16:54:53 +04:00
if ( dm_snprintf ( img_name , len , " %s_mimage_%%d " , lv - > name ) < 0 ) {
2005-06-03 18:49:51 +04:00
log_error ( " img_name allocation failed. "
" Remove new LV and retry. " ) ;
return 0 ;
}
for ( m = 0 ; m < num_mirrors ; m + + ) {
2007-10-11 23:20:38 +04:00
if ( ! ( img_lvs [ m ] = lv_create_empty ( img_name ,
2005-06-03 18:49:51 +04:00
NULL , LVM_READ | LVM_WRITE ,
2009-05-14 01:28:31 +04:00
ALLOC_INHERIT , lv - > vg ) ) ) {
2005-10-27 23:58:22 +04:00
log_error ( " Aborting. Failed to create mirror image LV. "
2005-06-03 18:49:51 +04:00
" Remove new LV and retry. " ) ;
return 0 ;
}
2007-12-20 18:42:55 +03:00
if ( ! lv_add_segment ( ah , m , 1 , img_lvs [ m ] ,
2005-06-03 18:49:51 +04:00
get_segtype_from_string ( lv - > vg - > cmd ,
" striped " ) ,
2007-12-20 18:42:55 +03:00
0 , 0 , 0 , NULL ) ) {
2005-10-27 23:58:22 +04:00
log_error ( " Aborting. Failed to add mirror image segment "
2005-06-03 18:49:51 +04:00
" to %s. Remove new LV and retry. " ,
img_lvs [ m ] - > name ) ;
return 0 ;
}
}
2005-10-28 16:48:50 +04:00
return 1 ;
}
2007-12-20 18:42:55 +03:00
/*
* Remove mirrors from each segment .
* ' new_mirrors ' is the number of mirrors after the removal . ' 0 ' for linear .
* If ' status_mask ' is non - zero , the removal happens only when all segments
* has the status bits on .
2003-05-06 16:22:24 +04:00
*/
2007-12-20 18:42:55 +03:00
int remove_mirrors_from_segments ( struct logical_volume * lv ,
2009-11-25 01:55:55 +03:00
uint32_t new_mirrors , uint64_t status_mask )
2003-05-06 16:22:24 +04:00
{
struct lv_segment * seg ;
2007-12-20 18:42:55 +03:00
uint32_t s ;
2004-05-25 00:51:56 +04:00
2007-12-20 18:42:55 +03:00
/* Check the segment params are compatible */
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( seg , & lv - > segments ) {
2007-12-20 18:42:55 +03:00
if ( ! seg_is_mirrored ( seg ) ) {
log_error ( " Segment is not mirrored: %s:% " PRIu32 ,
lv - > name , seg - > le ) ;
return 0 ;
} if ( ( seg - > status & status_mask ) ! = status_mask ) {
log_error ( " Segment status does not match: %s:% " PRIu32
2009-11-25 01:55:55 +03:00
" status:0x% " PRIx64 " /0x% " PRIx64 , lv - > name , seg - > le ,
2007-12-20 18:42:55 +03:00
seg - > status , status_mask ) ;
return 0 ;
2004-08-18 02:09:02 +04:00
}
}
2003-05-06 16:22:24 +04:00
2007-12-20 18:42:55 +03:00
/* Convert the segments */
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( seg , & lv - > segments ) {
2007-12-20 18:42:55 +03:00
if ( ! new_mirrors & & seg - > extents_copied = = seg - > area_len ) {
if ( ! move_lv_segment_area ( seg , 0 , seg , 1 ) )
return_0 ;
2003-05-06 16:22:24 +04:00
}
2007-12-20 18:42:55 +03:00
for ( s = new_mirrors + 1 ; s < seg - > area_count ; s + + )
release_lv_segment_area ( seg , s , seg - > area_len ) ;
2005-06-14 21:54:48 +04:00
2007-12-20 18:42:55 +03:00
seg - > area_count = new_mirrors + 1 ;
2003-05-06 16:22:24 +04:00
2007-12-20 18:42:55 +03:00
if ( ! new_mirrors )
seg - > segtype = get_segtype_from_string ( lv - > vg - > cmd ,
" striped " ) ;
2005-06-14 21:54:48 +04:00
}
2004-08-18 02:09:02 +04:00
2003-05-06 16:22:24 +04:00
return 1 ;
}
2004-05-05 21:56:20 +04:00
const char * get_pvmove_pvname_from_lv_mirr ( struct logical_volume * lv_mirr )
2003-05-06 16:22:24 +04:00
{
struct lv_segment * seg ;
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( seg , & lv_mirr - > segments ) {
2005-05-09 20:59:01 +04:00
if ( ! seg_is_mirrored ( seg ) )
2003-05-06 16:22:24 +04:00
continue ;
2005-06-14 21:54:48 +04:00
if ( seg_type ( seg , 0 ) ! = AREA_PV )
2003-05-06 16:22:24 +04:00
continue ;
2005-06-01 20:51:55 +04:00
return dev_name ( seg_dev ( seg , 0 ) ) ;
2003-05-06 16:22:24 +04:00
}
return NULL ;
}
2004-05-05 21:56:20 +04:00
const char * get_pvmove_pvname_from_lv ( struct logical_volume * lv )
2003-05-06 16:22:24 +04:00
{
struct lv_segment * seg ;
uint32_t s ;
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( seg , & lv - > segments ) {
2003-05-06 16:22:24 +04:00
for ( s = 0 ; s < seg - > area_count ; s + + ) {
2005-06-01 20:51:55 +04:00
if ( seg_type ( seg , s ) ! = AREA_LV )
2003-05-06 16:22:24 +04:00
continue ;
2005-06-01 20:51:55 +04:00
return get_pvmove_pvname_from_lv_mirr ( seg_lv ( seg , s ) ) ;
2003-05-06 16:22:24 +04:00
}
}
return NULL ;
}
struct logical_volume * find_pvmove_lv ( struct volume_group * vg ,
2004-05-05 21:56:20 +04:00
struct device * dev ,
uint32_t lv_type )
2003-05-06 16:22:24 +04:00
{
2005-06-01 20:51:55 +04:00
struct lv_list * lvl ;
2003-05-06 16:22:24 +04:00
struct logical_volume * lv ;
struct lv_segment * seg ;
/* Loop through all LVs */
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( lvl , & vg - > lvs ) {
2005-06-01 20:51:55 +04:00
lv = lvl - > lv ;
2003-05-06 16:22:24 +04:00
2004-05-05 21:56:20 +04:00
if ( ! ( lv - > status & lv_type ) )
2003-05-06 16:22:24 +04:00
continue ;
2004-05-05 22:35:04 +04:00
/* Check segment origins point to pvname */
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( seg , & lv - > segments ) {
2005-06-14 21:54:48 +04:00
if ( seg_type ( seg , 0 ) ! = AREA_PV )
2003-05-06 16:22:24 +04:00
continue ;
2005-06-01 20:51:55 +04:00
if ( seg_dev ( seg , 0 ) ! = dev )
2003-05-06 16:22:24 +04:00
continue ;
return lv ;
}
}
return NULL ;
}
2004-05-05 21:56:20 +04:00
struct logical_volume * find_pvmove_lv_from_pvname ( struct cmd_context * cmd ,
2009-06-01 18:43:27 +04:00
struct volume_group * vg ,
const char * name ,
const char * uuid __attribute ( ( unused ) ) ,
uint32_t lv_type )
2004-05-05 21:56:20 +04:00
{
struct physical_volume * pv ;
2008-01-30 16:19:47 +03:00
if ( ! ( pv = find_pv_by_name ( cmd , name ) ) )
return_NULL ;
2004-05-05 21:56:20 +04:00
return find_pvmove_lv ( vg , pv - > dev , lv_type ) ;
}
2008-11-04 01:14:30 +03:00
struct dm_list * lvs_using_lv ( struct cmd_context * cmd , struct volume_group * vg ,
2003-05-06 16:22:24 +04:00
struct logical_volume * lv )
{
2008-11-04 01:14:30 +03:00
struct dm_list * lvs ;
2003-05-06 16:22:24 +04:00
struct logical_volume * lv1 ;
2005-06-01 20:51:55 +04:00
struct lv_list * lvl , * lvl1 ;
2003-05-06 16:22:24 +04:00
struct lv_segment * seg ;
uint32_t s ;
2005-10-17 03:03:59 +04:00
if ( ! ( lvs = dm_pool_alloc ( cmd - > mem , sizeof ( * lvs ) ) ) ) {
2003-05-06 16:22:24 +04:00
log_error ( " lvs list alloc failed " ) ;
return NULL ;
}
2008-11-04 01:14:30 +03:00
dm_list_init ( lvs ) ;
2003-05-06 16:22:24 +04:00
/* Loop through all LVs except the one supplied */
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( lvl1 , & vg - > lvs ) {
2005-06-01 20:51:55 +04:00
lv1 = lvl1 - > lv ;
2003-05-06 16:22:24 +04:00
if ( lv1 = = lv )
continue ;
2004-05-05 22:35:04 +04:00
/* Find whether any segment points at the supplied LV */
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( seg , & lv1 - > segments ) {
2003-05-06 16:22:24 +04:00
for ( s = 0 ; s < seg - > area_count ; s + + ) {
2005-06-01 20:51:55 +04:00
if ( seg_type ( seg , s ) ! = AREA_LV | |
seg_lv ( seg , s ) ! = lv )
2003-05-06 16:22:24 +04:00
continue ;
2005-10-17 03:03:59 +04:00
if ( ! ( lvl = dm_pool_alloc ( cmd - > mem , sizeof ( * lvl ) ) ) ) {
2003-05-06 16:22:24 +04:00
log_error ( " lv_list alloc failed " ) ;
return NULL ;
}
lvl - > lv = lv1 ;
2008-11-04 01:14:30 +03:00
dm_list_add ( lvs , & lvl - > list ) ;
2003-05-06 16:22:24 +04:00
goto next_lv ;
}
}
next_lv :
2003-07-05 02:34:56 +04:00
;
2003-05-06 16:22:24 +04:00
}
return lvs ;
}
2009-10-01 05:04:27 +04:00
float copy_percent ( struct logical_volume * lv_mirr ,
percent_range_t * percent_range )
2003-05-06 16:22:24 +04:00
{
uint32_t numerator = 0u , denominator = 0u ;
struct lv_segment * seg ;
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( seg , & lv_mirr - > segments ) {
2003-05-06 16:22:24 +04:00
denominator + = seg - > area_len ;
2004-05-05 21:56:20 +04:00
2008-01-16 22:18:51 +03:00
if ( seg_is_mirrored ( seg ) & & seg - > area_count > 1 )
2004-05-05 21:56:20 +04:00
numerator + = seg - > extents_copied ;
else
numerator + = seg - > area_len ;
2003-05-06 16:22:24 +04:00
}
2009-10-01 05:04:27 +04:00
if ( ! denominator | | ( numerator = = denominator ) )
* percent_range = PERCENT_100 ;
else if ( numerator = = 0 )
* percent_range = PERCENT_0 ;
else
* percent_range = PERCENT_0_TO_100 ;
2003-05-06 16:22:24 +04:00
return denominator ? ( float ) numerator * 100 / denominator : 100.0 ;
}
2005-10-28 01:51:28 +04:00
/*
* Fixup mirror pointers after single - pass segment import
*/
int fixup_imported_mirrors ( struct volume_group * vg )
{
struct lv_list * lvl ;
struct lv_segment * seg ;
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( lvl , & vg - > lvs ) {
dm_list_iterate_items ( seg , & lvl - > lv - > segments ) {
2005-10-28 01:51:28 +04:00
if ( seg - > segtype ! =
get_segtype_from_string ( vg - > cmd , " mirror " ) )
continue ;
2008-01-16 22:00:59 +03:00
if ( seg - > log_lv & & ! add_seg_to_segs_using_this_lv ( seg - > log_lv , seg ) )
return_0 ;
2005-10-28 01:51:28 +04:00
}
}
2005-10-28 16:48:50 +04:00
return 1 ;
2005-10-28 01:51:28 +04:00
}
2007-12-20 18:42:55 +03:00
/*
* Add mirrors to " linear " or " mirror " segments
*/
int add_mirrors_to_segments ( struct cmd_context * cmd , struct logical_volume * lv ,
uint32_t mirrors , uint32_t region_size ,
2008-11-04 01:14:30 +03:00
struct dm_list * allocatable_pvs , alloc_policy_t alloc )
2007-12-20 18:42:55 +03:00
{
struct alloc_handle * ah ;
const struct segment_type * segtype ;
2008-11-04 01:14:30 +03:00
struct dm_list * parallel_areas ;
2007-12-20 18:42:55 +03:00
uint32_t adjusted_region_size ;
2009-04-07 14:20:28 +04:00
int r = 1 ;
2007-12-20 18:42:55 +03:00
if ( ! ( parallel_areas = build_parallel_areas_from_lv ( cmd , lv ) ) )
return_0 ;
if ( ! ( segtype = get_segtype_from_string ( cmd , " mirror " ) ) )
return_0 ;
adjusted_region_size = adjusted_mirror_region_size ( lv - > vg - > extent_size ,
lv - > le_count ,
region_size ) ;
2008-12-19 18:24:52 +03:00
if ( ! ( ah = allocate_extents ( lv - > vg , NULL , segtype , 1 , mirrors , 0 , 0 ,
2007-12-20 18:42:55 +03:00
lv - > le_count , allocatable_pvs , alloc ,
parallel_areas ) ) ) {
log_error ( " Unable to allocate mirror extents for %s. " , lv - > name ) ;
return 0 ;
}
if ( ! lv_add_mirror_areas ( ah , lv , 0 , adjusted_region_size ) ) {
log_error ( " Failed to add mirror areas to %s " , lv - > name ) ;
2009-04-07 14:20:28 +04:00
r = 0 ;
2007-12-20 18:42:55 +03:00
}
2009-04-07 14:20:28 +04:00
alloc_destroy ( ah ) ;
return r ;
2007-12-20 18:42:55 +03:00
}
/*
* Convert mirror log
*
* FIXME : Can ' t handle segment - by - segment mirror ( like pvmove )
*/
int remove_mirror_log ( struct cmd_context * cmd ,
struct logical_volume * lv ,
2008-11-04 01:14:30 +03:00
struct dm_list * removable_pvs )
2007-12-20 18:42:55 +03:00
{
float sync_percent ;
2009-10-01 04:35:29 +04:00
percent_range_t percent_range = PERCENT_0 ;
2008-06-27 03:05:11 +04:00
struct lvinfo info ;
struct volume_group * vg = lv - > vg ;
2007-12-20 18:42:55 +03:00
/* Unimplemented features */
2008-11-04 01:14:30 +03:00
if ( dm_list_size ( & lv - > segments ) ! = 1 ) {
2007-12-20 18:42:55 +03:00
log_error ( " Multiple-segment mirror is not supported " ) ;
return 0 ;
}
/* Had disk log, switch to core. */
2008-06-27 03:05:11 +04:00
if ( lv_info ( cmd , lv , & info , 0 , 0 ) & & info . exists ) {
2009-10-01 04:35:29 +04:00
if ( ! lv_mirror_percent ( cmd , lv , 0 , & sync_percent ,
& percent_range , NULL ) ) {
2008-06-27 03:05:11 +04:00
log_error ( " Unable to determine mirror sync status. " ) ;
return 0 ;
}
} else if ( vg_is_clustered ( vg ) ) {
2009-10-14 18:55:44 +04:00
log_error ( " Unable to convert the log of an inactive "
" cluster mirror, %s " , lv - > name ) ;
2008-06-27 03:05:11 +04:00
return 0 ;
} else if ( yes_no_prompt ( " Full resync required to convert "
" inactive mirror %s to core log. "
2009-04-10 13:53:42 +04:00
" Proceed? [y/n]: " ) = = ' y ' )
2008-06-27 03:05:11 +04:00
sync_percent = 0 ;
else
2007-12-20 18:42:55 +03:00
return 0 ;
2009-10-01 04:35:29 +04:00
if ( percent_range = = PERCENT_100 )
2007-12-20 18:42:55 +03:00
init_mirror_in_sync ( 1 ) ;
else {
/* A full resync will take place */
lv - > status & = ~ MIRROR_NOTSYNCED ;
init_mirror_in_sync ( 0 ) ;
}
2007-12-20 21:55:46 +03:00
if ( ! remove_mirror_images ( lv , lv_mirror_count ( lv ) ,
2007-12-20 18:42:55 +03:00
removable_pvs , 1U ) )
return_0 ;
return 1 ;
}
2007-12-21 01:37:42 +03:00
static struct logical_volume * _create_mirror_log ( struct logical_volume * lv ,
struct alloc_handle * ah ,
alloc_policy_t alloc ,
2007-12-22 05:13:00 +03:00
const char * lv_name ,
const char * suffix )
2007-12-20 18:42:55 +03:00
{
struct logical_volume * log_lv ;
char * log_name ;
size_t len ;
len = strlen ( lv_name ) + 32 ;
if ( ! ( log_name = alloca ( len ) ) ) {
log_error ( " log_name allocation failed. " ) ;
return NULL ;
}
2008-01-31 15:19:36 +03:00
if ( dm_snprintf ( log_name , len , " %s%s " , lv_name , suffix ) < 0 ) {
2007-12-20 18:42:55 +03:00
log_error ( " log_name allocation failed. " ) ;
return NULL ;
}
if ( ! ( log_lv = lv_create_empty ( log_name , NULL ,
VISIBLE_LV | LVM_READ | LVM_WRITE ,
2009-05-14 01:28:31 +04:00
alloc , lv - > vg ) ) )
2007-12-20 18:42:55 +03:00
return_NULL ;
if ( ! lv_add_log_segment ( ah , log_lv ) )
return_NULL ;
return log_lv ;
}
static struct logical_volume * _set_up_mirror_log ( struct cmd_context * cmd ,
struct alloc_handle * ah ,
struct logical_volume * lv ,
uint32_t log_count ,
2007-12-21 01:37:42 +03:00
uint32_t region_size __attribute ( ( unused ) ) ,
2007-12-20 18:42:55 +03:00
alloc_policy_t alloc ,
int in_sync )
{
struct logical_volume * log_lv ;
2008-01-31 15:19:36 +03:00
const char * suffix , * c ;
char * lv_name ;
size_t len ;
2007-12-22 15:13:29 +03:00
struct lv_segment * seg ;
2007-12-20 18:42:55 +03:00
init_mirror_in_sync ( in_sync ) ;
2007-12-21 01:37:42 +03:00
if ( log_count ! = 1 ) {
log_error ( " log_count != 1 is not supported. " ) ;
return NULL ;
}
2008-01-31 15:19:36 +03:00
/* Mirror log name is lv_name + suffix, determined as the following:
* 1. suffix is :
* o " _mlog " for the original mirror LV .
* o " _mlogtmp_%d " for temporary mirror LV ,
* 2. lv_name is :
* o lv - > name , if the log is temporary
* o otherwise , the top - level LV name
*/
2007-12-22 15:13:29 +03:00
seg = first_seg ( lv ) ;
if ( seg_type ( seg , 0 ) = = AREA_LV & &
2008-01-31 15:19:36 +03:00
strstr ( seg_lv ( seg , 0 ) - > name , MIRROR_SYNC_LAYER ) ) {
lv_name = lv - > name ;
2007-12-22 15:13:29 +03:00
suffix = " _mlogtmp_%d " ;
2008-01-31 15:19:36 +03:00
} else if ( ( c = strstr ( lv - > name , MIRROR_SYNC_LAYER ) ) ) {
len = c - lv - > name + 1 ;
if ( ! ( lv_name = alloca ( len ) ) | |
! dm_snprintf ( lv_name , len , " %s " , lv - > name ) ) {
log_error ( " mirror log name allocation failed " ) ;
return 0 ;
}
suffix = " _mlog " ;
} else {
lv_name = lv - > name ;
2007-12-22 15:13:29 +03:00
suffix = " _mlog " ;
2008-01-31 15:19:36 +03:00
}
2007-12-22 15:13:29 +03:00
2008-01-31 15:19:36 +03:00
if ( ! ( log_lv = _create_mirror_log ( lv , ah , alloc ,
( const char * ) lv_name , suffix ) ) ) {
2007-12-20 18:42:55 +03:00
log_error ( " Failed to create mirror log. " ) ;
return NULL ;
}
2008-01-17 16:37:51 +03:00
if ( ! _init_mirror_log ( cmd , log_lv , in_sync , & lv - > tags , 1 ) ) {
2007-12-20 18:42:55 +03:00
log_error ( " Failed to create mirror log. " ) ;
return NULL ;
}
return log_lv ;
}
2008-01-26 03:25:04 +03:00
int attach_mirror_log ( struct lv_segment * seg , struct logical_volume * log_lv )
2007-12-20 18:42:55 +03:00
{
2008-01-26 03:25:04 +03:00
seg - > log_lv = log_lv ;
2007-12-20 18:42:55 +03:00
log_lv - > status | = MIRROR_LOG ;
2009-05-21 07:04:52 +04:00
lv_set_hidden ( log_lv ) ;
2008-01-26 03:25:04 +03:00
return add_seg_to_segs_using_this_lv ( log_lv , seg ) ;
2007-12-20 18:42:55 +03:00
}
2008-06-27 03:05:11 +04:00
int add_mirror_log ( struct cmd_context * cmd , struct logical_volume * lv ,
uint32_t log_count , uint32_t region_size ,
2008-11-04 01:14:30 +03:00
struct dm_list * allocatable_pvs , alloc_policy_t alloc )
2007-12-20 18:42:55 +03:00
{
struct alloc_handle * ah ;
const struct segment_type * segtype ;
2008-11-04 01:14:30 +03:00
struct dm_list * parallel_areas ;
2007-12-20 18:42:55 +03:00
float sync_percent ;
2009-10-01 04:35:29 +04:00
percent_range_t percent_range ;
2007-12-20 18:42:55 +03:00
int in_sync ;
struct logical_volume * log_lv ;
2008-06-27 03:05:11 +04:00
struct lvinfo info ;
2009-04-07 14:20:28 +04:00
int r = 0 ;
2007-12-20 18:42:55 +03:00
/* Unimplemented features */
if ( log_count > 1 ) {
log_error ( " log_count > 1 is not supported " ) ;
return 0 ;
}
2008-06-27 03:05:11 +04:00
2008-11-04 01:14:30 +03:00
if ( dm_list_size ( & lv - > segments ) ! = 1 ) {
2007-12-20 18:42:55 +03:00
log_error ( " Multiple-segment mirror is not supported " ) ;
return 0 ;
}
2008-06-27 03:05:11 +04:00
/*
* We are unable to convert the log of inactive cluster mirrors
* due to the inability to detect whether the mirror is active
* on remote nodes ( even though it is inactive on this node )
*/
if ( vg_is_clustered ( lv - > vg ) & &
! ( lv_info ( cmd , lv , & info , 0 , 0 ) & & info . exists ) ) {
log_error ( " Unable to convert the log of inactive "
" cluster mirror %s " , lv - > name ) ;
return 0 ;
}
2007-12-20 18:42:55 +03:00
if ( ! ( parallel_areas = build_parallel_areas_from_lv ( cmd , lv ) ) )
return_0 ;
if ( ! ( segtype = get_segtype_from_string ( cmd , " mirror " ) ) )
return_0 ;
if ( activation ( ) & & segtype - > ops - > target_present & &
2009-02-28 23:04:24 +03:00
! segtype - > ops - > target_present ( cmd , NULL , NULL ) ) {
2007-12-20 18:42:55 +03:00
log_error ( " %s: Required device-mapper target(s) not "
" detected in your kernel " , segtype - > name ) ;
return 0 ;
}
/* allocate destination extents */
ah = allocate_extents ( lv - > vg , NULL , segtype ,
2008-12-19 18:24:52 +03:00
0 , 0 , log_count , region_size , 0 ,
2007-12-20 18:42:55 +03:00
allocatable_pvs , alloc , parallel_areas ) ;
if ( ! ah ) {
2008-01-16 22:50:23 +03:00
log_error ( " Unable to allocate extents for mirror log. " ) ;
2007-12-20 18:42:55 +03:00
return 0 ;
}
/* check sync status */
2009-10-01 04:35:29 +04:00
if ( lv_mirror_percent ( cmd , lv , 0 , & sync_percent , & percent_range ,
NULL ) & &
( percent_range = = PERCENT_100 ) )
2007-12-20 18:42:55 +03:00
in_sync = 1 ;
else
in_sync = 0 ;
if ( ! ( log_lv = _set_up_mirror_log ( cmd , ah , lv , log_count ,
region_size , alloc , in_sync ) ) )
2009-04-07 14:20:28 +04:00
goto_out ;
2007-12-20 18:42:55 +03:00
2008-01-26 03:25:04 +03:00
if ( ! attach_mirror_log ( first_seg ( lv ) , log_lv ) )
2009-04-07 14:20:28 +04:00
goto_out ;
2007-12-20 18:42:55 +03:00
2009-04-07 14:20:28 +04:00
r = 1 ;
out :
2007-12-20 18:42:55 +03:00
alloc_destroy ( ah ) ;
2009-04-07 14:20:28 +04:00
return r ;
2007-12-20 18:42:55 +03:00
}
/*
* Convert " linear " LV to " mirror " .
*/
int add_mirror_images ( struct cmd_context * cmd , struct logical_volume * lv ,
uint32_t mirrors , uint32_t stripes , uint32_t region_size ,
2008-11-04 01:14:30 +03:00
struct dm_list * allocatable_pvs , alloc_policy_t alloc ,
2007-12-20 18:42:55 +03:00
uint32_t log_count )
{
struct alloc_handle * ah ;
const struct segment_type * segtype ;
2008-11-04 01:14:30 +03:00
struct dm_list * parallel_areas ;
2008-06-13 16:15:55 +04:00
struct logical_volume * * img_lvs ;
struct logical_volume * log_lv = NULL ;
2007-12-20 18:42:55 +03:00
if ( stripes > 1 ) {
log_error ( " stripes > 1 is not supported " ) ;
return 0 ;
}
/*
* allocate destination extents
*/
if ( ! ( parallel_areas = build_parallel_areas_from_lv ( cmd , lv ) ) )
return_0 ;
if ( ! ( segtype = get_segtype_from_string ( cmd , " mirror " ) ) )
return_0 ;
ah = allocate_extents ( lv - > vg , NULL , segtype ,
2008-12-19 18:24:52 +03:00
stripes , mirrors , log_count , region_size , lv - > le_count ,
2007-12-20 18:42:55 +03:00
allocatable_pvs , alloc , parallel_areas ) ;
if ( ! ah ) {
log_error ( " Unable to allocate extents for mirror(s). " ) ;
return 0 ;
}
/*
* create and initialize mirror log
*/
if ( log_count & &
2008-01-19 01:02:37 +03:00
! ( log_lv = _set_up_mirror_log ( cmd , ah , lv , log_count , region_size ,
2009-04-07 14:20:28 +04:00
alloc , mirror_in_sync ( ) ) ) ) {
stack ;
2009-05-21 07:04:52 +04:00
goto out_remove_images ;
2009-04-07 14:20:28 +04:00
}
2007-12-20 18:42:55 +03:00
/* The log initialization involves vg metadata commit.
So from here on , if failure occurs , the log must be explicitly
removed and the updated vg metadata should be committed . */
/*
* insert a mirror layer
*/
2008-11-04 01:14:30 +03:00
if ( dm_list_size ( & lv - > segments ) ! = 1 | |
2007-12-20 18:42:55 +03:00
seg_type ( first_seg ( lv ) , 0 ) ! = AREA_LV )
if ( ! insert_layer_for_lv ( cmd , lv , 0 , " _mimage_%d " ) )
goto out_remove_log ;
/*
* create mirror image LVs
*/
if ( ! ( img_lvs = alloca ( sizeof ( * img_lvs ) * mirrors ) ) ) {
log_error ( " img_lvs allocation failed. "
" Remove new LV and retry. " ) ;
goto out_remove_log ;
}
if ( ! _create_mimage_lvs ( ah , mirrors , lv , img_lvs ) )
goto out_remove_log ;
if ( ! lv_add_mirror_lvs ( lv , img_lvs , mirrors ,
MIRROR_IMAGE | ( lv - > status & LOCKED ) ,
region_size ) ) {
log_error ( " Aborting. Failed to add mirror segment. "
" Remove new LV and retry. " ) ;
2009-05-21 07:04:52 +04:00
goto out_remove_images ;
2007-12-20 18:42:55 +03:00
}
2008-01-26 03:25:04 +03:00
if ( log_count & & ! attach_mirror_log ( first_seg ( lv ) , log_lv ) )
stack ;
2007-12-20 18:42:55 +03:00
alloc_destroy ( ah ) ;
return 1 ;
out_remove_log :
2009-04-21 18:31:57 +04:00
if ( log_lv ) {
if ( ! lv_remove ( log_lv ) | |
! vg_write ( log_lv - > vg ) | |
! vg_commit ( log_lv - > vg ) )
log_error ( " Manual intervention may be required to remove "
" abandoned log LV before retrying. " ) ;
else
backup ( log_lv - > vg ) ;
}
2009-05-21 07:04:52 +04:00
out_remove_images :
2009-04-07 14:20:28 +04:00
alloc_destroy ( ah ) ;
2007-12-20 18:42:55 +03:00
return 0 ;
}
/*
* Generic interface for adding mirror and / or mirror log .
* ' mirror ' is the number of mirrors to be added .
* ' pvs ' is either allocatable pvs .
*/
int lv_add_mirrors ( struct cmd_context * cmd , struct logical_volume * lv ,
uint32_t mirrors , uint32_t stripes ,
uint32_t region_size , uint32_t log_count ,
2008-11-04 01:14:30 +03:00
struct dm_list * pvs , alloc_policy_t alloc , uint32_t flags )
2007-12-20 18:42:55 +03:00
{
if ( ! mirrors & & ! log_count ) {
log_error ( " No conversion is requested " ) ;
return 0 ;
}
2008-01-10 21:35:51 +03:00
/* For corelog mirror, activation code depends on
* the global mirror_in_sync status . As we are adding
* a new mirror , it should be set as ' out - of - sync '
* so that the sync starts . */
2008-01-19 01:02:37 +03:00
/* However, MIRROR_SKIP_INIT_SYNC even overrides it. */
if ( flags & MIRROR_SKIP_INIT_SYNC )
init_mirror_in_sync ( 1 ) ;
else if ( ! log_count )
2008-01-10 21:35:51 +03:00
init_mirror_in_sync ( 0 ) ;
2007-12-20 18:42:55 +03:00
if ( flags & MIRROR_BY_SEG ) {
if ( log_count ) {
log_error ( " Persistent log is not supported on "
" segment-by-segment mirroring " ) ;
return 0 ;
}
if ( stripes > 1 ) {
log_error ( " Striped-mirroring is not supported on "
" segment-by-segment mirroring " ) ;
return 0 ;
}
return add_mirrors_to_segments ( cmd , lv , mirrors ,
region_size , pvs , alloc ) ;
} else if ( flags & MIRROR_BY_LV ) {
if ( ! mirrors )
return add_mirror_log ( cmd , lv , log_count ,
region_size , pvs , alloc ) ;
return add_mirror_images ( cmd , lv , mirrors ,
stripes , region_size ,
pvs , alloc , log_count ) ;
}
log_error ( " Unsupported mirror conversion type " ) ;
return 0 ;
}
/*
* Generic interface for removing mirror and / or mirror log .
* ' mirror ' is the number of mirrors to be removed .
* ' pvs ' is removable pvs .
*/
2007-12-21 01:37:42 +03:00
int lv_remove_mirrors ( struct cmd_context * cmd __attribute ( ( unused ) ) ,
struct logical_volume * lv ,
2008-11-04 01:14:30 +03:00
uint32_t mirrors , uint32_t log_count , struct dm_list * pvs ,
2009-11-25 01:55:55 +03:00
uint64_t status_mask )
2007-12-20 18:42:55 +03:00
{
uint32_t new_mirrors ;
struct lv_segment * seg ;
if ( ! mirrors & & ! log_count ) {
log_error ( " No conversion is requested " ) ;
return 0 ;
}
seg = first_seg ( lv ) ;
if ( ! seg_is_mirrored ( seg ) ) {
log_error ( " Not a mirror segment " ) ;
return 0 ;
}
2007-12-20 21:55:46 +03:00
if ( lv_mirror_count ( lv ) < = mirrors ) {
2007-12-20 18:42:55 +03:00
log_error ( " Removing more than existing: %d <= %d " ,
seg - > area_count , mirrors ) ;
return 0 ;
}
2007-12-20 21:55:46 +03:00
new_mirrors = lv_mirror_count ( lv ) - mirrors - 1 ;
2007-12-20 18:42:55 +03:00
/* MIRROR_BY_LV */
if ( seg_type ( seg , 0 ) = = AREA_LV & &
2008-01-17 20:17:09 +03:00
seg_lv ( seg , 0 ) - > status & MIRROR_IMAGE )
2007-12-20 21:55:46 +03:00
return remove_mirror_images ( lv , new_mirrors + 1 ,
2007-12-20 18:42:55 +03:00
pvs , log_count ? 1U : 0 ) ;
/* MIRROR_BY_SEG */
if ( log_count ) {
log_error ( " Persistent log is not supported on "
" segment-by-segment mirroring " ) ;
return 0 ;
}
return remove_mirrors_from_segments ( lv , new_mirrors , status_mask ) ;
}