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 .
2005-11-24 21:00:47 +03:00
* Copyright ( C ) 2004 - 2005 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
2005-11-28 23:01:00 +03:00
/*
* PVs used by a segment of an LV
*/
struct seg_pvs {
struct list list ;
struct list pvs ; /* struct pv_list */
uint32_t le ;
uint32_t len ;
} ;
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-10-17 03:03:59 +04:00
struct lv_segment * alloc_lv_segment ( struct dm_pool * mem ,
2006-05-10 01:23:51 +04:00
const struct segment_type * segtype ,
2005-04-22 19:44:00 +04:00
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-10-18 17:43:40 +04:00
uint32_t areas_sz = area_count * sizeof ( * seg - > areas ) ;
2001-11-29 21:45:35 +03:00
2005-10-18 17:43:40 +04:00
if ( ! ( seg = dm_pool_zalloc ( mem , sizeof ( * seg ) ) ) ) {
stack ;
return NULL ;
}
if ( ! ( seg - > areas = dm_pool_zalloc ( mem , areas_sz ) ) ) {
dm_pool_free ( mem , seg ) ;
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 ;
2005-10-27 23:58:22 +04:00
seg - > mirror_seg = NULL ;
2004-03-08 20:19:15 +03:00
list_init ( & seg - > tags ) ;
2005-10-27 23:58:22 +04:00
if ( log_lv ) {
2005-06-01 20:51:55 +04:00
log_lv - > status | = MIRROR_LOG ;
2005-10-28 16:48:50 +04:00
first_seg ( log_lv ) - > mirror_seg = seg ;
2005-10-27 23:58:22 +04:00
}
2005-06-01 20:51:55 +04:00
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 ;
2006-05-10 01:23:51 +04:00
const struct segment_type * segtype ;
2005-06-01 20:51:55 +04:00
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 ) {
2006-09-11 18:24:58 +04:00
lv_reduce ( seg_lv ( seg , s ) , area_reduction ) ;
2005-06-14 21:54:48 +04:00
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
{
2005-10-18 17:43:40 +04:00
seg - > areas [ 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
{
2005-10-18 17:43:40 +04:00
seg - > areas [ 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-10-18 17:43:40 +04:00
/*
* Prepare for adding parallel areas to an existing segment .
*/
static int _lv_segment_add_areas ( struct logical_volume * lv ,
struct lv_segment * seg ,
uint32_t new_area_count )
{
struct lv_segment_area * newareas ;
uint32_t areas_sz = new_area_count * sizeof ( * newareas ) ;
if ( ! ( newareas = dm_pool_zalloc ( lv - > vg - > cmd - > mem , areas_sz ) ) ) {
stack ;
return 0 ;
}
memcpy ( newareas , seg - > areas , seg - > area_count * sizeof ( * seg - > areas ) ) ;
seg - > areas = newareas ;
seg - > area_count = new_area_count ;
return 1 ;
}
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
/*
2005-11-24 23:58:44 +03:00
* Empty an LV .
2005-06-14 21:54:48 +04:00
*/
int lv_empty ( struct logical_volume * lv )
{
2005-11-24 21:46:51 +03:00
return _lv_reduce ( lv , lv - > le_count , 0 ) ;
2005-06-14 21:54:48 +04:00
}
2005-11-24 21:46:51 +03:00
/*
2005-11-24 23:58:44 +03:00
* Remove given number of extents from LV .
2005-11-24 21:46:51 +03:00
*/
2005-06-14 21:54:48 +04:00
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 {
2006-10-08 03:40:36 +04:00
struct cmd_context * cmd ;
2005-10-17 03:03:59 +04:00
struct dm_pool * mem ;
2005-06-01 20:51:55 +04:00
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
2005-11-24 23:58:44 +03:00
struct physical_volume * mirrored_pv ; /* FIXME Remove this */
uint32_t mirrored_pe ; /* FIXME Remove this */
struct list * parallel_areas ; /* PVs to avoid */
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 */
} ;
2006-12-13 06:39:58 +03:00
static uint32_t calc_area_multiple ( const struct segment_type * segtype ,
const uint32_t area_count )
{
if ( ! segtype_is_striped ( segtype ) | | ! area_count )
return 1 ;
return area_count ;
}
2005-06-01 20:51:55 +04:00
/*
* Preparation for a specific allocation attempt
*/
2006-10-08 03:40:36 +04:00
static struct alloc_handle * _alloc_init ( struct cmd_context * cmd ,
struct dm_pool * mem ,
2006-05-10 01:23:51 +04:00
const struct segment_type * segtype ,
2005-06-01 20:51:55 +04:00
alloc_policy_t alloc ,
uint32_t mirrors ,
uint32_t stripes ,
uint32_t log_count ,
2005-11-24 23:58:44 +03:00
struct physical_volume * mirrored_pv ,
uint32_t mirrored_pe ,
struct list * parallel_areas )
2005-06-01 20:51:55 +04:00
{
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 ;
2005-10-17 03:03:59 +04:00
if ( ! ( ah = dm_pool_zalloc ( mem , sizeof ( * ah ) + sizeof ( ah - > alloced_areas [ 0 ] ) * area_count ) ) ) {
2005-06-01 20:51:55 +04:00
log_error ( " allocation handle allocation failed " ) ;
return NULL ;
}
if ( segtype_is_virtual ( segtype ) )
return ah ;
2006-10-08 03:40:36 +04:00
ah - > cmd = cmd ;
2005-10-17 03:03:59 +04:00
if ( ! ( ah - > mem = dm_pool_create ( " allocation " , 1024 ) ) ) {
2005-06-01 20:51:55 +04:00
log_error ( " allocation pool creation failed " ) ;
return NULL ;
}
ah - > area_count = area_count ;
ah - > log_count = log_count ;
ah - > alloc = alloc ;
2006-12-13 06:39:58 +03:00
ah - > area_multiple = calc_area_multiple ( segtype , area_count ) ;
2005-06-01 20:51:55 +04:00
for ( s = 0 ; s < ah - > area_count ; s + + )
list_init ( & ah - > alloced_areas [ s ] ) ;
2005-11-24 23:58:44 +03:00
ah - > mirrored_pv = mirrored_pv ;
ah - > mirrored_pe = mirrored_pe ;
ah - > parallel_areas = parallel_areas ;
2005-06-01 20:51:55 +04:00
return ah ;
}
void alloc_destroy ( struct alloc_handle * ah )
{
if ( ah - > mem )
2005-10-17 03:03:59 +04:00
dm_pool_destroy ( ah - > mem ) ;
2005-06-01 20:51:55 +04:00
}
2006-09-11 18:24:58 +04:00
static int _log_parallel_areas ( struct dm_pool * mem , struct list * parallel_areas )
{
struct seg_pvs * spvs ;
struct pv_list * pvl ;
char * pvnames ;
if ( ! parallel_areas )
return 1 ;
if ( ! dm_pool_begin_object ( mem , 256 ) ) {
log_error ( " dm_pool_begin_object failed " ) ;
return 0 ;
}
list_iterate_items ( spvs , parallel_areas ) {
list_iterate_items ( pvl , & spvs - > pvs ) {
if ( ! dm_pool_grow_object ( mem , dev_name ( pvl - > pv - > dev ) , strlen ( dev_name ( pvl - > pv - > dev ) ) ) ) {
log_error ( " dm_pool_grow_object failed " ) ;
dm_pool_abandon_object ( mem ) ;
return 0 ;
}
if ( ! dm_pool_grow_object ( mem , " " , 1 ) ) {
log_error ( " dm_pool_grow_object failed " ) ;
dm_pool_abandon_object ( mem ) ;
return 0 ;
}
}
if ( ! dm_pool_grow_object ( mem , " \0 " , 1 ) ) {
log_error ( " dm_pool_grow_object failed " ) ;
dm_pool_abandon_object ( mem ) ;
return 0 ;
}
pvnames = dm_pool_end_object ( mem ) ;
log_debug ( " Parallel PVs at LE % " PRIu32 " length % " PRIu32 " : %s " ,
spvs - > le , spvs - > len , pvnames ) ;
dm_pool_free ( mem , pvnames ) ;
}
return 1 ;
}
2005-06-01 20:51:55 +04:00
static int _setup_alloced_segment ( struct logical_volume * lv , uint32_t status ,
uint32_t area_count ,
uint32_t stripe_size ,
2006-05-10 01:23:51 +04:00
const struct segment_type * segtype ,
2005-06-01 20:51:55 +04:00
struct alloced_area * aa ,
struct physical_volume * mirrored_pv ,
uint32_t mirrored_pe ,
uint32_t region_size ,
2006-05-11 21:58:58 +04:00
struct logical_volume * log_lv __attribute ( ( unused ) ) )
2005-06-01 20:51:55 +04:00
{
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 ;
2006-12-13 06:39:58 +03:00
area_multiple = calc_area_multiple ( segtype , area_count ) ;
2001-11-29 21:45:35 +03:00
2005-10-28 01:51:28 +04:00
/* log_lv gets set up elsehere */
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 ,
2005-10-28 01:51:28 +04:00
status , stripe_size , NULL ,
2005-06-01 20:51:55 +04:00
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 ,
2006-05-10 01:23:51 +04:00
const struct segment_type * segtype ,
2005-06-01 20:51:55 +04:00
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 )
{
2006-12-12 22:30:10 +03:00
uint32_t area_len , remaining ;
2005-06-01 20:51:55 +04:00
uint32_t s ;
struct alloced_area * aa ;
remaining = needed - * ix ;
area_len = remaining / ah - > area_multiple ;
2006-12-12 22:30:10 +03:00
/* Reduce area_len to the smallest of the areas */
for ( s = 0 ; s < ah - > area_count ; s + + )
if ( area_len > areas [ s ] - > count )
area_len = areas [ s ] - > count ;
2005-06-01 20:51:55 +04:00
2005-10-17 03:03:59 +04:00
if ( ! ( aa = dm_pool_alloc ( ah - > mem , sizeof ( * aa ) *
2005-06-01 20:51:55 +04:00
( 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 ;
2006-09-12 01:14:56 +04:00
ah - > log_area . len = MIRROR_LOG_SIZE ; /* FIXME Calculate & check this */
2005-06-01 20:51:55 +04:00
consume_pv_area ( log_area , ah - > log_area . len ) ;
}
* ix + = area_len * ah - > area_multiple ;
return 1 ;
}
2006-10-07 15:23:22 +04:00
/*
* Call fn for each AREA_PV used by the LV segment at lv : le of length * max_seg_len .
* If any constituent area contains more than one segment , max_seg_len is
* reduced to cover only the first .
2006-10-07 16:41:06 +04:00
* fn should return 0 on error , 1 to continue scanning or > 1 to terminate without error .
* In the last case , this function passes on the return code .
2006-10-07 15:23:22 +04:00
*/
static int _for_each_pv ( struct cmd_context * cmd , struct logical_volume * lv ,
uint32_t le , uint32_t len , uint32_t * max_seg_len ,
2006-10-08 03:40:36 +04:00
uint32_t first_area , uint32_t max_areas ,
int top_level_area_index ,
int only_single_area_segments ,
int ( * fn ) ( struct cmd_context * cmd ,
struct pv_segment * peg , uint32_t s ,
void * data ) ,
2006-10-07 15:23:22 +04:00
void * data )
{
struct lv_segment * seg ;
uint32_t s ;
uint32_t remaining_seg_len , area_len , area_multiple ;
2006-10-07 20:00:28 +04:00
int r = 1 ;
2006-10-07 15:23:22 +04:00
if ( ! ( seg = find_seg_by_le ( lv , le ) ) ) {
log_error ( " Failed to find segment for %s extent % " PRIu32 ,
lv - > name , le ) ;
return 0 ;
}
/* Remaining logical length of segment */
remaining_seg_len = seg - > len - ( le - seg - > le ) ;
if ( remaining_seg_len > len )
remaining_seg_len = len ;
if ( max_seg_len & & * max_seg_len > remaining_seg_len )
* max_seg_len = remaining_seg_len ;
2006-12-13 06:39:58 +03:00
area_multiple = calc_area_multiple ( seg - > segtype , seg - > area_count ) ;
2006-10-07 15:23:22 +04:00
area_len = remaining_seg_len / area_multiple ? : 1 ;
2006-10-08 03:40:36 +04:00
for ( s = first_area ;
s < seg - > area_count & & ( ! max_areas | | s < = max_areas ) ;
s + + ) {
2006-10-07 15:23:22 +04:00
if ( seg_type ( seg , s ) = = AREA_LV ) {
2006-10-07 16:41:06 +04:00
if ( ! ( r = _for_each_pv ( cmd , seg_lv ( seg , s ) ,
seg_le ( seg , s ) +
( le - seg - > le ) / area_multiple ,
2006-10-08 03:40:36 +04:00
area_len , max_seg_len ,
only_single_area_segments ? 0 : 0 ,
only_single_area_segments ? 1 : 0 ,
top_level_area_index ! = - 1 ? top_level_area_index : s ,
only_single_area_segments , fn ,
2006-10-07 16:41:06 +04:00
data ) ) )
stack ;
} else if ( seg_type ( seg , s ) = = AREA_PV )
2006-10-08 03:40:36 +04:00
if ( ! ( r = fn ( cmd , seg_pvseg ( seg , s ) , top_level_area_index ! = - 1 ? top_level_area_index : s , data ) ) )
2006-10-07 16:41:06 +04:00
stack ;
if ( r ! = 1 )
return r ;
}
2006-10-08 03:40:36 +04:00
/* FIXME only_single_area_segments used as workaround to skip log LV - needs new param? */
if ( ! only_single_area_segments & & seg_is_mirrored ( seg ) & & seg - > log_lv ) {
2006-10-07 16:41:06 +04:00
if ( ! ( r = _for_each_pv ( cmd , seg - > log_lv , 0 , MIRROR_LOG_SIZE ,
2006-10-08 03:40:36 +04:00
NULL , 0 , 0 , 0 , only_single_area_segments ,
fn , data ) ) )
2006-10-07 16:41:06 +04:00
stack ;
if ( r ! = 1 )
return r ;
}
2006-10-07 15:23:22 +04:00
/* FIXME Add snapshot cow LVs etc. */
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 ;
}
2006-10-08 03:40:36 +04:00
/*
* Search for pvseg that matches condition
*/
struct pv_match {
int ( * condition ) ( struct pv_segment * pvseg , struct pv_area * pva ) ;
struct pv_area * * areas ;
struct pv_area * pva ;
uint32_t areas_size ;
int s ; /* Area index of match */
} ;
2006-10-08 16:01:13 +04:00
/*
* Is PV area on the same PV ?
*/
static int _is_same_pv ( struct pv_segment * pvseg , struct pv_area * pva )
{
if ( pvseg - > pv ! = pva - > map - > pv )
return 0 ;
return 1 ;
}
2006-10-07 15:34:53 +04:00
/*
* Is PV area contiguous to PV segment ?
*/
static int _is_contiguous ( struct pv_segment * pvseg , struct pv_area * pva )
{
if ( pvseg - > pv ! = pva - > map - > pv )
return 0 ;
if ( pvseg - > pe + pvseg - > len ! = pva - > start )
return 0 ;
return 1 ;
}
2006-10-08 16:01:13 +04:00
static int _is_condition ( struct cmd_context * cmd ,
struct pv_segment * pvseg , uint32_t s ,
void * data )
2006-10-07 20:00:28 +04:00
{
2006-10-08 03:40:36 +04:00
struct pv_match * pvmatch = data ;
2006-10-07 20:00:28 +04:00
2006-10-08 03:40:36 +04:00
if ( ! pvmatch - > condition ( pvseg , pvmatch - > pva ) )
return 1 ; /* Continue */
2006-10-07 20:00:28 +04:00
2006-10-08 03:40:36 +04:00
if ( s > = pvmatch - > areas_size )
return 1 ;
pvmatch - > areas [ s ] = pvmatch - > pva ;
2006-10-07 20:00:28 +04:00
2006-10-08 03:40:36 +04:00
return 2 ; /* Finished */
2006-10-07 20:00:28 +04:00
}
2006-10-08 16:01:13 +04:00
/*
* Is pva on same PV as any existing areas ?
*/
static int _check_cling ( struct cmd_context * cmd ,
struct lv_segment * prev_lvseg , struct pv_area * pva ,
struct pv_area * * areas , uint32_t areas_size )
{
struct pv_match pvmatch ;
int r ;
pvmatch . condition = _is_same_pv ;
pvmatch . areas = areas ;
pvmatch . areas_size = areas_size ;
pvmatch . pva = pva ;
/* FIXME Cope with stacks by flattening */
if ( ! ( r = _for_each_pv ( cmd , prev_lvseg - > lv ,
prev_lvseg - > le + prev_lvseg - > len - 1 , 1 , NULL ,
0 , 0 , - 1 , 1 ,
_is_condition , & pvmatch ) ) )
stack ;
if ( r ! = 2 )
return 0 ;
return 1 ;
}
2005-06-01 20:51:55 +04:00
/*
* Is pva contiguous to any existing areas or on the same PV ?
*/
2006-10-08 03:40:36 +04:00
static int _check_contiguous ( struct cmd_context * cmd ,
struct lv_segment * prev_lvseg , struct pv_area * pva ,
2006-09-12 01:14:56 +04:00
struct pv_area * * areas , uint32_t areas_size )
2001-11-29 21:45:35 +03:00
{
2006-10-08 03:40:36 +04:00
struct pv_match pvmatch ;
2006-10-07 20:00:28 +04:00
int r ;
2005-06-01 20:51:55 +04:00
2006-10-08 03:40:36 +04:00
pvmatch . condition = _is_contiguous ;
pvmatch . areas = areas ;
pvmatch . areas_size = areas_size ;
pvmatch . pva = pva ;
/* FIXME Cope with stacks by flattening */
if ( ! ( r = _for_each_pv ( cmd , prev_lvseg - > lv ,
prev_lvseg - > le + prev_lvseg - > len - 1 , 1 , NULL ,
0 , 0 , - 1 , 1 ,
2006-10-08 16:01:13 +04:00
_is_condition , & pvmatch ) ) )
2006-10-07 20:00:28 +04:00
stack ;
2005-05-17 17:49:45 +04:00
2006-10-08 03:40:36 +04:00
if ( r ! = 2 )
return 0 ;
return 1 ;
2005-06-01 20:51:55 +04:00
}
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-11-28 23:01:00 +03: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 )
2005-06-01 20:51:55 +04:00
{
struct pv_map * pvm ;
struct pv_area * pva ;
2005-11-25 00:23:55 +03:00
struct pv_list * pvl ;
2005-06-01 20:51:55 +04:00
unsigned already_found_one = 0 ;
2006-10-08 16:01:13 +04:00
unsigned contiguous = 0 , cling = 0 , preferred_count = 0 ;
2005-06-01 20:51:55 +04:00
unsigned ix ;
2006-10-08 16:01:13 +04:00
unsigned ix_offset = 0 ; /* Offset for non-preferred allocations */
2005-11-28 23:01:00 +03:00
uint32_t max_parallel ; /* Maximum extents to allocate */
uint32_t next_le ;
struct seg_pvs * spvs ;
struct list * parallel_pvs ;
2006-10-23 19:54:51 +04:00
uint32_t free_pes ;
/* Is there enough total space? */
free_pes = pv_maps_size ( pvms ) ;
2006-10-30 19:10:55 +03:00
if ( needed - * allocated > free_pes ) {
2006-10-23 19:54:51 +04:00
log_error ( " Insufficient free space: % " PRIu32 " extents needed, "
2006-10-30 19:10:55 +03:00
" but only % " PRIu32 " available " ,
needed - * allocated , free_pes ) ;
2006-10-23 19:54:51 +04:00
return 0 ;
}
2001-11-29 21:45:35 +03:00
2005-06-01 20:51:55 +04:00
/* FIXME Select log PV appropriately if there isn't one yet */
2005-10-28 02:20:33 +04:00
/* Are there any preceding segments we must follow on from? */
2006-10-08 16:01:13 +04:00
if ( prev_lvseg ) {
2005-10-28 02:20:33 +04:00
ix_offset = prev_lvseg - > area_count ;
2006-10-08 16:01:13 +04:00
if ( ( alloc = = ALLOC_CONTIGUOUS ) )
contiguous = 1 ;
else if ( ( alloc = = ALLOC_CLING ) )
cling = 1 ;
else
ix_offset = 0 ;
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 ;
2006-10-08 16:01:13 +04:00
preferred_count = 0 ;
2005-06-01 20:51:55 +04:00
2005-11-28 23:01:00 +03:00
parallel_pvs = NULL ;
max_parallel = needed ;
/*
* If there are existing parallel PVs , avoid them and reduce
* the maximum we can allocate in one go accordingly .
*/
if ( ah - > parallel_areas ) {
2006-09-11 18:24:58 +04:00
next_le = ( prev_lvseg ? prev_lvseg - > le + prev_lvseg - > len : 0 ) + * allocated / ah - > area_multiple ;
2005-11-28 23:01:00 +03:00
list_iterate_items ( spvs , ah - > parallel_areas ) {
2006-09-11 18:24:58 +04:00
if ( next_le > = spvs - > le + spvs - > len )
continue ;
if ( max_parallel > ( spvs - > le + spvs - > len ) * ah - > area_multiple )
max_parallel = ( spvs - > le + spvs - > len ) * ah - > area_multiple ;
parallel_pvs = & spvs - > pvs ;
break ;
2005-11-28 23:01:00 +03:00
}
}
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-11-25 00:23:55 +03:00
if ( alloc ! = ALLOC_ANYWHERE ) {
/* Don't allocate onto the log pv */
if ( ah - > log_count & &
pvm - > pv = = ah - > log_area . pv )
continue ; /* Next PV */
/* Avoid PVs used by existing parallel areas */
if ( parallel_pvs )
list_iterate_items ( pvl , parallel_pvs )
if ( pvm - > pv = = pvl - > pv )
goto next_pv ;
}
2005-06-01 20:51:55 +04:00
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 & &
2006-10-08 03:40:36 +04:00
_check_contiguous ( ah - > cmd ,
prev_lvseg ,
2006-09-12 01:14:56 +04:00
pva , areas ,
areas_size ) ) {
2006-10-08 16:01:13 +04:00
preferred_count + + ;
2005-11-24 21:00:47 +03:00
goto next_pv ;
2005-06-01 20:51:55 +04:00
}
continue ;
}
2001-11-29 21:45:35 +03:00
2006-10-08 16:01:13 +04:00
if ( cling ) {
if ( prev_lvseg & &
_check_cling ( ah - > cmd ,
prev_lvseg ,
pva , areas ,
areas_size ) ) {
preferred_count + + ;
}
goto next_pv ;
}
2005-06-01 20:51:55 +04:00
/* Is it big enough on its own? */
2006-09-11 18:24:58 +04:00
if ( pva - > count * ah - > area_multiple <
max_parallel - * allocated & &
2005-06-01 20:51:55 +04:00
( ( ! can_split & & ! ah - > log_count ) | |
( already_found_one & &
! ( alloc = = ALLOC_ANYWHERE ) ) ) )
2005-11-24 21:00:47 +03:00
goto next_pv ;
2005-06-01 20:51:55 +04:00
if ( ! already_found_one | |
alloc = = ALLOC_ANYWHERE ) {
ix + + ;
already_found_one = 1 ;
2005-05-17 17:49:45 +04:00
}
2005-11-10 17:45:39 +03:00
areas [ ix + ix_offset - 1 ] = pva ;
2005-06-01 20:51:55 +04:00
2005-11-24 21:00:47 +03:00
goto next_pv ;
2005-05-17 17:49:45 +04:00
}
2005-11-24 21:00:47 +03:00
next_pv :
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
2006-10-08 16:01:13 +04:00
if ( ( contiguous | | cling ) & & ( preferred_count < ix_offset ) )
2005-06-01 20:51:55 +04:00
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-11-28 23:01:00 +03:00
if ( ! _alloc_parallel_area ( ah , max_parallel , areas ,
2005-06-01 20:51:55 +04:00
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 ,
2005-11-24 23:58:44 +03:00
struct logical_volume * lv , uint32_t status ,
uint32_t new_extents ,
struct list * allocatable_pvs ,
uint32_t stripes , uint32_t mirrors ,
2006-05-10 01:23:51 +04:00
const struct segment_type * segtype )
2005-06-01 20:51:55 +04:00
{
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 ;
2006-12-13 06:39:58 +03:00
alloc_policy_t alloc ;
2005-06-01 20:51:55 +04:00
2005-11-25 00:23:55 +03:00
if ( allocated > = new_extents & & ! ah - > log_count ) {
2005-06-01 20:51:55 +04:00
log_error ( " _allocate called with no work to do! " ) ;
return 1 ;
}
2005-11-24 23:58:44 +03:00
if ( ah - > 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 ;
}
2006-09-11 18:24:58 +04:00
if ( ! _log_parallel_areas ( ah - > mem , ah - > parallel_areas ) )
stack ;
2005-06-01 20:51:55 +04:00
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 ;
}
2005-11-10 17:45:39 +03:00
/* Upper bound if none of the PVs in prev_lvseg is in pvms */
/* FIXME Work size out properly */
if ( prev_lvseg )
areas_size + = prev_lvseg - > area_count ;
2005-06-01 20:51:55 +04:00
/* Allocate an array of pv_areas to hold the largest space on each PV */
2005-10-17 03:03:59 +04:00
if ( ! ( areas = dm_malloc ( sizeof ( * areas ) * areas_size ) ) ) {
2005-06-01 20:51:55 +04:00
log_err ( " Couldn't allocate areas array. " ) ;
return 0 ;
}
2006-12-13 06:39:58 +03:00
/* Attempt each defined allocation policy in turn */
for ( alloc = ALLOC_CONTIGUOUS ; alloc < ALLOC_INHERIT ; alloc + + ) {
old_allocated = allocated ;
if ( ! _find_parallel_space ( ah , alloc , pvms , areas ,
areas_size , can_split ,
prev_lvseg , & allocated , new_extents ) )
goto_out ;
if ( ( allocated = = new_extents ) | | ( ah - > alloc = = alloc ) | |
( ! can_split & & ( allocated ! = old_allocated ) ) )
break ;
2003-04-30 19:23:43 +04:00
}
2005-06-01 20:51:55 +04:00
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
2006-12-13 06:39:58 +03:00
if ( ah - > log_count & & ! ah - > log_area . len ) {
log_error ( " Insufficient extents for log allocation "
" for logical volume %s. " ,
lv ? lv - > name : " " ) ;
goto out ;
}
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 :
2005-10-17 03:03:59 +04:00
dm_free ( areas ) ;
2005-05-17 17:49:45 +04:00
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 ,
2006-05-10 01:23:51 +04:00
uint32_t extents , const 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 ,
2006-05-10 01:23:51 +04:00
const struct segment_type * segtype ,
2005-06-01 20:51:55 +04:00
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 ,
2005-11-24 23:58:44 +03:00
alloc_policy_t alloc ,
struct list * parallel_areas )
2005-06-01 20:51:55 +04:00
{
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
2006-10-08 03:40:36 +04:00
if ( ! ( ah = _alloc_init ( vg - > cmd , vg - > cmd - > mem , segtype , alloc , mirrors ,
2005-11-24 23:58:44 +03:00
stripes , log_count , mirrored_pv ,
mirrored_pe , parallel_areas ) ) ) {
2005-06-01 20:51:55 +04:00
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 ,
2005-11-24 23:58:44 +03:00
allocatable_pvs , stripes , mirrors , segtype ) ) {
2005-06-01 20:51:55 +04:00
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 ,
2006-05-10 01:23:51 +04:00
const struct segment_type * segtype ,
2005-06-01 20:51:55 +04:00
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 ,
2006-05-10 01:23:51 +04:00
const struct segment_type * segtype ,
2005-06-03 18:49:51 +04:00
uint32_t status ,
uint32_t region_size ,
struct logical_volume * log_lv )
{
struct lv_segment * seg ;
uint32_t m ;
2006-05-11 22:54:04 +04:00
if ( log_lv & & list_empty ( & log_lv - > segments ) ) {
2005-06-03 18:49:51 +04:00
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 ;
}
2005-10-27 23:58:22 +04:00
for ( m = 0 ; m < mirrors ; m + + ) {
2005-06-03 18:49:51 +04:00
set_lv_segment_area_lv ( seg , m , sub_lvs [ m ] , 0 , MIRROR_IMAGE ) ;
2005-10-28 16:48:50 +04:00
first_seg ( sub_lvs [ m ] ) - > mirror_seg = seg ;
2005-10-27 23:58:22 +04:00
}
2005-06-03 18:49:51 +04:00
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 ;
}
2005-10-28 16:48:50 +04:00
/*
* Add parallel areas to an existing mirror
*/
int lv_add_more_mirrored_areas ( struct logical_volume * lv ,
struct logical_volume * * sub_lvs ,
uint32_t num_extra_areas ,
uint32_t status )
{
struct lv_segment * seg ;
uint32_t old_area_count , new_area_count ;
uint32_t m ;
if ( list_size ( & lv - > segments ) ! = 1 ) {
log_error ( " Mirrored LV must only have one segment. " ) ;
return 0 ;
}
2005-11-25 00:23:55 +03:00
seg = first_seg ( lv ) ;
2005-10-28 16:48:50 +04:00
old_area_count = seg - > area_count ;
new_area_count = old_area_count + num_extra_areas ;
if ( ! _lv_segment_add_areas ( lv , seg , new_area_count ) ) {
log_error ( " Failed to allocate widened LV segment for %s. " ,
lv - > name ) ;
return 0 ;
}
for ( m = old_area_count ; m < new_area_count ; m + + ) {
set_lv_segment_area_lv ( seg , m , sub_lvs [ m - old_area_count ] , 0 , status ) ;
first_seg ( sub_lvs [ m - old_area_count ] ) - > mirror_seg = seg ;
}
return 1 ;
}
2005-06-03 18:49:51 +04:00
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 ,
2006-05-10 01:23:51 +04:00
const struct segment_type * segtype ,
2005-06-01 20:51:55 +04:00
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-10-28 16:48:50 +04:00
struct lv_segment * 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 ,
2005-11-24 23:58:44 +03:00
allocatable_pvs , alloc , NULL ) ) ) {
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 {
2005-10-28 16:48:50 +04:00
seg = first_seg ( lv ) ;
2005-06-03 23:48:19 +04:00
for ( m = 0 ; m < mirrors ; m + + ) {
2005-10-28 16:48:50 +04:00
if ( ! lv_add_segment ( ah , m , 1 , seg_lv ( seg , m ) ,
2005-06-03 23:48:19 +04:00
get_segtype_from_string ( lv - > vg - > cmd ,
" striped " ) ,
0 , NULL , 0 , 0 , 0 , NULL ) ) {
log_error ( " Aborting. Failed to extend %s. " ,
2005-10-28 16:48:50 +04:00
seg_lv ( seg , m ) - > name ) ;
2005-06-03 23:48:19 +04:00
return 0 ;
2006-09-11 18:24:58 +04:00
}
2005-06-03 23:48:19 +04:00
}
2005-10-28 16:48:50 +04:00
seg - > area_len + = extents ;
seg - > len + = extents ;
2005-06-03 23:48:19 +04:00
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
}
2006-08-21 16:54:53 +04:00
if ( dm_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 ;
2007-01-05 18:53:40 +03:00
char dname [ NAME_LEN ] ;
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
2005-10-17 03:03:59 +04:00
if ( ! ( ll = dm_pool_zalloc ( cmd - > mem , sizeof ( * ll ) ) ) | |
! ( ll - > lv = dm_pool_zalloc ( cmd - > mem , sizeof ( * ll - > lv ) ) ) ) {
2003-04-25 02:23:24 +04:00
log_error ( " lv_list allocation failed " ) ;
if ( ll )
2005-10-17 03:03:59 +04:00
dm_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
2005-10-17 03:03:59 +04:00
if ( ! ( lv - > name = dm_pool_strdup ( cmd - > mem , name ) ) ) {
2003-04-25 02:23:24 +04:00
log_error ( " lv name strdup failed " ) ;
if ( ll )
2005-10-17 03:03:59 +04:00
dm_pool_free ( cmd - > mem , ll ) ;
2003-04-25 02:23:24 +04:00
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 )
2005-10-17 03:03:59 +04:00
dm_pool_free ( cmd - > mem , ll ) ;
2003-04-25 02:23:24 +04:00
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
}
2005-11-24 23:58:44 +03:00
2006-10-08 03:40:36 +04:00
static int _add_pvs ( struct cmd_context * cmd , struct pv_segment * peg ,
uint32_t s __attribute ( ( unused ) ) , void * data )
2005-11-28 23:01:00 +03:00
{
2006-09-12 01:14:56 +04:00
struct seg_pvs * spvs = ( struct seg_pvs * ) data ;
2005-11-28 23:01:00 +03:00
struct pv_list * pvl ;
2006-09-12 01:14:56 +04:00
/* Don't add again if it's already on list. */
list_iterate_items ( pvl , & spvs - > pvs )
if ( pvl - > pv = = peg - > pv )
return 1 ;
2005-11-28 23:01:00 +03:00
if ( ! ( pvl = dm_pool_alloc ( cmd - > mem , sizeof ( * pvl ) ) ) ) {
log_error ( " pv_list allocation failed " ) ;
return 0 ;
}
pvl - > pv = peg - > pv ;
list_add ( & spvs - > pvs , & pvl - > list ) ;
return 1 ;
}
2005-11-24 23:58:44 +03:00
/*
* Construct list of segments of LVs showing which PVs they use .
*/
struct list * build_parallel_areas_from_lv ( struct cmd_context * cmd ,
struct logical_volume * lv )
{
struct list * parallel_areas ;
2005-11-28 23:01:00 +03:00
struct seg_pvs * spvs ;
uint32_t current_le = 0 ;
2005-11-24 23:58:44 +03:00
if ( ! ( parallel_areas = dm_pool_alloc ( cmd - > mem , sizeof ( * parallel_areas ) ) ) ) {
log_error ( " parallel_areas allocation failed " ) ;
return NULL ;
}
list_init ( parallel_areas ) ;
2005-11-28 23:01:00 +03:00
do {
if ( ! ( spvs = dm_pool_zalloc ( cmd - > mem , sizeof ( * spvs ) ) ) ) {
log_error ( " allocation failed " ) ;
return NULL ;
}
list_init ( & spvs - > pvs ) ;
spvs - > le = current_le ;
spvs - > len = lv - > le_count - current_le ;
list_add ( parallel_areas , & spvs - > list ) ;
/* Find next segment end */
/* FIXME Unnecessary nesting! */
2006-10-08 03:40:36 +04:00
if ( ! _for_each_pv ( cmd , lv , current_le , spvs - > len , & spvs - > len ,
0 , 0 , - 1 , 0 , _add_pvs , ( void * ) spvs ) ) {
2005-11-28 23:01:00 +03:00
stack ;
return NULL ;
}
current_le = spvs - > le + spvs - > len ;
} while ( current_le < lv - > le_count ) ;
/* FIXME Merge adjacent segments with identical PV lists (avoids need for contiguous allocation attempts between successful allocations) */
2005-11-24 23:58:44 +03:00
return parallel_areas ;
}