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 .
2007-08-21 00:55:30 +04:00
* Copyright ( C ) 2004 - 2006 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
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-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
2008-11-04 18:07:45 +03:00
# include <assert.h>
2001-11-29 21:45:35 +03:00
/*
2005-05-11 19:02:49 +04:00
* Areas are maintained in size order , largest first .
2006-10-22 03:18:43 +04:00
*
* FIXME Cope with overlap .
2001-11-29 21:45:35 +03:00
*/
2010-03-26 00:19:26 +03:00
static void _insert_area ( struct dm_list * head , struct pv_area * a , unsigned reduced )
2001-11-29 21:45:35 +03:00
{
2005-05-11 19:02:49 +04:00
struct pv_area * pva ;
2010-03-26 00:19:26 +03:00
uint32_t count = reduced ? a - > unreserved : a - > count ;
dm_list_iterate_items ( pva , head )
if ( count > pva - > count )
2001-11-29 21:45:35 +03:00
break ;
2008-11-04 01:14:30 +03:00
dm_list_add ( & pva - > list , & a - > list ) ;
2006-10-23 19:54:51 +04:00
a - > map - > pe_count + = a - > count ;
2001-11-29 21:45:35 +03:00
}
2010-03-26 00:19:26 +03:00
static void _remove_area ( struct pv_area * a )
{
dm_list_del ( & a - > list ) ;
a - > map - > pe_count - = a - > count ;
}
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 ;
2008-01-30 16:19:47 +03:00
if ( ! ( pva = dm_pool_zalloc ( mem , sizeof ( * pva ) ) ) )
return_0 ;
2001-11-05 19:41:38 +03:00
2003-04-25 02:23:24 +04:00
log_debug ( " Allowing allocation on %s start PE % " PRIu32 " length % "
2007-10-12 18:29:32 +04:00
PRIu32 , pv_dev_name ( pvm - > pv ) , 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 ;
2010-03-26 00:19:26 +03:00
pva - > unreserved = pva - > count ;
_insert_area ( & pvm - > areas , pva , 0 ) ;
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
{
2008-01-30 17:00:02 +03:00
struct pv_segment * peg ;
2005-05-11 19:02:49 +04:00
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 */
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( peg , & pvm - > pv - > segments ) {
2005-05-11 19:02:49 +04:00
/* 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 ;
2008-01-30 16:19:47 +03:00
if ( ! _create_single_area ( mem , pvm , pe , area_len ) )
return_0 ;
2001-11-05 19:41:38 +03:00
2005-05-11 19:02:49 +04:00
next :
pe = peg - > pe + peg - > len ;
2008-01-30 17:00:02 +03:00
}
2005-05-11 19:02:49 +04:00
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 ,
2008-11-04 01:14:30 +03:00
struct dm_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 ) ,
2008-01-30 16:19:47 +03:00
pvm - > pv - > pe_count ) )
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
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( aa , pe_ranges ) {
2005-05-11 19:02:49 +04:00
if ( ! _create_alloc_areas_for_pv ( mem , pvm , aa - > start ,
2008-01-30 16:19:47 +03:00
aa - > count ) )
return_0 ;
2003-04-25 02:23:24 +04:00
}
return 1 ;
}
2008-11-04 01:14:30 +03:00
static int _create_maps ( struct dm_pool * mem , struct dm_list * pvs , struct dm_list * pvms )
2001-11-05 19:41:38 +03:00
{
2006-10-22 03:18:43 +04:00
struct pv_map * pvm , * pvm2 ;
2005-05-11 19:02:49 +04:00
struct pv_list * pvl ;
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( pvl , pvs ) {
2005-05-11 19:02:49 +04:00
if ( ! ( pvl - > pv - > status & ALLOCATABLE_PV ) )
continue ;
2010-03-16 17:37:38 +03:00
if ( is_missing_pv ( pvl - > pv ) )
2009-04-23 20:41:27 +04:00
continue ;
assert ( pvl - > pv - > dev ) ;
2005-05-11 19:02:49 +04:00
2006-10-22 03:18:43 +04:00
pvm = NULL ;
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( pvm2 , pvms )
2006-10-22 03:18:43 +04:00
if ( pvm2 - > pv - > dev = = pvl - > pv - > dev ) {
pvm = pvm2 ;
break ;
}
2001-11-05 19:41:38 +03:00
2006-10-22 03:18:43 +04:00
if ( ! pvm ) {
2008-01-30 16:19:47 +03:00
if ( ! ( pvm = dm_pool_zalloc ( mem , sizeof ( * pvm ) ) ) )
return_0 ;
2001-11-05 19:41:38 +03:00
2006-10-22 03:18:43 +04:00
pvm - > pv = pvl - > pv ;
2008-11-04 01:14:30 +03:00
dm_list_init ( & pvm - > areas ) ;
dm_list_add ( pvms , & pvm - > list ) ;
2006-10-22 03:18:43 +04:00
}
2005-05-11 19:02:49 +04:00
2008-01-30 16:19:47 +03:00
if ( ! _create_all_areas_for_pv ( mem , pvm , pvl - > pe_ranges ) )
return_0 ;
2001-11-05 19:41:38 +03:00
}
return 1 ;
}
2005-05-11 19:02:49 +04:00
/*
* Create list of PV areas available for this particular allocation
*/
2008-11-04 01:14:30 +03:00
struct dm_list * create_pv_maps ( struct dm_pool * mem , struct volume_group * vg ,
struct dm_list * allocatable_pvs )
2001-11-05 19:41:38 +03:00
{
2008-11-04 01:14:30 +03:00
struct dm_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 ;
}
2008-11-04 01:14:30 +03:00
dm_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 )
{
2010-03-26 00:19:26 +03:00
_remove_area ( pva ) ;
2001-11-29 21:45:35 +03:00
assert ( to_go < = pva - > count ) ;
if ( to_go < pva - > count ) {
/* split the area */
pva - > start + = to_go ;
pva - > count - = to_go ;
2010-03-26 00:19:26 +03:00
pva - > unreserved = pva - > count ;
_insert_area ( & pva - > map - > areas , pva , 0 ) ;
2001-11-29 21:45:35 +03:00
}
}
2006-10-23 19:54:51 +04:00
2010-03-26 00:19:26 +03:00
/*
* Remove an area from list and reinsert it based on its new smaller size
* after a provisional allocation .
*/
void reinsert_reduced_pv_area ( struct pv_area * pva )
{
_remove_area ( pva ) ;
_insert_area ( & pva - > map - > areas , pva , 1 ) ;
}
2008-11-04 01:14:30 +03:00
uint32_t pv_maps_size ( struct dm_list * pvms )
2006-10-23 19:54:51 +04:00
{
struct pv_map * pvm ;
uint32_t pe_count = 0 ;
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( pvm , pvms )
2006-10-23 19:54:51 +04:00
pe_count + = pvm - > pe_count ;
return pe_count ;
}