2001-10-04 00:38:07 +04:00
/*
* Copyright ( C ) 2001 Sistina Software
*
* LVM is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 , or ( at your option )
* any later version .
*
* LVM is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with LVM ; see the file COPYING . If not , write to
* the Free Software Foundation , 59 Temple Place - Suite 330 ,
* Boston , MA 02111 - 1307 , USA .
*
*/
# include "tools.h"
int vgcreate ( int argc , char * * argv )
{
int count_sav = 0 ;
int np = 0 ;
int opt ;
int p = 0 ;
int p1 = 0 ;
int max_lv = MAX_LV - 1 ;
int max_pv = MAX_PV - 1 ;
int min_pv_index = 0 ;
ulong max_pv_size = 0 ;
ulong min_pv_size = - 1 ;
long pe_size = LVM_DEFAULT_PE_SIZE ;
int ret = 0 ;
int size = 0 ;
int v = 0 ;
int vg_count = 0 ;
char * dummy ;
char * vg_name ;
struct volume_group * vg ;
struct physical_volume * pv , * * pvp = NULL ;
struct device pv_dev ;
char * pv_name = NULL ;
char * * vg_name_ptr = NULL ;
if ( arg_count ( maxlogicalvolumes_ARG ) )
max_lv = arg_int_value ( maxlogicalvolumes_ARG , 0 ) ;
if ( arg_count ( maxphysicalvolumes_ARG ) )
max_pv = arg_int_value ( maxphysicalvolumes_ARG , 0 ) ;
if ( arg_count ( physicalextentsize_ARG ) ) {
pe_size = arg_int_value ( physicalextentsize_ARG , 0 ) ;
pe_size = ( ( unsigned long long ) pe_size * 1024 ) / SECTOR_SIZE ;
if ( vg_check_pe_size ( pe_size ) < 0 ) {
log_error ( " invalid physical extent size %s " ,
display_size ( sectors_to_k ( pe_size ) ,
SIZE_SHORT ) ) ;
log_error ( " must be power of 2 and between %s and %s " ,
display_size ( sectors_to_k ( LVM_MIN_PE_SIZE ) ,
SIZE_SHORT ) ,
display_size ( sectors_to_k ( LVM_MAX_PE_SIZE ) ,
SIZE_SHORT ) ) ;
2001-10-05 02:53:37 +04:00
return EINVALID_CMD_LINE ;
2001-10-04 00:38:07 +04:00
}
}
if ( argc = = 0 ) {
log_error
( " please enter a volume group name and physical volumes " ) ;
2001-10-05 02:53:37 +04:00
return EINVALID_CMD_LINE ;
2001-10-04 00:38:07 +04:00
}
vg_name = argv [ 0 ] ;
if ( argc = = 1 ) {
log_error ( " please enter physical volume name(s) " ) ;
2001-10-05 02:53:37 +04:00
return EINVALID_CMD_LINE ;
2001-10-04 00:38:07 +04:00
}
if ( ( vg = ios - > vg_read ( ios , vg_name ) ) ) {
log_error
( " Volume group already exists: please use a different name " ) ;
2001-10-05 02:53:37 +04:00
return ECMD_FAILED ;
2001-10-04 00:38:07 +04:00
}
/***** FIXME: confirm we're now free of this restriction
log_verbose ( " counting all existing volume groups " ) ;
vg_name_ptr = lvm_tab_vg_check_exist_all_vg ( ) ;
vg_count = 0 ;
if ( vg_name_ptr ! = NULL )
for ( v = 0 ; vg_name_ptr [ v ] ! = NULL & & vg_count < MAX_VG ; v + + )
vg_count + + ;
if ( vg_count > = MAX_VG ) {
log_error ( " maximum volume group count of %d reached " , MAX_VG ) ;
return LVM_E_MAX_VG ;
}
* * * * */
if ( ! ( vg = vg_create ( ) ) ) {
2001-10-05 02:53:37 +04:00
return ECMD_FAILED ;
2001-10-04 00:38:07 +04:00
}
/* read all PVs */
/* check, if PVs are all defined and new */
log_verbose ( " Checking all physical volumes specified are new " ) ;
count_sav = argc - 1 ;
np = 0 ;
for ( opt = 1 ; opt < argc ; opt + + ) {
pv_name = argv [ opt ] ;
if ( ! ( pv_dev = dev_cache_get ( pv_name ) ) ) {
log_error ( " Device %s not found " , pv_name ) ;
2001-10-05 02:53:37 +04:00
return ECMD_FAILED ;
2001-10-04 00:38:07 +04:00
}
if ( ! ( pv = ios - > pv_read ( ios , pv_dev ) ) ) {
log_error ( " Physical volume %s not found " , pv_name ) ;
2001-10-05 02:53:37 +04:00
return ECMD_FAILED ;
2001-10-04 00:38:07 +04:00
}
log_verbose ( " checking physical volume %s " , pv_name ) ;
log_verbose ( " getting size of physical volume %s " , pv_name ) ;
/* FIXME size should already be filled in pv structure?! */
if ( ( size = dev_get_size ( pv_dev ) ) < 0 ) {
log_error ( " Unable to get size of %s " , pv_name ) ;
2001-10-05 02:53:37 +04:00
return ECMD_FAILED ;
2001-10-04 00:38:07 +04:00
}
log_verbose ( " physical volume %s is %d 512-byte sectors " ,
pv_name , size ) ;
log_verbose ( " checking physical volume %s is new " , pv_name ) ;
if ( pv - > vg_name [ 0 ] ) {
log_error ( " %s already belongs to volume group %s " ,
pv_name pv - > vg_name ) ;
}
log_verbose ( " checking for identical physical volumes "
" on command line " ) ;
for ( p1 = 0 ; pvp ! = NULL & & pvp [ p1 ] ! = NULL ; p1 + + ) {
if ( ! strcmp ( pv_name , pvp [ p1 ] - > dev - > name ) ) {
log_error
( " physical volume %s occurs multiple times " ,
pv_name ) ;
2001-10-05 02:53:37 +04:00
return ECMD_FAILED ;
2001-10-04 00:38:07 +04:00
}
}
if ( ( pvp = dbg_realloc ( pvp , ( np + 2 ) * sizeof ( pv * ) ) ) = = NULL ) {
log_error ( " realloc error in file \" %s \" [line %d] " ,
__FILE__ , __LINE__ ) ;
2001-10-05 02:53:37 +04:00
return ECMD_FAILED ;
2001-10-04 00:38:07 +04:00
}
pvp [ np ] = pv ;
if ( max_pv_size < pvp [ np ] - > size )
max_pv_size = pvp [ np ] - > size ;
if ( min_pv_size > pvp [ np ] - > size ) {
min_pv_size = pvp [ np ] - > size ;
min_pv_index = np ;
}
np + + ;
pvp [ np ] = NULL ;
}
if ( np = = 0 ) {
log_error ( " no valid physical volumes in command line " ) ;
2001-10-05 02:53:37 +04:00
return ECMD_FAILED ;
2001-10-04 00:38:07 +04:00
}
if ( np ! = count_sav ) {
log_error ( " some invalid physical volumes in command line " ) ;
2001-10-05 02:53:37 +04:00
return ECMD_FAILED ; /* Impossible to reach here? */
2001-10-04 00:38:07 +04:00
}
log_verbose ( " %d physical volume%s will be inserted into "
" volume group %s " , np , np > 1 ? " s " : " " , vg_name ) ;
vg - > pv = pvp ;
/* load volume group */
/* checking command line arguments */
log_verbose ( " checking command line arguments " ) ;
log_verbose ( " maximum of %d physical volumes " , max_pv ) ;
if ( max_pv < 0 | | max_pv < = np | | max_pv > MAX_PV ) {
log_error ( " invalid maximum physical volumes -p %d " , max_pv ) ;
2001-10-05 02:53:37 +04:00
return EINVALID_CMD_LINE ;
2001-10-04 00:38:07 +04:00
}
vg - > max_pv = max_pv ;
log_verbose ( " maximum of %d logical volumes " , max_lv ) ;
if ( max_lv < 0 | | max_lv > MAX_LV ) {
log_error ( " invalid maximum logical volumes -l %d " , max_lv ) ;
2001-10-05 02:53:37 +04:00
return EINVALID_CMD_LINE ;
2001-10-04 00:38:07 +04:00
}
vg - > max_lv = max_lv ;
/******** FIXME: Enforce these checks internally within vg_write?
size = ( LVM_PV_DISK_SIZE + LVM_VG_DISK_SIZE + max_pv * NAME_LEN + max_lv * sizeof ( lv_t ) ) ;
if ( size / SECTOR_SIZE > min_pv_size / 5 ) {
log_error ( " more than 20%% [%d KB] of physical volume %s with %u KB would be used " , size ,
pvp [ min_pv_index ] - > pv_name , pvp [ min_pv_index ] - > pv_size / 2 ) ;
return LVM_E_PV_TOO_SMALL ;
}
* * * * * * * * * * * */
/* FIXME More work required here */
/* Check extent sizes compatible and set up pe's? */
if (
( ret =
vg_setup_for_create ( vg_name , & vg , pvp , pe_size , max_pv ,
max_lv ) ) < 0 ) {
if ( ret = = - LVM_EVG_SETUP_FOR_CREATE_PV_SIZE_MIN ) {
log_error
( " %d physical volume%s too small for physical extent size of %s " ,
count_sav , count_sav > 1 ? " s " : " " , vg_name ) ;
log_error
( " Minimum physical volume at this physical extent size is %s " ,
( dummy =
display_size ( sectors_to_k ( vg . pe_size ) *
LVM_PE_SIZE_PV_SIZE_REL ,
SIZE_SHORT ) ) ) ;
dbg_free ( dummy ) ;
} else if ( ret = = - LVM_EVG_SETUP_FOR_CREATE_PV_SIZE_MAX ) {
log_error
( " %d physical volume%s too large for physical extent size of %s " ,
count_sav , count_sav > 1 ? " s " : " " , vg_name ) ;
log_error
( " Maximum physical volume at this physical extent size is %s " ,
( dummy =
display_size ( sectors_to_k ( vg . pe_size ) *
LVM_PE_T_MAX , SHORT ) ) ) ;
dbg_free ( dummy ) ;
}
2001-10-05 02:53:37 +04:00
return ECMD_FAILED ;
2001-10-04 00:38:07 +04:00
}
if ( arg_count ( physicalextentsize_ARG ) = = 0 ) {
log_print ( " Using default physical extent size %s " ,
( dummy = display_size ( pe_size / 2 , SIZE_SHORT ) ) ) ;
dbg_free ( dummy ) ;
}
log_print ( " Maximum logical volume size is %s " ,
( dummy = display_size ( LVM_LV_SIZE_MAX ( & vg ) / 2 , SIZE_LONG ) ) ) ;
dbg_free ( dummy ) ;
vg_remove_dir_and_group_and_nodes ( vg_name ) ;
/* FIXME Set active flag */
/* store vg on disk(s) */
if ( ios - > vg_write ( ios , vg ) ) {
2001-10-05 02:53:37 +04:00
return ECMD_FAILED ;
2001-10-04 00:38:07 +04:00
}
log_verbose ( " creating volume group directory %s%s " , prefix , vg_name ) ;
if ( vg_create_dir_and_group ( & vg ) ) {
2001-10-05 02:53:37 +04:00
return ECMD_FAILED ;
2001-10-04 00:38:07 +04:00
}
/* FIXME Activate it */
if ( ( ret = do_autobackup ( vg_name , & vg ) ) )
return ret ;
log_print ( " Volume group %s successfully created and activated " ,
vg_name ) ;
return 0 ;
}