2001-11-05 19:41:38 +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-05 19:41:38 +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-05 19:41:38 +03:00
*/
2002-11-18 17:04:08 +03:00
# include "lib.h"
2001-11-05 19:41:38 +03:00
# include "pv_map.h"
2005-05-11 19:02:49 +04:00
# include "pv_alloc.h"
2001-11-05 19:41:38 +03:00
2001-11-29 21:45:35 +03:00
/*
2005-05-11 19:02:49 +04:00
* Areas are maintained in size order , largest first .
2001-11-29 21:45:35 +03:00
*/
static void _insert_area ( struct list * head , struct pv_area * a )
{
2005-05-11 19:02:49 +04:00
struct pv_area * pva ;
2001-11-29 21:45:35 +03:00
2005-05-11 19:02:49 +04:00
list_iterate_items ( pva , head ) {
if ( a - > count > pva - > count )
2001-11-29 21:45:35 +03:00
break ;
}
2005-05-11 19:02:49 +04:00
list_add ( & pva - > list , & a - > list ) ;
2001-11-29 21:45:35 +03:00
}
2005-10-17 03:03:59 +04:00
static int _create_single_area ( struct dm_pool * mem , struct pv_map * pvm ,
2005-05-11 19:02:49 +04:00
uint32_t start , uint32_t length )
2001-11-05 19:41:38 +03:00
{
struct pv_area * pva ;
2005-10-17 03:03:59 +04:00
if ( ! ( pva = dm_pool_zalloc ( mem , sizeof ( * pva ) ) ) ) {
2001-11-05 19:41:38 +03:00
stack ;
return 0 ;
}
2003-04-25 02:23:24 +04:00
log_debug ( " Allowing allocation on %s start PE % " PRIu32 " length % "
2005-05-11 19:02:49 +04:00
PRIu32 , dev_name ( pvm - > pv - > dev ) , start , length ) ;
2001-11-29 21:45:35 +03:00
pva - > map = pvm ;
2005-05-11 19:02:49 +04:00
pva - > start = start ;
pva - > count = length ;
2001-11-29 21:45:35 +03:00
_insert_area ( & pvm - > areas , pva ) ;
2001-11-05 19:41:38 +03:00
return 1 ;
}
2005-10-17 03:03:59 +04:00
static int _create_alloc_areas_for_pv ( struct dm_pool * mem , struct pv_map * pvm ,
2005-05-11 19:02:49 +04:00
uint32_t start , uint32_t count )
2001-11-05 19:41:38 +03:00
{
2005-05-11 19:02:49 +04:00
struct pv_segment * peg ;
uint32_t pe , end , area_len ;
2001-11-05 19:41:38 +03:00
2005-05-11 19:02:49 +04:00
/* Only select extents from start to end inclusive */
2003-04-25 02:23:24 +04:00
end = start + count - 1 ;
2005-05-11 19:02:49 +04:00
if ( end > pvm - > pv - > pe_count - 1 )
end = pvm - > pv - > pe_count - 1 ;
2003-04-25 02:23:24 +04:00
pe = start ;
2005-05-11 19:02:49 +04:00
/* Walk through complete ordered list of device segments */
list_iterate_items ( peg , & pvm - > pv - > segments ) {
/* pe holds the next extent we want to check */
/* Beyond the range we're interested in? */
if ( pe > end )
break ;
/* Skip if we haven't reached the first seg we want yet */
if ( pe > peg - > pe + peg - > len - 1 )
continue ;
/* Free? */
if ( peg - > lvseg )
goto next ;
/* How much of this peg do we need? */
area_len = ( end > = peg - > pe + peg - > len - 1 ) ?
peg - > len - ( pe - peg - > pe ) : end - pe + 1 ;
if ( ! _create_single_area ( mem , pvm , pe , area_len ) ) {
2001-11-05 19:41:38 +03:00
stack ;
return 0 ;
}
2005-05-11 19:02:49 +04:00
next :
pe = peg - > pe + peg - > len ;
}
2001-11-05 19:41:38 +03:00
return 1 ;
}
2005-10-17 03:03:59 +04:00
static int _create_all_areas_for_pv ( struct dm_pool * mem , struct pv_map * pvm ,
2005-05-11 19:02:49 +04:00
struct list * pe_ranges )
2003-04-25 02:23:24 +04:00
{
2004-08-18 01:55:23 +04:00
struct pe_range * aa ;
2003-04-25 02:23:24 +04:00
2005-05-11 19:02:49 +04:00
if ( ! pe_ranges ) {
/* Use whole PV */
if ( ! _create_alloc_areas_for_pv ( mem , pvm , UINT32_C ( 0 ) ,
pvm - > pv - > pe_count ) ) {
stack ;
return 0 ;
}
2003-04-25 02:23:24 +04:00
2005-05-11 19:02:49 +04:00
return 1 ;
}
2003-04-25 02:23:24 +04:00
2005-05-11 19:02:49 +04:00
list_iterate_items ( aa , pe_ranges ) {
if ( ! _create_alloc_areas_for_pv ( mem , pvm , aa - > start ,
aa - > count ) ) {
2003-04-25 02:23:24 +04:00
stack ;
return 0 ;
}
}
return 1 ;
}
2005-10-17 03:03:59 +04:00
static int _create_maps ( struct dm_pool * mem , struct list * pvs , struct list * pvms )
2001-11-05 19:41:38 +03:00
{
struct pv_map * pvm ;
2005-05-11 19:02:49 +04:00
struct pv_list * pvl ;
list_iterate_items ( pvl , pvs ) {
if ( ! ( pvl - > pv - > status & ALLOCATABLE_PV ) )
continue ;
2005-10-17 03:03:59 +04:00
if ( ! ( pvm = dm_pool_zalloc ( mem , sizeof ( * pvm ) ) ) ) {
2005-05-11 19:02:49 +04:00
stack ;
return 0 ;
}
2001-11-05 19:41:38 +03:00
2005-05-11 19:02:49 +04:00
pvm - > pv = pvl - > pv ;
2001-11-05 19:41:38 +03:00
2005-05-11 19:02:49 +04:00
list_init ( & pvm - > areas ) ;
list_add ( pvms , & pvm - > list ) ;
if ( ! _create_all_areas_for_pv ( mem , pvm , pvl - > pe_ranges ) ) {
2001-11-05 19:41:38 +03:00
stack ;
return 0 ;
}
}
return 1 ;
}
2005-05-11 19:02:49 +04:00
/*
* Create list of PV areas available for this particular allocation
*/
2005-10-17 03:03:59 +04:00
struct list * create_pv_maps ( struct dm_pool * mem , struct volume_group * vg ,
2005-05-11 19:02:49 +04:00
struct list * allocatable_pvs )
2001-11-05 19:41:38 +03:00
{
2005-05-11 19:02:49 +04:00
struct list * pvms ;
2001-11-05 19:41:38 +03:00
2005-10-17 03:03:59 +04:00
if ( ! ( pvms = dm_pool_zalloc ( mem , sizeof ( * pvms ) ) ) ) {
2005-05-11 19:02:49 +04:00
log_error ( " create_pv_maps alloc failed " ) ;
2001-11-05 19:41:38 +03:00
return NULL ;
}
2005-05-11 19:02:49 +04:00
list_init ( pvms ) ;
2001-11-05 19:41:38 +03:00
2005-05-11 19:02:49 +04:00
if ( ! _create_maps ( mem , allocatable_pvs , pvms ) ) {
2001-11-13 20:53:06 +03:00
log_error ( " Couldn't create physical volume maps in %s " ,
2001-11-06 22:02:26 +03:00
vg - > name ) ;
2005-10-17 03:03:59 +04:00
dm_pool_free ( mem , pvms ) ;
2005-05-11 19:02:49 +04:00
return NULL ;
2001-11-05 19:41:38 +03:00
}
2005-05-11 19:02:49 +04:00
return pvms ;
2001-11-05 19:41:38 +03:00
}
2001-11-29 21:45:35 +03:00
void consume_pv_area ( struct pv_area * pva , uint32_t to_go )
{
list_del ( & pva - > list ) ;
assert ( to_go < = pva - > count ) ;
if ( to_go < pva - > count ) {
/* split the area */
pva - > start + = to_go ;
pva - > count - = to_go ;
_insert_area ( & pva - > map - > areas , pva ) ;
}
}