2001-11-05 19:41:38 +03:00
/*
* Copyright ( C ) 2001 Sistina Software
*
* This file is released under the LGPL .
*/
# include "pv_map.h"
# include "log.h"
2001-11-27 20:39:15 +03:00
# include "hash.h"
2001-11-05 19:41:38 +03:00
2001-11-27 19:37:33 +03:00
# include <assert.h>
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 physical_volume * pv ;
struct pv_map * pvm ;
2001-11-06 14:19:33 +03:00
list_iterate ( tmp , pvs ) {
2001-11-05 19:41:38 +03:00
pv = & ( list_item ( tmp , struct pv_list ) - > pv ) ;
if ( ! ( pvm = pool_zalloc ( mem , sizeof ( * pvm ) ) ) ) {
stack ;
return 0 ;
}
pvm - > pv = pv ;
if ( ! ( pvm - > allocated_extents =
bitset_create ( mem , pv - > pe_count ) ) ) {
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 ;
}
2001-11-27 19:37:33 +03:00
static int _set_allocated ( struct hash_table * hash ,
struct physical_volume * pv , int pe )
{
struct pv_map * pvm ;
if ( ! ( pvm = ( struct pv_map * ) hash_lookup ( hash , dev_name ( pv - > dev ) ) ) ) {
log_err ( " pv_map not present in hash table. " ) ;
return 0 ;
}
/* sanity check */
assert ( ! bit ( pvm - > allocated_extents , pe ) ) ;
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-11-27 19:37:33 +03:00
uint32_t i , r = 0 ;
struct hash_table * hash ;
2001-11-27 20:39:15 +03:00
struct stripe_segment * seg ;
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 */
list_iterate ( pvmh , maps ) {
pvm = list_item ( pvmh , struct pv_map ) ;
if ( ! hash_insert ( hash , dev_name ( pvm - > pv - > dev ) , pvm ) ) {
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 */
list_iterate ( lvh , & vg - > lvs ) {
lv = & ( list_item ( lvh , struct lv_list ) - > lv ) ;
2001-11-05 19:41:38 +03:00
2001-11-27 19:37:33 +03:00
list_iterate ( segh , & lv - > segments ) {
seg = list_item ( segh , struct stripe_segment ) ;
for ( i = 0 ; i < seg - > len ; i + + ) {
if ( ! _set_allocated ( hash ,
seg - > area [ i % seg - > stripes ] . pv ,
seg - > area [ i % seg - > stripes ] . pe +
2001-11-27 20:39:15 +03:00
( i / seg - > stripes ) ) ) {
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
r = 1 ;
2001-11-05 19:41:38 +03:00
2001-11-27 19:37:33 +03: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 ;
struct pv_area * pva ;
2001-12-03 19:27:16 +03:00
if ( list_empty ( head ) ) {
list_add ( head , & a - > list ) ;
return ;
}
2001-11-29 21:45:35 +03:00
list_iterate ( pvah , head ) {
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 ) ;
return ;
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 ,
uint32_t * extent )
{
uint32_t e = * extent , b , count = pvm - > pv - > pe_count ;
struct pv_area * pva ;
while ( e < count & & bit ( pvm - > allocated_extents , e ) )
e + + ;
if ( e = = count ) {
* extent = e ;
return 1 ;
}
b = e + + ;
while ( e < count & & ! bit ( pvm - > allocated_extents , e ) )
e + + ;
if ( ! ( pva = pool_zalloc ( mem , sizeof ( * pva ) ) ) ) {
stack ;
return 0 ;
}
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 ;
}
static int _create_areas ( struct pool * mem , struct pv_map * pvm )
{
uint32_t pe = 0 ;
while ( pe < pvm - > pv - > pe_count )
if ( ! _create_single_area ( mem , pvm , & pe ) ) {
stack ;
return 0 ;
}
return 1 ;
}
static int _create_all_areas ( struct pool * mem , struct list * maps )
{
struct list * tmp ;
struct pv_map * pvm ;
list_iterate ( tmp , maps ) {
pvm = list_item ( tmp , struct pv_map ) ;
if ( ! _create_areas ( mem , pvm ) ) {
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 ;
}
if ( ! _create_all_areas ( mem , maps ) ) {
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 ) ;
}
}