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"
/*
* 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
* is unlinked from the pv_map .
*/
static int _alloc_area ( struct logical_volume * lv , uint32_t index ,
struct physical_volume * pv , struct pv_area * pva )
{
uint32_t count , remaining , i , start ;
start = pva - > start ;
count = pva - > count ;
remaining = lv - > le_count - index ;
if ( remaining < count ) {
/* split the area */
count = remaining ;
pva - > start + = count ;
pva - > count - = count ;
} else {
/* unlink the area */
list_del ( & pva - > list ) ;
}
for ( i = 0 ; i < count ; i + + ) {
lv - > map [ i + index ] . pv = pv ;
lv - > map [ i + index ] . pe = start + i ;
}
return count ;
}
2001-11-06 14:19:33 +03:00
static int _alloc_striped ( struct logical_volume * lv ,
struct list * pvms , uint32_t allocated )
2001-11-06 13:29:56 +03:00
{
2001-11-06 14:19:33 +03:00
/* FIXME: finish */
2001-11-06 22:02:26 +03:00
log_error ( " Striped allocation not implemented yet in LVM2. " ) ;
2001-11-06 13:29:56 +03:00
return 0 ;
}
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-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-06 13:55:01 +03:00
struct list * tmp1 , * tmp2 ;
struct pv_map * pvm ;
struct pv_area * pva , * biggest ;
list_iterate ( tmp1 , pvms ) {
pvm = list_item ( tmp1 , struct pv_map ) ;
biggest = NULL ;
list_iterate ( tmp2 , & pvm - > areas ) {
pva = list_item ( tmp2 , struct pv_area ) ;
if ( ! biggest | | ( pva - > count > biggest - > count ) )
biggest = pva ;
if ( biggest - > count > = ( lv - > le_count - allocated ) )
break ;
}
allocated + = _alloc_area ( lv , allocated , pvm - > pv , pva ) ;
if ( allocated = = lv - > le_count )
break ;
}
if ( allocated ! = lv - > le_count ) {
2001-11-06 22:02:26 +03:00
log_error ( " Insufficient free extents to "
" allocate logical volume %s: %u required " ,
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 ;
list_iterate ( tmp1 , pvms ) {
pvm = list_item ( tmp1 , struct pv_map ) ;
list_iterate ( tmp2 , & pvm - > areas ) {
pva = list_item ( tmp2 , struct pv_area ) ;
allocated + = _alloc_area ( lv , allocated , pvm - > pv , pva ) ;
if ( allocated = = lv - > le_count )
break ;
}
if ( allocated = = lv - > le_count ) /* FIXME: yuck, repeated test */
break ;
}
if ( allocated ! = lv - > le_count ) {
2001-11-06 22:02:26 +03:00
log_error ( " Insufficient free logical extents to "
" allocate logical volume %s: %u required " ,
lv - > name , lv - > le_count ) ;
2001-11-06 13:29:56 +03:00
return 0 ;
}
return 1 ;
}
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-06 15:01:46 +03:00
struct list * acceptable_pvs , uint32_t allocated )
2001-11-06 14:31:29 +03:00
{
int r = 0 ;
struct pool * scratch ;
struct list * pvms ;
if ( ! ( scratch = pool_create ( 1024 ) ) ) {
stack ;
return 0 ;
}
/*
* Build the sets of available areas on
* the pv ' s .
*/
if ( ! ( pvms = create_pv_maps ( scratch , vg , acceptable_pvs ) ) ) {
goto out ;
}
if ( lv - > stripes > 1 )
r = _alloc_striped ( lv , pvms , allocated ) ;
else if ( lv - > status & ALLOC_CONTIGUOUS )
r = _alloc_contiguous ( lv , pvms , allocated ) ;
else
r = _alloc_simple ( lv , pvms , allocated ) ;
if ( r ) {
vg - > lv_count + + ;
2001-11-06 15:01:46 +03:00
vg - > free_count - = lv - > le_count - allocated ;
2001-11-06 14:31:29 +03:00
}
out :
pool_destroy ( scratch ) ;
return r ;
}
2001-11-06 13:29:56 +03:00
struct logical_volume * lv_create ( struct io_space * ios ,
const char * name ,
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
{
struct lv_list * ll = NULL ;
struct logical_volume * lv ;
if ( ! extents ) {
2001-11-06 22:02:26 +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-06 22:02:26 +03:00
log_error ( " Insufficient free extents (%u) in volume group %s: "
" %u required " , vg - > free_count , vg - > name , extents ) ;
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
}
if ( ! ( ll = pool_zalloc ( ios - > mem , sizeof ( * ll ) ) ) ) {
stack ;
return NULL ;
}
2001-11-06 22:02:26 +03:00
list_init ( & ll - > list ) ;
2001-11-06 13:29:56 +03:00
lv = & ll - > lv ;
strcpy ( lv - > id . uuid , " " ) ;
if ( ! ( lv - > name = pool_strdup ( ios - > mem , name ) ) ) {
stack ;
goto bad ;
}
lv - > vg = vg ;
lv - > status = status ;
lv - > read_ahead = 0 ;
lv - > stripes = stripes ;
lv - > size = extents * vg - > extent_size ;
lv - > le_count = extents ;
if ( ! ( lv - > map = pool_zalloc ( ios - > mem , sizeof ( * lv - > map ) * extents ) ) ) {
stack ;
goto bad ;
}
2001-11-06 15:01:46 +03:00
if ( ! _allocate ( vg , lv , acceptable_pvs , 0u ) ) {
2001-11-06 14:31:29 +03:00
stack ;
2001-11-06 13:29:56 +03:00
goto bad ;
}
2001-11-06 22:02:26 +03:00
list_add ( & vg - > lvs , & ll - > list ) ;
2001-11-06 13:29:56 +03:00
return lv ;
bad :
if ( ll )
pool_free ( ios - > mem , ll ) ;
return NULL ;
}
2001-11-06 14:19:33 +03:00
int lv_reduce ( struct io_space * ios ,
struct logical_volume * lv , uint32_t extents )
{
if ( extents % lv - > stripes ) {
2001-11-06 22:02:26 +03:00
log_error ( " For a striped volume you must reduce by a "
" multiple of the number of stripes " ) ;
2001-11-06 14:19:33 +03:00
return 0 ;
}
if ( lv - > le_count < = extents ) {
2001-11-06 22:02:26 +03:00
log_error ( " Attempt to reduce by so many extents there would "
" be nothing left of the logical volume. " ) ;
2001-11-06 14:19:33 +03:00
return 0 ;
}
/* Hmmm ... I think all we need to do is ... */
lv - > le_count - = extents ;
return 1 ;
}
int lv_extend ( struct io_space * ios ,
struct logical_volume * lv , 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-06 15:01:46 +03:00
struct pe_specifier * new_map ;
struct logical_volume * new_lv ;
2001-11-07 18:02:07 +03:00
if ( ! ( new_map = pool_zalloc ( ios - > mem , sizeof ( * new_map ) *
2001-11-06 15:01:46 +03:00
( extents + lv - > le_count ) ) ) ) {
stack ;
return 0 ;
}
memcpy ( new_map , lv - > map , sizeof ( * new_map ) * lv - > le_count ) ;
if ( ! ( new_lv = pool_alloc ( ios - > mem , sizeof ( * new_lv ) ) ) ) {
pool_free ( ios - > mem , new_map ) ;
stack ;
return 0 ;
}
2001-11-07 18:02:07 +03:00
2001-11-06 15:01:46 +03:00
memcpy ( new_lv , lv , sizeof ( * lv ) ) ;
new_lv - > map = new_map ;
new_lv - > le_count + = extents ;
2001-11-07 18:02:07 +03:00
if ( ! _allocate ( new_lv - > vg , new_lv , acceptable_pvs , new_lv - > le_count ) ) {
2001-11-06 15:01:46 +03:00
stack ;
goto bad ;
}
memcpy ( lv , new_lv , sizeof ( * lv ) ) ;
/* now you see why new_lv had to be allocated last */
pool_free ( ios - > mem , new_lv ) ;
return 1 ;
bad :
pool_free ( ios - > mem , new_map ) ;
2001-11-06 14:19:33 +03:00
return 0 ;
}