2001-09-25 12:49:28 +00:00
/*
2001-10-12 10:32:06 +00:00
* Copyright ( C ) 2001 Sistina Software ( UK ) Limited .
2001-09-25 12:49:28 +00:00
*
2001-10-12 10:32:06 +00:00
* This file is released under the GPL .
2001-09-25 12:49:28 +00:00
*/
2001-10-01 15:14:39 +00:00
# include "log.h"
2001-10-12 10:32:06 +00:00
# include "pool.h"
# include "device.h"
# include "dev-cache.h"
2001-10-01 15:14:39 +00:00
# include "metadata.h"
2001-09-25 12:49:28 +00:00
2001-10-12 10:32:06 +00:00
# include <string.h>
2001-09-25 12:49:28 +00:00
2001-10-12 14:25:53 +00:00
int _add_pv_to_vg ( struct io_space * ios , struct volume_group * vg ,
2001-10-15 18:39:40 +00:00
const char * pv_name )
2001-10-12 14:25:53 +00:00
{
2001-10-15 18:39:40 +00:00
struct pv_list * pvl ;
struct physical_volume * pv ;
2001-10-12 14:25:53 +00:00
2001-10-15 18:39:40 +00:00
log_verbose ( " Adding physical volume '%s' to volume group '%s' " ,
pv_name , vg - > name ) ;
if ( ! ( pvl = pool_alloc ( ios - > mem , sizeof ( * pvl ) ) ) ) {
log_error ( " pv_list allocation for '%s' failed " , pv_name ) ;
2001-10-12 14:25:53 +00:00
return 0 ;
}
2001-10-15 18:39:40 +00:00
if ( ! ( pv = ios - > pv_read ( ios , pv_name ) ) ) {
log_error ( " Failed to read existing physical volume '%s' " ,
pv_name ) ;
return 0 ;
}
2001-10-12 14:25:53 +00:00
2001-10-15 18:39:40 +00:00
if ( * pv - > vg_name ) {
log_error ( " Physical volume '%s' is already in volume group "
" '%s' " , pv_name , pv - > vg_name ) ;
2001-10-15 12:49:58 +00:00
return 0 ;
}
2001-10-12 14:25:53 +00:00
2001-10-15 18:39:40 +00:00
/* FIXME For LVM2, set on PV creation instead of here? */
pv - > status | = ALLOCATED_PV ;
/* FIXME check this */
pv - > exported = NULL ;
2001-10-12 14:25:53 +00:00
if ( ! ( pv - > vg_name = pool_strdup ( ios - > mem , vg - > name ) ) ) {
2001-10-15 18:39:40 +00:00
log_error ( " vg->name allocation failed for '%s' " , pv_name ) ;
2001-10-12 14:25:53 +00:00
return 0 ;
}
2001-10-15 18:39:40 +00:00
/* FIXME Tie this to activation or not? */
pv - > status | = ACTIVE ;
2001-10-12 14:25:53 +00:00
2001-10-15 20:29:15 +00:00
/* Units of 512-byte sectors */
2001-10-12 14:25:53 +00:00
if ( ! dev_get_size ( pv - > dev , & pv - > size ) ) {
stack ;
return 0 ;
}
2001-10-15 20:29:15 +00:00
/* Units of 512-byte sectors */
2001-10-12 14:25:53 +00:00
pv - > pe_size = vg - > extent_size ;
/*
* The next two fields should be corrected
* by ios - > pv_setup .
*/
pv - > pe_start = 0 ;
pv - > pe_count = pv - > size / pv - > pe_size ;
pv - > pe_allocated = 0 ;
if ( ! ios - > pv_setup ( ios , pv , vg ) ) {
2001-10-15 20:29:15 +00:00
log_debug ( " Format-specific setup of physical volume '%s' "
2001-10-15 18:39:40 +00:00
" failed. " , pv_name ) ;
return 0 ;
}
if ( find_pv_in_vg ( vg , pv_name ) ) {
log_error ( " Physical volume '%s' listed more than once. " ,
pv_name ) ;
2001-10-12 14:25:53 +00:00
return 0 ;
}
2001-10-15 18:39:40 +00:00
if ( vg - > pv_count = = vg - > max_pv ) {
log_error ( " No space for '%s' - volume group '%s' "
" holds max %d physical volume(s). " , pv_name ,
vg - > name , vg - > max_pv ) ;
return 0 ;
}
memcpy ( & pvl - > pv , pv , sizeof ( struct physical_volume ) ) ;
2001-10-12 14:25:53 +00:00
list_add ( & pvl - > list , & vg - > pvs ) ;
vg - > pv_count + + ;
return 1 ;
}
2001-10-15 22:04:27 +00:00
int vg_extend ( struct io_space * ios , struct volume_group * vg , int pv_count ,
char * * pv_names )
{
int i ;
/* attach each pv */
for ( i = 0 ; i < pv_count ; i + + )
if ( ! _add_pv_to_vg ( ios , vg , pv_names [ i ] ) ) {
log_error ( " Unable to add physical volume '%s' to "
" volume group '%s'. " , pv_names [ i ] , vg - > name ) ;
return 0 ;
}
return 1 ;
}
2001-10-15 18:39:40 +00:00
struct volume_group * vg_create ( struct io_space * ios , const char * vg_name ,
2001-10-12 14:25:53 +00:00
uint64_t extent_size , int max_pv , int max_lv ,
int pv_count , char * * pv_names )
{
struct volume_group * vg ;
2001-10-15 18:39:40 +00:00
if ( ! ( vg = pool_alloc ( ios - > mem , sizeof ( * vg ) ) ) ) {
2001-10-12 14:25:53 +00:00
stack ;
return NULL ;
}
/* is this vg name already in use ? */
2001-10-15 18:39:40 +00:00
if ( ios - > vg_read ( ios , vg_name ) ) {
log_err ( " A volume group called '%s' already exists. " , vg_name ) ;
2001-10-12 14:25:53 +00:00
goto bad ;
}
if ( ! id_create ( & vg - > id ) ) {
2001-10-15 18:39:40 +00:00
log_err ( " Couldn't create uuid for volume group '%s'. " , vg_name ) ;
2001-10-12 14:25:53 +00:00
goto bad ;
}
2001-10-15 18:39:40 +00:00
/* Strip prefix if present */
if ( ! strncmp ( vg_name , ios - > prefix , strlen ( ios - > prefix ) ) )
vg_name + = strlen ( ios - > prefix ) ;
if ( ! ( vg - > name = pool_strdup ( ios - > mem , vg_name ) ) ) {
2001-10-12 14:25:53 +00:00
stack ;
goto bad ;
}
2001-10-15 18:39:40 +00:00
vg - > status = ( ACTIVE | EXTENDABLE_VG | LVM_READ | LVM_WRITE ) ;
2001-10-12 14:25:53 +00:00
2001-10-15 18:39:40 +00:00
vg - > extent_size = extent_size ;
vg - > extent_count = 0 ;
vg - > free_count = 0 ;
2001-10-12 14:25:53 +00:00
2001-10-15 18:39:40 +00:00
vg - > max_lv = max_lv ;
vg - > max_pv = max_pv ;
2001-10-12 14:25:53 +00:00
2001-10-15 18:39:40 +00:00
vg - > pv_count = 0 ;
2001-10-12 14:25:53 +00:00
INIT_LIST_HEAD ( & vg - > pvs ) ;
2001-10-15 18:39:40 +00:00
vg - > lv_count = 0 ;
2001-10-12 14:25:53 +00:00
INIT_LIST_HEAD ( & vg - > lvs ) ;
if ( ! ios - > vg_setup ( ios , vg ) ) {
2001-10-15 18:39:40 +00:00
log_error ( " Format specific setup of volume group '%s' failed. " ,
vg_name ) ;
2001-10-12 14:25:53 +00:00
goto bad ;
}
/* attach the pv's */
2001-10-15 22:04:27 +00:00
if ( ! vg_extend ( ios , vg , pv_count , pv_names ) )
goto bad ;
2001-10-12 14:25:53 +00:00
return vg ;
2001-10-15 18:39:40 +00:00
bad :
2001-10-12 14:25:53 +00:00
pool_free ( ios - > mem , vg ) ;
return NULL ;
}
2001-10-12 10:52:32 +00:00
struct physical_volume * pv_create ( struct io_space * ios , const char * name )
2001-09-25 12:49:28 +00:00
{
2001-10-15 18:39:40 +00:00
struct physical_volume * pv = pool_alloc ( ios - > mem , sizeof ( * pv ) ) ;
2001-10-12 10:32:06 +00:00
if ( ! pv ) {
stack ;
return NULL ;
}
2001-10-15 18:39:40 +00:00
id_create ( & pv - > id ) ;
2001-10-12 10:32:06 +00:00
if ( ! ( pv - > dev = dev_cache_get ( name , ios - > filter ) ) ) {
log_err ( " Couldn't find device '%s' " , name ) ;
goto bad ;
}
2001-10-12 12:21:43 +00:00
if ( ! ( pv - > vg_name = pool_alloc ( ios - > mem , NAME_LEN ) ) ) {
stack ;
goto bad ;
}
* pv - > vg_name = 0 ;
2001-10-12 10:32:06 +00:00
pv - > exported = NULL ;
2001-10-15 18:39:40 +00:00
pv - > status = 0 ;
2001-10-12 10:32:06 +00:00
if ( ! dev_get_size ( pv - > dev , & pv - > size ) ) {
log_err ( " Couldn't get size of device '%s' " , name ) ;
goto bad ;
}
2001-10-15 18:39:40 +00:00
pv - > pe_size = 0 ;
pv - > pe_start = 0 ;
pv - > pe_count = 0 ;
pv - > pe_allocated = 0 ;
2001-10-12 10:32:06 +00:00
return pv ;
2001-10-15 18:39:40 +00:00
bad :
2001-10-12 10:32:06 +00:00
pool_free ( ios - > mem , pv ) ;
return NULL ;
2001-09-25 12:49:28 +00:00
}
2001-10-15 18:39:40 +00:00
struct list_head * find_pv_in_vg ( struct volume_group * vg , const char * pv_name )
{
struct list_head * pvh ;
list_for_each ( pvh , & vg - > pvs ) {
if ( ! strcmp ( list_entry ( pvh , struct pv_list , list ) - > pv . dev - > name ,
pv_name ) ) return pvh ;
}
2001-09-25 12:49:28 +00:00
2001-10-15 18:39:40 +00:00
return NULL ;
2001-10-12 10:32:06 +00:00
2001-10-15 18:39:40 +00:00
}