2001-11-06 13:29:56 +03:00
/*
* Copyright ( C ) 2001 Sistina Software
*
* This file is released under the LGPL .
*/
# include "metadata.h"
# include "pv_map.h"
# include "log.h"
2001-11-29 21:45:35 +03:00
# include "dbg_malloc.h"
2001-12-31 22:09:51 +03:00
# include "lvm-string.h"
2002-02-11 23:50:53 +03:00
# include "toolcontext.h"
2001-11-06 13:29:56 +03:00
2001-11-27 19:37:33 +03:00
# include <assert.h>
/*
* These functions adjust the pe counts in pv ' s
* after we ' ve added or removed segments .
*/
static void _get_extents ( struct stripe_segment * seg )
{
int s , count ;
struct physical_volume * pv ;
2001-11-27 20:39:15 +03:00
for ( s = 0 ; s < seg - > stripes ; s + + ) {
2001-12-08 00:17:12 +03:00
pv = seg - > area [ s ] . pv ;
2001-11-27 19:37:33 +03:00
count = seg - > len / seg - > stripes ;
pv - > pe_allocated + = count ;
}
}
static void _put_extents ( struct stripe_segment * seg )
{
int s , count ;
struct physical_volume * pv ;
2001-11-27 20:39:15 +03:00
for ( s = 0 ; s < seg - > stripes ; s + + ) {
2001-12-08 00:17:12 +03:00
pv = seg - > area [ s ] . pv ;
2001-11-27 19:37:33 +03:00
count = seg - > len / seg - > stripes ;
assert ( pv - > pe_allocated > = count ) ;
pv - > pe_allocated - = count ;
}
}
2001-11-29 21:45:35 +03:00
static struct stripe_segment * _alloc_segment ( struct pool * mem , int stripes )
{
struct stripe_segment * seg ;
uint32_t len = sizeof ( * seg ) + ( stripes * sizeof ( seg - > area [ 0 ] ) ) ;
if ( ! ( seg = pool_zalloc ( mem , len ) ) ) {
stack ;
return NULL ;
}
return seg ;
}
2001-12-08 00:17:12 +03:00
static int _alloc_stripe_area ( struct logical_volume * lv , uint32_t stripes ,
uint32_t stripe_size ,
2001-11-29 21:45:35 +03:00
struct pv_area * * areas , uint32_t * index )
{
uint32_t count = lv - > le_count - * index ;
uint32_t per_area = count / stripes ;
uint32_t smallest = areas [ stripes - 1 ] - > count ;
uint32_t s ;
struct stripe_segment * seg ;
if ( smallest < per_area )
per_area = smallest ;
if ( ! ( seg = _alloc_segment ( lv - > vg - > cmd - > mem , stripes ) ) ) {
log_err ( " Couldn't allocate new stripe segment. " ) ;
return 0 ;
}
seg - > lv = lv ;
seg - > le = * index ;
seg - > len = per_area * stripes ;
seg - > stripes = stripes ;
2001-12-08 00:17:12 +03:00
seg - > stripe_size = stripe_size ;
2001-11-29 21:45:35 +03:00
for ( s = 0 ; s < stripes ; s + + ) {
struct pv_area * pva = areas [ s ] ;
seg - > area [ s ] . pv = pva - > map - > pv ;
seg - > area [ s ] . pe = pva - > start ;
consume_pv_area ( pva , per_area ) ;
}
list_add ( & lv - > segments , & seg - > list ) ;
* index + = seg - > len ;
return 1 ;
}
static int _comp_area ( const void * l , const void * r )
{
struct pv_area * lhs = * ( ( struct pv_area * * ) l ) ;
struct pv_area * rhs = * ( ( struct pv_area * * ) r ) ;
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 ;
}
static int _alloc_striped ( struct logical_volume * lv ,
struct list * pvms , uint32_t allocated ,
uint32_t stripes , uint32_t stripe_size )
{
2001-11-30 12:19:46 +03:00
int r = 0 ;
2001-11-29 21:45:35 +03:00
struct list * pvmh ;
struct pv_area * * areas ;
int pv_count = 0 , index ;
struct pv_map * pvm ;
size_t len ;
list_iterate ( pvmh , pvms )
pv_count + + ;
/* allocate an array of pv_areas, one candidate per pv */
len = sizeof ( * areas ) * pv_count ;
if ( ! ( areas = dbg_malloc ( sizeof ( * areas ) * pv_count ) ) ) {
log_err ( " Couldn't allocate areas array. " ) ;
return 0 ;
}
while ( allocated ! = lv - > le_count ) {
index = 0 ;
list_iterate ( pvmh , pvms ) {
pvm = list_item ( pvmh , struct pv_map ) ;
if ( list_empty ( & pvm - > areas ) )
continue ;
areas [ index + + ] = list_item ( pvm - > areas . n ,
struct pv_area ) ;
}
2001-11-30 12:19:46 +03:00
if ( index < stripes ) {
2002-01-24 20:26:00 +03:00
log_error ( " Insufficient allocatable extents suitable "
" for striping for logical volume "
2001-11-30 12:19:46 +03:00
" %s: %u required " ,
lv - > name , lv - > le_count ) ;
goto out ;
}
2001-11-29 21:45:35 +03:00
/* sort the areas so we allocate from the biggest */
qsort ( areas , index , sizeof ( * areas ) , _comp_area ) ;
2002-01-07 18:08:28 +03:00
if ( ! _alloc_stripe_area ( lv , stripes , stripe_size , areas ,
2001-12-08 00:17:12 +03:00
& allocated ) ) {
2001-11-29 21:45:35 +03:00
stack ;
2001-11-30 12:19:46 +03:00
goto out ;
2001-11-29 21:45:35 +03:00
}
}
2001-11-30 12:19:46 +03:00
r = 1 ;
2001-11-29 21:45:35 +03:00
2001-11-30 12:19:46 +03:00
out :
dbg_free ( areas ) ;
return r ;
2001-11-29 21:45:35 +03:00
}
2001-11-06 13:29:56 +03:00
/*
2002-01-24 20:15:49 +03:00
* The heart of the allocation code . This function takes a
* pv_area and allocates it to the lv . If the lv doesn ' t need
* the complete area then the area is split , otherwise the area
2001-11-06 13:29:56 +03:00
* is unlinked from the pv_map .
*/
2001-11-27 19:37:33 +03:00
static int _alloc_linear_area ( struct logical_volume * lv , uint32_t * index ,
2001-11-29 21:45:35 +03:00
struct pv_map * map , struct pv_area * pva )
2001-11-06 13:29:56 +03:00
{
2001-11-29 21:45:35 +03:00
uint32_t count , remaining ;
2001-11-27 19:37:33 +03:00
struct stripe_segment * seg ;
2001-11-06 13:29:56 +03:00
count = pva - > count ;
2001-11-27 19:37:33 +03:00
remaining = lv - > le_count - * index ;
2001-12-08 00:17:12 +03:00
if ( count > remaining )
2001-11-06 13:29:56 +03:00
count = remaining ;
2001-11-29 21:45:35 +03:00
if ( ! ( seg = _alloc_segment ( lv - > vg - > cmd - > mem , 1 ) ) ) {
2001-11-27 19:37:33 +03:00
log_err ( " Couldn't allocate new stripe segment. " ) ;
return 0 ;
2001-11-06 13:29:56 +03:00
}
2001-11-27 19:37:33 +03:00
seg - > lv = lv ;
seg - > le = * index ;
seg - > len = count ;
seg - > stripe_size = 0 ;
seg - > stripes = 1 ;
2001-11-29 21:45:35 +03:00
seg - > area [ 0 ] . pv = map - > pv ;
seg - > area [ 0 ] . pe = pva - > start ;
2001-11-27 19:37:33 +03:00
list_add ( & lv - > segments , & seg - > list ) ;
2001-11-29 21:45:35 +03:00
consume_pv_area ( pva , count ) ;
2001-11-27 19:37:33 +03:00
* index + = count ;
return 1 ;
2001-11-06 13:29:56 +03:00
}
2001-11-06 13:55:01 +03:00
/*
* Only one area per pv is allowed , so we search
* for the biggest area , or the first area that
* can complete the allocation .
*/
2001-11-29 21:45:35 +03:00
/*
* FIXME : subsequent lvextends may not be contiguous .
*/
2001-11-06 14:19:33 +03:00
static int _alloc_contiguous ( struct logical_volume * lv ,
struct list * pvms , uint32_t allocated )
2001-11-06 13:29:56 +03:00
{
2001-11-29 21:45:35 +03:00
struct list * tmp1 ;
2001-11-06 13:55:01 +03:00
struct pv_map * pvm ;
2001-11-29 21:45:35 +03:00
struct pv_area * pva ;
2001-11-06 13:55:01 +03:00
2001-11-10 01:01:04 +03:00
list_iterate ( tmp1 , pvms ) {
2001-11-06 13:55:01 +03:00
pvm = list_item ( tmp1 , struct pv_map ) ;
2001-11-29 21:45:35 +03:00
if ( list_empty ( & pvm - > areas ) )
continue ;
2001-11-06 13:55:01 +03:00
2001-11-29 21:45:35 +03:00
/* first item in the list is the biggest */
pva = list_item ( pvm - > areas . n , struct pv_area ) ;
2001-11-06 13:55:01 +03:00
2001-11-29 21:45:35 +03:00
if ( ! _alloc_linear_area ( lv , & allocated , pvm , pva ) ) {
2001-11-27 19:37:33 +03:00
stack ;
return 0 ;
}
2001-11-06 13:55:01 +03:00
if ( allocated = = lv - > le_count )
break ;
}
if ( allocated ! = lv - > le_count ) {
2002-01-24 20:26:00 +03:00
log_error ( " Insufficient allocatable extents (%u) "
" for logical volume %s: %u required " ,
allocated , lv - > name , lv - > le_count ) ;
2001-11-06 13:55:01 +03:00
return 0 ;
}
return 1 ;
2001-11-06 13:29:56 +03:00
}
2001-11-06 13:55:01 +03:00
/*
* Areas just get allocated in order until the lv
* is full .
*/
2001-11-06 14:19:33 +03:00
static int _alloc_simple ( struct logical_volume * lv ,
struct list * pvms , uint32_t allocated )
2001-11-06 13:29:56 +03:00
{
struct list * tmp1 , * tmp2 ;
struct pv_map * pvm ;
struct pv_area * pva ;
2001-11-10 01:01:04 +03:00
list_iterate ( tmp1 , pvms ) {
2001-11-06 13:29:56 +03:00
pvm = list_item ( tmp1 , struct pv_map ) ;
2001-11-10 01:01:04 +03:00
list_iterate ( tmp2 , & pvm - > areas ) {
2001-11-06 13:29:56 +03:00
pva = list_item ( tmp2 , struct pv_area ) ;
2001-11-29 21:45:35 +03:00
if ( ! _alloc_linear_area ( lv , & allocated , pvm , pva ) | |
2001-11-27 19:37:33 +03:00
( allocated = = lv - > le_count ) )
2001-11-12 15:16:57 +03:00
goto done ;
2001-11-06 13:29:56 +03:00
}
}
2001-11-29 21:45:35 +03:00
done :
2001-11-06 13:29:56 +03:00
if ( allocated ! = lv - > le_count ) {
2002-01-24 20:26:00 +03:00
log_error ( " Insufficient allocatable logical extents (%u) "
" for logical volume %s: %u required " ,
allocated , lv - > name , lv - > le_count ) ;
2001-11-06 13:29:56 +03:00
return 0 ;
}
2001-12-08 00:17:12 +03:00
return 1 ;
2001-11-06 13:29:56 +03:00
}
2001-11-06 14:31:29 +03:00
/*
* Chooses a correct allocation policy .
*/
static int _allocate ( struct volume_group * vg , struct logical_volume * lv ,
2001-11-27 20:39:15 +03:00
struct list * acceptable_pvs , uint32_t allocated ,
uint32_t stripes , uint32_t stripe_size )
2001-11-06 14:31:29 +03:00
{
int r = 0 ;
struct pool * scratch ;
2001-11-27 20:39:15 +03:00
struct list * pvms , * old_tail = lv - > segments . p , * segh ;
2001-11-06 14:31:29 +03:00
if ( ! ( scratch = pool_create ( 1024 ) ) ) {
stack ;
return 0 ;
}
/*
2002-01-24 20:15:49 +03:00
* Build the sets of available areas on the pv ' s .
2001-11-06 14:31:29 +03:00
*/
2002-01-24 20:15:49 +03:00
if ( ! ( pvms = create_pv_maps ( scratch , vg , acceptable_pvs ) ) )
2001-11-06 14:31:29 +03:00
goto out ;
2001-11-27 20:39:15 +03:00
if ( stripes > 1 )
r = _alloc_striped ( lv , pvms , allocated , stripes , stripe_size ) ;
2001-11-06 14:31:29 +03:00
else if ( lv - > status & ALLOC_CONTIGUOUS )
r = _alloc_contiguous ( lv , pvms , allocated ) ;
2001-11-12 20:55:05 +03:00
else if ( lv - > status & ALLOC_SIMPLE )
2001-11-06 14:31:29 +03:00
r = _alloc_simple ( lv , pvms , allocated ) ;
2001-11-12 20:55:05 +03:00
else {
2001-11-14 16:52:38 +03:00
log_error ( " Unknown allocation policy: "
" unable to setup logical volume. " ) ;
2001-11-12 20:55:05 +03:00
goto out ;
}
2001-11-06 14:31:29 +03:00
if ( r ) {
2001-11-06 15:01:46 +03:00
vg - > free_count - = lv - > le_count - allocated ;
2001-11-27 19:37:33 +03:00
2002-01-24 20:15:49 +03:00
/*
* Iterate through the new segments , updating pe
* counts in pv ' s .
*/
2001-11-27 19:37:33 +03:00
for ( segh = lv - > segments . p ; segh ! = old_tail ; segh = segh - > p )
_get_extents ( list_item ( segh , struct stripe_segment ) ) ;
} else {
2002-01-24 20:15:49 +03:00
/*
* Put the segment list back how we found it .
*/
2001-11-27 19:37:33 +03:00
old_tail - > n = & lv - > segments ;
lv - > segments . p = old_tail ;
2001-11-06 14:31:29 +03:00
}
2001-11-13 17:17:50 +03:00
out :
2001-11-06 14:31:29 +03:00
pool_destroy ( scratch ) ;
return r ;
}
2001-11-14 17:12:01 +03:00
static char * _generate_lv_name ( struct volume_group * vg ,
2001-11-14 21:38:07 +03:00
char * buffer , size_t len )
2001-11-14 15:07:37 +03:00
{
struct list * lvh ;
struct logical_volume * lv ;
2002-01-07 12:16:20 +03:00
int high = - 1 , i ;
2001-11-14 15:07:37 +03:00
list_iterate ( lvh , & vg - > lvs ) {
2002-01-21 19:49:32 +03:00
lv = ( list_item ( lvh , struct lv_list ) - > lv ) ;
2001-11-14 15:07:37 +03:00
if ( sscanf ( lv - > name , " lvol%d " , & i ) ! = 1 )
continue ;
if ( i > high )
2001-11-14 17:12:01 +03:00
high = i ;
2001-11-14 15:07:37 +03:00
}
2001-12-31 22:09:51 +03:00
if ( lvm_snprintf ( buffer , len , " lvol%d " , high + 1 ) < 0 )
2001-11-14 15:07:37 +03:00
return NULL ;
return buffer ;
}
2002-01-24 20:15:49 +03:00
struct logical_volume * lv_create ( struct format_instance * fi ,
const char * name ,
2001-11-06 13:29:56 +03:00
uint32_t status ,
uint32_t stripes ,
uint32_t stripe_size ,
uint32_t extents ,
struct volume_group * vg ,
2001-11-06 14:19:33 +03:00
struct list * acceptable_pvs )
2001-11-06 13:29:56 +03:00
{
2001-11-12 15:16:57 +03:00
struct cmd_context * cmd = vg - > cmd ;
2001-11-06 13:29:56 +03:00
struct lv_list * ll = NULL ;
struct logical_volume * lv ;
2001-11-14 15:07:37 +03:00
char dname [ 32 ] ;
2001-11-06 13:29:56 +03:00
if ( ! extents ) {
2001-11-14 16:52:38 +03:00
log_error ( " Unable to create logical volume %s with no extents " ,
name ) ;
2001-11-06 13:29:56 +03:00
return NULL ;
}
if ( vg - > free_count < extents ) {
2001-11-14 16:52:38 +03:00
log_error ( " Insufficient free extents (%u) in volume group %s: "
" %u required " , vg - > free_count , vg - > name , extents ) ;
2001-11-06 22:02:26 +03:00
return NULL ;
2001-11-06 13:29:56 +03:00
}
if ( 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
}
2001-12-08 00:17:12 +03:00
if ( stripes > list_size ( acceptable_pvs ) ) {
log_error ( " Number of stripes (%u) must not exceed "
" number of physical volumes (%d) " , stripes ,
list_size ( acceptable_pvs ) ) ;
return NULL ;
}
2001-11-14 21:38:07 +03:00
if ( ! name & & ! ( name = _generate_lv_name ( vg , 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 ;
}
log_verbose ( " Creating logical volume %s " , name ) ;
2002-01-21 20:43:10 +03:00
if ( ! ( ll = pool_zalloc ( cmd - > mem , sizeof ( * ll ) ) ) | |
! ( ll - > lv = pool_zalloc ( cmd - > mem , sizeof ( * ll - > lv ) ) ) ) {
2001-11-06 13:29:56 +03:00
stack ;
return NULL ;
}
2002-01-21 19:49:32 +03:00
lv = ll - > lv ;
2001-11-06 13:29:56 +03:00
2002-03-05 23:03:09 +03:00
lv - > vg = vg ;
2001-11-06 13:29:56 +03:00
2001-11-12 15:16:57 +03:00
if ( ! ( lv - > name = pool_strdup ( cmd - > mem , name ) ) ) {
2001-11-06 13:29:56 +03:00
stack ;
goto bad ;
}
lv - > status = status ;
lv - > read_ahead = 0 ;
2002-02-01 20:54:39 +03:00
lv - > minor = - 1 ;
2002-02-15 04:26:16 +03:00
lv - > size = ( uint64_t ) extents * vg - > extent_size ;
2001-11-06 13:29:56 +03:00
lv - > le_count = extents ;
2001-11-27 19:37:33 +03:00
list_init ( & lv - > segments ) ;
2001-11-06 13:29:56 +03:00
2001-11-27 20:39:15 +03:00
if ( ! _allocate ( vg , lv , acceptable_pvs , 0u , stripes , stripe_size ) ) {
2001-11-06 14:31:29 +03:00
stack ;
2001-11-06 13:29:56 +03:00
goto bad ;
}
2002-01-24 20:15:49 +03:00
if ( fi - > ops - > lv_setup & & ! fi - > ops - > lv_setup ( fi , lv ) ) {
stack ;
goto bad ;
}
2001-11-10 01:01:04 +03:00
vg - > lv_count + + ;
2001-11-06 22:02:26 +03:00
list_add ( & vg - > lvs , & ll - > list ) ;
2001-11-10 01:01:04 +03:00
2001-11-06 13:29:56 +03:00
return lv ;
2001-11-27 19:37:33 +03:00
bad :
2001-11-06 13:29:56 +03:00
if ( ll )
2001-11-12 15:16:57 +03:00
pool_free ( cmd - > mem , ll ) ;
2001-11-06 13:29:56 +03:00
return NULL ;
}
2001-11-06 14:19:33 +03:00
2002-01-24 20:15:49 +03:00
int lv_reduce ( struct format_instance * fi ,
struct logical_volume * lv , uint32_t extents )
2001-11-06 14:19:33 +03:00
{
2001-11-27 19:37:33 +03:00
struct list * segh ;
struct stripe_segment * seg ;
uint32_t count = extents ;
for ( segh = lv - > segments . p ;
( segh ! = & lv - > segments ) & & count ;
segh = segh - > p ) {
seg = list_item ( segh , struct stripe_segment ) ;
if ( seg - > len < = count ) {
/* remove this segment completely */
count - = seg - > len ;
_put_extents ( seg ) ;
list_del ( segh ) ;
} else {
/* reduce this segment */
_put_extents ( seg ) ;
seg - > len - = count ;
_get_extents ( seg ) ;
count = 0 ;
}
2001-11-06 14:19:33 +03:00
}
2001-11-27 19:37:33 +03:00
lv - > le_count - = extents ;
2002-02-15 04:26:16 +03:00
lv - > size = ( uint64_t ) lv - > le_count * lv - > vg - > extent_size ;
2001-11-13 17:17:50 +03:00
2002-01-24 20:15:49 +03:00
if ( fi - > ops - > lv_setup & & ! fi - > ops - > lv_setup ( fi , lv ) ) {
stack ;
return 0 ;
}
2001-11-06 14:19:33 +03:00
return 1 ;
}
2002-01-24 20:15:49 +03:00
int lv_extend ( struct format_instance * fi ,
struct logical_volume * lv ,
2001-11-27 20:39:15 +03:00
uint32_t stripes , uint32_t stripe_size ,
uint32_t extents ,
2001-11-06 15:01:46 +03:00
struct list * acceptable_pvs )
2001-11-06 14:19:33 +03:00
{
2001-11-27 19:37:33 +03:00
uint32_t old_le_count = lv - > le_count ;
uint64_t old_size = lv - > size ;
2001-11-06 15:01:46 +03:00
2001-11-27 19:37:33 +03:00
lv - > le_count + = extents ;
2002-02-15 04:26:16 +03:00
lv - > size + = ( uint64_t ) extents * lv - > vg - > extent_size ;
2001-11-06 15:01:46 +03:00
2001-12-13 03:07:29 +03:00
/* FIXME: Format1 must ensure stripes is consistent with 1st seg */
2001-11-27 20:39:15 +03:00
if ( ! _allocate ( lv - > vg , lv , acceptable_pvs , old_le_count ,
stripes , stripe_size ) ) {
2001-11-27 19:37:33 +03:00
lv - > le_count = old_le_count ;
2001-11-27 20:39:15 +03:00
lv - > size = old_size ;
2001-11-06 15:01:46 +03:00
return 0 ;
}
2001-11-07 18:02:07 +03:00
2002-01-11 02:21:07 +03:00
if ( ! lv_merge_segments ( lv ) ) {
2002-01-07 18:08:28 +03:00
log_err ( " Couldn't merge segments after extending "
" logical volume. " ) ;
return 0 ;
}
2002-01-24 20:15:49 +03:00
if ( fi - > ops - > lv_setup & & ! fi - > ops - > lv_setup ( fi , lv ) ) {
stack ;
return 0 ;
}
2001-11-06 15:01:46 +03:00
return 1 ;
2001-11-06 14:19:33 +03:00
}
2001-11-12 22:28:50 +03:00
2001-11-14 21:38:07 +03:00
int lv_remove ( struct volume_group * vg , struct logical_volume * lv )
2001-11-12 22:28:50 +03:00
{
2001-11-27 19:37:33 +03:00
struct list * segh ;
2002-01-21 20:43:10 +03:00
struct lv_list * lvl ;
/* find the lv list */
if ( ! ( lvl = find_lv_in_vg ( vg , lv - > name ) ) ) {
stack ;
return 0 ;
}
2001-11-12 22:28:50 +03:00
2001-11-27 19:37:33 +03:00
/* iterate through the lv's segments freeing off the pe's */
list_iterate ( segh , & lv - > segments )
_put_extents ( list_item ( segh , struct stripe_segment ) ) ;
2001-11-12 22:28:50 +03:00
vg - > lv_count - - ;
vg - > free_count + = lv - > le_count ;
2002-01-21 20:43:10 +03:00
list_del ( & lvl - > list ) ;
2001-11-12 22:28:50 +03:00
return 1 ;
}