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 .
* Copyright ( C ) 2004 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
* of the GNU General Public License v .2 .
*
* You should have received a copy of the GNU General Public License
* 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"
2004-03-08 20:19:15 +03:00
# include "str_list.h"
2004-05-05 01:25:57 +04:00
# include "segtypes.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 .
2003-09-01 23:55:16 +04:00
* Returns success if successful , in which case ' first '
* 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 | |
! 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
{
2003-08-27 19:30:39 +04:00
struct 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
2003-08-27 19:30:39 +04:00
list_iterate_safe ( segh , t , & lv - > segments ) {
2002-11-18 17:04:08 +03:00
current = list_item ( segh , struct lv_segment ) ;
2002-01-07 18:08:28 +03:00
if ( _merge ( prev , current ) )
list_del ( & current - > list ) ;
else
prev = current ;
}
return 1 ;
}
2003-09-01 23:55:16 +04:00
/*
* Verify that an LV ' s segments are consecutive , complete and don ' t overlap .
*/
2002-01-11 02:21:07 +03:00
int lv_check_segments ( struct logical_volume * lv )
{
2003-09-01 23:55:16 +04:00
struct lv_segment * seg ;
uint32_t le = 0 ;
unsigned seg_count = 0 ;
list_iterate_items ( seg , & lv - > segments ) {
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 ) ;
return 0 ;
}
le + = seg - > len ;
}
2002-01-11 02:21:07 +03:00
return 1 ;
}
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
*/
static int _lv_split_segment ( struct logical_volume * lv , struct lv_segment * seg ,
uint32_t le )
{
size_t len ;
struct lv_segment * split_seg ;
uint32_t s ;
uint32_t offset = le - seg - > le ;
2004-05-05 01:25:57 +04:00
if ( ! ( seg - > segtype - > flags & SEG_CAN_SPLIT ) ) {
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 */
2004-05-05 01:25:57 +04:00
if ( ! ( split_seg = alloc_lv_segment ( lv - > vg - > cmd - > mem , seg - > area_count ) ) ) {
2003-09-15 22:22:50 +04:00
log_error ( " Couldn't allocate new LV segment. " ) ;
return 0 ;
}
len = sizeof ( * seg ) + ( seg - > area_count * sizeof ( seg - > area [ 0 ] ) ) ;
memcpy ( split_seg , seg , len ) ;
2004-03-08 20:19:15 +03:00
if ( ! str_list_dup ( lv - > vg - > cmd - > mem , & split_seg - > tags , & seg - > tags ) ) {
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-05-05 01:25:57 +04:00
if ( seg - > segtype - > flags & SEG_AREAS_STRIPED )
2003-09-15 22:22:50 +04:00
offset / = seg - > area_count ;
/* Adjust the PV mapping */
for ( s = 0 ; s < seg - > area_count ; s + + ) {
/* Split area at the offset */
switch ( seg - > area [ s ] . type ) {
case AREA_LV :
split_seg - > area [ s ] . u . lv . le =
seg - > area [ s ] . u . lv . le + offset ;
break ;
case AREA_PV :
split_seg - > area [ s ] . u . pv . pe =
seg - > area [ s ] . u . pv . pe + offset ;
break ;
default :
log_error ( " Unrecognised segment type %u " ,
seg - > area [ s ] . type ) ;
return 0 ;
}
}
split_seg - > area_len = seg - > area_len - offset ;
seg - > area_len = offset ;
/* Add split off segment to the list _after_ the original one */
list_add_h ( & seg - > list , & split_seg - > list ) ;
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 ;
if ( ! _lv_split_segment ( lv , seg , le ) ) {
stack ;
return 0 ;
}
return 1 ;
}