2001-09-25 16:49:28 +04:00
/*
2001-10-12 14:32:06 +04:00
* Copyright ( C ) 2001 Sistina Software ( UK ) Limited .
2001-09-25 16:49:28 +04:00
*
2001-10-31 15:47:01 +03:00
* This file is released under the LGPL .
2001-09-25 16:49:28 +04:00
*/
2001-10-01 19:14:39 +04:00
# include "log.h"
2001-10-12 14:32:06 +04:00
# include "pool.h"
# include "device.h"
# include "dev-cache.h"
2001-10-01 19:14:39 +04:00
# include "metadata.h"
2001-09-25 16:49:28 +04:00
2001-10-12 14:32:06 +04:00
# include <string.h>
2001-09-25 16:49:28 +04:00
2001-11-12 15:16:57 +03:00
int _add_pv_to_vg ( struct format_instance * fi , struct volume_group * vg ,
2001-10-15 22:39:40 +04:00
const char * pv_name )
2001-10-12 18:25:53 +04:00
{
2001-10-15 22:39:40 +04:00
struct pv_list * pvl ;
struct physical_volume * pv ;
2001-11-12 15:16:57 +03:00
struct pool * mem = fi - > cmd - > mem ;
2001-10-12 18:25:53 +04:00
2001-10-15 22:39:40 +04:00
log_verbose ( " Adding physical volume '%s' to volume group '%s' " ,
2001-11-10 01:01:04 +03:00
pv_name , vg - > name ) ;
2001-10-15 22:39:40 +04:00
2001-11-12 15:16:57 +03:00
if ( ! ( pvl = pool_alloc ( mem , sizeof ( * pvl ) ) ) ) {
2001-10-15 22:39:40 +04:00
log_error ( " pv_list allocation for '%s' failed " , pv_name ) ;
2001-10-12 18:25:53 +04:00
return 0 ;
}
2001-11-12 15:16:57 +03:00
if ( ! ( pv = fi - > ops - > pv_read ( fi , pv_name ) ) ) {
2001-10-15 22:39:40 +04:00
log_error ( " Failed to read existing physical volume '%s' " ,
pv_name ) ;
return 0 ;
}
2001-10-12 18:25:53 +04:00
2001-10-15 22:39:40 +04:00
if ( * pv - > vg_name ) {
log_error ( " Physical volume '%s' is already in volume group "
" '%s' " , pv_name , pv - > vg_name ) ;
2001-10-15 16:49:58 +04:00
return 0 ;
}
2001-10-12 18:25:53 +04:00
2001-10-15 22:39:40 +04:00
/* FIXME check this */
pv - > exported = NULL ;
2001-11-12 15:16:57 +03:00
if ( ! ( pv - > vg_name = pool_strdup ( mem , vg - > name ) ) ) {
2001-10-15 22:39:40 +04:00
log_error ( " vg->name allocation failed for '%s' " , pv_name ) ;
2001-10-12 18:25:53 +04:00
return 0 ;
}
2001-10-16 00:29:15 +04:00
/* Units of 512-byte sectors */
2001-10-12 18:25:53 +04:00
if ( ! dev_get_size ( pv - > dev , & pv - > size ) ) {
stack ;
return 0 ;
}
2001-10-16 00:29:15 +04:00
/* Units of 512-byte sectors */
2001-10-12 18:25:53 +04:00
pv - > pe_size = vg - > extent_size ;
/*
* The next two fields should be corrected
2001-11-12 15:16:57 +03:00
* by fi - > pv_setup .
2001-10-12 18:25:53 +04:00
*/
pv - > pe_start = 0 ;
pv - > pe_count = pv - > size / pv - > pe_size ;
pv - > pe_allocated = 0 ;
2001-11-12 15:16:57 +03:00
if ( ! fi - > ops - > pv_setup ( fi , pv , vg ) ) {
2001-10-16 00:29:15 +04:00
log_debug ( " Format-specific setup of physical volume '%s' "
2001-10-15 22:39:40 +04: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 18:25:53 +04:00
return 0 ;
}
2001-10-15 22:39:40 +04: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 ;
}
2002-01-21 19:05:23 +03:00
pvl - > pv = pv ;
2001-10-15 22:39:40 +04:00
2001-10-31 15:47:01 +03:00
list_add ( & vg - > pvs , & pvl - > list ) ;
2001-10-12 18:25:53 +04:00
vg - > pv_count + + ;
2001-11-06 22:02:26 +03:00
vg - > extent_count + = pv - > pe_count ;
vg - > free_count + = pv - > pe_count ;
2001-10-12 18:25:53 +04:00
return 1 ;
}
2001-11-12 15:16:57 +03:00
int vg_extend ( struct format_instance * fi ,
struct volume_group * vg , int pv_count , char * * pv_names )
2001-10-16 02:04:27 +04:00
{
int i ;
/* attach each pv */
for ( i = 0 ; i < pv_count ; i + + )
2001-11-12 15:16:57 +03:00
if ( ! _add_pv_to_vg ( fi , vg , pv_names [ i ] ) ) {
2001-10-16 02:04:27 +04:00
log_error ( " Unable to add physical volume '%s' to "
" volume group '%s'. " , pv_names [ i ] , vg - > name ) ;
return 0 ;
}
return 1 ;
}
2001-11-12 18:10:01 +03:00
const char * strip_dir ( const char * vg_name , const char * dev_dir )
2001-11-12 15:16:57 +03:00
{
int len = strlen ( dev_dir ) ;
if ( ! strncmp ( vg_name , dev_dir , len ) )
vg_name + = len ;
return vg_name ;
}
struct volume_group * vg_create ( struct format_instance * fi , const char * vg_name ,
2001-11-06 22:02:26 +03:00
uint32_t extent_size , int max_pv , int max_lv ,
2001-10-12 18:25:53 +04:00
int pv_count , char * * pv_names )
{
struct volume_group * vg ;
2001-11-12 15:16:57 +03:00
struct pool * mem = fi - > cmd - > mem ;
2001-10-12 18:25:53 +04:00
2001-11-12 15:16:57 +03:00
if ( ! ( vg = pool_alloc ( mem , sizeof ( * vg ) ) ) ) {
2001-10-12 18:25:53 +04:00
stack ;
return NULL ;
}
/* is this vg name already in use ? */
2001-11-12 15:16:57 +03:00
if ( fi - > ops - > vg_read ( fi , vg_name ) ) {
2001-10-15 22:39:40 +04:00
log_err ( " A volume group called '%s' already exists. " , vg_name ) ;
2001-10-12 18:25:53 +04:00
goto bad ;
}
if ( ! id_create ( & vg - > id ) ) {
2001-11-12 15:16:57 +03:00
log_err ( " Couldn't create uuid for volume group '%s'. " ,
vg_name ) ;
2001-10-12 18:25:53 +04:00
goto bad ;
}
2001-11-14 16:52:38 +03:00
/* Strip dev_dir if present */
2001-11-12 15:16:57 +03:00
vg_name = strip_dir ( vg_name , fi - > cmd - > dev_dir ) ;
2001-10-15 22:39:40 +04:00
2002-01-07 18:27:55 +03:00
vg - > cmd = fi - > cmd ;
2001-11-12 15:16:57 +03:00
if ( ! ( vg - > name = pool_strdup ( mem , vg_name ) ) ) {
2001-10-12 18:25:53 +04:00
stack ;
goto bad ;
}
2002-01-11 02:21:07 +03:00
vg - > status = ( RESIZEABLE_VG | LVM_READ | LVM_WRITE ) ;
2001-10-12 18:25:53 +04:00
2001-10-15 22:39:40 +04:00
vg - > extent_size = extent_size ;
vg - > extent_count = 0 ;
vg - > free_count = 0 ;
2001-10-12 18:25:53 +04:00
2001-10-15 22:39:40 +04:00
vg - > max_lv = max_lv ;
vg - > max_pv = max_pv ;
2001-10-12 18:25:53 +04:00
2001-10-15 22:39:40 +04:00
vg - > pv_count = 0 ;
2001-10-31 15:47:01 +03:00
list_init ( & vg - > pvs ) ;
2001-10-12 18:25:53 +04:00
2001-10-15 22:39:40 +04:00
vg - > lv_count = 0 ;
2001-10-31 15:47:01 +03:00
list_init ( & vg - > lvs ) ;
2001-10-12 18:25:53 +04:00
2001-11-12 15:16:57 +03:00
if ( ! fi - > ops - > vg_setup ( fi , vg ) ) {
2001-10-15 22:39:40 +04:00
log_error ( " Format specific setup of volume group '%s' failed. " ,
vg_name ) ;
2001-10-12 18:25:53 +04:00
goto bad ;
}
/* attach the pv's */
2001-11-12 15:16:57 +03:00
if ( ! vg_extend ( fi , vg , pv_count , pv_names ) )
2001-10-16 02:04:27 +04:00
goto bad ;
2001-10-12 18:25:53 +04:00
return vg ;
2001-11-12 15:16:57 +03:00
bad :
pool_free ( mem , vg ) ;
2001-10-12 18:25:53 +04:00
return NULL ;
}
2002-01-16 21:10:08 +03:00
struct physical_volume * pv_create ( struct format_instance * fi ,
const char * name ,
struct id * id )
2001-09-25 16:49:28 +04:00
{
2001-11-12 15:16:57 +03:00
struct pool * mem = fi - > cmd - > mem ;
struct physical_volume * pv = pool_alloc ( mem , sizeof ( * pv ) ) ;
2001-10-12 14:32:06 +04:00
if ( ! pv ) {
stack ;
return NULL ;
}
2002-01-16 21:10:08 +03:00
if ( ! id )
id_create ( & pv - > id ) ;
else
memcpy ( & pv - > id , id , sizeof ( * id ) ) ;
2001-11-12 15:16:57 +03:00
if ( ! ( pv - > dev = dev_cache_get ( name , fi - > cmd - > filter ) ) ) {
2001-10-12 14:32:06 +04:00
log_err ( " Couldn't find device '%s' " , name ) ;
goto bad ;
}
2001-11-12 15:16:57 +03:00
if ( ! ( pv - > vg_name = pool_alloc ( mem , NAME_LEN ) ) ) {
2001-10-12 16:21:43 +04:00
stack ;
goto bad ;
}
* pv - > vg_name = 0 ;
2001-10-12 14:32:06 +04:00
pv - > exported = NULL ;
2002-01-10 18:09:51 +03:00
pv - > status = ALLOCATABLE_PV ;
2001-10-12 14:32:06 +04:00
if ( ! dev_get_size ( pv - > dev , & pv - > size ) ) {
log_err ( " Couldn't get size of device '%s' " , name ) ;
goto bad ;
}
2001-10-15 22:39:40 +04:00
pv - > pe_size = 0 ;
pv - > pe_start = 0 ;
pv - > pe_count = 0 ;
pv - > pe_allocated = 0 ;
2001-10-12 14:32:06 +04:00
return pv ;
2001-10-15 22:39:40 +04:00
bad :
2001-11-12 15:16:57 +03:00
pool_free ( mem , pv ) ;
2001-10-12 14:32:06 +04:00
return NULL ;
2001-09-25 16:49:28 +04:00
}
2002-01-21 17:28:12 +03:00
struct pv_list * find_pv_in_vg ( struct volume_group * vg , const char * pv_name )
2001-10-15 22:39:40 +04:00
{
2001-10-31 15:47:01 +03:00
struct list * pvh ;
2002-01-21 17:28:12 +03:00
struct pv_list * pvl ;
2001-10-25 18:04:18 +04:00
2001-10-31 15:47:01 +03:00
list_iterate ( pvh , & vg - > pvs ) {
2002-01-21 17:28:12 +03:00
pvl = list_item ( pvh , struct pv_list ) ;
2001-10-29 16:52:23 +03:00
/* FIXME check dev not name */
2002-01-21 19:05:23 +03:00
if ( ! strcmp ( dev_name ( pvl - > pv - > dev ) , pv_name ) )
2002-01-21 17:28:12 +03:00
return pvl ;
2001-10-15 22:39:40 +04:00
}
2001-09-25 16:49:28 +04:00
2001-10-15 22:39:40 +04:00
return NULL ;
2001-10-12 14:32:06 +04:00
2001-10-15 22:39:40 +04:00
}
2001-10-29 16:52:23 +03:00
2002-01-21 17:28:12 +03:00
struct lv_list * find_lv_in_vg ( struct volume_group * vg , const char * lv_name )
2001-10-29 16:52:23 +03:00
{
2001-10-31 15:47:01 +03:00
struct list * lvh ;
2002-01-21 17:28:12 +03:00
struct lv_list * lvl ;
2001-10-29 16:52:23 +03:00
const char * ptr ;
/* Use last component */
if ( ( ptr = strrchr ( lv_name , ' / ' ) ) )
ptr + + ;
else
ptr = lv_name ;
2001-10-31 15:47:01 +03:00
2002-01-21 17:28:12 +03:00
list_iterate ( lvh , & vg - > lvs ) {
lvl = list_item ( lvh , struct lv_list ) ;
2002-01-21 19:49:32 +03:00
if ( ! strcmp ( lvl - > lv - > name , ptr ) )
2002-01-21 17:28:12 +03:00
return lvl ;
}
2001-10-29 16:52:23 +03:00
2001-11-10 01:01:04 +03:00
return NULL ;
2001-10-29 16:52:23 +03:00
}
struct logical_volume * find_lv ( struct volume_group * vg , const char * lv_name )
{
2002-01-21 17:28:12 +03:00
struct lv_list * lvl = find_lv_in_vg ( vg , lv_name ) ;
2002-01-21 19:49:32 +03:00
return lvl ? lvl - > lv : NULL ;
2001-10-29 16:52:23 +03:00
}
2001-11-28 16:45:50 +03:00
struct physical_volume * find_pv ( struct volume_group * vg , struct device * dev )
2001-10-29 16:52:23 +03:00
{
2001-10-31 15:47:01 +03:00
struct list * pvh ;
2001-11-10 01:01:04 +03:00
struct physical_volume * pv ;
list_iterate ( pvh , & vg - > pvs ) {
2002-01-21 19:05:23 +03:00
pv = list_item ( pvh , struct pv_list ) - > pv ;
2001-11-10 01:01:04 +03:00
if ( dev = = pv - > dev )
return pv ;
}
return NULL ;
2001-10-29 16:52:23 +03:00
}