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 .
2007-08-21 00:55:30 +04:00
* Copyright ( C ) 2004 - 2007 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
2007-08-21 00:55:30 +04:00
* of the GNU Lesser General Public License v .2 .1 .
2004-03-30 23:35:44 +04:00
*
2007-08-21 00:55:30 +04:00
* You should have received a copy of the GNU Lesser General Public License
2004-03-30 23:35:44 +04:00
* along with this program ; if not , write to the Free Software Foundation ,
* Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
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"
2007-08-04 01:22:10 +04:00
# include "archiver.h"
2007-08-20 21:04:53 +04:00
# include "activate.h"
2001-11-06 13:29:56 +03:00
2007-08-07 22:55:38 +04:00
struct lv_names {
const char * old ;
const char * new ;
} ;
2008-01-17 20:17:09 +03:00
int add_seg_to_segs_using_this_lv ( struct logical_volume * lv ,
struct lv_segment * seg )
2008-01-16 22:00:59 +03:00
{
struct seg_list * sl ;
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( sl , & lv - > segs_using_this_lv ) {
2008-01-16 22:00:59 +03:00
if ( sl - > seg = = seg ) {
sl - > count + + ;
return 1 ;
}
}
2008-01-19 01:00:46 +03:00
log_very_verbose ( " Adding %s:% " PRIu32 " as an user of %s " ,
seg - > lv - > name , seg - > le , lv - > name ) ;
2008-01-16 22:00:59 +03:00
if ( ! ( sl = dm_pool_zalloc ( lv - > vg - > cmd - > mem , sizeof ( * sl ) ) ) ) {
log_error ( " Failed to allocate segment list " ) ;
return 0 ;
}
sl - > count = 1 ;
sl - > seg = seg ;
2008-11-04 01:14:30 +03:00
dm_list_add ( & lv - > segs_using_this_lv , & sl - > list ) ;
2008-01-16 22:00:59 +03:00
return 1 ;
}
2008-01-17 20:17:09 +03:00
int remove_seg_from_segs_using_this_lv ( struct logical_volume * lv ,
struct lv_segment * seg )
2008-01-16 22:00:59 +03:00
{
struct seg_list * sl ;
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( sl , & lv - > segs_using_this_lv ) {
2008-01-16 22:00:59 +03:00
if ( sl - > seg ! = seg )
continue ;
if ( sl - > count > 1 )
sl - > count - - ;
2008-01-19 01:00:46 +03:00
else {
log_very_verbose ( " %s:% " PRIu32 " is no longer a user "
" of %s " , seg - > lv - > name , seg - > le ,
lv - > name ) ;
2008-11-04 01:14:30 +03:00
dm_list_del ( & sl - > list ) ;
2008-01-19 01:00:46 +03:00
}
2008-01-16 22:00:59 +03:00
return 1 ;
}
return 0 ;
}
/*
* This is a function specialized for the common case where there is
* only one segment which uses the LV .
* e . g . the LV is a layer inserted by insert_layer_for_lv ( ) .
*
* In general , walk through lv - > segs_using_this_lv .
*/
struct lv_segment * get_only_segment_using_this_lv ( struct logical_volume * lv )
{
struct seg_list * sl ;
2008-11-04 01:14:30 +03:00
if ( dm_list_size ( & lv - > segs_using_this_lv ) ! = 1 ) {
2008-01-16 22:00:59 +03:00
log_error ( " %s is expected to have only one segment using it, "
" while it has %d " , lv - > name ,
2008-11-04 01:14:30 +03:00
dm_list_size ( & lv - > segs_using_this_lv ) ) ;
2008-01-16 22:00:59 +03:00
return NULL ;
}
2008-11-04 01:14:30 +03:00
sl = dm_list_item ( dm_list_first ( & lv - > segs_using_this_lv ) , struct seg_list ) ;
2008-01-16 22:00:59 +03:00
2008-01-16 23:00:01 +03:00
if ( sl - > count ! = 1 ) {
log_error ( " %s is expected to have only one segment using it, "
" while %s:% " PRIu32 " uses it %d times " ,
lv - > name , sl - > seg - > lv - > name , sl - > seg - > le , sl - > count ) ;
return NULL ;
}
2008-01-16 22:00:59 +03:00
return sl - > seg ;
}
2005-11-28 23:01:00 +03:00
/*
* PVs used by a segment of an LV
*/
struct seg_pvs {
2008-11-04 01:14:30 +03:00
struct dm_list list ;
2005-11-28 23:01:00 +03:00
2008-11-04 01:14:30 +03:00
struct dm_list pvs ; /* struct pv_list */
2005-11-28 23:01:00 +03:00
uint32_t le ;
uint32_t len ;
} ;
2008-11-04 01:14:30 +03:00
static struct seg_pvs * _find_seg_pvs_by_le ( struct dm_list * list , uint32_t le )
2007-12-20 18:42:55 +03:00
{
struct seg_pvs * spvs ;
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( spvs , list )
2007-12-20 18:42:55 +03:00
if ( le > = spvs - > le & & le < spvs - > le + spvs - > len )
return spvs ;
return NULL ;
}
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
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( lvl , & lv - > vg - > lvs ) {
2005-06-01 20:51:55 +04:00
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
2008-01-30 16:19:47 +03:00
if ( ! ( seg = dm_pool_zalloc ( mem , sizeof ( * seg ) ) ) )
return_NULL ;
2005-10-18 17:43:40 +04:00
if ( ! ( seg - > areas = dm_pool_zalloc ( mem , areas_sz ) ) ) {
dm_pool_free ( mem , seg ) ;
2008-01-30 16:19:47 +03:00
return_NULL ;
2001-11-29 21:45:35 +03:00
}
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 ;
2008-11-04 01:14:30 +03:00
dm_list_init ( & seg - > tags ) ;
2004-03-08 20:19:15 +03:00
2008-01-26 03:25:04 +03:00
if ( log_lv & & ! attach_mirror_log ( seg , log_lv ) )
return_NULL ;
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 ;
}
2008-11-04 01:14:30 +03:00
dm_list_add ( & lv - > segments , & seg - > list ) ;
2005-06-01 20:51:55 +04:00
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 ) {
2007-12-20 18:42:55 +03:00
if ( release_pv_segment ( seg_pvseg ( seg , s ) , area_reduction ) & &
seg - > area_len = = area_reduction )
seg_type ( seg , s ) = AREA_UNASSIGNED ;
2005-06-14 21:54:48 +04:00
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 ) {
2008-01-19 01:00:46 +03:00
log_very_verbose ( " Remove %s:% " PRIu32 " [% " PRIu32 " ] from "
" the top of LV %s:% " PRIu32 ,
seg - > lv - > name , seg - > le , s ,
seg_lv ( seg , s ) - > name , seg_le ( seg , s ) ) ;
2008-01-16 22:00:59 +03:00
remove_seg_from_segs_using_this_lv ( seg_lv ( seg , s ) , seg ) ;
2005-06-14 21:54:48 +04:00
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 ) ;
2008-01-30 16:19:47 +03:00
if ( ! set_lv_segment_area_pv ( seg_to , area_to , pv , pe ) )
return_0 ;
2005-06-14 21:54:48 +04:00
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 ) ;
2008-01-16 22:00:59 +03:00
if ( ! set_lv_segment_area_lv ( seg_to , area_to , lv , le , 0 ) )
return_0 ;
2005-06-14 21:54:48 +04:00
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 ) =
2008-01-30 16:19:47 +03:00
assign_peg_to_lvseg ( pv , pe , seg - > area_len , seg , area_num ) ) )
return_0 ;
2005-05-03 21:28:23 +04:00
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 .
*/
2008-01-16 22:00:59 +03:00
int set_lv_segment_area_lv ( struct lv_segment * seg , uint32_t area_num ,
struct logical_volume * lv , uint32_t le ,
uint32_t flags )
2005-04-22 19:43:02 +04:00
{
2008-01-19 01:00:46 +03:00
log_very_verbose ( " Stack %s:% " PRIu32 " [% " PRIu32 " ] on LV %s:% " PRIu32 ,
seg - > lv - > name , seg - > le , area_num , lv - > name , le ) ;
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 ;
2008-01-16 22:00:59 +03:00
if ( ! add_seg_to_segs_using_this_lv ( lv , seg ) )
return_0 ;
return 1 ;
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 ) ;
2008-01-30 16:19:47 +03:00
if ( ! ( newareas = dm_pool_zalloc ( lv - > vg - > cmd - > mem , areas_sz ) ) )
return_0 ;
2005-10-18 17:43:40 +04:00
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 ;
2008-11-04 01:14:30 +03:00
dm_list_iterate_back_items ( seg , & lv - > segments ) {
2005-06-01 20:51:55 +04:00
if ( ! count )
break ;
if ( seg - > len < = count ) {
/* remove this segment completely */
/* FIXME Check this is safe */
2008-01-30 16:19:47 +03:00
if ( seg - > log_lv & & ! lv_remove ( seg - > log_lv ) )
return_0 ;
2008-11-04 01:14:30 +03:00
dm_list_del ( & seg - > list ) ;
2005-06-01 20:51:55 +04:00
reduction = seg - > len ;
} else
reduction = count ;
2008-01-30 16:19:47 +03:00
if ( ! _lv_segment_reduce ( seg , reduction ) )
return_0 ;
2005-06-01 20:51:55 +04:00
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 ) {
2008-01-30 16:19:47 +03:00
if ( ! ( lvl = find_lv_in_vg ( lv - > vg , lv - > name ) ) )
return_0 ;
2005-06-03 19:44:12 +04:00
2008-11-04 01:14:30 +03:00
dm_list_del ( & lvl - > list ) ;
2005-06-03 19:44:12 +04:00
2008-04-22 16:54:33 +04:00
if ( ! ( lv - > status & SNAPSHOT ) )
lv - > vg - > lv_count - - ;
2005-06-03 19:44:12 +04:00
} else if ( lv - > vg - > fid - > fmt - > ops - > lv_setup & &
2008-01-30 16:19:47 +03:00
! lv - > vg - > fid - > fmt - > ops - > lv_setup ( lv - > vg - > fid , lv ) )
return_0 ;
2005-06-01 20:51:55 +04:00
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
}
2008-01-17 16:13:54 +03:00
/*
* Empty an LV and add error segment .
*/
2008-01-17 16:54:05 +03:00
int replace_lv_with_error_segment ( struct logical_volume * lv )
2008-01-17 16:13:54 +03:00
{
uint32_t len = lv - > le_count ;
if ( ! lv_empty ( lv ) )
return_0 ;
if ( ! lv_add_virtual_segment ( lv , 0 , len ,
get_segtype_from_string ( lv - > vg - > cmd ,
" error " ) ) )
return_0 ;
return 1 ;
}
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 )
{
2008-01-30 16:19:47 +03:00
if ( ! lv_reduce ( lv , lv - > le_count ) )
return_0 ;
2005-06-01 20:51:55 +04:00
return 1 ;
}
/*
* A set of contiguous physical extents allocated
*/
struct alloced_area {
2008-11-04 01:14:30 +03:00
struct dm_list list ;
2005-06-01 20:51:55 +04:00
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
2008-11-04 01:14:30 +03:00
struct dm_list * parallel_areas ; /* PVs to avoid */
2005-11-24 23:58:44 +03:00
2005-06-01 20:51:55 +04:00
struct alloced_area log_area ; /* Extent used for log */
2008-11-04 01:14:30 +03:00
struct dm_list alloced_areas [ 0 ] ; /* Lists of areas in each stripe */
2005-06-01 20:51:55 +04:00
} ;
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 ,
2008-11-04 01:14:30 +03:00
struct dm_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 ;
}
2007-11-22 17:54:35 +03:00
if ( log_count & & stripes > 1 ) {
log_error ( " Can't mix striping with a mirror log yet. " ) ;
2005-06-01 20:51:55 +04:00
return NULL ;
}
if ( segtype_is_virtual ( segtype ) )
area_count = 0 ;
else if ( mirrors > 1 )
area_count = mirrors ;
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 + + )
2008-11-04 01:14:30 +03:00
dm_list_init ( & ah - > alloced_areas [ s ] ) ;
2005-06-01 20:51:55 +04:00
2005-11-24 23:58:44 +03:00
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
}
2008-11-04 01:14:30 +03:00
static int _log_parallel_areas ( struct dm_pool * mem , struct dm_list * parallel_areas )
2006-09-11 18:24:58 +04:00
{
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 ;
}
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( spvs , parallel_areas ) {
dm_list_iterate_items ( pvl , & spvs - > pvs ) {
2007-10-12 18:29:32 +04:00
if ( ! dm_pool_grow_object ( mem , pv_dev_name ( pvl - > pv ) , strlen ( pv_dev_name ( pvl - > pv ) ) ) ) {
2006-09-11 18:24:58 +04:00
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 ,
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
{
2007-12-20 18:42:55 +03:00
uint32_t s , extents , area_multiple ;
2005-06-01 20:51:55 +04:00
struct lv_segment * seg ;
2004-03-26 23:35:14 +03:00
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 ,
2007-12-20 18:42:55 +03:00
area_count ,
2005-06-01 20:51:55 +04:00
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 ;
}
2008-01-30 16:19:47 +03:00
for ( s = 0 ; s < area_count ; s + + )
if ( ! set_lv_segment_area_pv ( seg , s , aa [ s ] . pv , aa [ s ] . pe ) )
return_0 ;
2001-11-29 21:45:35 +03:00
2008-11-04 01:14:30 +03:00
dm_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 ,
2008-11-04 01:14:30 +03:00
struct dm_list * alloced_areas ,
2005-06-01 20:51:55 +04:00
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
uint32_t region_size ,
struct logical_volume * log_lv )
{
struct alloced_area * aa ;
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( aa , & alloced_areas [ 0 ] ) {
2005-06-01 20:51:55 +04:00
if ( ! _setup_alloced_segment ( lv , status , area_count ,
stripe_size , segtype , aa ,
2008-01-30 16:19:47 +03:00
region_size , log_lv ) )
return_0 ;
2005-06-01 20:51:55 +04:00
}
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 ;
2008-11-04 01:14:30 +03:00
dm_list_add ( & ah - > alloced_areas [ s ] , & aa [ s ] . list ) ;
2005-06-01 20:51:55 +04:00
}
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 ,
2007-08-22 18:38:18 +04:00
only_single_area_segments ? 1U : 0U ,
top_level_area_index ! = - 1 ? top_level_area_index : ( int ) s ,
2006-10-08 03:40:36 +04:00
only_single_area_segments , fn ,
2006-10-07 16:41:06 +04:00
data ) ) )
stack ;
} else if ( seg_type ( seg , s ) = = AREA_PV )
2007-08-22 18:38:18 +04:00
if ( ! ( r = fn ( cmd , seg_pvseg ( seg , s ) , top_level_area_index ! = - 1 ? ( uint32_t ) 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 ;
}
2007-08-22 18:38:18 +04:00
static int _is_condition ( struct cmd_context * cmd __attribute ( ( unused ) ) ,
2006-10-08 16:01:13 +04:00
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 ,
2008-11-04 01:14:30 +03:00
struct dm_list * pvms , struct pv_area * * areas ,
2005-11-28 23:01:00 +03:00
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 ;
2008-11-04 01:14:30 +03:00
struct dm_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 ;
2008-11-04 01:14:30 +03:00
dm_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 .
*/
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( pvm , pvms ) {
if ( dm_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 )
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( pvl , parallel_pvs )
2005-11-25 00:23:55 +03:00
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 */
2008-11-04 01:14:30 +03:00
dm_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 ) :
2008-01-30 16:19:47 +03:00
NULL ) )
return_0 ;
2005-06-01 20:51:55 +04:00
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 ,
2007-08-22 18:38:18 +04:00
struct logical_volume * lv ,
2005-11-24 23:58:44 +03:00
uint32_t new_extents ,
2007-12-06 01:11:20 +03:00
unsigned can_split ,
2008-11-04 01:14:30 +03:00
struct dm_list * allocatable_pvs )
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 ;
int r = 0 ;
2008-11-04 01:14:30 +03:00
struct dm_list * pvms ;
2005-06-01 20:51:55 +04:00
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 ;
}
2007-11-22 17:54:35 +03:00
if ( ah - > alloc = = ALLOC_CONTIGUOUS )
2005-06-01 20:51:55 +04:00
can_split = 0 ;
2008-11-04 01:14:30 +03:00
if ( lv & & ! dm_list_empty ( & lv - > segments ) )
prev_lvseg = dm_list_item ( dm_list_last ( & lv - > segments ) ,
2005-06-01 20:51:55 +04:00
struct lv_segment ) ;
/*
* Build the sets of available areas on the pv ' s .
*/
2008-01-30 16:19:47 +03:00
if ( ! ( pvms = create_pv_maps ( ah - > mem , vg , allocatable_pvs ) ) )
return_0 ;
2005-06-01 20:51:55 +04:00
2006-09-11 18:24:58 +04:00
if ( ! _log_parallel_areas ( ah - > mem , ah - > parallel_areas ) )
stack ;
2008-11-04 01:14:30 +03:00
areas_size = dm_list_size ( pvms ) ;
2008-09-29 13:59:10 +04:00
if ( areas_size & & areas_size < ( ah - > area_count + ah - > log_count ) ) {
2005-06-01 20:51:55 +04:00
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
2008-11-04 01:14:30 +03:00
dm_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 ,
2008-11-04 01:14:30 +03:00
struct dm_list * allocatable_pvs ,
2005-11-24 23:58:44 +03:00
alloc_policy_t alloc ,
2008-11-04 01:14:30 +03:00
struct dm_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 ,
2007-11-22 17:54:35 +03:00
stripes , log_count , parallel_areas ) ) )
return_NULL ;
2001-11-06 13:55:01 +03:00
2005-06-01 20:51:55 +04:00
if ( ! segtype_is_virtual ( segtype ) & &
2007-08-22 18:38:18 +04:00
! _allocate ( ah , vg , lv , ( lv ? lv - > le_count : 0 ) + extents ,
2007-12-20 18:42:55 +03:00
1 , allocatable_pvs ) ) {
2005-06-01 20:51:55 +04:00
alloc_destroy ( ah ) ;
2008-01-30 16:19:47 +03:00
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 ,
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 ,
2008-01-30 16:19:47 +03:00
region_size , log_lv ) )
return_0 ;
2004-05-11 20:01:58 +04:00
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 & &
2008-01-30 16:19:47 +03:00
! lv - > vg - > fid - > fmt - > ops - > lv_setup ( lv - > vg - > fid , lv ) )
return_0 ;
2004-05-11 20:01:58 +04:00
return 1 ;
}
2005-06-01 20:51:55 +04:00
/*
2007-12-20 18:42:55 +03:00
* " mirror " segment type doesn ' t support split .
* So , when adding mirrors to linear LV segment , first split it ,
* then convert it to " mirror " and add areas .
2005-06-01 20:51:55 +04:00
*/
2007-12-20 18:42:55 +03:00
static struct lv_segment * _convert_seg_to_mirror ( struct lv_segment * seg ,
uint32_t region_size ,
struct logical_volume * log_lv )
2005-04-07 16:39:44 +04:00
{
2007-12-20 18:42:55 +03:00
struct lv_segment * newseg ;
uint32_t s ;
2005-04-07 16:39:44 +04:00
2007-12-20 18:42:55 +03:00
if ( ! seg_is_striped ( seg ) ) {
log_error ( " Can't convert non-striped segment to mirrored. " ) ;
return NULL ;
2005-04-07 16:39:44 +04:00
}
2007-12-20 18:42:55 +03:00
if ( seg - > area_count > 1 ) {
log_error ( " Can't convert striped segment with multiple areas "
" to mirrored. " ) ;
return NULL ;
2005-04-07 16:39:44 +04:00
}
2005-04-22 19:44:00 +04:00
2007-12-20 18:42:55 +03:00
if ( ! ( newseg = alloc_lv_segment ( seg - > lv - > vg - > cmd - > mem ,
get_segtype_from_string ( seg - > lv - > vg - > cmd , " mirror " ) ,
seg - > lv , seg - > le , seg - > len ,
seg - > status , seg - > stripe_size ,
log_lv ,
seg - > area_count , seg - > area_len ,
seg - > chunk_size , region_size ,
seg - > extents_copied ) ) ) {
log_error ( " Couldn't allocate converted LV segment " ) ;
return NULL ;
2005-06-01 20:51:55 +04:00
}
2005-04-07 16:39:44 +04:00
2007-12-20 18:42:55 +03:00
for ( s = 0 ; s < seg - > area_count ; s + + )
if ( ! move_lv_segment_area ( newseg , s , seg , s ) )
return_NULL ;
2005-06-01 20:51:55 +04:00
2008-11-04 01:14:30 +03:00
dm_list_add ( & seg - > list , & newseg - > list ) ;
dm_list_del ( & seg - > list ) ;
2005-06-01 20:51:55 +04:00
2007-12-20 18:42:55 +03:00
return newseg ;
2005-04-07 16:39:44 +04:00
}
2005-06-03 18:49:51 +04:00
/*
2007-12-20 18:42:55 +03:00
* Add new areas to mirrored segments
2005-06-03 18:49:51 +04:00
*/
2007-12-20 18:42:55 +03:00
int lv_add_mirror_areas ( struct alloc_handle * ah ,
struct logical_volume * lv , uint32_t le ,
uint32_t region_size )
2005-06-03 18:49:51 +04:00
{
2007-12-20 18:42:55 +03:00
struct alloced_area * aa ;
2005-06-03 18:49:51 +04:00
struct lv_segment * seg ;
2007-12-20 18:42:55 +03:00
uint32_t current_le = le ;
uint32_t s , old_area_count , new_area_count ;
2005-06-03 18:49:51 +04:00
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( aa , & ah - > alloced_areas [ 0 ] ) {
2007-12-20 18:42:55 +03:00
if ( ! ( seg = find_seg_by_le ( lv , current_le ) ) ) {
log_error ( " Failed to find segment for %s extent % "
PRIu32 , lv - > name , current_le ) ;
return 0 ;
}
2005-06-03 18:49:51 +04:00
2007-12-20 18:42:55 +03:00
/* Allocator assures aa[0].len <= seg->area_len */
if ( aa [ 0 ] . len < seg - > area_len ) {
if ( ! lv_split_segment ( lv , seg - > le + aa [ 0 ] . len ) ) {
log_error ( " Failed to split segment at %s "
" extent % " PRIu32 , lv - > name , le ) ;
return 0 ;
}
}
if ( ! seg_is_mirrored ( seg ) & &
( ! ( seg = _convert_seg_to_mirror ( seg , region_size , NULL ) ) ) )
2008-01-17 20:17:09 +03:00
return_0 ;
2005-06-03 18:49:51 +04:00
2007-12-20 18:42:55 +03:00
old_area_count = seg - > area_count ;
new_area_count = old_area_count + ah - > area_count ;
if ( ! _lv_segment_add_areas ( lv , seg , new_area_count ) )
return_0 ;
for ( s = 0 ; s < ah - > area_count ; s + + ) {
if ( ! set_lv_segment_area_pv ( seg , s + old_area_count ,
aa [ s ] . pv , aa [ s ] . pe ) )
return_0 ;
}
current_le + = seg - > area_len ;
2005-10-27 23:58:22 +04:00
}
2005-06-03 18:49:51 +04:00
2007-12-20 18:42:55 +03:00
lv - > status | = MIRRORED ;
2005-06-03 18:49:51 +04:00
if ( lv - > vg - > fid - > fmt - > ops - > lv_setup & &
2007-12-20 18:42:55 +03:00
! lv - > vg - > fid - > fmt - > ops - > lv_setup ( lv - > vg - > fid , lv ) )
return_0 ;
2005-06-03 18:49:51 +04:00
return 1 ;
}
2005-10-28 16:48:50 +04:00
/*
2007-12-20 18:42:55 +03:00
* Add mirror image LVs to mirrored segments
2005-10-28 16:48:50 +04:00
*/
2007-12-20 18:42:55 +03:00
int lv_add_mirror_lvs ( struct logical_volume * lv ,
struct logical_volume * * sub_lvs ,
uint32_t num_extra_areas ,
uint32_t status , uint32_t region_size )
2005-10-28 16:48:50 +04:00
{
struct lv_segment * seg ;
uint32_t old_area_count , new_area_count ;
uint32_t m ;
2007-12-20 18:42:55 +03:00
struct segment_type * mirror_segtype ;
2005-10-28 16:48:50 +04:00
2007-12-20 18:42:55 +03:00
seg = first_seg ( lv ) ;
2008-11-04 01:14:30 +03:00
if ( dm_list_size ( & lv - > segments ) ! = 1 | | seg_type ( seg , 0 ) ! = AREA_LV ) {
2007-12-20 18:42:55 +03:00
log_error ( " Mirror layer must be inserted before adding mirrors " ) ;
return_0 ;
2005-10-28 16:48:50 +04:00
}
2007-12-20 18:42:55 +03:00
mirror_segtype = get_segtype_from_string ( lv - > vg - > cmd , " mirror " ) ;
if ( seg - > segtype ! = mirror_segtype )
if ( ! ( seg = _convert_seg_to_mirror ( seg , region_size , NULL ) ) )
return_0 ;
if ( region_size & & region_size ! = seg - > region_size ) {
log_error ( " Conflicting region_size " ) ;
return 0 ;
}
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 ;
}
2008-01-16 22:00:59 +03:00
for ( m = 0 ; m < old_area_count ; m + + )
2007-12-20 18:42:55 +03:00
seg_lv ( seg , m ) - > status | = status ;
2005-10-28 16:48:50 +04:00
for ( m = old_area_count ; m < new_area_count ; m + + ) {
2008-01-16 22:00:59 +03:00
if ( ! set_lv_segment_area_lv ( seg , m , sub_lvs [ m - old_area_count ] ,
0 , status ) )
return_0 ;
2007-12-20 21:55:46 +03:00
sub_lvs [ m - old_area_count ] - > status & = ~ VISIBLE_LV ;
2005-10-28 16:48:50 +04:00
}
2007-12-21 02:12:27 +03:00
lv - > status | = MIRRORED ;
2005-10-28 16:48:50 +04:00
return 1 ;
}
2005-06-03 18:49:51 +04:00
2007-12-20 18:42:55 +03:00
/*
* Turn an empty LV into a mirror log .
*/
int lv_add_log_segment ( struct alloc_handle * ah , struct logical_volume * log_lv )
{
struct lv_segment * seg ;
2008-11-04 01:14:30 +03:00
if ( dm_list_size ( & log_lv - > segments ) ) {
2007-12-20 18:42:55 +03:00
log_error ( " Log segments can only be added to an empty LV " ) ;
return 0 ;
}
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 ;
}
2008-01-17 20:17:09 +03:00
if ( ! set_lv_segment_area_pv ( seg , 0 , ah - > log_area . pv , ah - > log_area . pe ) )
return_0 ;
2007-12-20 18:42:55 +03:00
2008-11-04 01:14:30 +03:00
dm_list_add ( & log_lv - > segments , & seg - > list ) ;
2007-12-20 18:42:55 +03:00
log_lv - > le_count + = ah - > log_area . len ;
2008-01-17 20:17:09 +03:00
log_lv - > size + = ( uint64_t ) log_lv - > le_count * log_lv - > vg - > extent_size ;
2007-12-20 18:42:55 +03:00
if ( log_lv - > vg - > fid - > fmt - > ops - > lv_setup & &
2008-01-17 20:17:09 +03:00
! log_lv - > vg - > fid - > fmt - > ops - > lv_setup ( log_lv - > vg - > fid , log_lv ) )
return_0 ;
2007-12-20 18:42:55 +03:00
return 1 ;
}
2007-12-20 21:55:46 +03:00
static int _lv_extend_mirror ( struct alloc_handle * ah ,
struct logical_volume * lv ,
uint32_t extents , uint32_t first_area )
{
struct lv_segment * seg ;
uint32_t m , s ;
seg = first_seg ( lv ) ;
for ( m = first_area , s = 0 ; s < seg - > area_count ; s + + ) {
if ( is_temporary_mirror_layer ( seg_lv ( seg , s ) ) ) {
if ( ! _lv_extend_mirror ( ah , seg_lv ( seg , s ) , extents , m ) )
return_0 ;
m + = lv_mirror_count ( seg_lv ( seg , s ) ) ;
continue ;
}
if ( ! lv_add_segment ( ah , m + + , 1 , seg_lv ( seg , s ) ,
get_segtype_from_string ( lv - > vg - > cmd ,
" striped " ) ,
0 , 0 , 0 , NULL ) ) {
log_error ( " Aborting. Failed to extend %s. " ,
seg_lv ( seg , s ) - > name ) ;
return 0 ;
}
}
seg - > area_len + = extents ;
seg - > len + = extents ;
lv - > le_count + = extents ;
lv - > size + = ( uint64_t ) extents * lv - > vg - > extent_size ;
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 ,
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 ,
2007-12-20 18:42:55 +03:00
struct physical_volume * mirrored_pv __attribute ( ( unused ) ) ,
uint32_t mirrored_pe __attribute ( ( unused ) ) ,
2008-11-04 01:14:30 +03:00
uint32_t status , struct dm_list * allocatable_pvs ,
2005-06-01 20:51:55 +04:00
alloc_policy_t alloc )
2001-11-06 14:31:29 +03:00
{
2005-06-01 20:51:55 +04:00
int r = 1 ;
struct alloc_handle * ah ;
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 ,
2007-12-20 18:42:55 +03:00
extents , allocatable_pvs , alloc , NULL ) ) )
2007-11-22 17:54:35 +03:00
return_0 ;
2001-11-06 14:31:29 +03:00
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 ,
2008-01-30 16:19:47 +03:00
status , 0 , NULL ) )
goto_out ;
2005-06-03 23:48:19 +04:00
} else {
2007-12-20 21:55:46 +03:00
if ( ! _lv_extend_mirror ( ah , lv , extents , 0 ) )
return_0 ;
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 ;
}
2007-08-07 00:35:48 +04:00
/*
* Minimal LV renaming function .
* Metadata transaction should be made by caller .
* Assumes new_name is allocated from cmd - > mem pool .
*/
static int _rename_single_lv ( struct logical_volume * lv , char * new_name )
{
struct volume_group * vg = lv - > vg ;
if ( find_lv_in_vg ( vg , new_name ) ) {
log_error ( " Logical volume \" %s \" already exists in "
" volume group \" %s \" " , new_name , vg - > name ) ;
2007-08-07 20:57:09 +04:00
return 0 ;
2007-08-07 00:35:48 +04:00
}
if ( lv - > status & LOCKED ) {
log_error ( " Cannot rename locked LV %s " , lv - > name ) ;
2007-08-07 20:57:09 +04:00
return 0 ;
2007-08-07 00:35:48 +04:00
}
lv - > name = new_name ;
return 1 ;
}
/*
* Rename sub LV .
2007-08-07 20:57:09 +04:00
* ' lv_name_old ' and ' lv_name_new ' are old and new names of the main LV .
2007-08-07 00:35:48 +04:00
*/
static int _rename_sub_lv ( struct cmd_context * cmd ,
struct logical_volume * lv ,
2007-08-07 20:57:09 +04:00
const char * lv_name_old , const char * lv_name_new )
2007-08-07 00:35:48 +04:00
{
char * suffix , * new_name ;
2007-08-07 20:57:09 +04:00
size_t len ;
2007-08-07 00:35:48 +04:00
2007-08-08 22:00:36 +04:00
/*
* A sub LV name starts with lv_name_old + ' _ ' .
* The suffix follows lv_name_old and includes ' _ ' .
*/
len = strlen ( lv_name_old ) ;
if ( strncmp ( lv - > name , lv_name_old , len ) | | lv - > name [ len ] ! = ' _ ' ) {
log_error ( " Cannot rename \" %s \" : name format not recognized "
" for internal LV \" %s \" " ,
lv_name_old , lv - > name ) ;
return 0 ;
}
suffix = lv - > name + len ;
2007-08-07 00:35:48 +04:00
2008-01-17 20:17:09 +03:00
/*
2007-08-07 00:35:48 +04:00
* Compose a new name for sub lv :
* e . g . new name is " lvol1_mlog "
* if the sub LV is " lvol0_mlog " and
* a new name for main LV is " lvol1 "
*/
2007-08-07 20:57:09 +04:00
len = strlen ( lv_name_new ) + strlen ( suffix ) + 1 ;
new_name = dm_pool_alloc ( cmd - > mem , len ) ;
2007-08-07 00:35:48 +04:00
if ( ! new_name ) {
log_error ( " Failed to allocate space for new name " ) ;
2007-08-07 20:57:09 +04:00
return 0 ;
2007-08-07 00:35:48 +04:00
}
2007-08-07 20:57:09 +04:00
if ( ! dm_snprintf ( new_name , len , " %s%s " , lv_name_new , suffix ) ) {
2007-08-07 00:35:48 +04:00
log_error ( " Failed to create new name " ) ;
2007-08-07 20:57:09 +04:00
return 0 ;
2007-08-07 00:35:48 +04:00
}
/* Rename it */
return _rename_single_lv ( lv , new_name ) ;
}
/* Callback for _for_each_sub_lv */
static int _rename_cb ( struct cmd_context * cmd , struct logical_volume * lv ,
void * data )
{
2007-08-07 22:55:38 +04:00
struct lv_names * lv_names = ( struct lv_names * ) data ;
2007-08-07 00:35:48 +04:00
2007-08-07 22:55:38 +04:00
return _rename_sub_lv ( cmd , lv , lv_names - > old , lv_names - > new ) ;
2007-08-07 00:35:48 +04:00
}
/*
* Loop down sub LVs and call " func " for each .
* " func " is responsible to log necessary information on failure .
*/
static int _for_each_sub_lv ( struct cmd_context * cmd , struct logical_volume * lv ,
int ( * func ) ( struct cmd_context * cmd ,
2008-01-30 17:00:02 +03:00
struct logical_volume * lv ,
void * data ) ,
2007-08-07 00:35:48 +04:00
void * data )
{
struct lv_segment * seg ;
2007-08-22 18:38:18 +04:00
uint32_t s ;
2007-08-07 00:35:48 +04:00
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( seg , & lv - > segments ) {
2007-08-07 00:35:48 +04:00
if ( seg - > log_lv & & ! func ( cmd , seg - > log_lv , data ) )
2007-08-07 20:57:09 +04:00
return 0 ;
2007-12-20 21:55:46 +03:00
for ( s = 0 ; s < seg - > area_count ; s + + ) {
if ( seg_type ( seg , s ) ! = AREA_LV )
continue ;
if ( ! func ( cmd , seg_lv ( seg , s ) , data ) )
return 0 ;
if ( ! _for_each_sub_lv ( cmd , seg_lv ( seg , s ) , func , data ) )
2007-08-07 20:57:09 +04:00
return 0 ;
2007-12-20 21:55:46 +03:00
}
2007-08-07 00:35:48 +04:00
}
return 1 ;
}
2007-08-04 01:22:10 +04:00
/*
* Core of LV renaming routine .
* VG must be locked by caller .
*/
int lv_rename ( struct cmd_context * cmd , struct logical_volume * lv ,
2007-08-06 18:57:48 +04:00
const char * new_name )
2007-08-04 01:22:10 +04:00
{
struct volume_group * vg = lv - > vg ;
2007-08-07 22:55:38 +04:00
struct lv_names lv_names ;
2007-08-07 00:35:48 +04:00
/* rename is not allowed on sub LVs */
2007-08-07 22:55:38 +04:00
if ( ! lv_is_visible ( lv ) ) {
2007-08-07 20:57:09 +04:00
log_error ( " Cannot rename internal LV \" %s \" . " , lv - > name ) ;
2007-08-07 00:35:48 +04:00
return 0 ;
}
2007-08-04 01:22:10 +04:00
2007-08-06 18:57:48 +04:00
if ( find_lv_in_vg ( vg , new_name ) ) {
2007-08-04 01:22:10 +04:00
log_error ( " Logical volume \" %s \" already exists in "
2007-08-06 18:57:48 +04:00
" volume group \" %s \" " , new_name , vg - > name ) ;
2007-08-04 01:22:10 +04:00
return 0 ;
}
if ( lv - > status & LOCKED ) {
log_error ( " Cannot rename locked LV %s " , lv - > name ) ;
return 0 ;
}
if ( ! archive ( vg ) )
2007-08-07 20:57:09 +04:00
return 0 ;
2007-08-04 01:22:10 +04:00
2007-08-07 00:35:48 +04:00
/* rename sub LVs */
2007-08-07 22:55:38 +04:00
lv_names . old = lv - > name ;
lv_names . new = new_name ;
if ( ! _for_each_sub_lv ( cmd , lv , _rename_cb , ( void * ) & lv_names ) )
2007-08-07 00:35:48 +04:00
return 0 ;
/* rename main LV */
2007-08-06 18:57:48 +04:00
if ( ! ( lv - > name = dm_pool_strdup ( cmd - > mem , new_name ) ) ) {
2007-08-04 01:22:10 +04:00
log_error ( " Failed to allocate space for new name " ) ;
return 0 ;
}
log_verbose ( " Writing out updated volume group " ) ;
if ( ! vg_write ( vg ) )
2007-08-07 20:57:09 +04:00
return 0 ;
2007-08-04 01:22:10 +04:00
backup ( vg ) ;
if ( ! suspend_lv ( cmd , lv ) ) {
2008-01-30 17:17:29 +03:00
stack ;
2007-08-04 01:22:10 +04:00
vg_revert ( vg ) ;
2008-01-30 17:17:29 +03:00
return 0 ;
2007-08-04 01:22:10 +04:00
}
if ( ! vg_commit ( vg ) ) {
2008-01-30 17:17:29 +03:00
stack ;
2007-08-04 01:22:10 +04:00
resume_lv ( cmd , lv ) ;
2008-01-30 17:17:29 +03:00
return 0 ;
2007-08-04 01:22:10 +04:00
}
resume_lv ( cmd , lv ) ;
return 1 ;
}
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
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( lvl , & vg - > lvs ) {
2005-05-11 20:46:59 +04:00
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 .
*/
2007-10-11 23:20:38 +04:00
struct logical_volume * lv_create_empty ( 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
{
2007-10-11 23:20:38 +04:00
struct format_instance * fi = vg - > fid ;
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 ;
2007-11-09 19:51:54 +03:00
lv - > read_ahead = vg - > cmd - > default_settings . read_ahead ;
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 ;
2008-11-04 01:14:30 +03:00
dm_list_init ( & lv - > snapshot_segs ) ;
dm_list_init ( & lv - > segments ) ;
dm_list_init ( & lv - > tags ) ;
dm_list_init ( & lv - > segs_using_this_lv ) ;
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 ) ) {
2003-04-25 02:23:24 +04:00
if ( ll )
2005-10-17 03:03:59 +04:00
dm_pool_free ( cmd - > mem , ll ) ;
2008-01-30 16:19:47 +03:00
return_NULL ;
2002-01-24 20:15:49 +03:00
}
2005-04-07 16:39:44 +04:00
if ( ! import )
vg - > lv_count + + ;
2008-11-04 01:14:30 +03:00
dm_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. */
2008-03-28 22:08:23 +03:00
if ( find_pv_in_pv_list ( & spvs - > pvs , peg - > pv ) )
2006-09-12 01:14:56 +04:00
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 ;
2008-11-04 01:14:30 +03:00
dm_list_add ( & spvs - > pvs , & pvl - > list ) ;
2005-11-28 23:01:00 +03:00
return 1 ;
}
2005-11-24 23:58:44 +03:00
/*
2008-11-04 01:14:30 +03:00
* Construct dm_list of segments of LVs showing which PVs they use .
2005-11-24 23:58:44 +03:00
*/
2008-11-04 01:14:30 +03:00
struct dm_list * build_parallel_areas_from_lv ( struct cmd_context * cmd ,
2005-11-24 23:58:44 +03:00
struct logical_volume * lv )
{
2008-11-04 01:14:30 +03:00
struct dm_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 ;
}
2008-11-04 01:14:30 +03:00
dm_list_init ( parallel_areas ) ;
2005-11-24 23:58:44 +03:00
2005-11-28 23:01:00 +03:00
do {
if ( ! ( spvs = dm_pool_zalloc ( cmd - > mem , sizeof ( * spvs ) ) ) ) {
log_error ( " allocation failed " ) ;
return NULL ;
}
2008-11-04 01:14:30 +03:00
dm_list_init ( & spvs - > pvs ) ;
2005-11-28 23:01:00 +03:00
spvs - > le = current_le ;
spvs - > len = lv - > le_count - current_le ;
2008-11-04 01:14:30 +03:00
dm_list_add ( parallel_areas , & spvs - > list ) ;
2005-11-28 23:01:00 +03:00
/* 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 ,
2008-01-30 16:19:47 +03:00
0 , 0 , - 1 , 0 , _add_pvs , ( void * ) spvs ) )
return_NULL ;
2005-11-28 23:01:00 +03:00
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 ;
}
2007-08-20 21:04:53 +04:00
int lv_remove_single ( struct cmd_context * cmd , struct logical_volume * lv ,
2007-09-25 01:30:00 +04:00
const force_t force )
2007-08-20 21:04:53 +04:00
{
struct volume_group * vg ;
struct lvinfo info ;
struct logical_volume * origin = NULL ;
vg = lv - > vg ;
if ( ! vg_check_status ( vg , LVM_WRITE ) )
return 0 ;
if ( lv_is_origin ( lv ) ) {
log_error ( " Can't remove logical volume \" %s \" under snapshot " ,
lv - > name ) ;
return 0 ;
}
if ( lv - > status & MIRROR_IMAGE ) {
log_error ( " Can't remove logical volume %s used by a mirror " ,
lv - > name ) ;
return 0 ;
}
if ( lv - > status & MIRROR_LOG ) {
log_error ( " Can't remove logical volume %s used as mirror log " ,
lv - > name ) ;
return 0 ;
}
if ( lv - > status & LOCKED ) {
log_error ( " Can't remove locked LV %s " , lv - > name ) ;
return 0 ;
}
/* FIXME Ensure not referred to by another existing LVs */
2007-11-12 23:51:54 +03:00
if ( lv_info ( cmd , lv , & info , 1 , 0 ) ) {
2007-11-04 19:28:57 +03:00
if ( info . open_count ) {
log_error ( " Can't remove open logical volume \" %s \" " ,
2007-08-20 21:04:53 +04:00
lv - > name ) ;
return 0 ;
}
2007-11-04 19:28:57 +03:00
/*
* Check for confirmation prompts in the following cases :
* 1 ) Clustered VG , and some remote nodes have the LV active
* 2 ) Non - clustered VG , but LV active locally
*/
2008-04-10 21:09:32 +04:00
if ( vg_is_clustered ( vg ) & & ! activate_lv_excl ( cmd , lv ) & &
2007-11-04 19:28:57 +03:00
( force = = PROMPT ) ) {
if ( yes_no_prompt ( " Logical volume \" %s \" is active on other "
" cluster nodes. Really remove? [y/n]: " ,
lv - > name ) = = ' n ' ) {
log_print ( " Logical volume \" %s \" not removed " ,
lv - > name ) ;
return 0 ;
}
} else if ( info . exists & & ( force = = PROMPT ) ) {
if ( yes_no_prompt ( " Do you really want to remove active "
" logical volume \" %s \" ? [y/n]: " ,
lv - > name ) = = ' n ' ) {
2008-01-17 20:17:09 +03:00
log_print ( " Logical volume \" %s \" not removed " ,
2007-11-04 19:28:57 +03:00
lv - > name ) ;
2008-01-17 20:17:09 +03:00
return 0 ;
2007-11-04 19:28:57 +03:00
}
}
}
2007-08-28 20:14:49 +04:00
if ( ! archive ( vg ) )
return 0 ;
2007-08-20 21:04:53 +04:00
/* FIXME Snapshot commit out of sequence if it fails after here? */
if ( ! deactivate_lv ( cmd , lv ) ) {
log_error ( " Unable to deactivate logical volume \" %s \" " ,
lv - > name ) ;
return 0 ;
}
if ( lv_is_cow ( lv ) ) {
origin = origin_from_cow ( lv ) ;
log_verbose ( " Removing snapshot %s " , lv - > name ) ;
2008-01-30 16:19:47 +03:00
if ( ! vg_remove_snapshot ( lv ) )
return_0 ;
2007-08-20 21:04:53 +04:00
}
log_verbose ( " Releasing logical volume \" %s \" " , lv - > name ) ;
if ( ! lv_remove ( lv ) ) {
log_error ( " Error releasing logical volume \" %s \" " , lv - > name ) ;
return 0 ;
}
/* store it on disks */
if ( ! vg_write ( vg ) )
return 0 ;
backup ( vg ) ;
if ( ! vg_commit ( vg ) )
return 0 ;
/* If no snapshots left, reload without -real. */
if ( origin & & ! lv_is_origin ( origin ) ) {
if ( ! suspend_lv ( cmd , origin ) )
log_error ( " Failed to refresh %s without snapshot. " , origin - > name ) ;
else if ( ! resume_lv ( cmd , origin ) )
log_error ( " Failed to resume %s. " , origin - > name ) ;
}
log_print ( " Logical volume \" %s \" successfully removed " , lv - > name ) ;
return 1 ;
}
2007-12-20 18:42:55 +03:00
2008-08-05 16:05:26 +04:00
/*
* remove LVs with its dependencies - LV leaf nodes should be removed first
*/
int lv_remove_with_dependencies ( struct cmd_context * cmd , struct logical_volume * lv ,
const force_t force )
{
2008-11-04 01:14:30 +03:00
struct dm_list * snh , * snht ;
2008-08-05 16:05:26 +04:00
if ( lv_is_origin ( lv ) ) {
/* remove snapshot LVs first */
2008-11-04 01:14:30 +03:00
dm_list_iterate_safe ( snh , snht , & lv - > snapshot_segs ) {
if ( ! lv_remove_with_dependencies ( cmd , dm_list_struct_base ( snh , struct lv_segment ,
2008-08-05 16:05:26 +04:00
origin_list ) - > cow ,
force ) )
return 0 ;
}
}
return lv_remove_single ( cmd , lv , force ) ;
}
2007-12-20 18:42:55 +03:00
/*
* insert_layer_for_segments_on_pv ( ) inserts a layer segment for a segment area .
* However , layer modification could split the underlying layer segment .
* This function splits the parent area according to keep the 1 : 1 relationship
* between the parent area and the underlying layer segment .
* Since the layer LV might have other layers below , build_parallel_areas ( )
* is used to find the lowest - level segment boundaries .
*/
static int _split_parent_area ( struct lv_segment * seg , uint32_t s ,
2008-11-04 01:14:30 +03:00
struct dm_list * layer_seg_pvs )
2007-12-20 18:42:55 +03:00
{
uint32_t parent_area_len , parent_le , layer_le ;
uint32_t area_multiple ;
struct seg_pvs * spvs ;
if ( seg_is_striped ( seg ) )
area_multiple = seg - > area_count ;
else
area_multiple = 1 ;
parent_area_len = seg - > area_len ;
parent_le = seg - > le ;
layer_le = seg_le ( seg , s ) ;
while ( parent_area_len > 0 ) {
/* Find the layer segment pointed at */
if ( ! ( spvs = _find_seg_pvs_by_le ( layer_seg_pvs , layer_le ) ) ) {
log_error ( " layer segment for %s:% " PRIu32 " not found " ,
seg - > lv - > name , parent_le ) ;
return 0 ;
}
if ( spvs - > le ! = layer_le ) {
log_error ( " Incompatible layer boundary: "
" %s:% " PRIu32 " [% " PRIu32 " ] on %s:% " PRIu32 ,
seg - > lv - > name , parent_le , s ,
seg_lv ( seg , s ) - > name , layer_le ) ;
return 0 ;
}
if ( spvs - > len < parent_area_len ) {
parent_le + = spvs - > len * area_multiple ;
if ( ! lv_split_segment ( seg - > lv , parent_le ) )
return_0 ;
}
parent_area_len - = spvs - > len ;
layer_le + = spvs - > len ;
}
return 1 ;
}
/*
* Split the parent LV segments if the layer LV below it is splitted .
*/
int split_parent_segments_for_layer ( struct cmd_context * cmd ,
struct logical_volume * layer_lv )
{
struct lv_list * lvl ;
struct logical_volume * parent_lv ;
struct lv_segment * seg ;
uint32_t s ;
2008-11-04 01:14:30 +03:00
struct dm_list * parallel_areas ;
2007-12-20 18:42:55 +03:00
if ( ! ( parallel_areas = build_parallel_areas_from_lv ( cmd , layer_lv ) ) )
return_0 ;
/* Loop through all LVs except itself */
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( lvl , & layer_lv - > vg - > lvs ) {
2007-12-20 18:42:55 +03:00
parent_lv = lvl - > lv ;
if ( parent_lv = = layer_lv )
continue ;
/* Find all segments that point at the layer LV */
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( seg , & parent_lv - > segments ) {
2007-12-20 18:42:55 +03:00
for ( s = 0 ; s < seg - > area_count ; s + + ) {
if ( seg_type ( seg , s ) ! = AREA_LV | |
seg_lv ( seg , s ) ! = layer_lv )
continue ;
if ( ! _split_parent_area ( seg , s , parallel_areas ) )
return_0 ;
}
}
}
return 1 ;
}
/* Remove a layer from the LV */
int remove_layers_for_segments ( struct cmd_context * cmd ,
struct logical_volume * lv ,
struct logical_volume * layer_lv ,
2008-11-04 01:14:30 +03:00
uint32_t status_mask , struct dm_list * lvs_changed )
2007-12-20 18:42:55 +03:00
{
struct lv_segment * seg , * lseg ;
uint32_t s ;
int lv_changed = 0 ;
struct lv_list * lvl ;
2008-01-19 01:00:46 +03:00
log_very_verbose ( " Removing layer %s for segments of %s " ,
layer_lv - > name , lv - > name ) ;
2007-12-20 18:42:55 +03:00
/* Find all segments that point at the temporary mirror */
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( seg , & lv - > segments ) {
2007-12-20 18:42:55 +03:00
for ( s = 0 ; s < seg - > area_count ; s + + ) {
if ( seg_type ( seg , s ) ! = AREA_LV | |
seg_lv ( seg , s ) ! = layer_lv )
continue ;
/* Find the layer segment pointed at */
if ( ! ( lseg = find_seg_by_le ( layer_lv , seg_le ( seg , s ) ) ) ) {
log_error ( " Layer segment found: %s:% " PRIu32 ,
layer_lv - > name , seg_le ( seg , s ) ) ;
return 0 ;
}
/* Check the segment params are compatible */
if ( ! seg_is_striped ( lseg ) | | lseg - > area_count ! = 1 ) {
log_error ( " Layer is not linear: %s:% " PRIu32 ,
layer_lv - > name , lseg - > le ) ;
return 0 ;
}
if ( ( lseg - > status & status_mask ) ! = status_mask ) {
log_error ( " Layer status does not match: "
" %s:% " PRIu32 " status: 0x%x/0x%x " ,
layer_lv - > name , lseg - > le ,
lseg - > status , status_mask ) ;
return 0 ;
}
if ( lseg - > le ! = seg_le ( seg , s ) | |
lseg - > area_len ! = seg - > area_len ) {
log_error ( " Layer boundary mismatch: "
" %s:% " PRIu32 " -% " PRIu32 " on "
" %s:% " PRIu32 " / "
" % " PRIu32 " -% " PRIu32 " / " ,
lv - > name , seg - > le , seg - > area_len ,
layer_lv - > name , seg_le ( seg , s ) ,
lseg - > le , lseg - > area_len ) ;
return 0 ;
}
if ( ! move_lv_segment_area ( seg , s , lseg , 0 ) )
return_0 ;
/* Replace mirror with error segment */
if ( ! ( lseg - > segtype =
get_segtype_from_string ( lv - > vg - > cmd , " error " ) ) ) {
log_error ( " Missing error segtype " ) ;
return 0 ;
}
lseg - > area_count = 0 ;
/* First time, add LV to list of LVs affected */
if ( ! lv_changed & & lvs_changed ) {
if ( ! ( lvl = dm_pool_alloc ( cmd - > mem , sizeof ( * lvl ) ) ) ) {
log_error ( " lv_list alloc failed " ) ;
return 0 ;
}
lvl - > lv = lv ;
2008-11-04 01:14:30 +03:00
dm_list_add ( lvs_changed , & lvl - > list ) ;
2007-12-20 18:42:55 +03:00
lv_changed = 1 ;
}
}
}
if ( lv_changed & & ! lv_merge_segments ( lv ) )
stack ;
return 1 ;
}
/* Remove a layer */
int remove_layers_for_segments_all ( struct cmd_context * cmd ,
struct logical_volume * layer_lv ,
uint32_t status_mask ,
2008-11-04 01:14:30 +03:00
struct dm_list * lvs_changed )
2007-12-20 18:42:55 +03:00
{
struct lv_list * lvl ;
struct logical_volume * lv1 ;
/* Loop through all LVs except the temporary mirror */
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( lvl , & layer_lv - > vg - > lvs ) {
2007-12-20 18:42:55 +03:00
lv1 = lvl - > lv ;
if ( lv1 = = layer_lv )
continue ;
if ( ! remove_layers_for_segments ( cmd , lv1 , layer_lv ,
status_mask , lvs_changed ) )
2008-01-17 20:17:09 +03:00
return_0 ;
2007-12-20 18:42:55 +03:00
}
if ( ! lv_empty ( layer_lv ) )
return_0 ;
return 1 ;
}
2007-12-21 02:12:27 +03:00
static int _move_lv_segments ( struct logical_volume * lv_to ,
struct logical_volume * lv_from ,
uint32_t set_status , uint32_t reset_status )
2007-12-20 18:42:55 +03:00
{
struct lv_segment * seg ;
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( seg , & lv_to - > segments ) {
2007-12-21 02:12:27 +03:00
if ( seg - > origin ) {
log_error ( " Can't move snapshot segment " ) ;
return 0 ;
}
}
2007-12-20 18:42:55 +03:00
lv_to - > segments = lv_from - > segments ;
lv_to - > segments . n - > p = & lv_to - > segments ;
lv_to - > segments . p - > n = & lv_to - > segments ;
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( seg , & lv_to - > segments ) {
2007-12-20 18:42:55 +03:00
seg - > lv = lv_to ;
seg - > status & = ~ reset_status ;
seg - > status | = set_status ;
}
2008-11-04 01:14:30 +03:00
dm_list_init ( & lv_from - > segments ) ;
2007-12-20 18:42:55 +03:00
lv_to - > le_count = lv_from - > le_count ;
lv_to - > size = lv_from - > size ;
lv_from - > le_count = 0 ;
lv_from - > size = 0 ;
2007-12-21 02:12:27 +03:00
return 1 ;
2007-12-20 18:42:55 +03:00
}
/* Remove a layer from the LV */
2007-12-20 21:55:46 +03:00
int remove_layer_from_lv ( struct logical_volume * lv ,
struct logical_volume * layer_lv )
2007-12-20 18:42:55 +03:00
{
2007-12-20 21:55:46 +03:00
struct logical_volume * parent ;
2008-01-16 22:00:59 +03:00
struct lv_segment * parent_seg ;
2007-12-20 21:55:46 +03:00
struct segment_type * segtype ;
2008-01-19 01:00:46 +03:00
log_very_verbose ( " Removing layer %s for %s " , layer_lv - > name , lv - > name ) ;
2008-01-16 22:00:59 +03:00
if ( ! ( parent_seg = get_only_segment_using_this_lv ( layer_lv ) ) ) {
2007-12-20 21:55:46 +03:00
log_error ( " Failed to find layer %s in %s " ,
layer_lv - > name , lv - > name ) ;
return 0 ;
}
2008-01-16 22:00:59 +03:00
parent = parent_seg - > lv ;
2007-12-20 18:42:55 +03:00
/*
* Before removal , the layer should be cleaned up ,
* i . e . additional segments and areas should have been removed .
*/
2008-11-04 01:14:30 +03:00
if ( dm_list_size ( & parent - > segments ) ! = 1 | |
2008-01-16 22:00:59 +03:00
parent_seg - > area_count ! = 1 | |
seg_type ( parent_seg , 0 ) ! = AREA_LV | |
layer_lv ! = seg_lv ( parent_seg , 0 ) | |
2007-12-20 21:55:46 +03:00
parent - > le_count ! = layer_lv - > le_count )
return_0 ;
2008-02-22 16:22:21 +03:00
if ( ! lv_empty ( parent ) )
return_0 ;
2007-12-21 02:12:27 +03:00
if ( ! _move_lv_segments ( parent , layer_lv , 0 , 0 ) )
return_0 ;
2007-12-20 18:42:55 +03:00
2007-12-20 21:55:46 +03:00
/* Replace the empty layer with error segment */
segtype = get_segtype_from_string ( lv - > vg - > cmd , " error " ) ;
if ( ! lv_add_virtual_segment ( layer_lv , 0 , parent - > le_count , segtype ) )
return_0 ;
2007-12-20 18:42:55 +03:00
return 1 ;
}
/*
* Create and insert a linear LV " above " lv_where .
* After the insertion , a new LV named lv_where - > name + suffix is created
* and all segments of lv_where is moved to the new LV .
* lv_where will have a single segment which maps linearly to the new LV .
*/
struct logical_volume * insert_layer_for_lv ( struct cmd_context * cmd ,
struct logical_volume * lv_where ,
uint32_t status ,
const char * layer_suffix )
{
struct logical_volume * layer_lv ;
char * name ;
size_t len ;
struct segment_type * segtype ;
struct lv_segment * mapseg ;
/* create an empty layer LV */
len = strlen ( lv_where - > name ) + 32 ;
if ( ! ( name = alloca ( len ) ) ) {
log_error ( " layer name allocation failed. "
" Remove new LV and retry. " ) ;
return NULL ;
}
if ( dm_snprintf ( name , len , " %s%s " , lv_where - > name , layer_suffix ) < 0 ) {
log_error ( " layer name allocation failed. "
" Remove new LV and retry. " ) ;
return NULL ;
}
if ( ! ( layer_lv = lv_create_empty ( name , NULL , LVM_READ | LVM_WRITE ,
ALLOC_INHERIT , 0 , lv_where - > vg ) ) ) {
log_error ( " Creation of layer LV failed " ) ;
return NULL ;
}
2008-10-23 15:21:04 +04:00
if ( lv_is_active ( lv_where ) & & strstr ( name , " _mimagetmp " ) ) {
log_very_verbose ( " Creating transient LV %s for mirror conversion in VG %s. " , name , lv_where - > vg - > name ) ;
2008-10-17 14:57:15 +04:00
2008-10-23 15:21:04 +04:00
segtype = get_segtype_from_string ( cmd , " error " ) ;
2008-10-17 14:57:15 +04:00
if ( ! lv_add_virtual_segment ( layer_lv , 0 , lv_where - > le_count , segtype ) ) {
2008-10-23 15:21:04 +04:00
log_error ( " Creation of transient LV %s for mirror conversion in VG %s failed. " , name , lv_where - > vg - > name ) ;
2008-10-17 14:57:15 +04:00
return NULL ;
}
if ( ! vg_write ( lv_where - > vg ) ) {
2008-10-23 15:21:04 +04:00
log_error ( " Failed to write intermediate VG %s metadata for mirror conversion. " , lv_where - > vg - > name ) ;
2008-10-17 14:57:15 +04:00
return NULL ;
}
if ( ! vg_commit ( lv_where - > vg ) ) {
2008-10-23 15:21:04 +04:00
log_error ( " Failed to commit intermediate VG %s metadata for mirror conversion. " , lv_where - > vg - > name ) ;
2008-10-17 14:57:15 +04:00
vg_revert ( lv_where - > vg ) ;
return NULL ;
}
if ( ! activate_lv ( cmd , layer_lv ) ) {
2008-10-23 15:21:04 +04:00
log_error ( " Failed to resume transient error LV %s for mirror conversion in VG %s. " , name , lv_where - > vg - > name ) ;
2008-10-17 14:57:15 +04:00
return NULL ;
}
}
2007-12-20 18:42:55 +03:00
log_very_verbose ( " Inserting layer %s for %s " ,
layer_lv - > name , lv_where - > name ) ;
2007-12-21 02:12:27 +03:00
if ( ! _move_lv_segments ( layer_lv , lv_where , 0 , 0 ) )
return_NULL ;
2007-12-20 18:42:55 +03:00
2008-10-17 14:57:15 +04:00
if ( ! ( segtype = get_segtype_from_string ( cmd , " striped " ) ) )
return_NULL ;
2007-12-20 18:42:55 +03:00
/* allocate a new linear segment */
2007-12-21 01:37:42 +03:00
if ( ! ( mapseg = alloc_lv_segment ( cmd - > mem , segtype ,
2007-12-20 18:42:55 +03:00
lv_where , 0 , layer_lv - > le_count ,
status , 0 , NULL , 1 , layer_lv - > le_count ,
0 , 0 , 0 ) ) )
return_NULL ;
/* map the new segment to the original underlying are */
2008-01-16 22:00:59 +03:00
if ( ! set_lv_segment_area_lv ( mapseg , 0 , layer_lv , 0 , 0 ) )
return_NULL ;
2007-12-20 18:42:55 +03:00
/* add the new segment to the layer LV */
2008-11-04 01:14:30 +03:00
dm_list_add ( & lv_where - > segments , & mapseg - > list ) ;
2007-12-20 18:42:55 +03:00
lv_where - > le_count = layer_lv - > le_count ;
lv_where - > size = lv_where - > le_count * lv_where - > vg - > extent_size ;
return layer_lv ;
}
/*
* Extend and insert a linear layer LV beneath the source segment area .
*/
static int _extend_layer_lv_for_segment ( struct logical_volume * layer_lv ,
struct lv_segment * seg , uint32_t s ,
uint32_t status )
{
struct lv_segment * mapseg ;
struct segment_type * segtype ;
struct physical_volume * src_pv = seg_pv ( seg , s ) ;
uint32_t src_pe = seg_pe ( seg , s ) ;
if ( seg_type ( seg , s ) ! = AREA_PV & & seg_type ( seg , s ) ! = AREA_LV )
return_0 ;
if ( ! ( segtype = get_segtype_from_string ( layer_lv - > vg - > cmd , " striped " ) ) )
return_0 ;
/* FIXME Incomplete message? Needs more context */
log_very_verbose ( " Inserting %s:% " PRIu32 " -% " PRIu32 " of %s/%s " ,
pv_dev_name ( src_pv ) ,
src_pe , src_pe + seg - > area_len - 1 ,
seg - > lv - > vg - > name , seg - > lv - > name ) ;
/* allocate a new segment */
if ( ! ( mapseg = alloc_lv_segment ( layer_lv - > vg - > cmd - > mem , segtype ,
layer_lv , layer_lv - > le_count ,
seg - > area_len , status , 0 ,
NULL , 1 , seg - > area_len , 0 , 0 , 0 ) ) )
return_0 ;
/* map the new segment to the original underlying are */
if ( ! move_lv_segment_area ( mapseg , 0 , seg , s ) )
return_0 ;
/* add the new segment to the layer LV */
2008-11-04 01:14:30 +03:00
dm_list_add ( & layer_lv - > segments , & mapseg - > list ) ;
2007-12-20 18:42:55 +03:00
layer_lv - > le_count + = seg - > area_len ;
layer_lv - > size + = seg - > area_len * layer_lv - > vg - > extent_size ;
/* map the original area to the new segment */
2008-01-16 22:00:59 +03:00
if ( ! set_lv_segment_area_lv ( seg , s , layer_lv , mapseg - > le , 0 ) )
return_0 ;
2007-12-20 18:42:55 +03:00
return 1 ;
}
/*
* Match the segment area to PEs in the pvl
* ( the segment area boundary should be aligned to PE ranges by
* _adjust_layer_segments ( ) so that there is no partial overlap . )
*/
static int _match_seg_area_to_pe_range ( struct lv_segment * seg , uint32_t s ,
struct pv_list * pvl )
{
struct pe_range * per ;
uint32_t pe_start , per_end ;
if ( ! pvl )
return 1 ;
if ( seg_type ( seg , s ) ! = AREA_PV | | seg_dev ( seg , s ) ! = pvl - > pv - > dev )
return 0 ;
pe_start = seg_pe ( seg , s ) ;
/* Do these PEs match to any of the PEs in pvl? */
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( per , pvl - > pe_ranges ) {
2007-12-20 18:42:55 +03:00
per_end = per - > start + per - > count - 1 ;
if ( ( pe_start < per - > start ) | | ( pe_start > per_end ) )
continue ;
/* FIXME Missing context in this message - add LV/seg details */
log_debug ( " Matched PE range %s:% " PRIu32 " -% " PRIu32 " against "
" %s % " PRIu32 " len % " PRIu32 , dev_name ( pvl - > pv - > dev ) ,
per - > start , per_end , dev_name ( seg_dev ( seg , s ) ) ,
seg_pe ( seg , s ) , seg - > area_len ) ;
return 1 ;
}
return 0 ;
}
/*
* For each segment in lv_where that uses a PV in pvl directly ,
* split the segment if it spans more than one underlying PV .
*/
static int _align_segment_boundary_to_pe_range ( struct logical_volume * lv_where ,
struct pv_list * pvl )
{
struct lv_segment * seg ;
struct pe_range * per ;
uint32_t pe_start , pe_end , per_end , stripe_multiplier , s ;
if ( ! pvl )
return 1 ;
/* Split LV segments to match PE ranges */
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( seg , & lv_where - > segments ) {
2007-12-20 18:42:55 +03:00
for ( s = 0 ; s < seg - > area_count ; s + + ) {
if ( seg_type ( seg , s ) ! = AREA_PV | |
seg_dev ( seg , s ) ! = pvl - > pv - > dev )
continue ;
/* Do these PEs match with the condition? */
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( per , pvl - > pe_ranges ) {
2007-12-20 18:42:55 +03:00
pe_start = seg_pe ( seg , s ) ;
pe_end = pe_start + seg - > area_len - 1 ;
per_end = per - > start + per - > count - 1 ;
/* No overlap? */
if ( ( pe_end < per - > start ) | |
( pe_start > per_end ) )
continue ;
if ( seg_is_striped ( seg ) )
stripe_multiplier = seg - > area_count ;
else
stripe_multiplier = 1 ;
if ( ( per - > start ! = pe_start & &
per - > start > pe_start ) & &
! lv_split_segment ( lv_where , seg - > le +
( per - > start - pe_start ) *
stripe_multiplier ) )
return_0 ;
if ( ( per_end ! = pe_end & &
per_end < pe_end ) & &
! lv_split_segment ( lv_where , seg - > le +
( per_end - pe_start + 1 ) *
stripe_multiplier ) )
return_0 ;
}
}
}
return 1 ;
}
/*
* Scan lv_where for segments on a PV in pvl , and for each one found
* append a linear segment to lv_layer and insert it between the two .
*
* If pvl is empty , a layer is placed under the whole of lv_where .
* If the layer is inserted , lv_where is added to lvs_changed .
*/
int insert_layer_for_segments_on_pv ( struct cmd_context * cmd ,
struct logical_volume * lv_where ,
struct logical_volume * layer_lv ,
uint32_t status ,
struct pv_list * pvl ,
2008-11-04 01:14:30 +03:00
struct dm_list * lvs_changed )
2007-12-20 18:42:55 +03:00
{
struct lv_segment * seg ;
struct lv_list * lvl ;
int lv_used = 0 ;
uint32_t s ;
2008-01-19 01:00:46 +03:00
log_very_verbose ( " Inserting layer %s for segments of %s on %s " ,
layer_lv - > name , lv_where - > name ,
pvl ? pv_dev_name ( pvl - > pv ) : " any " ) ;
2007-12-20 18:42:55 +03:00
if ( ! _align_segment_boundary_to_pe_range ( lv_where , pvl ) )
return_0 ;
/* Work through all segments on the supplied PV */
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( seg , & lv_where - > segments ) {
2007-12-20 18:42:55 +03:00
for ( s = 0 ; s < seg - > area_count ; s + + ) {
if ( ! _match_seg_area_to_pe_range ( seg , s , pvl ) )
continue ;
/* First time, add LV to list of LVs affected */
if ( ! lv_used & & lvs_changed ) {
if ( ! ( lvl = dm_pool_alloc ( cmd - > mem , sizeof ( * lvl ) ) ) ) {
log_error ( " lv_list alloc failed " ) ;
return 0 ;
}
lvl - > lv = lv_where ;
2008-11-04 01:14:30 +03:00
dm_list_add ( lvs_changed , & lvl - > list ) ;
2007-12-20 18:42:55 +03:00
lv_used = 1 ;
}
if ( ! _extend_layer_lv_for_segment ( layer_lv , seg , s ,
status ) ) {
log_error ( " Failed to insert segment in layer "
" LV %s under %s:% " PRIu32 " -% " PRIu32 ,
layer_lv - > name , lv_where - > name ,
seg - > le , seg - > le + seg - > len ) ;
return 0 ;
}
}
}
return 1 ;
}
2007-12-21 01:37:42 +03:00
/*
* Initialize the LV with ' value ' .
*/
int set_lv ( struct cmd_context * cmd , struct logical_volume * lv ,
uint64_t sectors , int value )
{
struct device * dev ;
char * name ;
/*
* FIXME :
* < clausen > also , more than 4 k
* < clausen > say , reiserfs puts it ' s superblock 32 k in , IIRC
* < ejt_ > k , I ' ll drop a fixme to that effect
* ( I know the device is at least 4 k , but not 32 k )
*/
if ( ! ( name = dm_pool_alloc ( cmd - > mem , PATH_MAX ) ) ) {
log_error ( " Name allocation failed - device not cleared " ) ;
return 0 ;
}
if ( dm_snprintf ( name , PATH_MAX , " %s%s/%s " , cmd - > dev_dir ,
2008-01-17 20:17:09 +03:00
lv - > vg - > name , lv - > name ) < 0 ) {
2007-12-21 01:37:42 +03:00
log_error ( " Name too long - device not cleared (%s) " , lv - > name ) ;
return 0 ;
}
log_verbose ( " Clearing start of logical volume \" %s \" " , lv - > name ) ;
if ( ! ( dev = dev_cache_get ( name , NULL ) ) ) {
log_error ( " %s: not found: device not cleared " , name ) ;
return 0 ;
}
if ( ! dev_open_quiet ( dev ) )
2008-01-17 20:17:09 +03:00
return_0 ;
2007-12-21 01:37:42 +03:00
dev_set ( dev , UINT64_C ( 0 ) ,
sectors ? ( size_t ) sectors < < SECTOR_SHIFT : ( size_t ) 4096 ,
value ) ;
dev_flush ( dev ) ;
dev_close_immediate ( dev ) ;
return 1 ;
}