2002-01-07 18:08:28 +03:00
/*
2004-03-30 23:35:44 +04:00
* Copyright ( C ) 2001 - 2004 Sistina Software , Inc . All rights reserved .
2007-08-21 00:55:30 +04:00
* Copyright ( C ) 2004 - 2007 Red Hat , Inc . All rights reserved .
2002-01-07 18:08:28 +03: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
2002-01-07 18:08:28 +03:00
*/
2002-11-18 17:04:08 +03:00
# include "lib.h"
2002-01-10 21:12:26 +03:00
# include "metadata.h"
2003-09-15 22:22:50 +04:00
# include "toolcontext.h"
# include "lv_alloc.h"
2005-05-03 21:28:23 +04:00
# include "pv_alloc.h"
2004-03-08 20:19:15 +03:00
# include "str_list.h"
2004-09-16 22:40:56 +04:00
# include "segtype.h"
2003-09-01 23:55:16 +04:00
/*
* Attempt to merge two adjacent segments .
2004-05-05 01:25:57 +04:00
* Currently only supports striped segments on AREA_PV .
2008-01-30 17:00:02 +03:00
* Returns success if successful , in which case ' first '
2003-09-01 23:55:16 +04:00
* gets adjusted to contain both areas .
*/
static int _merge ( struct lv_segment * first , struct lv_segment * second )
{
2004-05-05 01:25:57 +04:00
if ( ! first | | ! second | | first - > segtype ! = second - > segtype | |
2010-04-09 05:00:10 +04:00
! first - > segtype - > ops - > merge_segments )
return 0 ;
2003-09-01 23:55:16 +04:00
2004-05-05 01:25:57 +04:00
return first - > segtype - > ops - > merge_segments ( first , second ) ;
2002-01-07 18:08:28 +03:00
}
2002-01-10 14:18:08 +03:00
int lv_merge_segments ( struct logical_volume * lv )
2002-01-07 18:08:28 +03:00
{
2008-11-04 01:14:30 +03:00
struct dm_list * segh , * t ;
2002-11-18 17:04:08 +03:00
struct lv_segment * current , * prev = NULL ;
2002-01-07 18:08:28 +03:00
2004-08-18 02:09:02 +04:00
if ( lv - > status & LOCKED | | lv - > status & PVMOVE )
return 1 ;
2008-11-04 01:14:30 +03:00
dm_list_iterate_safe ( segh , t , & lv - > segments ) {
current = dm_list_item ( segh , struct lv_segment ) ;
2002-01-07 18:08:28 +03:00
if ( _merge ( prev , current ) )
2008-11-04 01:14:30 +03:00
dm_list_del ( & current - > list ) ;
2002-01-07 18:08:28 +03:00
else
prev = current ;
}
return 1 ;
}
2010-04-01 16:14:20 +04:00
# define ERROR_MAX 100
# define inc_error_count \
if ( error_count + + > ERROR_MAX ) \
goto out
2003-09-01 23:55:16 +04:00
/*
* Verify that an LV ' s segments are consecutive , complete and don ' t overlap .
*/
2005-10-28 01:51:28 +04:00
int check_lv_segments ( struct logical_volume * lv , int complete_vg )
2002-01-11 02:21:07 +03:00
{
2005-10-28 01:51:28 +04:00
struct lv_segment * seg , * seg2 ;
2003-09-01 23:55:16 +04:00
uint32_t le = 0 ;
2008-01-16 22:00:59 +03:00
unsigned seg_count = 0 , seg_found ;
2005-06-01 20:51:55 +04:00
uint32_t area_multiplier , s ;
2008-01-16 22:00:59 +03:00
struct seg_list * sl ;
2010-04-01 16:14:20 +04:00
int error_count = 0 ;
2010-05-21 16:36:30 +04:00
struct replicator_site * rsite ;
struct replicator_device * rdev ;
2003-09-01 23:55:16 +04:00
2011-09-08 20:41:18 +04:00
/* Check LV flags match first segment type */
if ( complete_vg ) {
if ( lv_is_thin_volume ( lv ) & &
( ! ( seg2 = first_seg ( lv ) ) | | ! seg_is_thin_volume ( seg2 ) ) ) {
log_error ( " LV %s is thin volume without first thin volume segment " ,
lv - > name ) ;
inc_error_count ;
}
if ( lv_is_thin_pool ( lv ) & &
( ! ( seg2 = first_seg ( lv ) ) | | ! seg_is_thin_pool ( seg2 ) ) ) {
log_error ( " LV %s is thin pool without first thin pool segment " ,
lv - > name ) ;
inc_error_count ;
}
if ( lv_is_thin_pool_data ( lv ) & &
( ! ( seg2 = first_seg ( lv ) ) | | ! ( seg2 = find_pool_seg ( seg2 ) ) | |
seg2 - > area_count ! = 1 | | seg_type ( seg2 , 0 ) ! = AREA_LV | |
seg_lv ( seg2 , 0 ) ! = lv ) ) {
log_error ( " LV %s: segment 1 pool data LV does not point back to same LV " ,
lv - > name ) ;
inc_error_count ;
}
if ( lv_is_thin_pool_metadata ( lv ) & &
( ! ( seg2 = first_seg ( lv ) ) | | ! ( seg2 = find_pool_seg ( seg2 ) ) | |
2012-01-19 19:23:50 +04:00
seg2 - > metadata_lv ! = lv ) ) {
2011-09-08 20:41:18 +04:00
log_error ( " LV %s: segment 1 pool metadata LV does not point back to same LV " ,
lv - > name ) ;
inc_error_count ;
}
}
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( seg , & lv - > segments ) {
2003-09-01 23:55:16 +04:00
seg_count + + ;
if ( seg - > le ! = le ) {
log_error ( " LV %s invalid: segment %u should begin at "
" LE % " PRIu32 " (found % " PRIu32 " ). " ,
lv - > name , seg_count , le , seg - > le ) ;
2010-04-01 16:14:20 +04:00
inc_error_count ;
2005-06-01 20:51:55 +04:00
}
2008-01-30 17:00:02 +03:00
area_multiplier = segtype_is_striped ( seg - > segtype ) ?
2005-06-01 20:51:55 +04:00
seg - > area_count : 1 ;
if ( seg - > area_len * area_multiplier ! = seg - > len ) {
log_error ( " LV %s: segment %u has inconsistent "
" area_len %u " ,
lv - > name , seg_count , seg - > area_len ) ;
2010-04-01 16:14:20 +04:00
inc_error_count ;
2005-06-01 20:51:55 +04:00
}
2011-08-03 02:07:20 +04:00
if ( complete_vg & & seg - > log_lv & &
! seg_is_mirrored ( seg ) & & ! ( seg - > status & RAID_IMAGE ) ) {
log_error ( " LV %s: segment %u log LV %s is not a "
" mirror log or a RAID image " ,
lv - > name , seg_count , seg - > log_lv - > name ) ;
inc_error_count ;
}
2005-10-27 23:58:22 +04:00
2011-08-03 02:07:20 +04:00
/*
* Check mirror log - which is attached to the mirrored seg
*/
if ( complete_vg & & seg - > log_lv & & seg_is_mirrored ( seg ) ) {
2005-10-27 23:58:22 +04:00
if ( ! ( seg - > log_lv - > status & MIRROR_LOG ) ) {
log_error ( " LV %s: segment %u log LV %s is not "
" a mirror log " ,
2011-08-03 02:07:20 +04:00
lv - > name , seg_count , seg - > log_lv - > name ) ;
2010-04-01 16:14:20 +04:00
inc_error_count ;
2005-10-27 23:58:22 +04:00
}
2005-10-28 16:48:50 +04:00
if ( ! ( seg2 = first_seg ( seg - > log_lv ) ) | |
2008-01-16 22:00:59 +03:00
find_mirror_seg ( seg2 ) ! = seg ) {
2005-10-27 23:58:22 +04:00
log_error ( " LV %s: segment %u log LV does not "
" point back to mirror segment " ,
2011-08-03 02:07:20 +04:00
lv - > name , seg_count ) ;
2010-04-01 16:14:20 +04:00
inc_error_count ;
2005-10-27 23:58:22 +04:00
}
}
2005-10-28 01:51:28 +04:00
if ( complete_vg & & seg - > status & MIRROR_IMAGE ) {
2008-01-16 22:00:59 +03:00
if ( ! find_mirror_seg ( seg ) | |
! seg_is_mirrored ( find_mirror_seg ( seg ) ) ) {
2005-10-27 23:58:22 +04:00
log_error ( " LV %s: segment %u mirror image "
" is not mirrored " ,
lv - > name , seg_count ) ;
2010-04-01 16:14:20 +04:00
inc_error_count ;
2005-10-27 23:58:22 +04:00
}
}
2011-09-08 20:41:18 +04:00
/* Check the various thin segment types */
if ( complete_vg ) {
if ( seg_is_thin_pool ( seg ) ) {
if ( ! lv_is_thin_pool ( lv ) ) {
log_error ( " LV %s is missing thin pool flag for segment %u " ,
lv - > name , seg_count ) ;
inc_error_count ;
}
if ( lv_is_thin_volume ( lv ) ) {
log_error ( " LV %s is a thin volume that must not contain thin pool segment %u " ,
lv - > name , seg_count ) ;
inc_error_count ;
}
if ( seg - > area_count ! = 1 | | seg_type ( seg , 0 ) ! = AREA_LV ) {
log_error ( " LV %s: thin pool segment %u is missing a pool data LV " ,
lv - > name , seg_count ) ;
inc_error_count ;
} else if ( ! ( seg2 = first_seg ( seg_lv ( seg , 0 ) ) ) | | find_pool_seg ( seg2 ) ! = seg ) {
log_error ( " LV %s: thin pool segment %u data LV does not refer back to pool LV " ,
lv - > name , seg_count ) ;
inc_error_count ;
}
2012-01-19 19:23:50 +04:00
if ( ! seg - > metadata_lv ) {
2011-09-08 20:41:18 +04:00
log_error ( " LV %s: thin pool segment %u is missing a pool metadata LV " ,
lv - > name , seg_count ) ;
inc_error_count ;
2012-01-19 19:23:50 +04:00
} else if ( ! ( seg2 = first_seg ( seg - > metadata_lv ) ) | |
2011-09-08 20:41:18 +04:00
find_pool_seg ( seg2 ) ! = seg ) {
log_error ( " LV %s: thin pool segment %u metadata LV does not refer back to pool LV " ,
lv - > name , seg_count ) ;
inc_error_count ;
}
2011-09-29 12:56:38 +04:00
2012-01-24 04:55:03 +04:00
if ( seg - > chunk_size < DM_THIN_MIN_DATA_BLOCK_SIZE | |
seg - > chunk_size > DM_THIN_MAX_DATA_BLOCK_SIZE ) {
2012-03-12 18:41:42 +04:00
log_error ( " LV %s: thin pool segment %u has chunk size %u out of range. " ,
2012-01-24 04:55:03 +04:00
lv - > name , seg_count , seg - > chunk_size ) ;
2011-09-29 12:56:38 +04:00
inc_error_count ;
}
2011-09-08 20:41:18 +04:00
} else {
2012-01-19 19:23:50 +04:00
if ( seg - > metadata_lv ) {
2011-09-08 20:41:18 +04:00
log_error ( " LV %s: segment %u must not have thin pool metadata LV set " ,
lv - > name , seg_count ) ;
inc_error_count ;
}
}
if ( seg_is_thin_volume ( seg ) ) {
if ( ! lv_is_thin_volume ( lv ) ) {
log_error ( " LV %s is missing thin volume flag for segment %u " ,
lv - > name , seg_count ) ;
inc_error_count ;
}
if ( lv_is_thin_pool ( lv ) ) {
log_error ( " LV %s is a thin pool that must not contain thin volume segment %u " ,
lv - > name , seg_count ) ;
inc_error_count ;
}
2011-09-16 15:53:14 +04:00
if ( ! seg - > pool_lv ) {
2011-09-08 20:41:18 +04:00
log_error ( " LV %s: segment %u is missing thin pool LV " ,
lv - > name , seg_count ) ;
inc_error_count ;
} else if ( ! lv_is_thin_pool ( seg - > pool_lv ) ) {
log_error ( " LV %s: thin volume segment %u pool LV is not flagged as a pool LV " ,
lv - > name , seg_count ) ;
inc_error_count ;
}
2011-09-29 12:56:38 +04:00
2011-10-06 15:05:56 +04:00
if ( seg - > device_id > DM_THIN_MAX_DEVICE_ID ) {
2012-03-12 18:41:42 +04:00
log_error ( " LV %s: thin volume segment %u has too large device id %u " ,
2011-09-29 12:56:38 +04:00
lv - > name , seg_count , seg - > device_id ) ;
inc_error_count ;
}
2011-09-08 20:41:18 +04:00
} else {
2011-09-16 15:53:14 +04:00
if ( seg - > pool_lv ) {
2011-09-08 20:41:18 +04:00
log_error ( " LV %s: segment %u must not have thin pool LV set " ,
lv - > name , seg_count ) ;
inc_error_count ;
}
}
}
2007-11-07 19:33:12 +03:00
if ( seg_is_snapshot ( seg ) ) {
if ( seg - > cow & & seg - > cow = = seg - > origin ) {
log_error ( " LV %s: segment %u has same LV %s for "
" both origin and snapshot " ,
lv - > name , seg_count , seg - > cow - > name ) ;
2010-04-01 16:14:20 +04:00
inc_error_count ;
2007-11-07 19:33:12 +03:00
}
}
2010-05-21 16:43:02 +04:00
if ( seg_is_replicator ( seg ) & & ! check_replicator_segment ( seg ) )
inc_error_count ;
2005-06-01 20:51:55 +04:00
for ( s = 0 ; s < seg - > area_count ; s + + ) {
2005-06-14 21:54:48 +04:00
if ( seg_type ( seg , s ) = = AREA_UNASSIGNED ) {
log_error ( " LV %s: segment %u has unassigned "
" area %u. " ,
lv - > name , seg_count , s ) ;
2010-04-01 16:14:20 +04:00
inc_error_count ;
2005-06-14 21:54:48 +04:00
} else if ( seg_type ( seg , s ) = = AREA_PV ) {
2005-06-01 20:51:55 +04:00
if ( ! seg_pvseg ( seg , s ) | |
seg_pvseg ( seg , s ) - > lvseg ! = seg | |
seg_pvseg ( seg , s ) - > lv_area ! = s ) {
log_error ( " LV %s: segment %u has "
" inconsistent PV area %u " ,
lv - > name , seg_count , s ) ;
2010-04-01 16:14:20 +04:00
inc_error_count ;
2005-06-01 20:51:55 +04:00
}
} else {
if ( ! seg_lv ( seg , s ) | |
seg_lv ( seg , s ) - > vg ! = lv - > vg | |
seg_lv ( seg , s ) = = lv ) {
log_error ( " LV %s: segment %u has "
" inconsistent LV area %u " ,
lv - > name , seg_count , s ) ;
2010-04-01 16:14:20 +04:00
inc_error_count ;
2005-06-01 20:51:55 +04:00
}
2005-10-27 23:58:22 +04:00
2005-10-28 01:51:28 +04:00
if ( complete_vg & & seg_lv ( seg , s ) & &
2005-10-27 23:58:22 +04:00
( seg_lv ( seg , s ) - > status & MIRROR_IMAGE ) & &
2007-07-10 22:50:03 +04:00
( ! ( seg2 = find_seg_by_le ( seg_lv ( seg , s ) ,
seg_le ( seg , s ) ) ) | |
2008-01-16 22:00:59 +03:00
find_mirror_seg ( seg2 ) ! = seg ) ) {
2005-10-27 23:58:22 +04:00
log_error ( " LV %s: segment %u mirror "
" image %u missing mirror ptr " ,
lv - > name , seg_count , s ) ;
2010-04-01 16:14:20 +04:00
inc_error_count ;
2005-10-27 23:58:22 +04:00
}
2005-06-14 21:54:48 +04:00
/* FIXME I don't think this ever holds?
2005-06-01 20:51:55 +04:00
if ( seg_le ( seg , s ) ! = le ) {
log_error ( " LV %s: segment %u has "
" inconsistent LV area %u "
" size " ,
lv - > name , seg_count , s ) ;
2010-04-01 16:14:20 +04:00
inc_error_count ;
2005-06-01 20:51:55 +04:00
}
2005-06-14 21:54:48 +04:00
*/
2008-01-16 22:00:59 +03:00
seg_found = 0 ;
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( sl , & seg_lv ( seg , s ) - > segs_using_this_lv )
2008-01-16 22:00:59 +03:00
if ( sl - > seg = = seg )
seg_found + + ;
2011-08-03 02:07:20 +04:00
2008-01-16 22:00:59 +03:00
if ( ! seg_found ) {
2012-03-12 18:41:42 +04:00
log_error ( " LV %s segment %u uses LV %s, "
2008-01-16 22:00:59 +03:00
" but missing ptr from %s to %s " ,
lv - > name , seg_count ,
seg_lv ( seg , s ) - > name ,
seg_lv ( seg , s ) - > name , lv - > name ) ;
2010-04-01 16:14:20 +04:00
inc_error_count ;
2008-01-16 22:00:59 +03:00
} else if ( seg_found > 1 ) {
log_error ( " LV %s has duplicated links "
2012-03-12 18:41:42 +04:00
" to LV %s segment %u " ,
2008-01-16 22:00:59 +03:00
seg_lv ( seg , s ) - > name ,
lv - > name , seg_count ) ;
2010-04-01 16:14:20 +04:00
inc_error_count ;
2008-01-16 22:00:59 +03:00
}
2005-06-01 20:51:55 +04:00
}
2011-06-09 23:36:16 +04:00
2011-08-03 02:07:20 +04:00
if ( complete_vg & &
seg_is_mirrored ( seg ) & & ! seg_is_raid ( seg ) & &
2011-06-09 23:36:16 +04:00
seg_type ( seg , s ) = = AREA_LV & &
seg_lv ( seg , s ) - > le_count ! = seg - > area_len ) {
log_error ( " LV %s: mirrored LV segment %u has "
" wrong size %u (should be %u). " ,
lv - > name , s , seg_lv ( seg , s ) - > le_count ,
seg - > area_len ) ;
inc_error_count ;
}
2003-09-01 23:55:16 +04:00
}
le + = seg - > len ;
}
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( sl , & lv - > segs_using_this_lv ) {
2008-01-16 22:00:59 +03:00
seg = sl - > seg ;
seg_found = 0 ;
for ( s = 0 ; s < seg - > area_count ; s + + ) {
if ( seg_type ( seg , s ) ! = AREA_LV )
continue ;
if ( lv = = seg_lv ( seg , s ) )
seg_found + + ;
2011-08-03 02:07:20 +04:00
if ( seg_is_raid ( seg ) & & ( lv = = seg_metalv ( seg , s ) ) )
seg_found + + ;
2008-01-16 22:00:59 +03:00
}
2010-05-21 16:36:30 +04:00
if ( seg_is_replicator_dev ( seg ) ) {
dm_list_iterate_items ( rsite , & seg - > replicator - > rsites ) {
dm_list_iterate_items ( rdev , & rsite - > rdevices ) {
if ( lv = = rdev - > lv | | lv = = rdev - > slog )
seg_found + + ;
}
}
if ( lv = = seg - > replicator )
seg_found + + ;
}
if ( seg_is_replicator ( seg ) & & lv = = seg - > rlog_lv )
seg_found + + ;
2008-01-16 22:00:59 +03:00
if ( seg - > log_lv = = lv )
seg_found + + ;
2012-01-19 19:23:50 +04:00
if ( seg - > metadata_lv = = lv | | seg - > pool_lv = = lv )
2011-09-08 20:41:18 +04:00
seg_found + + ;
2011-11-07 15:03:47 +04:00
if ( seg_is_thin_volume ( seg ) & & seg - > origin = = lv )
seg_found + + ;
2008-01-16 22:00:59 +03:00
if ( ! seg_found ) {
2008-01-26 03:30:28 +03:00
log_error ( " LV %s is used by LV %s:% " PRIu32 " -% " PRIu32
" , but missing ptr from %s to %s " ,
2008-01-16 22:00:59 +03:00
lv - > name , seg - > lv - > name , seg - > le ,
2008-01-26 03:30:28 +03:00
seg - > le + seg - > len - 1 ,
2008-01-16 22:00:59 +03:00
seg - > lv - > name , lv - > name ) ;
2010-04-01 16:14:20 +04:00
inc_error_count ;
2008-01-16 22:00:59 +03:00
} else if ( seg_found ! = sl - > count ) {
2012-03-12 18:41:42 +04:00
log_error ( " Reference count mismatch: LV %s has %u "
2008-01-26 03:30:28 +03:00
" links to LV %s:% " PRIu32 " -% " PRIu32
2012-03-12 18:41:42 +04:00
" , which has %u links " ,
2008-01-26 03:30:28 +03:00
lv - > name , sl - > count , seg - > lv - > name , seg - > le ,
seg - > le + seg - > len - 1 , seg_found ) ;
2010-04-01 16:14:20 +04:00
inc_error_count ;
2008-01-16 22:00:59 +03:00
}
2008-02-22 16:22:44 +03:00
seg_found = 0 ;
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( seg2 , & seg - > lv - > segments )
2008-02-22 16:22:44 +03:00
if ( sl - > seg = = seg2 ) {
seg_found + + ;
break ;
}
if ( ! seg_found ) {
log_error ( " LV segment %s:% " PRIu32 " -% " PRIu32
2010-03-31 16:06:30 +04:00
" is incorrectly listed as being used by LV %s " ,
2008-02-22 16:22:44 +03:00
seg - > lv - > name , seg - > le , seg - > le + seg - > len - 1 ,
lv - > name ) ;
2010-04-01 16:14:20 +04:00
inc_error_count ;
2008-02-22 16:22:44 +03:00
}
2008-01-16 22:00:59 +03:00
}
2005-06-01 20:51:55 +04:00
if ( le ! = lv - > le_count ) {
log_error ( " LV %s: inconsistent LE count %u != %u " ,
lv - > name , le , lv - > le_count ) ;
2010-04-01 16:14:20 +04:00
inc_error_count ;
2005-06-01 20:51:55 +04:00
}
2010-04-01 16:14:20 +04:00
out :
return ! error_count ;
2002-01-11 02:21:07 +03:00
}
2003-09-01 23:55:16 +04:00
2003-09-15 22:22:50 +04:00
/*
* Split the supplied segment at the supplied logical extent
2004-08-18 02:09:02 +04:00
* NB Use LE numbering that works across stripes PV1 : 0 , 2 , 4 PV2 : 1 , 3 , 5 etc .
2003-09-15 22:22:50 +04:00
*/
static int _lv_split_segment ( struct logical_volume * lv , struct lv_segment * seg ,
uint32_t le )
{
struct lv_segment * split_seg ;
uint32_t s ;
uint32_t offset = le - seg - > le ;
2004-08-18 02:09:02 +04:00
uint32_t area_offset ;
2003-09-15 22:22:50 +04:00
2005-05-09 20:59:01 +04:00
if ( ! seg_can_split ( seg ) ) {
2004-05-05 01:25:57 +04:00
log_error ( " Unable to split the %s segment at LE % " PRIu32
" in LV %s " , seg - > segtype - > name , le , lv - > name ) ;
2003-09-15 22:22:50 +04:00
return 0 ;
}
/* Clone the existing segment */
2011-10-23 20:02:01 +04:00
if ( ! ( split_seg = alloc_lv_segment ( seg - > segtype ,
2005-04-22 19:44:00 +04:00
seg - > lv , seg - > le , seg - > len ,
seg - > status , seg - > stripe_size ,
2011-09-07 02:43:56 +04:00
seg - > log_lv , seg - > pool_lv ,
2005-04-22 19:44:00 +04:00
seg - > area_count , seg - > area_len ,
2005-06-01 20:51:55 +04:00
seg - > chunk_size , seg - > region_size ,
2010-04-08 04:28:57 +04:00
seg - > extents_copied , seg - > pvmove_source_seg ) ) ) {
2005-04-22 19:44:00 +04:00
log_error ( " Couldn't allocate cloned LV segment. " ) ;
2003-09-15 22:22:50 +04:00
return 0 ;
}
2010-03-31 21:23:18 +04:00
if ( ! str_list_dup ( lv - > vg - > vgmem , & split_seg - > tags , & seg - > tags ) ) {
2004-03-08 20:19:15 +03:00
log_error ( " LV segment tags duplication failed " ) ;
return 0 ;
}
2003-09-15 22:22:50 +04:00
/* In case of a striped segment, the offset has to be / stripes */
2004-08-18 02:09:02 +04:00
area_offset = offset ;
2005-05-09 20:59:01 +04:00
if ( seg_is_striped ( seg ) )
2004-08-18 02:09:02 +04:00
area_offset / = seg - > area_count ;
2003-09-15 22:22:50 +04:00
2005-05-03 21:28:23 +04:00
split_seg - > area_len - = area_offset ;
seg - > area_len = area_offset ;
split_seg - > len - = offset ;
seg - > len = offset ;
split_seg - > le = seg - > le + seg - > len ;
2003-09-15 22:22:50 +04:00
/* Adjust the PV mapping */
for ( s = 0 ; s < seg - > area_count ; s + + ) {
2005-06-01 20:51:55 +04:00
seg_type ( split_seg , s ) = seg_type ( seg , s ) ;
2005-05-03 21:28:23 +04:00
2003-09-15 22:22:50 +04:00
/* Split area at the offset */
2005-06-01 20:51:55 +04:00
switch ( seg_type ( seg , s ) ) {
2003-09-15 22:22:50 +04:00
case AREA_LV :
2008-01-16 22:00:59 +03:00
if ( ! set_lv_segment_area_lv ( split_seg , s , seg_lv ( seg , s ) ,
seg_le ( seg , s ) + seg - > area_len , 0 ) )
return_0 ;
2004-08-18 02:09:02 +04:00
log_debug ( " Split %s:%u[%u] at %u: %s LE %u " , lv - > name ,
2005-06-01 20:51:55 +04:00
seg - > le , s , le , seg_lv ( seg , s ) - > name ,
seg_le ( split_seg , s ) ) ;
2003-09-15 22:22:50 +04:00
break ;
case AREA_PV :
2005-07-12 23:40:59 +04:00
if ( ! ( seg_pvseg ( split_seg , s ) =
assign_peg_to_lvseg ( seg_pv ( seg , s ) ,
2005-06-01 20:51:55 +04:00
seg_pe ( seg , s ) +
2005-05-03 21:28:23 +04:00
seg - > area_len ,
2005-06-01 20:51:55 +04:00
seg_pvseg ( seg , s ) - > len -
2005-05-03 21:28:23 +04:00
seg - > area_len ,
2008-01-30 16:19:47 +03:00
split_seg , s ) ) )
return_0 ;
2004-08-18 02:09:02 +04:00
log_debug ( " Split %s:%u[%u] at %u: %s PE %u " , lv - > name ,
seg - > le , s , le ,
2005-06-01 20:51:55 +04:00
dev_name ( seg_dev ( seg , s ) ) ,
seg_pe ( split_seg , s ) ) ;
2003-09-15 22:22:50 +04:00
break ;
2005-06-14 21:54:48 +04:00
case AREA_UNASSIGNED :
log_error ( " Unassigned area %u found in segment " , s ) ;
2003-09-15 22:22:50 +04:00
return 0 ;
}
}
/* Add split off segment to the list _after_ the original one */
2008-11-04 01:14:30 +03:00
dm_list_add_h ( & seg - > list , & split_seg - > list ) ;
2003-09-15 22:22:50 +04:00
return 1 ;
}
/*
* Ensure there ' s a segment boundary at the given logical extent
*/
int lv_split_segment ( struct logical_volume * lv , uint32_t le )
{
struct lv_segment * seg ;
if ( ! ( seg = find_seg_by_le ( lv , le ) ) ) {
log_error ( " Segment with extent % " PRIu32 " in LV %s not found " ,
le , lv - > name ) ;
return 0 ;
}
/* This is a segment start already */
if ( le = = seg - > le )
return 1 ;
2008-01-30 16:19:47 +03:00
if ( ! _lv_split_segment ( lv , seg , le ) )
return_0 ;
2003-09-15 22:22:50 +04:00
2008-01-30 16:19:47 +03:00
if ( ! vg_validate ( lv - > vg ) )
return_0 ;
2005-07-12 23:40:59 +04:00
2003-09-15 22:22:50 +04:00
return 1 ;
}