2001-11-06 22:02:26 +03:00
/*
2001-11-08 01:47:43 +03:00
* Copyright ( C ) 2001 Sistina Software
2001-11-06 22:02:26 +03:00
*
2001-11-08 01:47:43 +03:00
* This file is released under the GPL .
2001-11-06 22:02:26 +03:00
*
*/
# include "tools.h"
2001-11-16 18:38:52 +03:00
# include <fcntl.h>
2001-11-06 22:02:26 +03:00
int lvcreate ( int argc , char * * argv )
{
int zero ;
uint32_t read_ahead = 0 ;
int stripes = 1 ;
int stripesize = 0 ;
int opt = 0 ;
uint32_t status = 0 ;
uint32_t size = 0 ;
2001-12-03 19:27:16 +03:00
uint32_t size_rest ;
2001-11-06 22:02:26 +03:00
uint32_t extents = 0 ;
struct volume_group * vg ;
struct logical_volume * lv ;
struct list * lvh , * pvh , * pvl ;
char * lv_name = NULL ;
char * vg_name ;
char * st ;
if ( arg_count ( snapshot_ARG ) | | arg_count ( chunksize_ARG ) ) {
log_error ( " Snapshots are not yet supported in LVM2. " ) ;
return EINVALID_CMD_LINE ;
}
/* mutually exclusive */
if ( ( arg_count ( zero_ARG ) & & arg_count ( snapshot_ARG ) ) | |
( arg_count ( extents_ARG ) & & arg_count ( size_ARG ) ) ) {
log_error ( " Invalid combination of arguments " ) ;
return EINVALID_CMD_LINE ;
}
if ( arg_count ( size_ARG ) + arg_count ( extents_ARG ) = = 0 ) {
log_error ( " Please indicate size using option -l or -L " ) ;
return EINVALID_CMD_LINE ;
}
if ( strcmp ( arg_str_value ( contiguous_ARG , " n " ) , " n " ) )
status | = ALLOC_CONTIGUOUS ;
2001-11-12 22:28:50 +03:00
else
status | = ALLOC_SIMPLE ;
2001-11-06 22:02:26 +03:00
zero = strcmp ( arg_str_value ( zero_ARG , " y " ) , " n " ) ;
if ( arg_count ( stripes_ARG ) ) {
stripes = arg_int_value ( stripes_ARG , 1 ) ;
if ( stripes = = 1 )
log_print ( " Redundant stripes argument: default is 1 " ) ;
}
if ( arg_count ( stripesize_ARG ) )
2001-12-03 19:27:16 +03:00
stripesize = 2 * arg_int_value ( stripesize_ARG , 0 ) ;
2001-11-06 22:02:26 +03:00
if ( stripes = = 1 & & stripesize ) {
log_print ( " Ignoring stripesize argument with single stripe " ) ;
stripesize = 0 ;
}
2001-12-03 19:27:16 +03:00
if ( stripes > 1 & & ! stripesize ) {
stripesize = 2 * STRIPE_SIZE_DEFAULT ;
log_print ( " Using default stripesize %dKB " , stripesize / 2 ) ;
}
2001-11-06 22:02:26 +03:00
if ( arg_count ( permission_ARG ) )
status | = arg_int_value ( permission_ARG , 0 ) ;
2001-11-08 01:47:43 +03:00
else
status | = LVM_READ | LVM_WRITE ;
2001-11-06 22:02:26 +03:00
if ( arg_count ( readahead_ARG ) )
read_ahead = arg_int_value ( readahead_ARG , 0 ) ;
if ( arg_count ( extents_ARG ) )
extents = arg_int_value ( extents_ARG , 0 ) ;
/* Size returned in kilobyte units; held in sectors */
if ( arg_count ( size_ARG ) )
size = arg_int_value ( size_ARG , 0 ) ;
if ( arg_count ( name_ARG ) )
lv_name = arg_value ( name_ARG ) ;
2001-11-12 22:28:50 +03:00
2001-11-06 22:02:26 +03:00
/* If VG not on command line, try -n arg and then environment */
if ( ! argc ) {
2001-11-14 16:52:38 +03:00
if ( ! ( vg_name = extract_vgname ( fid , lv_name ) ) ) {
2001-11-06 22:02:26 +03:00
log_error ( " Please provide a volume group name " ) ;
return EINVALID_CMD_LINE ;
}
} else {
/* Ensure lv_name doesn't contain a different VG! */
2001-11-14 15:07:37 +03:00
if ( lv_name & & strchr ( lv_name , ' / ' ) ) {
2001-11-12 18:10:01 +03:00
if ( ! ( vg_name = extract_vgname ( fid , lv_name ) ) )
2001-11-06 22:02:26 +03:00
return EINVALID_CMD_LINE ;
if ( strcmp ( vg_name , argv [ 0 ] ) ) {
log_error ( " Inconsistent volume group names "
" given: %s and %s " , vg_name , argv [ 0 ] ) ;
return EINVALID_CMD_LINE ;
}
}
vg_name = argv [ 0 ] ;
argv + + ;
argc - - ;
}
2001-11-14 15:07:37 +03:00
if ( lv_name & & ( st = strrchr ( lv_name , ' / ' ) ) )
2001-11-06 22:02:26 +03:00
lv_name = st + 1 ;
/* does VG exist? */
log_verbose ( " Finding volume group %s " , vg_name ) ;
2001-11-12 18:10:01 +03:00
if ( ! ( vg = fid - > ops - > vg_read ( fid , vg_name ) ) ) {
2001-11-06 22:02:26 +03:00
log_error ( " Volume group %s doesn't exist " , vg_name ) ;
return ECMD_FAILED ;
}
2001-11-21 22:32:35 +03:00
/******* Removed check
2001-11-06 22:02:26 +03:00
if ( ! ( vg - > status & ACTIVE ) ) {
log_error ( " Volume group %s must be active before changing a "
" logical volume " , vg_name ) ;
return ECMD_FAILED ;
}
2001-11-21 22:32:35 +03:00
* * * * * * * */
2001-11-06 22:02:26 +03:00
if ( lv_name & & ( lvh = find_lv_in_vg ( vg , lv_name ) ) ) {
2001-11-14 15:07:37 +03:00
log_error ( " Logical volume %s already exists in "
" volume group %s " , lv_name , vg_name ) ;
2001-11-06 22:02:26 +03:00
return ECMD_FAILED ;
}
if ( argc ) {
/* Build up list of PVs */
2001-11-13 20:53:06 +03:00
if ( ! ( pvh = pool_alloc ( fid - > cmd - > mem , sizeof ( struct list ) ) ) ) {
2001-11-06 22:02:26 +03:00
log_error ( " pvh list allocation failed " ) ;
return ECMD_FAILED ;
}
list_init ( pvh ) ;
for ( ; opt < argc ; opt + + ) {
if ( ! ( pvl = find_pv_in_vg ( vg , argv [ opt ] ) ) ) {
log_error ( " Physical Volume %s not found in "
" Volume Group %s " , argv [ opt ] ,
vg - > name ) ;
return EINVALID_CMD_LINE ;
}
if ( list_item ( pvl , struct pv_list ) - > pv . pe_count = =
2001-11-10 01:01:04 +03:00
list_item ( pvl , struct pv_list ) - > pv . pe_allocated ) {
2001-11-13 20:53:06 +03:00
log_error ( " No free extents on physical volume "
" %s " , argv [ opt ] ) ;
2001-11-10 01:01:04 +03:00
continue ;
/* FIXME But check not null at end! */
}
2001-11-06 22:02:26 +03:00
list_add ( pvh , pvl ) ;
}
} else {
/* Use full list from VG */
pvh = & vg - > pvs ;
}
2001-12-03 19:27:16 +03:00
if ( argc & & argc < stripes ) {
log_error ( " Too few physical volumes on "
2001-11-06 22:02:26 +03:00
" command line for %d-way striping " , stripes ) ;
return EINVALID_CMD_LINE ;
}
2001-12-03 19:27:16 +03:00
if ( stripes < 1 | | stripes > MAX_STRIPES ) {
log_error ( " Number of stripes (%d) must be between %d and %d " ,
stripes , 1 , MAX_STRIPES ) ;
2001-11-06 22:02:26 +03:00
return EINVALID_CMD_LINE ;
}
2001-12-03 19:27:16 +03:00
if ( stripes > 1 & & ( stripesize < STRIPE_SIZE_MIN | |
stripesize > STRIPE_SIZE_MAX | |
stripesize & ( stripesize - 1 ) ) ) {
log_error ( " Invalid stripe size %d " , stripesize ) ;
2001-11-06 22:02:26 +03:00
return EINVALID_CMD_LINE ;
}
2001-12-03 19:27:16 +03:00
if ( stripesize > vg - > extent_size ) {
log_error ( " Setting stripe size %d KB to physical extent "
" size %u KB " ,
stripesize / 2 , vg - > extent_size / 2 ) ;
stripesize = vg - > extent_size ;
2001-11-06 22:02:26 +03:00
}
if ( size ) {
/* No of 512-byte sectors */
extents = size * 2 ;
if ( extents % vg - > extent_size ) {
char * s1 ;
extents + = vg - > extent_size - extents % vg - > extent_size ;
log_print ( " Rounding up size to full physical extent %s " ,
2001-11-13 20:53:06 +03:00
( s1 = display_size ( extents / 2 , SIZE_SHORT ) ) ) ;
2001-11-06 22:02:26 +03:00
dbg_free ( s1 ) ;
}
extents / = vg - > extent_size ;
}
2001-12-03 19:27:16 +03:00
if ( ( size_rest = extents % stripes ) ) {
log_print ( " Rounding size (%d extents) up to stripe boundary "
" size (%d extents) " , extents ,
extents - size_rest + stripes ) ;
extents = extents - size_rest + stripes ;
}
2001-11-06 22:02:26 +03:00
2001-11-16 18:38:52 +03:00
if ( ! ( lv = lv_create ( lv_name , status , stripes , stripesize , extents ,
2001-12-08 00:17:12 +03:00
vg , pvh ) ) )
return ECMD_FAILED ;
2001-11-06 22:02:26 +03:00
if ( arg_count ( readahead_ARG ) ) {
log_verbose ( " Setting read ahead sectors " ) ;
lv - > read_ahead = read_ahead ;
}
/* store vg on disk(s) */
2001-11-12 18:10:01 +03:00
if ( ! fid - > ops - > vg_write ( fid , vg ) )
2001-11-06 22:02:26 +03:00
return ECMD_FAILED ;
2001-11-14 17:12:01 +03:00
log_print ( " Logical volume %s created " , lv - > name ) ;
2001-11-06 22:02:26 +03:00
if ( ! lv_activate ( lv ) )
return ECMD_FAILED ;
2001-11-14 16:52:38 +03:00
if ( zero ) {
2001-11-06 22:02:26 +03:00
struct device * dev ;
2001-11-16 18:38:52 +03:00
char * name ;
2001-11-06 22:02:26 +03:00
2001-12-31 22:09:51 +03:00
if ( ! ( name = dbg_malloc ( PATH_MAX ) ) ) {
2001-11-16 18:38:52 +03:00
log_error ( " Name allocation failed - device not zeroed " ) ;
return ECMD_FAILED ;
}
2001-11-06 22:02:26 +03:00
2001-12-31 22:09:51 +03:00
if ( lvm_snprintf ( name , PATH_MAX , " %s%s/%s " , fid - > cmd - > dev_dir ,
lv - > vg - > name , lv - > name ) < 0 ) {
log_error ( " Name too long - device not zeroed (%s) " ,
lv - > name ) ;
return ECMD_FAILED ;
}
2001-11-06 22:02:26 +03:00
2001-11-16 18:38:52 +03:00
log_verbose ( " Zeroing start of logical volume %s " , name ) ;
if ( ! ( dev = dev_cache_get ( name , NULL ) ) ) {
log_error ( " %s not found: device not zeroed " , name ) ;
2001-11-06 22:02:26 +03:00
return ECMD_FAILED ;
}
2001-11-16 18:38:52 +03:00
if ( ! ( dev_open ( dev , O_WRONLY ) ) )
return ECMD_FAILED ;
dev_zero ( dev , 0 , 4096 ) ;
dev_close ( dev ) ;
2001-11-06 22:02:26 +03:00
} else
2001-11-14 15:07:37 +03:00
log_print ( " WARNING: %s not zeroed " , lv - > name ) ;
2001-11-06 22:02:26 +03:00
/******** FIXME backup
if ( ( ret = do_autobackup ( vg_name , vg ) ) )
return ret ;
* * * * * * * * * * */
return 0 ;
}