2001-11-06 13:29:56 +03:00
/*
2004-03-30 23:35:44 +04:00
* Copyright ( C ) 2001 - 2004 Sistina Software , Inc . All rights reserved .
* Copyright ( C ) 2004 Red Hat , Inc . All rights reserved .
2001-11-06 13:29:56 +03:00
*
2004-03-30 23:35:44 +04:00
* This file is part of LVM2 .
*
* This copyrighted material is made available to anyone wishing to use ,
* modify , copy , or redistribute it subject to the terms and conditions
* of the GNU General Public License v .2 .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software Foundation ,
* Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
2001-11-06 13:29:56 +03:00
*/
2002-11-18 17:04:08 +03:00
# include "lib.h"
2001-11-06 13:29:56 +03:00
# include "metadata.h"
2003-04-25 02:23:24 +04:00
# include "locking.h"
2001-11-06 13:29:56 +03:00
# include "pv_map.h"
2001-12-31 22:09:51 +03:00
# include "lvm-string.h"
2002-02-11 23:50:53 +03:00
# include "toolcontext.h"
2003-09-15 22:22:50 +04:00
# include "lv_alloc.h"
2004-05-05 01:25:57 +04:00
# include "display.h"
# include "segtypes.h"
2001-11-06 13:29:56 +03:00
2001-11-27 19:37:33 +03:00
/*
* These functions adjust the pe counts in pv ' s
* after we ' ve added or removed segments .
*/
2002-11-18 17:04:08 +03:00
static void _get_extents ( struct lv_segment * seg )
2001-11-27 19:37:33 +03:00
{
2002-12-20 02:25:55 +03:00
unsigned int s , count ;
2001-11-27 19:37:33 +03:00
struct physical_volume * pv ;
2003-04-25 02:23:24 +04:00
for ( s = 0 ; s < seg - > area_count ; s + + ) {
if ( seg - > area [ s ] . type ! = AREA_PV )
continue ;
pv = seg - > area [ s ] . u . pv . pv ;
count = seg - > area_len ;
2002-04-24 22:20:51 +04:00
pv - > pe_alloc_count + = count ;
2001-11-27 19:37:33 +03:00
}
}
2002-11-18 17:04:08 +03:00
static void _put_extents ( struct lv_segment * seg )
2001-11-27 19:37:33 +03:00
{
2002-12-20 02:25:55 +03:00
unsigned int s , count ;
2001-11-27 19:37:33 +03:00
struct physical_volume * pv ;
2003-04-25 02:23:24 +04:00
for ( s = 0 ; s < seg - > area_count ; s + + ) {
if ( seg - > area [ s ] . type ! = AREA_PV )
continue ;
pv = seg - > area [ s ] . u . pv . pv ;
2001-11-27 19:37:33 +03:00
2003-01-18 00:04:26 +03:00
if ( pv ) {
2003-04-25 02:23:24 +04:00
count = seg - > area_len ;
2003-01-18 00:04:26 +03:00
assert ( pv - > pe_alloc_count > = count ) ;
pv - > pe_alloc_count - = count ;
}
2001-11-27 19:37:33 +03:00
}
}
2004-03-26 23:35:14 +03:00
struct lv_segment * alloc_lv_segment ( struct pool * mem , uint32_t num_areas )
2001-11-29 21:45:35 +03:00
{
2002-11-18 17:04:08 +03:00
struct lv_segment * seg ;
2004-03-26 23:35:14 +03:00
uint32_t len = sizeof ( * seg ) + ( num_areas * sizeof ( seg - > area [ 0 ] ) ) ;
2001-11-29 21:45:35 +03:00
if ( ! ( seg = pool_zalloc ( mem , len ) ) ) {
stack ;
return NULL ;
}
2004-03-08 20:19:15 +03:00
list_init ( & seg - > tags ) ;
2001-11-29 21:45:35 +03:00
return seg ;
}
2004-03-26 23:35:14 +03:00
static int _alloc_parallel_area ( struct logical_volume * lv , uint32_t area_count ,
uint32_t stripe_size ,
2004-05-05 01:25:57 +04:00
struct segment_type * segtype ,
2004-03-26 23:35:14 +03:00
struct pv_area * * areas , uint32_t * ix )
2001-11-29 21:45:35 +03:00
{
2004-03-26 23:35:14 +03:00
uint32_t count , area_len , smallest ;
2001-11-29 21:45:35 +03:00
uint32_t s ;
2002-11-18 17:04:08 +03:00
struct lv_segment * seg ;
2004-03-26 23:35:14 +03:00
int striped = 0 ;
2004-05-05 01:25:57 +04:00
/* Striped or mirrored? */
if ( segtype - > flags & SEG_AREAS_STRIPED )
striped = 1 ;
2004-03-26 23:35:14 +03:00
count = lv - > le_count - * ix ;
area_len = count / ( striped ? area_count : 1 ) ;
smallest = areas [ area_count - 1 ] - > count ;
2001-11-29 21:45:35 +03:00
2003-04-25 02:23:24 +04:00
if ( smallest < area_len )
area_len = smallest ;
2001-11-29 21:45:35 +03:00
2004-03-26 23:35:14 +03:00
if ( ! ( seg = alloc_lv_segment ( lv - > vg - > cmd - > mem , area_count ) ) ) {
log_err ( " Couldn't allocate new parallel segment. " ) ;
2001-11-29 21:45:35 +03:00
return 0 ;
}
seg - > lv = lv ;
2004-05-05 01:25:57 +04:00
seg - > segtype = segtype ;
2002-12-20 02:25:55 +03:00
seg - > le = * ix ;
2004-03-26 23:35:14 +03:00
seg - > len = area_len * ( striped ? area_count : 1 ) ;
2003-04-25 02:23:24 +04:00
seg - > area_len = area_len ;
2004-03-26 23:35:14 +03:00
seg - > area_count = area_count ;
2001-12-08 00:17:12 +03:00
seg - > stripe_size = stripe_size ;
2004-05-05 21:56:20 +04:00
seg - > extents_copied = 0u ;
2001-11-29 21:45:35 +03:00
2004-03-26 23:35:14 +03:00
for ( s = 0 ; s < area_count ; s + + ) {
2001-11-29 21:45:35 +03:00
struct pv_area * pva = areas [ s ] ;
2003-04-25 02:23:24 +04:00
seg - > area [ s ] . type = AREA_PV ;
seg - > area [ s ] . u . pv . pv = pva - > map - > pvl - > pv ;
seg - > area [ s ] . u . pv . pe = pva - > start ;
consume_pv_area ( pva , area_len ) ;
2001-11-29 21:45:35 +03:00
}
list_add ( & lv - > segments , & seg - > list ) ;
2002-12-20 02:25:55 +03:00
* ix + = seg - > len ;
2004-05-05 01:25:57 +04:00
if ( ! striped )
lv - > status | = MIRRORED ;
2001-11-29 21:45:35 +03:00
return 1 ;
}
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 ;
}
2004-03-26 23:35:14 +03:00
static int _alloc_parallel ( struct logical_volume * lv ,
struct list * pvms , uint32_t allocated ,
2004-05-05 01:25:57 +04:00
uint32_t stripes , uint32_t stripe_size ,
uint32_t mirrors , struct segment_type * segtype )
2001-11-29 21:45:35 +03:00
{
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 ;
2002-12-20 02:25:55 +03:00
unsigned int pv_count = 0 , ix ;
2001-11-29 21:45:35 +03:00
struct pv_map * pvm ;
size_t len ;
2004-03-26 23:35:14 +03:00
uint32_t area_count ;
2004-05-05 01:25:57 +04:00
if ( stripes > 1 & & mirrors > 1 ) {
log_error ( " striped mirrors are not supported yet " ) ;
return 0 ;
}
if ( stripes > 1 )
area_count = stripes ;
else
area_count = mirrors ;
2001-11-29 21:45:35 +03:00
2002-04-24 22:20:51 +04:00
list_iterate ( pvmh , pvms )
pv_count + + ;
2001-11-29 21:45:35 +03:00
/* 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 ) {
2002-12-20 02:25:55 +03:00
ix = 0 ;
2002-04-24 22:20:51 +04:00
list_iterate ( pvmh , pvms ) {
2001-11-29 21:45:35 +03:00
pvm = list_item ( pvmh , struct pv_map ) ;
if ( list_empty ( & pvm - > areas ) )
continue ;
2002-12-20 02:25:55 +03:00
areas [ ix + + ] = list_item ( pvm - > areas . n , struct pv_area ) ;
2001-11-29 21:45:35 +03:00
}
2004-03-26 23:35:14 +03:00
if ( ix < area_count ) {
2002-01-24 20:26:00 +03:00
log_error ( " Insufficient allocatable extents suitable "
2004-03-26 23:35:14 +03:00
" for parallel use for logical volume "
2002-04-24 22:20:51 +04:00
" %s: %u required " , lv - > name , lv - > le_count ) ;
2001-11-30 12:19:46 +03:00
goto out ;
}
2001-11-29 21:45:35 +03:00
/* sort the areas so we allocate from the biggest */
2002-12-20 02:25:55 +03:00
qsort ( areas , ix , sizeof ( * areas ) , _comp_area ) ;
2001-11-29 21:45:35 +03:00
2004-05-05 01:25:57 +04:00
if ( ! _alloc_parallel_area ( lv , area_count , stripe_size , segtype ,
areas , & 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
2002-04-24 22:20:51 +04:00
out :
2001-11-30 12:19:46 +03:00
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 .
*/
2002-12-20 02:25:55 +03:00
static int _alloc_linear_area ( struct logical_volume * lv , uint32_t * ix ,
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 ;
2002-11-18 17:04:08 +03:00
struct lv_segment * seg ;
2001-11-06 13:29:56 +03:00
count = pva - > count ;
2002-12-20 02:25:55 +03:00
remaining = lv - > le_count - * ix ;
2001-12-08 00:17:12 +03:00
if ( count > remaining )
2001-11-06 13:29:56 +03:00
count = remaining ;
2003-09-15 22:22:50 +04:00
if ( ! ( seg = alloc_lv_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 ;
2004-05-05 01:25:57 +04:00
if ( ! ( seg - > segtype = get_segtype_from_string ( lv - > vg - > cmd , " striped " ) ) ) {
stack ;
return 0 ;
}
seg - > le = * ix ;
2002-12-20 02:25:55 +03:00
seg - > le = * ix ;
2001-11-27 19:37:33 +03:00
seg - > len = count ;
2003-04-25 02:23:24 +04:00
seg - > area_len = count ;
2001-11-27 19:37:33 +03:00
seg - > stripe_size = 0 ;
2003-04-25 02:23:24 +04:00
seg - > area_count = 1 ;
seg - > area [ 0 ] . type = AREA_PV ;
seg - > area [ 0 ] . u . pv . pv = map - > pvl - > pv ;
seg - > area [ 0 ] . u . pv . 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 ) ;
2002-12-20 02:25:55 +03:00
* ix + = count ;
2001-11-27 19:37:33 +03:00
return 1 ;
2001-11-06 13:29:56 +03:00
}
2003-04-30 19:23:43 +04:00
static int _alloc_mirrored_area ( struct logical_volume * lv , uint32_t * ix ,
struct pv_map * map , struct pv_area * pva ,
2004-05-05 01:25:57 +04:00
struct segment_type * segtype ,
2003-04-30 19:23:43 +04:00
struct physical_volume * mirrored_pv ,
uint32_t mirrored_pe )
{
uint32_t count , remaining ;
struct lv_segment * seg ;
count = pva - > count ;
remaining = lv - > le_count - * ix ;
if ( count > remaining )
count = remaining ;
2003-09-15 22:22:50 +04:00
if ( ! ( seg = alloc_lv_segment ( lv - > vg - > cmd - > mem , 2 ) ) ) {
2003-04-30 19:23:43 +04:00
log_err ( " Couldn't allocate new mirrored segment. " ) ;
return 0 ;
}
seg - > lv = lv ;
2004-05-05 01:25:57 +04:00
seg - > segtype = segtype ;
seg - > le = * ix ;
2003-05-06 16:06:02 +04:00
seg - > status = 0u ;
2003-04-30 19:23:43 +04:00
seg - > le = * ix ;
seg - > len = count ;
seg - > area_len = count ;
seg - > stripe_size = 0 ;
seg - > area_count = 2 ;
2004-05-05 21:56:20 +04:00
seg - > extents_copied = 0u ;
2003-04-30 19:23:43 +04:00
/* FIXME Remove AREA_PV restriction here? */
seg - > area [ 0 ] . type = AREA_PV ;
seg - > area [ 0 ] . u . pv . pv = mirrored_pv ;
seg - > area [ 0 ] . u . pv . pe = mirrored_pe ;
seg - > area [ 1 ] . type = AREA_PV ;
seg - > area [ 1 ] . u . pv . pv = map - > pvl - > pv ;
seg - > area [ 1 ] . u . pv . pe = pva - > start ;
list_add ( & lv - > segments , & seg - > list ) ;
consume_pv_area ( pva , count ) ;
* ix + = count ;
return 1 ;
}
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 ) ;
2003-05-06 16:06:02 +04:00
if ( pva - > count < lv - > le_count )
continue ;
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 ;
}
2003-05-06 16:06:02 +04:00
break ;
2001-11-06 13:55:01 +03:00
}
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
}
2003-04-30 19:23:43 +04:00
/* FIXME Contiguous depends on *segment* (i.e. stripe) not LV */
static int _alloc_mirrored ( struct logical_volume * lv ,
struct list * pvms , uint32_t allocated ,
2004-05-05 01:25:57 +04:00
struct segment_type * segtype ,
2003-04-30 19:23:43 +04:00
struct physical_volume * mirrored_pv ,
uint32_t mirrored_pe )
{
struct list * tmp1 ;
struct pv_map * pvm ;
struct pv_area * pva ;
2003-05-06 16:06:02 +04:00
uint32_t max_found = 0 ;
2003-04-30 19:23:43 +04:00
2003-05-06 16:06:02 +04:00
/* Try each PV in turn */
2003-04-30 19:23:43 +04:00
list_iterate ( tmp1 , pvms ) {
pvm = list_item ( tmp1 , struct pv_map ) ;
if ( list_empty ( & pvm - > areas ) )
continue ;
/* first item in the list is the biggest */
pva = list_item ( pvm - > areas . n , struct pv_area ) ;
2003-05-06 16:06:02 +04:00
if ( pva - > count < lv - > le_count - allocated ) {
max_found = pva - > count ;
continue ;
}
2003-04-30 19:23:43 +04:00
2004-05-05 01:25:57 +04:00
if ( ! _alloc_mirrored_area ( lv , & allocated , pvm , pva , segtype ,
2003-04-30 19:23:43 +04:00
mirrored_pv , mirrored_pe ) ) {
stack ;
return 0 ;
}
break ;
}
if ( allocated ! = lv - > le_count ) {
log_error ( " Insufficient contiguous allocatable extents (%u) "
" for logical volume %s: %u required " ,
2003-05-06 16:06:02 +04:00
allocated + max_found , lv - > name , lv - > le_count ) ;
2003-04-30 19:23:43 +04:00
return 0 ;
}
return 1 ;
}
2001-11-06 13:55:01 +03:00
/*
* Areas just get allocated in order until the lv
* is full .
*/
2002-11-18 17:04:08 +03:00
static int _alloc_next_free ( 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
}
}
2002-04-24 22:20:51 +04: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 ,
2003-04-25 02:23:24 +04:00
struct list * allocatable_pvs , uint32_t allocated ,
2004-05-05 01:25:57 +04:00
struct segment_type * segtype ,
uint32_t stripes , uint32_t stripe_size , uint32_t mirrors ,
2003-05-06 16:06:02 +04:00
struct physical_volume * mirrored_pv , uint32_t mirrored_pe ,
uint32_t status )
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 ;
2003-05-06 16:06:02 +04:00
struct lv_segment * seg ;
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
*/
2003-04-25 02:23:24 +04:00
if ( ! ( pvms = create_pv_maps ( scratch , vg , allocatable_pvs ) ) )
2001-11-06 14:31:29 +03:00
goto out ;
2004-05-05 01:25:57 +04:00
if ( stripes > 1 | | mirrors > 1 )
r = _alloc_parallel ( lv , pvms , allocated , stripes , stripe_size ,
mirrors , segtype ) ;
2001-11-06 14:31:29 +03:00
2003-04-30 19:23:43 +04:00
else if ( mirrored_pv )
2004-05-05 01:25:57 +04:00
r = _alloc_mirrored ( lv , pvms , allocated , segtype , mirrored_pv ,
2003-04-30 19:23:43 +04:00
mirrored_pe ) ;
2002-07-11 18:21:49 +04:00
else if ( lv - > alloc = = ALLOC_CONTIGUOUS )
2001-11-06 14:31:29 +03:00
r = _alloc_contiguous ( lv , pvms , allocated ) ;
2002-11-18 17:04:08 +03:00
else if ( lv - > alloc = = ALLOC_NEXT_FREE | | lv - > alloc = = ALLOC_DEFAULT )
r = _alloc_next_free ( lv , pvms , allocated ) ;
2001-11-06 14:31:29 +03:00
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 .
*/
2003-05-06 16:06:02 +04:00
for ( segh = lv - > segments . p ; segh ! = old_tail ; segh = segh - > p ) {
seg = list_item ( segh , struct lv_segment ) ;
_get_extents ( seg ) ;
seg - > status = status ;
}
2001-11-27 19:37:33 +03:00
} 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 ;
}
2003-05-06 16:06:02 +04:00
static char * _generate_lv_name ( struct volume_group * vg , const char * format ,
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
2003-05-06 16:06:02 +04:00
if ( sscanf ( lv - > name , format , & i ) ! = 1 )
2001-11-14 15:07:37 +03:00
continue ;
if ( i > high )
2001-11-14 17:12:01 +03:00
high = i ;
2001-11-14 15:07:37 +03:00
}
2003-05-06 16:06:02 +04:00
if ( lvm_snprintf ( buffer , len , format , high + 1 ) < 0 )
2001-11-14 15:07:37 +03:00
return NULL ;
return buffer ;
}
2003-04-25 02:23:24 +04:00
struct logical_volume * lv_create_empty ( struct format_instance * fi ,
const char * name ,
2003-05-06 16:06:02 +04:00
const char * name_format ,
2003-04-25 02:23:24 +04:00
uint32_t status ,
alloc_policy_t alloc ,
struct volume_group * vg )
2001-11-06 13:29:56 +03:00
{
2001-11-12 15:16:57 +03:00
struct cmd_context * cmd = vg - > cmd ;
2001-11-06 13:29:56 +03:00
struct lv_list * ll = NULL ;
struct logical_volume * lv ;
2001-11-14 15:07:37 +03:00
char dname [ 32 ] ;
2001-11-06 13:29:56 +03:00
2003-11-06 23:33:34 +03:00
if ( vg - > max_lv & & ( vg - > max_lv = = vg - > lv_count ) ) {
2001-11-06 22:02:26 +03:00
log_error ( " Maximum number of logical volumes (%u) reached "
" in volume group %s " , vg - > max_lv , vg - > name ) ;
return NULL ;
2001-11-06 13:29:56 +03:00
}
2003-05-06 16:06:02 +04:00
if ( ! name & & ! ( name = _generate_lv_name ( vg , name_format , 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 ) ) ) ) {
2003-04-25 02:23:24 +04:00
log_error ( " lv_list allocation failed " ) ;
if ( ll )
pool_free ( cmd - > mem , ll ) ;
2001-11-06 13:29:56 +03:00
return NULL ;
}
2002-01-21 19:49:32 +03:00
lv = ll - > lv ;
2002-03-05 23:03:09 +03:00
lv - > vg = vg ;
2001-11-06 13:29:56 +03:00
2001-11-12 15:16:57 +03:00
if ( ! ( lv - > name = pool_strdup ( cmd - > mem , name ) ) ) {
2003-04-25 02:23:24 +04:00
log_error ( " lv name strdup failed " ) ;
if ( ll )
pool_free ( cmd - > mem , ll ) ;
return NULL ;
2001-11-06 13:29:56 +03:00
}
lv - > status = status ;
2002-07-11 18:21:49 +04:00
lv - > alloc = alloc ;
2001-11-06 13:29:56 +03:00
lv - > read_ahead = 0 ;
2003-04-02 23:14:43 +04:00
lv - > major = - 1 ;
2002-02-01 20:54:39 +03:00
lv - > minor = - 1 ;
2003-04-25 02:23:24 +04:00
lv - > size = UINT64_C ( 0 ) ;
lv - > le_count = 0 ;
2001-11-27 19:37:33 +03:00
list_init ( & lv - > segments ) ;
2004-03-08 20:19:15 +03:00
list_init ( & lv - > tags ) ;
2001-11-06 13:29:56 +03:00
2002-04-24 22:20:51 +04:00
if ( fi - > fmt - > ops - > lv_setup & & ! fi - > fmt - > ops - > lv_setup ( fi , lv ) ) {
2002-01-24 20:15:49 +03:00
stack ;
2003-04-25 02:23:24 +04:00
if ( ll )
pool_free ( cmd - > mem , ll ) ;
return NULL ;
2002-01-24 20:15:49 +03:00
}
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 ;
2003-04-25 02:23:24 +04:00
}
2001-11-06 13:29:56 +03:00
2004-05-05 01:25:57 +04:00
int lv_extend ( struct format_instance * fid ,
struct logical_volume * lv ,
struct segment_type * segtype ,
uint32_t stripes , uint32_t stripe_size ,
uint32_t mirrors , uint32_t extents ,
struct physical_volume * mirrored_pv , uint32_t mirrored_pe ,
uint32_t status , struct list * allocatable_pvs )
{
uint32_t old_le_count = lv - > le_count ;
uint64_t old_size = lv - > size ;
lv - > le_count + = extents ;
lv - > size + = ( uint64_t ) extents * lv - > vg - > extent_size ;
if ( ! _allocate ( lv - > vg , lv , allocatable_pvs , old_le_count , segtype ,
stripes , stripe_size , mirrors , mirrored_pv , mirrored_pe ,
status ) ) {
lv - > le_count = old_le_count ;
lv - > size = old_size ;
stack ;
return 0 ;
}
if ( ( segtype - > flags & SEG_CAN_SPLIT ) & & ! lv_merge_segments ( lv ) ) {
log_err ( " Couldn't merge segments after extending "
" logical volume. " ) ;
return 0 ;
}
if ( fid - > fmt - > ops - > lv_setup & & ! fid - > fmt - > ops - > lv_setup ( fid , lv ) ) {
stack ;
return 0 ;
}
return 1 ;
}
struct logical_volume * lv_create ( struct format_instance * fid ,
2003-04-25 02:23:24 +04:00
const char * name ,
uint32_t status ,
alloc_policy_t alloc ,
2004-05-05 01:25:57 +04:00
struct segment_type * segtype ,
2003-04-25 02:23:24 +04:00
uint32_t stripes ,
uint32_t stripe_size ,
2004-05-05 01:25:57 +04:00
uint32_t mirrors ,
2003-04-25 02:23:24 +04:00
uint32_t extents ,
struct volume_group * vg ,
struct list * allocatable_pvs )
{
struct logical_volume * lv ;
2001-11-06 13:29:56 +03:00
2003-04-25 02:23:24 +04:00
if ( ! extents ) {
log_error ( " Unable to create logical volume %s with no extents " ,
name ) ;
return NULL ;
}
if ( vg - > free_count < extents ) {
log_error ( " Insufficient free extents (%u) in volume group %s: "
" %u required " , vg - > free_count , vg - > name , extents ) ;
return NULL ;
}
if ( stripes > list_size ( allocatable_pvs ) ) {
log_error ( " Number of stripes (%u) must not exceed "
" number of physical volumes (%d) " , stripes ,
list_size ( allocatable_pvs ) ) ;
return NULL ;
}
2004-05-05 01:25:57 +04:00
if ( ! ( lv = lv_create_empty ( fid , name , " lvol%d " , status , alloc , vg ) ) ) {
2003-04-25 02:23:24 +04:00
stack ;
return NULL ;
}
2004-05-05 01:25:57 +04:00
if ( ! lv_extend ( fid , lv , segtype , stripes , stripe_size , mirrors ,
extents , NULL , 0u , 0u , allocatable_pvs ) ) {
2003-04-25 02:23:24 +04:00
stack ;
return NULL ;
}
return lv ;
2001-11-06 13:29:56 +03:00
}
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 ;
2002-11-18 17:04:08 +03:00
struct lv_segment * seg ;
2001-11-27 19:37:33 +03:00
uint32_t count = extents ;
2004-03-19 19:19:41 +03:00
int striped ;
2001-11-27 19:37:33 +03:00
for ( segh = lv - > segments . p ;
2002-04-24 22:20:51 +04:00
( segh ! = & lv - > segments ) & & count ; segh = segh - > p ) {
2002-11-18 17:04:08 +03:00
seg = list_item ( segh , struct lv_segment ) ;
2001-11-27 19:37:33 +03:00
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 ;
2004-05-05 01:25:57 +04:00
striped = seg - > segtype - > flags & SEG_AREAS_STRIPED ;
2004-03-19 19:19:41 +03:00
/* Caller must ensure exact divisibility */
if ( striped & & ( count % seg - > area_count ) ) {
log_error ( " Segment extent reduction % " PRIu32
" not divisible by #stripes % " PRIu32 ,
count , seg - > area_count ) ;
return 0 ;
}
seg - > area_len - =
count / ( striped ? seg - > area_count : 1 ) ;
2001-11-27 19:37:33 +03:00
_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 ;
2002-05-30 20:08:19 +04:00
lv - > vg - > free_count + = extents ;
2001-11-13 17:17:50 +03:00
2002-04-24 22:20:51 +04:00
if ( fi - > fmt - > ops - > lv_setup & & ! fi - > fmt - > ops - > lv_setup ( fi , lv ) ) {
2002-01-24 20:15:49 +03:00
stack ;
return 0 ;
}
2001-11-06 14:19:33 +03:00
return 1 ;
}
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 */
2002-04-24 22:20:51 +04:00
list_iterate ( segh , & lv - > segments )
2002-11-18 17:04:08 +03:00
_put_extents ( list_item ( segh , struct lv_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 ;
}
2003-04-25 02:23:24 +04:00
2003-11-06 19:58:38 +03:00
uint32_t find_free_lvnum ( struct logical_volume * lv )
{
int lvnum_used [ MAX_RESTRICTED_LVS + 1 ] ;
uint32_t i = 0 ;
struct list * lvh ;
struct lv_list * lvl ;
int lvnum ;
memset ( & lvnum_used , 0 , sizeof ( lvnum_used ) ) ;
list_iterate ( lvh , & lv - > vg - > lvs ) {
lvl = list_item ( lvh , struct lv_list ) ;
lvnum = lvnum_from_lvid ( & lvl - > lv - > lvid ) ;
if ( lvnum < = MAX_RESTRICTED_LVS )
lvnum_used [ lvnum ] = 1 ;
}
while ( lvnum_used [ i ] )
i + + ;
return i ;
}