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 ) {
2002-01-21 19:05:23 +03:00
pv = list_item ( tmp , struct pv_list ) - > pv ;
2001-11-05 19:41:38 +03:00
2002-01-10 18:09:51 +03:00
if ( ! ( pv - > status & ALLOCATABLE_PV ) )
continue ;
2001-11-05 19:41:38 +03:00
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 ) ) ) ) {
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 ;
2001-11-27 20:39:15 +03:00
struct stripe_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 ) ;
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 */
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 ) {
2001-11-27 19:37:33 +03:00
seg = list_item ( segh , struct stripe_segment ) ;
2001-12-08 00:17:12 +03:00
for ( s = 0 ; s < seg - > stripes ; s + + ) {
for ( pe = 0 ; pe < ( seg - > len / seg - > stripes ) ;
pe + + ) {
if ( ! _set_allocated ( hash ,
2002-04-24 22:20:51 +04:00
seg - > area [ s ] . pv ,
seg - > area [ s ] . pe
2001-12-08 00:17:12 +03:00
+ pe ) ) {
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 ;
struct pv_area * pva ;
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 ,
2002-04-24 22:20:51 +04:00
uint32_t * extent )
2001-11-05 19:41:38 +03:00
{
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 ) ;
}
}