2001-11-06 13:29:56 +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 .
2001-11-06 13:29:56 +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
2001-11-06 13:29:56 +03:00
*/
2002-11-18 17:04:08 +03:00
# include "lib.h"
2001-11-06 13:29:56 +03:00
# include "metadata.h"
2003-04-25 02:23:24 +04:00
# include "locking.h"
2001-11-06 13:29:56 +03:00
# include "pv_map.h"
2001-12-31 22:09:51 +03:00
# include "lvm-string.h"
2002-02-11 23:50:53 +03:00
# include "toolcontext.h"
2003-09-15 22:22:50 +04:00
# include "lv_alloc.h"
2005-05-03 21:28:23 +04:00
# include "pv_alloc.h"
2004-05-05 01:25:57 +04:00
# include "display.h"
2004-09-16 22:40:56 +04:00
# include "segtype.h"
2001-11-06 13:29:56 +03:00
2001-11-27 19:37:33 +03:00
/*
2005-06-01 20:51:55 +04:00
* Find first unused LV number .
2001-11-27 19:37:33 +03:00
*/
2005-06-01 20:51:55 +04:00
uint32_t find_free_lvnum ( struct logical_volume * lv )
2001-11-27 19:37:33 +03:00
{
2005-06-01 20:51:55 +04:00
int lvnum_used [ MAX_RESTRICTED_LVS + 1 ] ;
uint32_t i = 0 ;
struct lv_list * lvl ;
int lvnum ;
2001-11-27 19:37:33 +03:00
2005-06-01 20:51:55 +04:00
memset ( & lvnum_used , 0 , sizeof ( lvnum_used ) ) ;
2003-04-25 02:23:24 +04:00
2005-06-01 20:51:55 +04:00
list_iterate_items ( lvl , & lv - > vg - > lvs ) {
lvnum = lvnum_from_lvid ( & lvl - > lv - > lvid ) ;
if ( lvnum < = MAX_RESTRICTED_LVS )
lvnum_used [ lvnum ] = 1 ;
2001-11-27 19:37:33 +03:00
}
2005-06-01 20:51:55 +04:00
while ( lvnum_used [ i ] )
i + + ;
2003-04-25 02:23:24 +04:00
2005-06-01 20:51:55 +04:00
/* FIXME What if none are free? */
2001-11-27 19:37:33 +03:00
2005-06-01 20:51:55 +04:00
return i ;
2001-11-27 19:37:33 +03:00
}
2005-06-01 20:51:55 +04:00
/*
* All lv_segments get created here .
*/
2005-04-22 19:44:00 +04:00
struct lv_segment * alloc_lv_segment ( struct pool * mem ,
struct segment_type * segtype ,
struct logical_volume * lv ,
uint32_t le , uint32_t len ,
uint32_t status ,
uint32_t stripe_size ,
2005-06-01 20:51:55 +04:00
struct logical_volume * log_lv ,
2005-04-22 19:44:00 +04:00
uint32_t area_count ,
uint32_t area_len ,
uint32_t chunk_size ,
2005-06-01 20:51:55 +04:00
uint32_t region_size ,
2005-04-22 19:44:00 +04:00
uint32_t extents_copied )
2001-11-29 21:45:35 +03:00
{
2002-11-18 17:04:08 +03:00
struct lv_segment * seg ;
2005-04-22 19:44:00 +04:00
uint32_t sz = sizeof ( * seg ) + ( area_count * sizeof ( seg - > area [ 0 ] ) ) ;
2001-11-29 21:45:35 +03:00
2005-04-22 19:44:00 +04:00
if ( ! ( seg = pool_zalloc ( mem , sz ) ) ) {
2001-11-29 21:45:35 +03:00
stack ;
return NULL ;
}
2005-06-03 18:49:51 +04:00
if ( ! segtype ) {
log_error ( " alloc_lv_segment: Missing segtype. " ) ;
return NULL ;
}
2005-04-22 19:44:00 +04:00
seg - > segtype = segtype ;
seg - > lv = lv ;
seg - > le = le ;
seg - > len = len ;
seg - > status = status ;
seg - > stripe_size = stripe_size ;
seg - > area_count = area_count ;
seg - > area_len = area_len ;
seg - > chunk_size = chunk_size ;
2005-06-01 20:51:55 +04:00
seg - > region_size = region_size ;
2005-04-22 19:44:00 +04:00
seg - > extents_copied = extents_copied ;
2005-06-01 20:51:55 +04:00
seg - > log_lv = log_lv ;
2004-03-08 20:19:15 +03:00
list_init ( & seg - > tags ) ;
2005-06-01 20:51:55 +04:00
if ( log_lv )
log_lv - > status | = MIRROR_LOG ;
2001-11-29 21:45:35 +03:00
return seg ;
}
2005-06-01 20:51:55 +04:00
struct lv_segment * alloc_snapshot_seg ( struct logical_volume * lv ,
uint32_t status , uint32_t old_le_count )
{
struct lv_segment * seg ;
struct segment_type * segtype ;
segtype = get_segtype_from_string ( lv - > vg - > cmd , " snapshot " ) ;
if ( ! segtype ) {
log_error ( " Failed to find snapshot segtype " ) ;
return NULL ;
}
if ( ! ( seg = alloc_lv_segment ( lv - > vg - > cmd - > mem , segtype , lv , old_le_count ,
lv - > le_count - old_le_count , status , 0 ,
NULL , 0 , lv - > le_count - old_le_count ,
0 , 0 , 0 ) ) ) {
log_error ( " Couldn't allocate new snapshot segment. " ) ;
return NULL ;
}
list_add ( & lv - > segments , & seg - > list ) ;
lv - > status | = VIRTUAL ;
return seg ;
}
2005-06-14 21:54:48 +04:00
void release_lv_segment_area ( struct lv_segment * seg , uint32_t s ,
uint32_t area_reduction )
{
if ( seg_type ( seg , s ) = = AREA_UNASSIGNED )
return ;
if ( seg_type ( seg , s ) = = AREA_PV ) {
release_pv_segment ( seg_pvseg ( seg , s ) , area_reduction ) ;
return ;
}
if ( seg_lv ( seg , s ) - > status & MIRROR_IMAGE ) {
lv_reduce ( seg_lv ( seg , s ) , area_reduction ) ;
return ;
}
if ( area_reduction = = seg - > area_len ) {
seg_lv ( seg , s ) = NULL ;
seg_le ( seg , s ) = 0 ;
seg_type ( seg , s ) = AREA_UNASSIGNED ;
}
}
/*
* Move a segment area from one segment to another
*/
int move_lv_segment_area ( struct lv_segment * seg_to , uint32_t area_to ,
struct lv_segment * seg_from , uint32_t area_from )
{
struct physical_volume * pv ;
struct logical_volume * lv ;
uint32_t pe , le ;
switch ( seg_type ( seg_from , area_from ) ) {
case AREA_PV :
pv = seg_pv ( seg_from , area_from ) ;
pe = seg_pe ( seg_from , area_from ) ;
release_lv_segment_area ( seg_from , area_from ,
seg_from - > area_len ) ;
release_lv_segment_area ( seg_to , area_to , seg_to - > area_len ) ;
if ( ! set_lv_segment_area_pv ( seg_to , area_to , pv , pe ) ) {
stack ;
return 0 ;
}
break ;
case AREA_LV :
lv = seg_lv ( seg_from , area_from ) ;
le = seg_le ( seg_from , area_from ) ;
release_lv_segment_area ( seg_from , area_from ,
seg_from - > area_len ) ;
release_lv_segment_area ( seg_to , area_to , seg_to - > area_len ) ;
set_lv_segment_area_lv ( seg_to , area_to , lv , le , 0 ) ;
break ;
case AREA_UNASSIGNED :
release_lv_segment_area ( seg_to , area_to , seg_to - > area_len ) ;
}
return 1 ;
}
2005-06-01 20:51:55 +04:00
/*
* Link part of a PV to an LV segment .
*/
2005-05-03 21:28:23 +04:00
int set_lv_segment_area_pv ( struct lv_segment * seg , uint32_t area_num ,
struct physical_volume * pv , uint32_t pe )
2005-04-22 19:43:02 +04:00
{
seg - > area [ area_num ] . type = AREA_PV ;
2005-05-03 21:28:23 +04:00
2005-06-01 20:51:55 +04:00
if ( ! ( seg_pvseg ( seg , area_num ) =
2005-05-03 21:28:23 +04:00
assign_peg_to_lvseg ( pv , pe , seg - > area_len , seg , area_num ) ) ) {
stack ;
return 0 ;
}
return 1 ;
2005-04-22 19:43:02 +04:00
}
2005-06-01 20:51:55 +04:00
/*
* Link one LV segment to another . Assumes sizes already match .
*/
2005-04-22 19:43:02 +04:00
void set_lv_segment_area_lv ( struct lv_segment * seg , uint32_t area_num ,
2005-06-03 18:49:51 +04:00
struct logical_volume * lv , uint32_t le ,
uint32_t flags )
2005-04-22 19:43:02 +04:00
{
seg - > area [ area_num ] . type = AREA_LV ;
2005-06-01 20:51:55 +04:00
seg_lv ( seg , area_num ) = lv ;
seg_le ( seg , area_num ) = le ;
2005-06-03 18:49:51 +04:00
lv - > status | = flags ;
2005-04-22 19:43:02 +04:00
}
2005-06-01 20:51:55 +04:00
/*
* Reduce the size of an lv_segment . New size can be zero .
*/
static int _lv_segment_reduce ( struct lv_segment * seg , uint32_t reduction )
2005-05-03 21:28:23 +04:00
{
2005-06-01 20:51:55 +04:00
uint32_t area_reduction , s ;
/* Caller must ensure exact divisibility */
if ( seg_is_striped ( seg ) ) {
if ( reduction % seg - > area_count ) {
log_error ( " Segment extent reduction % " PRIu32
" not divisible by #stripes % " PRIu32 ,
reduction , seg - > area_count ) ;
return 0 ;
}
area_reduction = ( reduction / seg - > area_count ) ;
} else
area_reduction = reduction ;
2005-06-14 21:54:48 +04:00
for ( s = 0 ; s < seg - > area_count ; s + + )
release_lv_segment_area ( seg , s , area_reduction ) ;
2005-06-01 20:51:55 +04:00
seg - > len - = reduction ;
seg - > area_len - = area_reduction ;
2005-05-03 21:28:23 +04:00
2005-06-01 20:51:55 +04:00
return 1 ;
2005-05-03 21:28:23 +04:00
}
2005-05-17 17:49:45 +04:00
/*
2005-06-01 20:51:55 +04:00
* Entry point for all LV reductions in size .
2005-05-17 17:49:45 +04:00
*/
2005-06-14 21:54:48 +04:00
static int _lv_reduce ( struct logical_volume * lv , uint32_t extents , int delete )
2001-11-29 21:45:35 +03:00
{
2005-06-03 19:44:12 +04:00
struct lv_list * lvl ;
2002-11-18 17:04:08 +03:00
struct lv_segment * seg ;
2005-06-01 20:51:55 +04:00
uint32_t count = extents ;
uint32_t reduction ;
list_iterate_back_items ( seg , & lv - > segments ) {
if ( ! count )
break ;
if ( seg - > len < = count ) {
/* remove this segment completely */
/* FIXME Check this is safe */
if ( seg - > log_lv & & ! lv_remove ( seg - > log_lv ) ) {
stack ;
return 0 ;
}
list_del ( & seg - > list ) ;
reduction = seg - > len ;
} else
reduction = count ;
if ( ! _lv_segment_reduce ( seg , reduction ) ) {
stack ;
return 0 ;
}
count - = reduction ;
}
lv - > le_count - = extents ;
lv - > size = ( uint64_t ) lv - > le_count * lv - > vg - > extent_size ;
2005-06-14 21:54:48 +04:00
if ( ! delete )
return 1 ;
2005-06-03 19:44:12 +04:00
/* Remove the LV if it is now empty */
if ( ! lv - > le_count ) {
if ( ! ( lvl = find_lv_in_vg ( lv - > vg , lv - > name ) ) ) {
stack ;
return 0 ;
}
list_del ( & lvl - > list ) ;
lv - > vg - > lv_count - - ;
} else if ( lv - > vg - > fid - > fmt - > ops - > lv_setup & &
! lv - > vg - > fid - > fmt - > ops - > lv_setup ( lv - > vg - > fid , lv ) ) {
2005-06-01 20:51:55 +04:00
stack ;
return 0 ;
}
return 1 ;
}
2005-06-14 21:54:48 +04:00
/*
* Empty an LV
*/
int lv_empty ( struct logical_volume * lv )
{
return _lv_reduce ( lv , 0 , lv - > le_count ) ;
}
int lv_reduce ( struct logical_volume * lv , uint32_t extents )
{
return _lv_reduce ( lv , extents , 1 ) ;
}
2005-06-01 20:51:55 +04:00
/*
* Completely remove an LV .
*/
int lv_remove ( struct logical_volume * lv )
{
if ( ! lv_reduce ( lv , lv - > le_count ) ) {
stack ;
return 0 ;
}
return 1 ;
}
/*
* A set of contiguous physical extents allocated
*/
struct alloced_area {
struct list list ;
struct physical_volume * pv ;
uint32_t pe ;
uint32_t len ;
} ;
/*
* Details of an allocation attempt
*/
struct alloc_handle {
struct pool * mem ;
alloc_policy_t alloc ; /* Overall policy */
uint32_t area_count ; /* Number of parallel areas */
uint32_t area_multiple ; /* seg->len = area_len * area_multiple */
uint32_t log_count ; /* Number of parallel 1-extent logs */
2005-06-03 18:49:51 +04:00
uint32_t total_area_len ; /* Total number of parallel extents */
2005-06-01 20:51:55 +04:00
struct alloced_area log_area ; /* Extent used for log */
struct list alloced_areas [ 0 ] ; /* Lists of areas in each stripe */
} ;
/*
* Preparation for a specific allocation attempt
*/
static struct alloc_handle * _alloc_init ( struct pool * mem ,
struct segment_type * segtype ,
alloc_policy_t alloc ,
uint32_t mirrors ,
uint32_t stripes ,
uint32_t log_count ,
struct physical_volume * mirrored_pv )
{
struct alloc_handle * ah ;
uint32_t s , area_count ;
if ( stripes > 1 & & mirrors > 1 ) {
2005-06-03 23:48:19 +04:00
log_error ( " Striped mirrors are not supported yet " ) ;
2005-06-01 20:51:55 +04:00
return NULL ;
}
if ( ( stripes > 1 | | mirrors > 1 ) & & mirrored_pv ) {
log_error ( " Can't mix striping or mirroring with "
" creation of a mirrored PV yet " ) ;
return NULL ;
}
if ( log_count & & ( stripes > 1 | | mirrored_pv ) ) {
log_error ( " Can't mix striping or pvmove with "
" a mirror log yet. " ) ;
return NULL ;
}
if ( segtype_is_virtual ( segtype ) )
area_count = 0 ;
else if ( mirrors > 1 )
area_count = mirrors ;
else if ( mirrored_pv )
area_count = 1 ;
else
area_count = stripes ;
if ( ! ( ah = pool_zalloc ( mem , sizeof ( * ah ) + sizeof ( ah - > alloced_areas [ 0 ] ) * area_count ) ) ) {
log_error ( " allocation handle allocation failed " ) ;
return NULL ;
}
if ( segtype_is_virtual ( segtype ) )
return ah ;
if ( ! ( ah - > mem = pool_create ( " allocation " , 1024 ) ) ) {
log_error ( " allocation pool creation failed " ) ;
return NULL ;
}
ah - > area_count = area_count ;
ah - > log_count = log_count ;
ah - > alloc = alloc ;
ah - > area_multiple = segtype_is_striped ( segtype ) ? ah - > area_count : 1 ;
list_init ( & ah - > alloced_areas [ 0 ] ) ;
2004-03-26 23:35:14 +03:00
2005-06-01 20:51:55 +04:00
for ( s = 0 ; s < ah - > area_count ; s + + )
list_init ( & ah - > alloced_areas [ s ] ) ;
return ah ;
}
void alloc_destroy ( struct alloc_handle * ah )
{
if ( ah - > mem )
pool_destroy ( ah - > mem ) ;
}
static int _setup_alloced_segment ( struct logical_volume * lv , uint32_t status ,
uint32_t area_count ,
uint32_t stripe_size ,
struct segment_type * segtype ,
struct alloced_area * aa ,
struct physical_volume * mirrored_pv ,
uint32_t mirrored_pe ,
uint32_t region_size ,
struct logical_volume * log_lv )
{
uint32_t s , extents , area_multiple , extra_areas = 0 ;
struct lv_segment * seg ;
2004-03-26 23:35:14 +03:00
2005-05-17 17:49:45 +04:00
if ( mirrored_pv )
extra_areas = 1 ;
2005-06-01 20:51:55 +04:00
area_multiple = segtype_is_striped ( segtype ) ? area_count : 1 ;
2001-11-29 21:45:35 +03:00
2005-06-01 20:51:55 +04:00
if ( ! ( seg = alloc_lv_segment ( lv - > vg - > cmd - > mem , segtype , lv ,
lv - > le_count ,
aa [ 0 ] . len * area_multiple ,
status , stripe_size , log_lv ,
area_count + extra_areas ,
aa [ 0 ] . len , 0u , region_size , 0u ) ) ) {
2005-05-17 17:49:45 +04:00
log_error ( " Couldn't allocate new LV segment. " ) ;
2001-11-29 21:45:35 +03:00
return 0 ;
}
2005-05-17 17:49:45 +04:00
if ( extra_areas ) {
if ( ! set_lv_segment_area_pv ( seg , 0 , mirrored_pv , mirrored_pe ) ) {
stack ;
return 0 ;
}
}
2004-03-26 23:35:14 +03:00
for ( s = 0 ; s < area_count ; s + + ) {
2005-06-01 20:51:55 +04:00
if ( ! set_lv_segment_area_pv ( seg , s + extra_areas , aa [ s ] . pv ,
aa [ s ] . pe ) ) {
2005-05-03 21:28:23 +04:00
stack ;
return 0 ;
}
2001-11-29 21:45:35 +03:00
}
list_add ( & lv - > segments , & seg - > list ) ;
2004-05-05 01:25:57 +04:00
2005-06-01 20:51:55 +04:00
extents = aa [ 0 ] . len * area_multiple ;
lv - > le_count + = extents ;
lv - > size + = ( uint64_t ) extents * lv - > vg - > extent_size ;
if ( segtype_is_mirrored ( segtype ) )
2004-05-05 01:25:57 +04:00
lv - > status | = MIRRORED ;
2001-11-29 21:45:35 +03:00
return 1 ;
}
2005-06-01 20:51:55 +04:00
static int _setup_alloced_segments ( struct logical_volume * lv ,
struct list * alloced_areas ,
uint32_t area_count ,
uint32_t status ,
uint32_t stripe_size ,
struct segment_type * segtype ,
struct physical_volume * mirrored_pv ,
uint32_t mirrored_pe ,
uint32_t region_size ,
struct logical_volume * log_lv )
{
struct alloced_area * aa ;
list_iterate_items ( aa , & alloced_areas [ 0 ] ) {
if ( ! _setup_alloced_segment ( lv , status , area_count ,
stripe_size , segtype , aa ,
mirrored_pv , mirrored_pe ,
region_size , log_lv ) ) {
stack ;
return 0 ;
}
}
return 1 ;
}
/*
* This function takes a list of pv_areas and adds them to allocated_areas .
* If the complete area is not needed then it gets split .
* The part used is removed from the pv_map so it can ' t be allocated twice .
*/
static int _alloc_parallel_area ( struct alloc_handle * ah , uint32_t needed ,
struct pv_area * * areas ,
uint32_t * ix , struct pv_area * log_area )
{
uint32_t area_len , smallest , remaining ;
uint32_t s ;
struct alloced_area * aa ;
remaining = needed - * ix ;
area_len = remaining / ah - > area_multiple ;
smallest = areas [ ah - > area_count - 1 ] - > count ;
if ( area_len > smallest )
area_len = smallest ;
if ( ! ( aa = pool_alloc ( ah - > mem , sizeof ( * aa ) *
( ah - > area_count + ( log_area ? 1 : 0 ) ) ) ) ) {
log_error ( " alloced_area allocation failed " ) ;
return 0 ;
}
for ( s = 0 ; s < ah - > area_count ; s + + ) {
aa [ s ] . pv = areas [ s ] - > map - > pv ;
aa [ s ] . pe = areas [ s ] - > start ;
aa [ s ] . len = area_len ;
list_add ( & ah - > alloced_areas [ s ] , & aa [ s ] . list ) ;
}
2005-06-03 18:49:51 +04:00
ah - > total_area_len + = area_len ;
2005-06-01 20:51:55 +04:00
for ( s = 0 ; s < ah - > area_count ; s + + )
consume_pv_area ( areas [ s ] , area_len ) ;
if ( log_area ) {
ah - > log_area . pv = log_area - > map - > pv ;
ah - > log_area . pe = log_area - > start ;
ah - > log_area . len = 1 ; /* FIXME Calculate & check this */
consume_pv_area ( log_area , ah - > log_area . len ) ;
}
* ix + = area_len * ah - > area_multiple ;
return 1 ;
}
2001-11-29 21:45:35 +03:00
static int _comp_area ( const void * l , const void * r )
{
2002-12-20 02:25:55 +03:00
const struct pv_area * lhs = * ( ( const struct pv_area * * ) l ) ;
const struct pv_area * rhs = * ( ( const struct pv_area * * ) r ) ;
2001-11-29 21:45:35 +03:00
if ( lhs - > count < rhs - > count )
2001-11-30 12:19:46 +03:00
return 1 ;
2001-11-29 21:45:35 +03:00
else if ( lhs - > count > rhs - > count )
2001-11-30 12:19:46 +03:00
return - 1 ;
2001-11-29 21:45:35 +03:00
return 0 ;
}
2005-06-01 20:51:55 +04:00
/*
* Is pva contiguous to any existing areas or on the same PV ?
*/
static int _check_contiguous ( struct lv_segment * prev_lvseg ,
struct physical_volume * pv , struct pv_area * pva ,
struct pv_area * * areas )
2001-11-29 21:45:35 +03:00
{
2005-06-01 20:51:55 +04:00
struct pv_segment * prev_pvseg ;
uint32_t s ;
2004-03-26 23:35:14 +03:00
2005-06-01 20:51:55 +04:00
for ( s = 0 ; s < prev_lvseg - > area_count ; s + + ) {
if ( seg_type ( prev_lvseg , s ) ! = AREA_PV )
continue ; /* FIXME Broken */
2004-05-05 01:25:57 +04:00
2005-06-01 20:51:55 +04:00
if ( ! ( prev_pvseg = seg_pvseg ( prev_lvseg , s ) ) )
continue ; /* FIXME Broken */
if ( ( prev_pvseg - > pv ! = pv ) )
continue ;
if ( prev_pvseg - > pe + prev_pvseg - > len = = pva - > start ) {
areas [ s ] = pva ;
return 1 ;
}
2005-05-17 17:49:45 +04:00
}
2005-06-01 20:51:55 +04:00
return 0 ;
}
2001-11-29 21:45:35 +03:00
2005-06-01 20:51:55 +04:00
/*
* Choose sets of parallel areas to use , respecting any constraints .
*/
2005-06-07 15:00:07 +04:00
/* FIXME Also accept existing areas new space must be parallel to */
2005-06-01 20:51:55 +04:00
static int _find_parallel_space ( struct alloc_handle * ah , alloc_policy_t alloc ,
struct list * pvms , struct pv_area * * areas ,
uint32_t areas_size , unsigned can_split ,
struct lv_segment * prev_lvseg ,
uint32_t * allocated , uint32_t needed )
{
struct pv_map * pvm ;
struct pv_area * pva ;
unsigned already_found_one = 0 ;
unsigned contiguous = 0 , contiguous_count = 0 ;
unsigned ix ;
unsigned ix_offset = 0 ; /* Offset for non-contiguous allocations */
2001-11-29 21:45:35 +03:00
2005-06-01 20:51:55 +04:00
/* FIXME Do calculations on free extent counts before selecting space */
/* FIXME Select log PV appropriately if there isn't one yet */
if ( ( alloc = = ALLOC_CONTIGUOUS ) ) {
contiguous = 1 ;
if ( prev_lvseg )
ix_offset = prev_lvseg - > area_count ;
else
ix_offset = ah - > area_count ;
2001-11-29 21:45:35 +03:00
}
2005-06-01 20:51:55 +04:00
/* FIXME This algorithm needs a lot of cleaning up! */
/* FIXME anywhere doesn't find all space yet */
/* ix_offset holds the number of allocations that must be contiguous */
/* ix holds the number of areas found on other PVs */
do {
2002-12-20 02:25:55 +03:00
ix = 0 ;
2005-06-01 20:51:55 +04:00
/*
* Put the smallest area of each PV that is at least the
* size we need into areas array . If there isn ' t one
* that fits completely and we ' re allowed more than one
* LV segment , then take the largest remaining instead .
*/
2005-05-11 20:46:59 +04:00
list_iterate_items ( pvm , pvms ) {
2001-11-29 21:45:35 +03:00
if ( list_empty ( & pvm - > areas ) )
2005-06-01 20:51:55 +04:00
continue ; /* Next PV */
2001-11-29 21:45:35 +03:00
2005-06-01 20:51:55 +04:00
/* Don't allocate onto the log pv */
if ( ( alloc ! = ALLOC_ANYWHERE ) & & ah - > log_count & &
( pvm - > pv = = ah - > log_area . pv ) )
continue ; /* Next PV */
already_found_one = 0 ;
/* First area in each list is the largest */
2005-05-17 17:49:45 +04:00
list_iterate_items ( pva , & pvm - > areas ) {
2005-06-01 20:51:55 +04:00
if ( contiguous ) {
if ( prev_lvseg & &
_check_contiguous ( prev_lvseg ,
pvm - > pv ,
pva , areas ) ) {
contiguous_count + + ;
break ; /* Next PV */
}
continue ;
}
2001-11-29 21:45:35 +03:00
2005-06-01 20:51:55 +04:00
/* Is it big enough on its own? */
if ( ( pva - > count < needed - * allocated ) & &
( ( ! can_split & & ! ah - > log_count ) | |
( already_found_one & &
! ( alloc = = ALLOC_ANYWHERE ) ) ) )
break ; /* Next PV */
if ( ! already_found_one | |
alloc = = ALLOC_ANYWHERE ) {
ix + + ;
already_found_one = 1 ;
2005-05-17 17:49:45 +04:00
}
2005-06-01 20:51:55 +04:00
areas [ ix + ix_offset - 1 ] = pva ;
break ; /* Next PV */
2005-05-17 17:49:45 +04:00
}
2005-06-01 20:51:55 +04:00
if ( ix > = areas_size )
break ;
2001-11-30 12:19:46 +03:00
}
2001-11-29 21:45:35 +03:00
2005-06-01 20:51:55 +04:00
if ( contiguous & & ( contiguous_count < ix_offset ) )
break ;
2005-06-03 22:07:13 +04:00
/* Only allocate log_area the first time around */
if ( ix + ix_offset < ah - > area_count +
2005-06-14 21:54:48 +04:00
( ( ah - > log_count & & ! ah - > log_area . len ) ?
ah - > log_count : 0 ) )
2005-06-01 20:51:55 +04:00
/* FIXME With ALLOC_ANYWHERE, need to split areas */
2005-05-17 17:49:45 +04:00
break ;
2001-11-29 21:45:35 +03:00
/* sort the areas so we allocate from the biggest */
2005-05-17 17:49:45 +04:00
if ( ix > 1 )
2005-06-01 20:51:55 +04:00
qsort ( areas + ix_offset , ix , sizeof ( * areas ) ,
_comp_area ) ;
2005-06-03 22:07:13 +04:00
/* First time around, use smallest area as log_area */
2005-06-07 15:00:07 +04:00
/* FIXME decide which PV to use at top of function instead */
2005-06-01 20:51:55 +04:00
if ( ! _alloc_parallel_area ( ah , needed , areas ,
allocated ,
2005-06-03 22:07:13 +04:00
( ah - > log_count & & ! ah - > log_area . len ) ?
2005-06-01 20:51:55 +04:00
* ( areas + ix_offset + ix - 1 ) :
NULL ) ) {
stack ;
return 0 ;
}
2005-07-12 18:50:45 +04:00
} while ( ! contiguous & & * allocated ! = needed & & can_split ) ;
2005-06-01 20:51:55 +04:00
return 1 ;
}
/*
* Allocate several segments , each the same size , in parallel .
* If mirrored_pv and mirrored_pe are supplied , it is used as
* the first area , and additional areas are allocated parallel to it .
*/
static int _allocate ( struct alloc_handle * ah ,
struct volume_group * vg ,
struct logical_volume * lv , uint32_t status ,
uint32_t new_extents ,
struct list * allocatable_pvs ,
uint32_t stripes , uint32_t mirrors ,
struct segment_type * segtype ,
struct physical_volume * mirrored_pv ,
uint32_t mirrored_pe )
{
struct pv_area * * areas ;
uint32_t allocated = lv ? lv - > le_count : 0 ;
uint32_t old_allocated ;
struct lv_segment * prev_lvseg = NULL ;
unsigned can_split = 1 ; /* Are we allowed more than one segment? */
int r = 0 ;
struct list * pvms ;
uint32_t areas_size ;
if ( allocated > = new_extents ) {
log_error ( " _allocate called with no work to do! " ) ;
return 1 ;
}
2005-06-03 22:07:13 +04:00
if ( mirrored_pv | | ( ah - > alloc = = ALLOC_CONTIGUOUS ) )
2005-06-01 20:51:55 +04:00
can_split = 0 ;
if ( lv & & ! list_empty ( & lv - > segments ) )
prev_lvseg = list_item ( list_last ( & lv - > segments ) ,
struct lv_segment ) ;
/*
* Build the sets of available areas on the pv ' s .
*/
if ( ! ( pvms = create_pv_maps ( ah - > mem , vg , allocatable_pvs ) ) ) {
stack ;
return 0 ;
}
areas_size = list_size ( pvms ) ;
if ( areas_size < ah - > area_count + ah - > log_count ) {
if ( ah - > alloc ! = ALLOC_ANYWHERE ) {
log_error ( " Not enough PVs with free space available "
" for parallel allocation. " ) ;
log_error ( " Consider --alloc anywhere if desperate. " ) ;
return 0 ;
}
areas_size = ah - > area_count + ah - > log_count ;
}
/* Allocate an array of pv_areas to hold the largest space on each PV */
if ( ! ( areas = dbg_malloc ( sizeof ( * areas ) * areas_size ) ) ) {
log_err ( " Couldn't allocate areas array. " ) ;
return 0 ;
}
old_allocated = allocated ;
if ( ! _find_parallel_space ( ah , ALLOC_CONTIGUOUS , pvms , areas ,
areas_size , can_split ,
prev_lvseg , & allocated , new_extents ) ) {
stack ;
goto out ;
}
if ( ( allocated = = new_extents ) | | ( ah - > alloc = = ALLOC_CONTIGUOUS ) | |
( ! can_split & & ( allocated ! = old_allocated ) ) )
goto finished ;
old_allocated = allocated ;
if ( ! _find_parallel_space ( ah , ALLOC_NORMAL , pvms , areas ,
areas_size , can_split ,
prev_lvseg , & allocated , new_extents ) ) {
stack ;
goto out ;
}
2001-11-29 21:45:35 +03:00
2005-06-01 20:51:55 +04:00
if ( ( allocated = = new_extents ) | | ( ah - > alloc = = ALLOC_NORMAL ) | |
( ! can_split & & ( allocated ! = old_allocated ) ) )
goto finished ;
2003-04-30 19:23:43 +04:00
2005-06-01 20:51:55 +04:00
if ( ! _find_parallel_space ( ah , ALLOC_ANYWHERE , pvms , areas ,
areas_size , can_split ,
prev_lvseg , & allocated , new_extents ) ) {
stack ;
goto out ;
2003-04-30 19:23:43 +04:00
}
2005-06-01 20:51:55 +04:00
finished :
if ( allocated ! = new_extents ) {
log_error ( " Insufficient suitable %sallocatable extents "
" for logical volume %s: %u more required " ,
can_split ? " " : " contiguous " ,
lv ? lv - > name : " " ,
( new_extents - allocated ) * ah - > area_count
/ ah - > area_multiple ) ;
2005-05-17 17:49:45 +04:00
goto out ;
2005-05-03 21:28:23 +04:00
}
2005-04-22 19:44:00 +04:00
2005-05-17 17:49:45 +04:00
r = 1 ;
2005-04-22 19:44:00 +04:00
2005-05-17 17:49:45 +04:00
out :
dbg_free ( areas ) ;
return r ;
2003-04-30 19:23:43 +04:00
}
2005-06-01 20:51:55 +04:00
int lv_add_virtual_segment ( struct logical_volume * lv , uint32_t status ,
uint32_t extents , struct segment_type * segtype )
2001-11-06 13:29:56 +03:00
{
2005-06-01 20:51:55 +04:00
struct lv_segment * seg ;
2005-05-17 17:49:45 +04:00
2005-06-01 20:51:55 +04:00
if ( ! ( seg = alloc_lv_segment ( lv - > vg - > cmd - > mem , segtype , lv ,
lv - > le_count , extents , status , 0 ,
NULL , 0 , extents , 0 , 0 , 0 ) ) ) {
log_error ( " Couldn't allocate new zero segment. " ) ;
return 0 ;
}
2005-05-11 20:46:59 +04:00
2005-06-01 20:51:55 +04:00
list_add ( & lv - > segments , & seg - > list ) ;
2001-11-06 13:55:01 +03:00
2005-06-01 20:51:55 +04:00
lv - > le_count + = extents ;
lv - > size + = ( uint64_t ) extents * lv - > vg - > extent_size ;
2001-11-06 13:55:01 +03:00
2005-06-01 20:51:55 +04:00
lv - > status | = VIRTUAL ;
2001-11-06 13:55:01 +03:00
2005-06-01 20:51:55 +04:00
return 1 ;
}
2001-11-06 13:55:01 +03:00
2005-06-01 20:51:55 +04:00
/*
* Entry point for all extent allocations .
*/
struct alloc_handle * allocate_extents ( struct volume_group * vg ,
struct logical_volume * lv ,
struct segment_type * segtype ,
uint32_t stripes ,
uint32_t mirrors , uint32_t log_count ,
uint32_t extents ,
struct physical_volume * mirrored_pv ,
uint32_t mirrored_pe ,
uint32_t status ,
struct list * allocatable_pvs ,
alloc_policy_t alloc )
{
struct alloc_handle * ah ;
2005-05-11 20:46:59 +04:00
2005-06-01 20:51:55 +04:00
if ( segtype_is_virtual ( segtype ) ) {
log_error ( " allocate_extents does not handle virtual segments " ) ;
return NULL ;
}
if ( vg - > fid - > fmt - > ops - > segtype_supported & &
! vg - > fid - > fmt - > ops - > segtype_supported ( vg - > fid , segtype ) ) {
log_error ( " Metadata format (%s) does not support required "
" LV segment type (%s). " , vg - > fid - > fmt - > name ,
segtype - > name ) ;
log_error ( " Consider changing the metadata format by running "
" vgconvert. " ) ;
return NULL ;
}
if ( alloc = = ALLOC_INHERIT )
alloc = vg - > alloc ;
2001-11-27 19:37:33 +03:00
2005-06-01 20:51:55 +04:00
if ( ! ( ah = _alloc_init ( vg - > cmd - > mem , segtype , alloc , mirrors ,
stripes , log_count , mirrored_pv ) ) ) {
stack ;
return NULL ;
2001-11-06 13:55:01 +03:00
}
2005-06-01 20:51:55 +04:00
if ( ! segtype_is_virtual ( segtype ) & &
! _allocate ( ah , vg , lv , status , ( lv ? lv - > le_count : 0 ) + extents ,
allocatable_pvs ,
stripes , mirrors , segtype , mirrored_pv , mirrored_pe ) ) {
stack ;
alloc_destroy ( ah ) ;
return NULL ;
2001-11-06 13:29:56 +03:00
}
2005-06-01 20:51:55 +04:00
return ah ;
2001-11-06 13:29:56 +03:00
}
2005-06-01 20:51:55 +04:00
/*
* Add new segments to an LV from supplied list of areas .
*/
int lv_add_segment ( struct alloc_handle * ah ,
uint32_t first_area , uint32_t num_areas ,
struct logical_volume * lv ,
struct segment_type * segtype ,
uint32_t stripe_size ,
struct physical_volume * mirrored_pv ,
uint32_t mirrored_pe ,
uint32_t status ,
uint32_t region_size ,
struct logical_volume * log_lv )
2004-05-11 20:01:58 +04:00
{
2005-06-03 18:49:51 +04:00
if ( ! segtype ) {
log_error ( " Missing segtype in lv_add_segment(). " ) ;
return 0 ;
}
2005-06-01 20:51:55 +04:00
if ( segtype_is_virtual ( segtype ) ) {
log_error ( " lv_add_segment cannot handle virtual segments " ) ;
return 0 ;
}
2004-05-11 20:01:58 +04:00
2005-06-01 20:51:55 +04:00
if ( ! _setup_alloced_segments ( lv , & ah - > alloced_areas [ first_area ] ,
num_areas , status ,
stripe_size , segtype ,
mirrored_pv , mirrored_pe ,
region_size , log_lv ) ) {
stack ;
2004-05-11 20:01:58 +04:00
return 0 ;
}
2005-06-01 20:51:55 +04:00
if ( ( segtype - > flags & SEG_CAN_SPLIT ) & & ! lv_merge_segments ( lv ) ) {
log_err ( " Couldn't merge segments after extending "
" logical volume. " ) ;
return 0 ;
}
if ( lv - > vg - > fid - > fmt - > ops - > lv_setup & &
! lv - > vg - > fid - > fmt - > ops - > lv_setup ( lv - > vg - > fid , lv ) ) {
stack ;
return 0 ;
}
2004-05-11 20:01:58 +04:00
return 1 ;
}
2005-06-01 20:51:55 +04:00
/*
* Turn an empty LV into a mirror log .
*/
int lv_add_log_segment ( struct alloc_handle * ah , struct logical_volume * log_lv )
2005-04-07 16:39:44 +04:00
{
struct lv_segment * seg ;
2005-06-01 20:51:55 +04:00
if ( list_size ( & log_lv - > segments ) ) {
log_error ( " Log segments can only be added to an empty LV " ) ;
return 0 ;
2005-04-07 16:39:44 +04:00
}
2005-06-01 20:51:55 +04:00
if ( ! ( seg = alloc_lv_segment ( log_lv - > vg - > cmd - > mem ,
get_segtype_from_string ( log_lv - > vg - > cmd ,
" striped " ) ,
log_lv , 0 , ah - > log_area . len , MIRROR_LOG ,
0 , NULL , 1 , ah - > log_area . len , 0 , 0 , 0 ) ) ) {
log_error ( " Couldn't allocate new mirror log segment. " ) ;
return 0 ;
2005-04-07 16:39:44 +04:00
}
2005-04-22 19:44:00 +04:00
2005-06-01 20:51:55 +04:00
if ( ! set_lv_segment_area_pv ( seg , 0 , ah - > log_area . pv , ah - > log_area . pe ) ) {
stack ;
return 0 ;
}
2005-04-07 16:39:44 +04:00
2005-06-01 20:51:55 +04:00
list_add ( & log_lv - > segments , & seg - > list ) ;
log_lv - > le_count + = ah - > log_area . len ;
log_lv - > size + = ( uint64_t ) log_lv - > le_count * log_lv - > vg - > extent_size ;
if ( log_lv - > vg - > fid - > fmt - > ops - > lv_setup & &
! log_lv - > vg - > fid - > fmt - > ops - > lv_setup ( log_lv - > vg - > fid , log_lv ) ) {
stack ;
return 0 ;
}
return 1 ;
2005-04-07 16:39:44 +04:00
}
2005-06-03 18:49:51 +04:00
/*
* Add a mirror segment
*/
int lv_add_mirror_segment ( struct alloc_handle * ah ,
struct logical_volume * lv ,
struct logical_volume * * sub_lvs ,
uint32_t mirrors ,
struct segment_type * segtype ,
uint32_t status ,
uint32_t region_size ,
struct logical_volume * log_lv )
{
struct lv_segment * seg ;
uint32_t m ;
if ( list_empty ( & log_lv - > segments ) ) {
log_error ( " Log LV %s is empty. " , log_lv - > name ) ;
return 0 ;
}
if ( ! ( seg = alloc_lv_segment ( lv - > vg - > cmd - > mem ,
get_segtype_from_string ( lv - > vg - > cmd ,
" mirror " ) ,
lv , lv - > le_count , ah - > total_area_len , 0 ,
0 , log_lv , mirrors , ah - > total_area_len , 0 ,
region_size , 0 ) ) ) {
log_error ( " Couldn't allocate new mirror segment. " ) ;
return 0 ;
}
for ( m = 0 ; m < mirrors ; m + + )
set_lv_segment_area_lv ( seg , m , sub_lvs [ m ] , 0 , MIRROR_IMAGE ) ;
list_add ( & lv - > segments , & seg - > list ) ;
lv - > le_count + = ah - > total_area_len ;
lv - > size + = ( uint64_t ) lv - > le_count * lv - > vg - > extent_size ;
if ( lv - > vg - > fid - > fmt - > ops - > lv_setup & &
! lv - > vg - > fid - > fmt - > ops - > lv_setup ( lv - > vg - > fid , lv ) ) {
stack ;
return 0 ;
}
return 1 ;
}
2001-11-06 14:31:29 +03:00
/*
2005-06-01 20:51:55 +04:00
* Entry point for single - step LV allocation + extension .
2001-11-06 14:31:29 +03:00
*/
2005-06-01 20:51:55 +04:00
int lv_extend ( struct logical_volume * lv ,
struct segment_type * segtype ,
uint32_t stripes , uint32_t stripe_size ,
uint32_t mirrors , uint32_t extents ,
struct physical_volume * mirrored_pv , uint32_t mirrored_pe ,
uint32_t status , struct list * allocatable_pvs ,
alloc_policy_t alloc )
2001-11-06 14:31:29 +03:00
{
2005-06-01 20:51:55 +04:00
int r = 1 ;
2005-06-03 23:48:19 +04:00
uint32_t m ;
2005-06-01 20:51:55 +04:00
struct alloc_handle * ah ;
2005-06-03 23:48:19 +04:00
struct lv_segment * first_seg ;
2001-11-06 14:31:29 +03:00
2005-06-01 20:51:55 +04:00
if ( segtype_is_virtual ( segtype ) )
return lv_add_virtual_segment ( lv , status , extents , segtype ) ;
2004-05-11 20:01:58 +04:00
2005-06-01 20:51:55 +04:00
if ( ! ( ah = allocate_extents ( lv - > vg , lv , segtype , stripes , mirrors , 0 ,
extents , mirrored_pv , mirrored_pe , status ,
allocatable_pvs , alloc ) ) ) {
2001-11-06 14:31:29 +03:00
stack ;
return 0 ;
}
2005-06-07 15:00:07 +04:00
if ( mirrors < 2 ) {
2005-06-03 23:48:19 +04:00
if ( ! lv_add_segment ( ah , 0 , ah - > area_count , lv , segtype , stripe_size ,
2005-06-01 20:51:55 +04:00
mirrored_pv , mirrored_pe , status , 0 , NULL ) ) {
2005-06-03 23:48:19 +04:00
stack ;
goto out ;
}
} else {
list_iterate_items ( first_seg , & lv - > segments )
break ;
for ( m = 0 ; m < mirrors ; m + + ) {
if ( ! lv_add_segment ( ah , m , 1 , seg_lv ( first_seg , m ) ,
get_segtype_from_string ( lv - > vg - > cmd ,
" striped " ) ,
0 , NULL , 0 , 0 , 0 , NULL ) ) {
log_error ( " Aborting. Failed to extend %s. " ,
seg_lv ( first_seg , m ) - > name ) ;
return 0 ;
}
}
first_seg - > area_len + = extents ;
first_seg - > len + = extents ;
lv - > le_count + = extents ;
lv - > size + = ( uint64_t ) extents * lv - > vg - > extent_size ;
2001-11-06 14:31:29 +03:00
}
2001-11-13 17:17:50 +03:00
out :
2005-06-01 20:51:55 +04:00
alloc_destroy ( ah ) ;
2001-11-06 14:31:29 +03:00
return r ;
}
2005-06-03 18:49:51 +04:00
char * generate_lv_name ( struct volume_group * vg , const char * format ,
char * buffer , size_t len )
2001-11-14 15:07:37 +03:00
{
2005-05-11 20:46:59 +04:00
struct lv_list * lvl ;
2002-01-07 12:16:20 +03:00
int high = - 1 , i ;
2001-11-14 15:07:37 +03:00
2005-05-11 20:46:59 +04:00
list_iterate_items ( lvl , & vg - > lvs ) {
if ( sscanf ( lvl - > lv - > name , format , & i ) ! = 1 )
2001-11-14 15:07:37 +03:00
continue ;
if ( i > high )
2001-11-14 17:12:01 +03:00
high = i ;
2001-11-14 15:07:37 +03:00
}
2003-05-06 16:06:02 +04:00
if ( lvm_snprintf ( buffer , len , format , high + 1 ) < 0 )
2001-11-14 15:07:37 +03:00
return NULL ;
return buffer ;
}
2005-06-01 20:51:55 +04:00
/*
* Create a new empty LV .
*/
2003-04-25 02:23:24 +04:00
struct logical_volume * lv_create_empty ( struct format_instance * fi ,
const char * name ,
2005-04-07 16:29:46 +04:00
union lvid * lvid ,
2003-04-25 02:23:24 +04:00
uint32_t status ,
alloc_policy_t alloc ,
2005-04-07 16:39:44 +04:00
int import ,
2003-04-25 02:23:24 +04:00
struct volume_group * vg )
2001-11-06 13:29:56 +03:00
{
2001-11-12 15:16:57 +03:00
struct cmd_context * cmd = vg - > cmd ;
2001-11-06 13:29:56 +03:00
struct lv_list * ll = NULL ;
struct logical_volume * lv ;
2001-11-14 15:07:37 +03:00
char dname [ 32 ] ;
2001-11-06 13:29:56 +03:00
2003-11-06 23:33:34 +03:00
if ( vg - > max_lv & & ( vg - > max_lv = = vg - > lv_count ) ) {
2001-11-06 22:02:26 +03:00
log_error ( " Maximum number of logical volumes (%u) reached "
" in volume group %s " , vg - > max_lv , vg - > name ) ;
return NULL ;
2001-11-06 13:29:56 +03:00
}
2005-06-03 18:49:51 +04:00
if ( strstr ( name , " %d " ) & &
! ( name = generate_lv_name ( vg , name , dname , sizeof ( dname ) ) ) ) {
2001-11-14 16:52:38 +03:00
log_error ( " Failed to generate unique name for the new "
" logical volume " ) ;
2001-11-14 15:07:37 +03:00
return NULL ;
}
2005-04-07 16:39:44 +04:00
if ( ! import )
log_verbose ( " Creating logical volume %s " , name ) ;
2001-11-14 15:07:37 +03:00
2002-01-21 20:43:10 +03:00
if ( ! ( ll = pool_zalloc ( cmd - > mem , sizeof ( * ll ) ) ) | |
! ( ll - > lv = pool_zalloc ( cmd - > mem , sizeof ( * ll - > lv ) ) ) ) {
2003-04-25 02:23:24 +04:00
log_error ( " lv_list allocation failed " ) ;
if ( ll )
pool_free ( cmd - > mem , ll ) ;
2001-11-06 13:29:56 +03:00
return NULL ;
}
2002-01-21 19:49:32 +03:00
lv = ll - > lv ;
2002-03-05 23:03:09 +03:00
lv - > vg = vg ;
2001-11-06 13:29:56 +03:00
2001-11-12 15:16:57 +03:00
if ( ! ( lv - > name = pool_strdup ( cmd - > mem , name ) ) ) {
2003-04-25 02:23:24 +04:00
log_error ( " lv name strdup failed " ) ;
if ( ll )
pool_free ( cmd - > mem , ll ) ;
return NULL ;
2001-11-06 13:29:56 +03:00
}
lv - > status = status ;
2002-07-11 18:21:49 +04:00
lv - > alloc = alloc ;
2001-11-06 13:29:56 +03:00
lv - > read_ahead = 0 ;
2003-04-02 23:14:43 +04:00
lv - > major = - 1 ;
2002-02-01 20:54:39 +03:00
lv - > minor = - 1 ;
2003-04-25 02:23:24 +04:00
lv - > size = UINT64_C ( 0 ) ;
lv - > le_count = 0 ;
2005-04-07 16:39:44 +04:00
lv - > snapshot = NULL ;
list_init ( & lv - > snapshot_segs ) ;
2001-11-27 19:37:33 +03:00
list_init ( & lv - > segments ) ;
2004-03-08 20:19:15 +03:00
list_init ( & lv - > tags ) ;
2001-11-06 13:29:56 +03:00
2005-04-07 16:29:46 +04:00
if ( lvid )
lv - > lvid = * lvid ;
2002-04-24 22:20:51 +04:00
if ( fi - > fmt - > ops - > lv_setup & & ! fi - > fmt - > ops - > lv_setup ( fi , lv ) ) {
2002-01-24 20:15:49 +03:00
stack ;
2003-04-25 02:23:24 +04:00
if ( ll )
pool_free ( cmd - > mem , ll ) ;
return NULL ;
2002-01-24 20:15:49 +03:00
}
2005-04-07 16:39:44 +04:00
if ( ! import )
vg - > lv_count + + ;
2001-11-06 22:02:26 +03:00
list_add ( & vg - > lvs , & ll - > list ) ;
2001-11-10 01:01:04 +03:00
2001-11-06 13:29:56 +03:00
return lv ;
2003-04-25 02:23:24 +04:00
}