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"
2001-11-27 20:39:15 +03:00
# include "hash.h"
2001-11-05 19:41:38 +03:00
2001-11-06 14:19:33 +03:00
static int _create_maps ( struct pool * mem , struct list * pvs , struct list * maps )
2001-11-05 19:41:38 +03:00
{
struct list * tmp ;
struct pv_map * pvm ;
2003-04-25 02:23:24 +04:00
struct pv_list * pvl ;
2001-11-05 19:41:38 +03:00
2001-11-06 14:19:33 +03:00
list_iterate ( tmp , pvs ) {
2003-04-25 02:23:24 +04:00
pvl = list_item ( tmp , struct pv_list ) ;
2001-11-05 19:41:38 +03:00
2003-04-25 02:23:24 +04:00
if ( ! ( pvl - > pv - > status & ALLOCATABLE_PV ) )
2002-01-10 18:09:51 +03:00
continue ;
2001-11-05 19:41:38 +03:00
if ( ! ( pvm = pool_zalloc ( mem , sizeof ( * pvm ) ) ) ) {
stack ;
return 0 ;
}
2003-04-25 02:23:24 +04:00
pvm - > pvl = pvl ;
2001-11-05 19:41:38 +03:00
if ( ! ( pvm - > allocated_extents =
2003-04-25 02:23:24 +04:00
bitset_create ( mem , pvl - > pv - > pe_count ) ) ) {
2001-11-05 19:41:38 +03:00
stack ;
return 0 ;
}
2001-11-13 20:53:06 +03:00
list_init ( & pvm - > areas ) ;
2001-11-05 19:41:38 +03:00
list_add ( maps , & pvm - > list ) ;
}
return 1 ;
}
2003-04-25 02:23:24 +04:00
static int _set_allocd ( struct hash_table * hash ,
struct physical_volume * pv , uint32_t pe )
2001-11-27 19:37:33 +03:00
{
struct pv_map * pvm ;
if ( ! ( pvm = ( struct pv_map * ) hash_lookup ( hash , dev_name ( pv - > dev ) ) ) ) {
2002-01-21 19:05:23 +03:00
/*
2002-01-21 19:10:36 +03:00
* it doesn ' t matter that this fails , it just
* means this part of the lv is on a pv that
* we ' re not interested in allocating to .
2002-01-21 19:05:23 +03:00
*/
return 1 ;
2001-11-27 19:37:33 +03:00
}
/* sanity check */
2001-12-08 00:17:12 +03:00
if ( bit ( pvm - > allocated_extents , pe ) ) {
log_error ( " Physical extent %d of %s referenced by more than "
" one logical volume " , pe , dev_name ( pv - > dev ) ) ;
return 0 ;
}
2001-11-27 19:37:33 +03:00
bit_set ( pvm - > allocated_extents , pe ) ;
return 1 ;
}
2001-11-05 19:41:38 +03:00
static int _fill_bitsets ( struct volume_group * vg , struct list * maps )
{
2001-11-27 20:39:15 +03:00
struct list * lvh , * pvmh , * segh ;
2001-11-05 19:41:38 +03:00
struct logical_volume * lv ;
struct pv_map * pvm ;
2001-12-08 00:17:12 +03:00
uint32_t s , pe ;
2001-11-27 19:37:33 +03:00
struct hash_table * hash ;
2002-11-18 17:04:08 +03:00
struct lv_segment * seg ;
2001-12-08 00:17:12 +03:00
int r = 0 ;
2001-11-05 19:41:38 +03:00
2001-11-27 20:39:15 +03:00
if ( ! ( hash = hash_create ( 128 ) ) ) {
2001-11-27 19:37:33 +03:00
log_err ( " Couldn't create hash table for pv maps. " ) ;
return 0 ;
}
2001-11-05 19:41:38 +03:00
2001-11-27 19:37:33 +03:00
/* populate the hash table */
2002-04-24 22:20:51 +04:00
list_iterate ( pvmh , maps ) {
2001-11-27 19:37:33 +03:00
pvm = list_item ( pvmh , struct pv_map ) ;
2003-04-25 02:23:24 +04:00
if ( ! hash_insert ( hash , dev_name ( pvm - > pvl - > pv - > dev ) , pvm ) ) {
2001-11-27 19:37:33 +03:00
stack ;
goto out ;
}
}
2001-11-05 19:41:38 +03:00
2001-11-27 19:37:33 +03:00
/* iterate through all the lv's setting bit's for used pe's */
2002-04-24 22:20:51 +04:00
list_iterate ( lvh , & vg - > lvs ) {
2002-01-21 19:49:32 +03:00
lv = list_item ( lvh , struct lv_list ) - > lv ;
2001-11-05 19:41:38 +03:00
2002-04-24 22:20:51 +04:00
list_iterate ( segh , & lv - > segments ) {
2002-11-18 17:04:08 +03:00
seg = list_item ( segh , struct lv_segment ) ;
2001-11-27 19:37:33 +03:00
2003-04-25 02:23:24 +04:00
for ( s = 0u ; s < seg - > area_count ; s + + ) {
for ( pe = 0u ; pe < seg - > area_len ; pe + + ) {
if ( seg - > area [ s ] . type ! = AREA_PV )
continue ;
if ( ! _set_allocd ( hash ,
seg - > area [ s ] . u . pv . pv ,
seg - > area [ s ] . u . pv . pe
+ pe ) ) {
2001-12-08 00:17:12 +03:00
stack ;
goto out ;
}
2001-11-27 19:37:33 +03:00
}
2001-11-05 19:41:38 +03:00
}
}
}
2001-11-27 19:37:33 +03:00
r = 1 ;
2001-11-05 19:41:38 +03:00
2002-04-24 22:20:51 +04:00
out :
2001-11-27 20:39:15 +03:00
hash_destroy ( hash ) ;
2001-11-27 19:37:33 +03:00
return r ;
2001-11-05 19:41:38 +03:00
}
2001-11-29 21:45:35 +03:00
/*
* Areas are maintained in size order .
*/
static void _insert_area ( struct list * head , struct pv_area * a )
{
struct list * pvah ;
2002-12-20 02:25:55 +03:00
struct pv_area * pva = NULL ;
2001-11-29 21:45:35 +03:00
2001-12-03 19:27:16 +03:00
if ( list_empty ( head ) ) {
list_add ( head , & a - > list ) ;
return ;
}
2002-04-24 22:20:51 +04:00
list_iterate ( pvah , head ) {
2001-11-29 21:45:35 +03:00
pva = list_item ( pvah , struct pv_area ) ;
if ( pva - > count < a - > count )
break ;
}
2001-12-03 19:27:16 +03:00
list_add_h ( & pva - > list , & a - > list ) ;
2001-11-29 21:45:35 +03:00
}
2001-11-05 19:41:38 +03:00
static int _create_single_area ( struct pool * mem , struct pv_map * pvm ,
2003-04-25 02:23:24 +04:00
uint32_t end , uint32_t * extent )
2001-11-05 19:41:38 +03:00
{
2003-04-25 02:23:24 +04:00
uint32_t e = * extent , b ;
2001-11-05 19:41:38 +03:00
struct pv_area * pva ;
2003-04-25 02:23:24 +04:00
while ( e < = end & & bit ( pvm - > allocated_extents , e ) )
2001-11-05 19:41:38 +03:00
e + + ;
2003-04-25 02:23:24 +04:00
if ( e > end ) {
2001-11-05 19:41:38 +03:00
* extent = e ;
return 1 ;
}
b = e + + ;
2003-04-25 02:23:24 +04:00
while ( e < = end & & ! bit ( pvm - > allocated_extents , e ) )
2001-11-05 19:41:38 +03:00
e + + ;
if ( ! ( pva = pool_zalloc ( mem , sizeof ( * pva ) ) ) ) {
stack ;
return 0 ;
}
2003-04-25 02:23:24 +04:00
log_debug ( " Allowing allocation on %s start PE % " PRIu32 " length % "
PRIu32 , dev_name ( pvm - > pvl - > pv - > dev ) , b , e - b ) ;
2001-11-29 21:45:35 +03:00
pva - > map = pvm ;
2001-11-05 19:41:38 +03:00
pva - > start = b ;
pva - > count = e - b ;
2001-11-29 21:45:35 +03:00
_insert_area ( & pvm - > areas , pva ) ;
2001-11-06 13:29:56 +03:00
* extent = e ;
2001-11-05 19:41:38 +03:00
return 1 ;
}
2003-04-25 02:23:24 +04:00
static int _create_areas ( struct pool * mem , struct pv_map * pvm , uint32_t start ,
uint32_t count )
2001-11-05 19:41:38 +03:00
{
2003-04-25 02:23:24 +04:00
uint32_t pe , end ;
2001-11-05 19:41:38 +03:00
2003-04-25 02:23:24 +04:00
end = start + count - 1 ;
if ( end > pvm - > pvl - > pv - > pe_count - 1 )
end = pvm - > pvl - > pv - > pe_count - 1 ;
pe = start ;
while ( pe < = end )
if ( ! _create_single_area ( mem , pvm , end , & pe ) ) {
2001-11-05 19:41:38 +03:00
stack ;
return 0 ;
}
return 1 ;
}
2003-04-25 02:23:24 +04:00
static int _create_allocatable_areas ( struct pool * mem , struct pv_map * pvm )
{
struct list * alloc_areas , * aah ;
struct alloc_area * aa ;
alloc_areas = pvm - > pvl - > alloc_areas ;
if ( alloc_areas ) {
list_iterate ( aah , alloc_areas ) {
aa = list_item ( aah , struct alloc_area ) ;
if ( ! _create_areas ( mem , pvm , aa - > start , aa - > count ) ) {
stack ;
return 0 ;
}
}
} else {
/* Use whole PV */
if ( ! _create_areas ( mem , pvm , UINT32_C ( 0 ) ,
pvm - > pvl - > pv - > pe_count ) ) {
stack ;
return 0 ;
}
}
return 1 ;
}
static int _create_all_areas ( struct pool * mem , struct list * maps ,
struct list * pvs )
2001-11-05 19:41:38 +03:00
{
struct list * tmp ;
struct pv_map * pvm ;
list_iterate ( tmp , maps ) {
pvm = list_item ( tmp , struct pv_map ) ;
2003-04-25 02:23:24 +04:00
if ( ! _create_allocatable_areas ( mem , pvm ) ) {
2001-11-05 19:41:38 +03:00
stack ;
return 0 ;
}
}
return 1 ;
}
2001-11-13 20:53:06 +03:00
struct list * create_pv_maps ( struct pool * mem , struct volume_group * vg ,
2001-11-06 14:19:33 +03:00
struct list * pvs )
2001-11-05 19:41:38 +03:00
{
struct list * maps = pool_zalloc ( mem , sizeof ( * maps ) ) ;
if ( ! maps ) {
stack ;
return NULL ;
}
list_init ( maps ) ;
2001-11-06 14:19:33 +03:00
if ( ! _create_maps ( mem , pvs , maps ) ) {
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 ) ;
2001-11-05 19:41:38 +03:00
goto bad ;
}
if ( ! _fill_bitsets ( vg , maps ) ) {
2001-11-06 22:02:26 +03:00
log_error ( " Couldn't fill extent allocation bitmaps in %s " ,
vg - > name ) ;
2001-11-05 19:41:38 +03:00
goto bad ;
}
2003-04-25 02:23:24 +04:00
if ( ! _create_all_areas ( mem , maps , pvs ) ) {
2001-11-06 22:02:26 +03:00
log_error ( " Couldn't create area maps in %s " , vg - > name ) ;
2001-11-05 19:41:38 +03:00
goto bad ;
}
return maps ;
2001-11-13 20:53:06 +03:00
bad :
2001-11-05 19:41:38 +03:00
pool_free ( mem , maps ) ;
return NULL ;
}
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 ) ;
}
}