2001-11-06 22:02:26 +03:00
/*
2008-01-30 17:00:02 +03:00
* Copyright ( C ) 2001 - 2004 Sistina Software , Inc . All rights reserved .
2007-08-21 00:55:30 +04:00
* Copyright ( C ) 2004 - 2007 Red Hat , Inc . All rights reserved .
2001-11-06 22:02:26 +03:00
*
2004-03-30 23:35:44 +04:00
* This file is part of LVM2 .
2001-11-06 22:02:26 +03:00
*
2004-03-30 23:35:44 +04:00
* This copyrighted material is made available to anyone wishing to use ,
* modify , copy , or redistribute it subject to the terms and conditions
2007-08-21 00:55:30 +04:00
* of the GNU Lesser General Public License v .2 .1 .
2004-03-30 23:35:44 +04:00
*
2007-08-21 00:55:30 +04:00
* You should have received a copy of the GNU Lesser General Public License
2004-03-30 23:35:44 +04:00
* along with this program ; if not , write to the Free Software Foundation ,
* Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
2001-11-06 22:02:26 +03:00
*/
# include "tools.h"
2005-06-01 20:51:55 +04:00
# include "lv_alloc.h"
2002-01-01 00:27:39 +03:00
2001-11-16 18:38:52 +03:00
# include <fcntl.h>
2001-11-06 22:02:26 +03:00
2002-02-15 14:53:22 +03:00
struct lvcreate_params {
/* flags */
int snapshot ;
2001-11-06 22:02:26 +03:00
int zero ;
2003-04-02 23:14:43 +04:00
int major ;
2002-02-21 22:04:37 +03:00
int minor ;
2006-05-11 22:54:04 +04:00
int corelog ;
2006-05-12 00:03:40 +04:00
int nosync ;
2001-11-06 22:02:26 +03:00
2002-02-15 14:53:22 +03:00
char * origin ;
2002-12-20 02:25:55 +03:00
const char * vg_name ;
const char * lv_name ;
2001-11-06 22:02:26 +03:00
2002-02-15 14:53:22 +03:00
uint32_t stripes ;
uint32_t stripe_size ;
uint32_t chunk_size ;
2005-06-01 20:51:55 +04:00
uint32_t region_size ;
2002-02-15 14:53:22 +03:00
2004-05-05 01:25:57 +04:00
uint32_t mirrors ;
2006-05-10 01:23:51 +04:00
const struct segment_type * segtype ;
2004-05-05 01:25:57 +04:00
2002-02-15 14:53:22 +03:00
/* size */
uint32_t extents ;
uint64_t size ;
2006-09-26 13:35:43 +04:00
percent_t percent ;
2002-02-15 14:53:22 +03:00
uint32_t permission ;
uint32_t read_ahead ;
2004-05-19 02:12:53 +04:00
alloc_policy_t alloc ;
2002-02-15 14:53:22 +03:00
int pv_count ;
char * * pvs ;
} ;
2006-04-19 19:33:07 +04:00
static int _lvcreate_name_params ( struct lvcreate_params * lp ,
struct cmd_context * cmd ,
int * pargc , char * * * pargv )
2002-02-15 14:53:22 +03:00
{
int argc = * pargc ;
char * * argv = * pargv , * ptr ;
2004-10-15 19:53:18 +04:00
char * vg_name ;
2002-02-15 14:53:22 +03:00
if ( arg_count ( cmd , name_ARG ) )
lp - > lv_name = arg_value ( cmd , name_ARG ) ;
2004-05-11 20:01:58 +04:00
if ( lp - > snapshot ) {
2002-02-15 14:53:22 +03:00
if ( ! argc ) {
log_err ( " Please specify a logical volume to act as "
" the snapshot origin. " ) ;
return 0 ;
}
lp - > origin = argv [ 0 ] ;
( * pargv ) + + , ( * pargc ) - - ;
2002-04-24 22:20:51 +04:00
if ( ! ( lp - > vg_name = extract_vgname ( cmd , lp - > origin ) ) ) {
2002-02-15 14:53:22 +03:00
log_err ( " The origin name should include the "
" volume group. " ) ;
return 0 ;
}
2002-02-18 13:59:51 +03:00
/* Strip the volume group from the origin */
if ( ( ptr = strrchr ( lp - > origin , ( int ) ' / ' ) ) )
lp - > origin = ptr + 1 ;
2002-02-15 14:53:22 +03:00
} else {
/*
* If VG not on command line , try - n arg and then
* environment .
*/
if ( ! argc ) {
2002-04-24 22:20:51 +04:00
if ( ! ( lp - > vg_name = extract_vgname ( cmd , lp - > lv_name ) ) ) {
2002-02-15 14:53:22 +03:00
log_err ( " Please provide a volume group name " ) ;
return 0 ;
}
} else {
2007-03-09 23:47:41 +03:00
vg_name = skip_dev_dir ( cmd , argv [ 0 ] , NULL ) ;
2004-10-15 19:53:18 +04:00
if ( strrchr ( vg_name , ' / ' ) ) {
2002-07-17 20:04:05 +04:00
log_error ( " Volume group name expected "
" (no slash) " ) ;
return 0 ;
}
2002-02-15 14:53:22 +03:00
/*
* Ensure lv_name doesn ' t contain a
* different VG .
*/
if ( lp - > lv_name & & strchr ( lp - > lv_name , ' / ' ) ) {
if ( ! ( lp - > vg_name =
2002-04-24 22:20:51 +04:00
extract_vgname ( cmd , lp - > lv_name ) ) )
2002-11-18 17:04:08 +03:00
return 0 ;
2002-02-15 14:53:22 +03:00
2004-10-15 19:53:18 +04:00
if ( strcmp ( lp - > vg_name , vg_name ) ) {
2002-02-15 14:53:22 +03:00
log_error ( " Inconsistent volume group "
" names "
" given: \" %s \" and \" %s \" " ,
2004-10-15 19:53:18 +04:00
lp - > vg_name , vg_name ) ;
2002-02-15 14:53:22 +03:00
return 0 ;
}
}
2004-10-15 19:53:18 +04:00
lp - > vg_name = vg_name ;
2002-02-15 14:53:22 +03:00
( * pargv ) + + , ( * pargc ) - - ;
}
2001-11-06 22:02:26 +03:00
}
2007-11-02 23:40:05 +03:00
if ( ! validate_name ( lp - > vg_name ) ) {
log_error ( " Volume group name %s has invalid characters " ,
lp - > vg_name ) ;
return 0 ;
}
2003-04-25 02:23:24 +04:00
if ( lp - > lv_name ) {
if ( ( ptr = strrchr ( lp - > lv_name , ' / ' ) ) )
lp - > lv_name = ptr + 1 ;
2008-01-30 16:19:47 +03:00
if ( ! apply_lvname_restrictions ( lp - > lv_name ) )
return_0 ;
2002-11-18 17:04:08 +03:00
2003-04-25 02:23:24 +04:00
if ( ! validate_name ( lp - > lv_name ) ) {
2003-09-15 19:01:00 +04:00
log_error ( " Logical volume name \" %s \" is invalid " ,
lp - > lv_name ) ;
2003-04-25 02:23:24 +04:00
return 0 ;
}
2003-02-03 23:09:58 +03:00
}
2002-02-15 14:53:22 +03:00
return 1 ;
}
static int _read_size_params ( struct lvcreate_params * lp ,
2006-05-10 01:23:51 +04:00
struct cmd_context * cmd )
2002-02-15 14:53:22 +03:00
{
2004-05-11 20:01:58 +04:00
if ( arg_count ( cmd , extents_ARG ) + arg_count ( cmd , size_ARG ) ! = 1 ) {
log_error ( " Please specify either size or extents (not both) " ) ;
2002-02-15 14:53:22 +03:00
return 0 ;
2001-11-06 22:02:26 +03:00
}
2003-09-15 19:04:39 +04:00
if ( arg_count ( cmd , extents_ARG ) ) {
if ( arg_sign_value ( cmd , extents_ARG , 0 ) = = SIGN_MINUS ) {
log_error ( " Negative number of extents is invalid " ) ;
return 0 ;
}
2002-12-20 02:25:55 +03:00
lp - > extents = arg_uint_value ( cmd , extents_ARG , 0 ) ;
2006-09-26 13:35:43 +04:00
lp - > percent = arg_percent_value ( cmd , extents_ARG , PERCENT_NONE ) ;
2003-09-15 19:04:39 +04:00
}
2002-02-15 14:53:22 +03:00
/* Size returned in kilobyte units; held in sectors */
2003-09-15 19:04:39 +04:00
if ( arg_count ( cmd , size_ARG ) ) {
if ( arg_sign_value ( cmd , size_ARG , 0 ) = = SIGN_MINUS ) {
log_error ( " Negative size is invalid " ) ;
return 0 ;
}
2007-11-14 03:08:25 +03:00
lp - > size = arg_uint64_value ( cmd , size_ARG , UINT64_C ( 0 ) ) ;
2006-09-26 13:35:43 +04:00
lp - > percent = PERCENT_NONE ;
2003-09-15 19:04:39 +04:00
}
2002-02-15 14:53:22 +03:00
return 1 ;
}
2007-09-24 17:25:31 +04:00
/*
* Generic stripe parameter checks .
* FIXME : Should eventually be moved into lvm library .
*/
static int _validate_stripe_params ( struct cmd_context * cmd ,
struct lvcreate_params * lp )
2002-02-15 14:53:22 +03:00
{
if ( lp - > stripes = = 1 & & lp - > stripe_size ) {
2001-11-06 22:02:26 +03:00
log_print ( " Ignoring stripesize argument with single stripe " ) ;
2002-02-15 14:53:22 +03:00
lp - > stripe_size = 0 ;
2001-11-06 22:02:26 +03:00
}
2002-02-15 14:53:22 +03:00
if ( lp - > stripes > 1 & & ! lp - > stripe_size ) {
2006-05-16 20:48:31 +04:00
lp - > stripe_size = find_config_tree_int ( cmd ,
2004-03-08 21:28:45 +03:00
" metadata/stripesize " ,
2008-01-17 18:53:01 +03:00
DEFAULT_STRIPESIZE ) * 2 ;
2006-04-30 02:08:43 +04:00
log_print ( " Using default stripesize %s " ,
2006-05-10 01:23:51 +04:00
display_size ( cmd , ( uint64_t ) lp - > stripe_size ) ) ;
2001-12-03 19:27:16 +03:00
}
2002-02-15 14:53:22 +03:00
if ( lp - > stripes < 1 | | lp - > stripes > MAX_STRIPES ) {
log_error ( " Number of stripes (%d) must be between %d and %d " ,
lp - > stripes , 1 , MAX_STRIPES ) ;
return 0 ;
}
2001-11-06 22:02:26 +03:00
2006-04-30 02:08:43 +04:00
/* MAX size check is in _lvcreate */
2002-02-15 14:53:22 +03:00
if ( lp - > stripes > 1 & & ( lp - > stripe_size < STRIPE_SIZE_MIN | |
lp - > stripe_size & ( lp - > stripe_size - 1 ) ) ) {
2006-04-30 02:08:43 +04:00
log_error ( " Invalid stripe size %s " ,
2006-05-10 01:23:51 +04:00
display_size ( cmd , ( uint64_t ) lp - > stripe_size ) ) ;
2002-02-15 14:53:22 +03:00
return 0 ;
}
2001-11-06 22:02:26 +03:00
2002-02-15 14:53:22 +03:00
return 1 ;
}
2001-11-06 22:02:26 +03:00
2007-09-24 17:25:31 +04:00
/* The stripe size is limited by the size of a uint32_t, but since the
* value given by the user is doubled , and the final result must be a
* power of 2 , we must divide UINT_MAX by four and add 1 ( to round it
* up to the power of 2 ) */
static int _read_stripe_params ( struct lvcreate_params * lp ,
2007-10-01 19:01:26 +04:00
struct cmd_context * cmd )
2007-09-24 17:25:31 +04:00
{
if ( arg_count ( cmd , stripesize_ARG ) ) {
if ( arg_sign_value ( cmd , stripesize_ARG , 0 ) = = SIGN_MINUS ) {
log_error ( " Negative stripesize is invalid " ) ;
return 0 ;
}
/* Check to make sure we won't overflow lp->stripe_size */
2007-11-14 03:08:25 +03:00
if ( arg_uint_value ( cmd , stripesize_ARG , 0 ) > STRIPE_SIZE_LIMIT * 2 ) {
2007-09-24 17:25:31 +04:00
log_error ( " Stripe size cannot be larger than %s " ,
display_size ( cmd , ( uint64_t ) STRIPE_SIZE_LIMIT ) ) ;
return 0 ;
}
2007-11-14 03:08:25 +03:00
lp - > stripe_size = arg_uint_value ( cmd , stripesize_ARG , 0 ) ;
2007-09-24 17:25:31 +04:00
}
if ( ! _validate_stripe_params ( cmd , lp ) )
return 0 ;
return 1 ;
}
2007-09-24 17:29:49 +04:00
/*
* Generic mirror parameter checks .
* FIXME : Should eventually be moved into lvm library .
*/
2007-11-12 16:34:14 +03:00
static int _validate_mirror_params ( const struct cmd_context * cmd __attribute ( ( unused ) ) ,
2007-09-25 01:30:00 +04:00
const struct lvcreate_params * lp )
2005-06-01 20:51:55 +04:00
{
2006-08-17 22:23:44 +04:00
int pagesize = lvm_getpagesize ( ) ;
2005-06-01 20:51:55 +04:00
if ( lp - > region_size & ( lp - > region_size - 1 ) ) {
log_error ( " Region size (% " PRIu32 " ) must be a power of 2 " ,
lp - > region_size ) ;
return 0 ;
}
2006-04-28 21:25:54 +04:00
if ( lp - > region_size % ( pagesize > > SECTOR_SHIFT ) ) {
log_error ( " Region size (% " PRIu32 " ) must be a multiple of "
" machine memory page size (%d) " ,
lp - > region_size , pagesize > > SECTOR_SHIFT ) ;
return 0 ;
}
2006-04-28 17:11:05 +04:00
if ( ! lp - > region_size ) {
log_error ( " Non-zero region size must be supplied. " ) ;
return 0 ;
}
2007-09-24 17:29:49 +04:00
return 1 ;
}
static int _read_mirror_params ( struct lvcreate_params * lp ,
2007-10-01 19:01:26 +04:00
struct cmd_context * cmd )
2007-09-24 17:29:49 +04:00
{
int region_size ;
const char * mirrorlog ;
2007-08-21 23:46:36 +04:00
if ( arg_count ( cmd , corelog_ARG ) )
2007-08-02 01:01:06 +04:00
lp - > corelog = 1 ;
2007-08-30 23:34:19 +04:00
mirrorlog = arg_str_value ( cmd , mirrorlog_ARG ,
lp - > corelog ? " core " : DEFAULT_MIRRORLOG ) ;
2007-08-21 23:46:36 +04:00
if ( ! strcmp ( " disk " , mirrorlog ) ) {
if ( lp - > corelog ) {
log_error ( " --mirrorlog disk and --corelog "
" are incompatible " ) ;
2007-08-02 01:01:06 +04:00
return 0 ;
}
2007-08-21 23:46:36 +04:00
lp - > corelog = 0 ;
} else if ( ! strcmp ( " core " , mirrorlog ) )
lp - > corelog = 1 ;
else {
log_error ( " Unknown mirrorlog type: %s " , mirrorlog ) ;
return 0 ;
2007-08-02 01:01:06 +04:00
}
2007-08-21 23:46:36 +04:00
log_verbose ( " Setting logging type to %s " , mirrorlog ) ;
2006-05-12 00:03:40 +04:00
lp - > nosync = arg_count ( cmd , nosync_ARG ) ? 1 : 0 ;
2006-05-11 22:54:04 +04:00
2007-09-24 17:29:49 +04:00
if ( arg_count ( cmd , regionsize_ARG ) ) {
if ( arg_sign_value ( cmd , regionsize_ARG , 0 ) = = SIGN_MINUS ) {
log_error ( " Negative regionsize is invalid " ) ;
return 0 ;
}
2007-11-14 03:08:25 +03:00
lp - > region_size = arg_uint_value ( cmd , regionsize_ARG , 0 ) ;
2007-09-24 17:29:49 +04:00
} else {
region_size = 2 * find_config_tree_int ( cmd ,
" activation/mirror_region_size " ,
DEFAULT_MIRROR_REGION_SIZE ) ;
if ( region_size < 0 ) {
log_error ( " Negative regionsize in configuration file "
" is invalid " ) ;
return 0 ;
}
lp - > region_size = region_size ;
}
if ( ! _validate_mirror_params ( cmd , lp ) )
return 0 ;
2005-06-01 20:51:55 +04:00
return 1 ;
}
2006-04-19 19:33:07 +04:00
static int _lvcreate_params ( struct lvcreate_params * lp , struct cmd_context * cmd ,
int argc , char * * argv )
2002-02-15 14:53:22 +03:00
{
2004-05-19 02:12:53 +04:00
int contiguous ;
2007-12-05 22:24:32 +03:00
unsigned pagesize ;
2004-05-19 02:12:53 +04:00
2002-07-17 20:04:05 +04:00
memset ( lp , 0 , sizeof ( * lp ) ) ;
2002-02-15 14:53:22 +03:00
/*
2004-05-11 20:01:58 +04:00
* Check selected options are compatible and determine segtype
2002-02-15 14:53:22 +03:00
*/
2006-05-10 01:23:51 +04:00
lp - > segtype = ( const struct segment_type * )
2004-05-11 20:01:58 +04:00
arg_ptr_value ( cmd , type_ARG ,
get_segtype_from_string ( cmd , " striped " ) ) ;
lp - > stripes = arg_uint_value ( cmd , stripes_ARG , 1 ) ;
if ( arg_count ( cmd , stripes_ARG ) & & lp - > stripes = = 1 )
log_print ( " Redundant stripes argument: default is 1 " ) ;
2005-05-09 20:59:01 +04:00
if ( arg_count ( cmd , snapshot_ARG ) | | seg_is_snapshot ( lp ) )
2004-05-11 20:01:58 +04:00
lp - > snapshot = 1 ;
2005-06-01 20:51:55 +04:00
lp - > mirrors = 1 ;
/* Default to 2 mirrored areas if --type mirror */
if ( seg_is_mirrored ( lp ) )
lp - > mirrors = 2 ;
if ( arg_count ( cmd , mirrors_ARG ) ) {
lp - > mirrors = arg_uint_value ( cmd , mirrors_ARG , 0 ) + 1 ;
if ( lp - > mirrors = = 1 )
log_print ( " Redundant mirrors argument: default is 0 " ) ;
2005-11-29 00:00:37 +03:00
if ( arg_sign_value ( cmd , mirrors_ARG , 0 ) = = SIGN_MINUS ) {
log_error ( " Mirrors argument may not be negative " ) ;
return 0 ;
}
2005-06-01 20:51:55 +04:00
}
2004-05-11 20:01:58 +04:00
if ( lp - > snapshot ) {
2002-07-17 20:04:05 +04:00
if ( arg_count ( cmd , zero_ARG ) ) {
2004-05-11 20:01:58 +04:00
log_error ( " -Z is incompatible with snapshots " ) ;
2002-07-17 20:04:05 +04:00
return 0 ;
}
2003-09-15 19:04:39 +04:00
if ( arg_sign_value ( cmd , chunksize_ARG , 0 ) = = SIGN_MINUS ) {
log_error ( " Negative chunk size is invalid " ) ;
return 0 ;
}
2007-11-14 03:08:25 +03:00
lp - > chunk_size = arg_uint_value ( cmd , chunksize_ARG , 8 ) ;
2005-10-01 02:20:14 +04:00
if ( lp - > chunk_size < 8 | | lp - > chunk_size > 1024 | |
( lp - > chunk_size & ( lp - > chunk_size - 1 ) ) ) {
log_error ( " Chunk size must be a power of 2 in the "
" range 4K to 512K " ) ;
return 0 ;
}
2002-07-17 20:04:05 +04:00
log_verbose ( " Setting chunksize to %d sectors. " , lp - > chunk_size ) ;
2004-05-25 00:51:56 +04:00
2008-01-30 16:19:47 +03:00
if ( ! ( lp - > segtype = get_segtype_from_string ( cmd , " snapshot " ) ) )
return_0 ;
2002-07-17 20:04:05 +04:00
} else {
if ( arg_count ( cmd , chunksize_ARG ) ) {
2004-05-11 20:01:58 +04:00
log_error ( " -c is only available with snapshots " ) ;
2002-07-17 20:04:05 +04:00
return 0 ;
}
}
2002-02-15 14:53:22 +03:00
2005-06-01 20:51:55 +04:00
if ( lp - > mirrors > 1 ) {
if ( lp - > snapshot ) {
log_error ( " mirrors and snapshots are currently "
" incompatible " ) ;
return 0 ;
}
if ( lp - > stripes > 1 ) {
log_error ( " mirrors and stripes are currently "
" incompatible " ) ;
return 0 ;
}
2008-01-30 16:19:47 +03:00
if ( ! ( lp - > segtype = get_segtype_from_string ( cmd , " striped " ) ) )
return_0 ;
2006-05-11 22:54:04 +04:00
} else {
if ( arg_count ( cmd , corelog_ARG ) ) {
log_error ( " --corelog is only available with mirrors " ) ;
return 0 ;
}
2006-05-12 00:03:40 +04:00
if ( arg_count ( cmd , nosync_ARG ) ) {
log_error ( " --nosync is only available with mirrors " ) ;
return 0 ;
}
2005-06-01 20:51:55 +04:00
}
2004-05-11 20:01:58 +04:00
if ( activation ( ) & & lp - > segtype - > ops - > target_present & &
2008-04-07 14:23:47 +04:00
! lp - > segtype - > ops - > target_present ( NULL , NULL ) ) {
2004-05-11 20:01:58 +04:00
log_error ( " %s: Required device-mapper target(s) not "
" detected in your kernel " , lp - > segtype - > name ) ;
return 0 ;
}
2006-04-19 19:33:07 +04:00
if ( ! _lvcreate_name_params ( lp , cmd , & argc , & argv ) | |
2006-05-10 01:23:51 +04:00
! _read_size_params ( lp , cmd ) | |
2007-10-01 19:01:26 +04:00
! _read_stripe_params ( lp , cmd ) | |
2008-01-30 16:19:47 +03:00
! _read_mirror_params ( lp , cmd ) )
return_0 ;
2001-11-12 22:28:50 +03:00
2002-02-15 14:53:22 +03:00
/*
* Should we zero the lv .
*/
2008-01-30 17:00:02 +03:00
lp - > zero = strcmp ( arg_str_value ( cmd , zero_ARG ,
2005-11-09 01:52:26 +03:00
( lp - > segtype - > flags & SEG_CANNOT_BE_ZEROED ) ? " n " : " y " ) , " n " ) ;
2002-01-21 17:28:12 +03:00
2002-02-15 14:53:22 +03:00
/*
2004-05-19 02:12:53 +04:00
* Alloc policy
2002-02-15 14:53:22 +03:00
*/
2004-05-19 02:12:53 +04:00
contiguous = strcmp ( arg_str_value ( cmd , contiguous_ARG , " n " ) , " n " ) ;
lp - > alloc = contiguous ? ALLOC_CONTIGUOUS : ALLOC_INHERIT ;
2006-05-10 01:23:51 +04:00
lp - > alloc = arg_uint_value ( cmd , alloc_ARG , lp - > alloc ) ;
2004-05-19 02:12:53 +04:00
if ( contiguous & & ( lp - > alloc ! = ALLOC_CONTIGUOUS ) ) {
log_error ( " Conflicting contiguous and alloc arguments " ) ;
return 0 ;
}
2002-02-15 14:53:22 +03:00
/*
* Read ahead .
*/
2008-01-19 00:56:39 +03:00
lp - > read_ahead = arg_uint_value ( cmd , readahead_ARG , DM_READ_AHEAD_NONE ) ;
pagesize = lvm_getpagesize ( ) > > SECTOR_SHIFT ;
if ( lp - > read_ahead ! = DM_READ_AHEAD_AUTO & &
lp - > read_ahead ! = DM_READ_AHEAD_NONE & &
lp - > read_ahead % pagesize ) {
lp - > read_ahead = ( lp - > read_ahead / pagesize ) * pagesize ;
log_verbose ( " Rounding down readahead to %u sectors, a multiple "
" of page size %u. " , lp - > read_ahead , pagesize ) ;
2007-12-05 22:24:32 +03:00
}
2002-02-15 14:53:22 +03:00
/*
* Permissions .
*/
if ( arg_count ( cmd , permission_ARG ) )
2002-12-20 02:25:55 +03:00
lp - > permission = arg_uint_value ( cmd , permission_ARG , 0 ) ;
2002-02-15 14:53:22 +03:00
else
lp - > permission = LVM_READ | LVM_WRITE ;
2007-01-10 17:13:46 +03:00
/* Must not zero read only volume */
if ( ! ( lp - > permission & LVM_WRITE ) )
lp - > zero = 0 ;
2002-02-15 14:53:22 +03:00
2002-02-21 22:04:37 +03:00
lp - > minor = arg_int_value ( cmd , minor_ARG , - 1 ) ;
2003-04-02 23:14:43 +04:00
lp - > major = arg_int_value ( cmd , major_ARG , - 1 ) ;
2002-02-15 14:53:22 +03:00
2002-02-21 22:04:37 +03:00
/* Persistent minor */
2002-02-15 14:53:22 +03:00
if ( arg_count ( cmd , persistent_ARG ) ) {
2002-02-21 22:04:37 +03:00
if ( ! strcmp ( arg_str_value ( cmd , persistent_ARG , " n " ) , " y " ) ) {
if ( lp - > minor = = - 1 ) {
log_error ( " Please specify minor number with "
" --minor when using -My " ) ;
return 0 ;
}
2003-04-02 23:14:43 +04:00
if ( lp - > major = = - 1 ) {
log_error ( " Please specify major number with "
" --major when using -My " ) ;
return 0 ;
}
2002-02-21 22:04:37 +03:00
} else {
2003-04-02 23:14:43 +04:00
if ( ( lp - > minor ! = - 1 ) | | ( lp - > major ! = - 1 ) ) {
2003-04-25 02:23:24 +04:00
log_error ( " --major and --minor incompatible "
" with -Mn " ) ;
2002-02-21 22:04:37 +03:00
return 0 ;
}
2001-11-06 22:02:26 +03:00
}
2008-09-24 20:32:51 +04:00
} else if ( arg_count ( cmd , minor_ARG ) | | arg_count ( cmd , major_ARG ) ) {
log_error ( " --major and --minor require -My " ) ;
return 0 ;
2001-11-06 22:02:26 +03:00
}
2002-02-15 14:53:22 +03:00
lp - > pv_count = argc ;
lp - > pvs = argv ;
2001-11-06 22:02:26 +03:00
2002-02-15 14:53:22 +03:00
return 1 ;
}
2007-11-15 05:20:03 +03:00
static int _lvcreate ( struct cmd_context * cmd , struct volume_group * vg ,
struct lvcreate_params * lp )
2002-02-15 14:53:22 +03:00
{
2005-08-12 23:23:08 +04:00
uint32_t size_rest ;
2002-02-21 22:04:37 +03:00
uint32_t status = 0 ;
2003-10-16 00:07:55 +04:00
uint64_t tmp_size ;
2007-12-20 18:42:55 +03:00
struct logical_volume * lv , * org = NULL ;
2008-11-04 01:14:30 +03:00
struct dm_list * pvh ;
2007-03-26 20:10:10 +04:00
const char * tag = NULL ;
2007-11-15 05:20:03 +03:00
int origin_active = 0 ;
2005-11-29 00:00:37 +03:00
char lv_name_buf [ 128 ] ;
2005-06-03 18:49:51 +04:00
const char * lv_name ;
2007-07-17 20:13:12 +04:00
struct lvinfo info ;
2007-09-21 01:39:08 +04:00
uint32_t pv_extent_count ;
2002-02-15 14:53:22 +03:00
if ( lp - > lv_name & & find_lv_in_vg ( vg , lp - > lv_name ) ) {
2002-01-30 18:04:48 +03:00
log_error ( " Logical volume \" %s \" already exists in "
2002-02-15 14:53:22 +03:00
" volume group \" %s \" " , lp - > lv_name , lp - > vg_name ) ;
return 0 ;
2001-11-06 22:02:26 +03:00
}
2005-06-22 18:56:14 +04:00
if ( lp - > mirrors > 1 & & ! ( vg - > fid - > fmt - > features & FMT_SEGMENTS ) ) {
2005-06-03 23:48:19 +04:00
log_error ( " Metadata does not support mirroring. " ) ;
return 0 ;
}
2007-11-09 19:51:54 +03:00
if ( lp - > read_ahead ! = DM_READ_AHEAD_AUTO & &
2008-01-19 00:56:39 +03:00
lp - > read_ahead ! = DM_READ_AHEAD_NONE & &
2007-11-09 19:51:54 +03:00
( vg - > fid - > fmt - > features & FMT_RESTRICTED_READAHEAD ) & &
( lp - > read_ahead < 2 | | lp - > read_ahead > 120 ) ) {
log_error ( " Metadata only supports readahead values between 2 and 120. " ) ;
return 0 ;
}
2002-02-15 14:53:22 +03:00
if ( lp - > stripe_size > vg - > extent_size ) {
2006-04-30 02:08:43 +04:00
log_error ( " Reducing requested stripe size %s to maximum, "
" physical extent size %s " ,
2006-05-10 01:23:51 +04:00
display_size ( cmd , ( uint64_t ) lp - > stripe_size ) ,
display_size ( cmd , ( uint64_t ) vg - > extent_size ) ) ;
2002-02-15 14:53:22 +03:00
lp - > stripe_size = vg - > extent_size ;
2001-11-06 22:02:26 +03:00
}
2006-04-30 02:08:43 +04:00
/* Need to check the vg's format to verify this - the cmd format isn't setup properly yet */
if ( lp - > stripes > 1 & &
! ( vg - > fid - > fmt - > features & FMT_UNLIMITED_STRIPESIZE ) & &
( lp - > stripe_size > STRIPE_SIZE_MAX ) ) {
log_error ( " Stripe size may not exceed %s " ,
2006-05-10 01:23:51 +04:00
display_size ( cmd , ( uint64_t ) STRIPE_SIZE_MAX ) ) ;
2006-04-30 02:08:43 +04:00
return 0 ;
}
2002-02-15 14:53:22 +03:00
if ( lp - > size ) {
2001-11-06 22:02:26 +03:00
/* No of 512-byte sectors */
2003-10-16 00:07:55 +04:00
tmp_size = lp - > size ;
2001-11-06 22:02:26 +03:00
2003-10-16 00:07:55 +04:00
if ( tmp_size % vg - > extent_size ) {
tmp_size + = vg - > extent_size - tmp_size %
2002-03-04 18:25:52 +03:00
vg - > extent_size ;
2002-12-12 23:55:49 +03:00
log_print ( " Rounding up size to full physical extent %s " ,
2006-05-10 01:23:51 +04:00
display_size ( cmd , tmp_size ) ) ;
2001-11-06 22:02:26 +03:00
}
2006-11-10 21:24:11 +03:00
if ( tmp_size > ( uint64_t ) UINT32_MAX * vg - > extent_size ) {
log_error ( " Volume too large (%s) for extent size %s. "
" Upper limit is %s. " ,
display_size ( cmd , tmp_size ) ,
2007-08-22 18:38:18 +04:00
display_size ( cmd , ( uint64_t ) vg - > extent_size ) ,
2006-11-10 21:24:11 +03:00
display_size ( cmd , ( uint64_t ) UINT32_MAX *
vg - > extent_size ) ) ;
return 0 ;
}
lp - > extents = ( uint64_t ) tmp_size / vg - > extent_size ;
2001-11-06 22:02:26 +03:00
}
2008-07-17 19:19:42 +04:00
/*
* Create the pv list .
*/
if ( lp - > pv_count ) {
if ( ! ( pvh = create_pv_list ( cmd - > mem , vg ,
lp - > pv_count , lp - > pvs , 1 ) ) )
return_0 ;
} else
pvh = & vg - > pvs ;
2006-09-26 13:35:43 +04:00
switch ( lp - > percent ) {
case PERCENT_VG :
lp - > extents = lp - > extents * vg - > extent_count / 100 ;
break ;
case PERCENT_FREE :
lp - > extents = lp - > extents * vg - > free_count / 100 ;
break ;
2007-09-21 01:39:08 +04:00
case PERCENT_PVS :
if ( ! lp - > pv_count ) {
log_error ( " Please specify physical volume(s) "
" with %%PVS " ) ;
return 0 ;
}
pv_extent_count = pv_list_extents_free ( pvh ) ;
lp - > extents = lp - > extents * pv_extent_count / 100 ;
break ;
2006-09-26 13:35:43 +04:00
case PERCENT_LV :
2007-09-21 01:39:08 +04:00
log_error ( " Please express size as %%VG, %%PVS, or "
" %%FREE. " ) ;
2006-09-26 13:35:43 +04:00
return 0 ;
case PERCENT_NONE :
break ;
}
2002-02-15 14:53:22 +03:00
if ( ( size_rest = lp - > extents % lp - > stripes ) ) {
2002-02-12 00:00:35 +03:00
log_print ( " Rounding size (%d extents) up to stripe boundary "
2002-02-15 14:53:22 +03:00
" size (%d extents) " , lp - > extents ,
lp - > extents - size_rest + lp - > stripes ) ;
lp - > extents = lp - > extents - size_rest + lp - > stripes ;
2002-02-12 00:00:35 +03:00
}
2001-11-06 22:02:26 +03:00
2007-11-12 23:02:55 +03:00
if ( lp - > zero & & ! activation ( ) ) {
2007-11-12 16:34:14 +03:00
log_error ( " Can't wipe start of new LV without using "
" device-mapper kernel driver " ) ;
return 0 ;
}
2008-07-17 19:19:42 +04:00
status | = lp - > permission | VISIBLE_LV ;
2002-11-22 17:19:56 +03:00
if ( lp - > snapshot ) {
if ( ! activation ( ) ) {
2002-11-18 17:04:08 +03:00
log_error ( " Can't create snapshot without using "
" device-mapper kernel driver " ) ;
2002-11-22 17:19:56 +03:00
return 0 ;
}
2005-08-15 03:18:28 +04:00
/* FIXME Allow exclusive activation. */
2008-04-10 21:09:32 +04:00
if ( vg_is_clustered ( vg ) ) {
2005-08-15 03:18:28 +04:00
log_error ( " Clustered snapshots are not yet supported. " ) ;
return 0 ;
}
2002-11-18 17:04:08 +03:00
if ( ! ( org = find_lv ( vg , lp - > origin ) ) ) {
log_err ( " Couldn't find origin volume '%s'. " ,
lp - > origin ) ;
return 0 ;
}
if ( lv_is_cow ( org ) ) {
log_error ( " Snapshots of snapshots are not supported "
" yet. " ) ;
return 0 ;
}
2003-05-06 16:10:18 +04:00
if ( org - > status & LOCKED ) {
log_error ( " Snapshots of locked devices are not "
" supported yet " ) ;
return 0 ;
}
2006-05-24 17:58:14 +04:00
if ( org - > status & MIRROR_IMAGE | |
org - > status & MIRROR_LOG | |
org - > status & MIRRORED ) {
log_error ( " Snapshots and mirrors may not yet be mixed. " ) ;
return 0 ;
}
2008-01-30 17:00:02 +03:00
2003-09-16 20:08:05 +04:00
/* Must zero cow */
status | = LVM_WRITE ;
2007-07-17 20:13:12 +04:00
2007-11-12 23:51:54 +03:00
if ( ! lv_info ( cmd , org , & info , 0 , 0 ) ) {
2007-07-17 20:13:12 +04:00
log_error ( " Check for existence of snapshot origin "
" '%s' failed. " , org - > name ) ;
return 0 ;
}
origin_active = info . exists ;
2002-11-18 17:04:08 +03:00
}
2002-07-11 19:28:49 +04:00
2004-05-05 22:49:21 +04:00
if ( ! lp - > extents ) {
2006-11-10 21:24:11 +03:00
log_error ( " Unable to create new logical volume with no extents " ) ;
2004-05-05 22:49:21 +04:00
return 0 ;
}
2005-05-09 20:59:01 +04:00
if ( ! seg_is_virtual ( lp ) & &
2004-05-11 20:01:58 +04:00
vg - > free_count < lp - > extents ) {
2004-05-05 22:49:21 +04:00
log_error ( " Insufficient free extents (%u) in volume group %s: "
" %u required " , vg - > free_count , vg - > name , lp - > extents ) ;
return 0 ;
}
2008-11-04 01:14:30 +03:00
if ( lp - > stripes > dm_list_size ( pvh ) & & lp - > alloc ! = ALLOC_ANYWHERE ) {
2004-05-05 22:49:21 +04:00
log_error ( " Number of stripes (%u) must not exceed "
" number of physical volumes (%d) " , lp - > stripes ,
2008-11-04 01:14:30 +03:00
dm_list_size ( pvh ) ) ;
2004-05-05 22:49:21 +04:00
return 0 ;
}
2008-01-16 18:26:40 +03:00
if ( lp - > mirrors > 1 & & ! activation ( ) ) {
log_error ( " Can't create mirror without using "
" device-mapper kernel driver. " ) ;
return 0 ;
}
2004-05-05 22:49:21 +04:00
2005-05-17 17:49:45 +04:00
/* The snapshot segment gets created later */
2005-06-01 20:51:55 +04:00
if ( lp - > snapshot & &
2008-01-30 16:19:47 +03:00
! ( lp - > segtype = get_segtype_from_string ( cmd , " striped " ) ) )
return_0 ;
2005-06-01 20:51:55 +04:00
if ( ! archive ( vg ) )
return 0 ;
2005-06-03 18:49:51 +04:00
if ( lp - > lv_name )
lv_name = lp - > lv_name ;
else {
if ( ! generate_lv_name ( vg , " lvol%d " , lv_name_buf , sizeof ( lv_name_buf ) ) ) {
log_error ( " Failed to generate LV name. " ) ;
return 0 ;
}
lv_name = & lv_name_buf [ 0 ] ;
}
2007-03-26 20:10:10 +04:00
if ( arg_count ( cmd , addtag_ARG ) ) {
if ( ! ( tag = arg_str_value ( cmd , addtag_ARG , NULL ) ) ) {
log_error ( " Failed to get tag " ) ;
return 0 ;
}
if ( ! ( vg - > fid - > fmt - > features & FMT_TAGS ) ) {
log_error ( " Volume group %s does not support tags " ,
vg - > name ) ;
return 0 ;
}
}
2007-12-22 05:13:00 +03:00
if ( lp - > mirrors > 1 ) {
init_mirror_in_sync ( lp - > nosync ) ;
if ( lp - > nosync ) {
log_warn ( " WARNING: New mirror won't be synchronised. "
" Don't read what you didn't write! " ) ;
status | = MIRROR_NOTSYNCED ;
}
}
2007-10-11 23:20:38 +04:00
if ( ! ( lv = lv_create_empty ( lv_name ? lv_name : " lvol%d " , NULL ,
2008-01-30 16:19:47 +03:00
status , lp - > alloc , 0 , vg ) ) )
return_0 ;
2002-02-18 13:59:51 +03:00
2002-02-15 14:53:22 +03:00
if ( lp - > read_ahead ) {
2001-11-06 22:02:26 +03:00
log_verbose ( " Setting read ahead sectors " ) ;
2002-02-15 14:53:22 +03:00
lv - > read_ahead = lp - > read_ahead ;
2001-11-06 22:02:26 +03:00
}
2002-02-15 14:53:22 +03:00
if ( lp - > minor > = 0 ) {
2003-04-02 23:14:43 +04:00
lv - > major = lp - > major ;
2002-02-15 14:53:22 +03:00
lv - > minor = lp - > minor ;
2002-02-21 22:04:37 +03:00
lv - > status | = FIXED_MINOR ;
2003-04-02 23:14:43 +04:00
log_verbose ( " Setting device number to (%d, %d) " , lv - > major ,
lv - > minor ) ;
2002-02-01 20:54:39 +03:00
}
2007-03-26 20:10:10 +04:00
if ( tag & & ! str_list_add ( cmd - > mem , & lv - > tags , tag ) ) {
log_error ( " Failed to add tag %s to %s/%s " ,
tag , lv - > vg - > name , lv - > name ) ;
2008-01-30 16:19:47 +03:00
return 0 ;
2004-03-08 20:19:15 +03:00
}
2007-12-20 18:42:55 +03:00
if ( ! lv_extend ( lv , lp - > segtype , lp - > stripes , lp - > stripe_size ,
1 , lp - > extents , NULL , 0u , 0u , pvh , lp - > alloc ) )
return_0 ;
2005-06-01 20:51:55 +04:00
if ( lp - > mirrors > 1 ) {
2007-12-20 18:42:55 +03:00
if ( ! lv_add_mirrors ( cmd , lv , lp - > mirrors - 1 , lp - > stripes ,
adjusted_mirror_region_size (
vg - > extent_size ,
lv - > le_count ,
lp - > region_size ) ,
lp - > corelog ? 0U : 1U , pvh , lp - > alloc ,
2008-01-19 01:02:37 +03:00
MIRROR_BY_LV |
( lp - > nosync ? MIRROR_SKIP_INIT_SYNC : 0 ) ) ) {
2007-12-20 18:42:55 +03:00
stack ;
goto revert_new_lv ;
}
}
2002-03-04 18:25:52 +03:00
2001-11-06 22:02:26 +03:00
/* store vg on disk(s) */
2007-11-12 16:34:14 +03:00
if ( ! vg_write ( vg ) )
return_0 ;
2003-07-05 02:34:56 +04:00
backup ( vg ) ;
2007-11-12 16:34:14 +03:00
if ( ! vg_commit ( vg ) )
return_0 ;
2001-11-06 22:02:26 +03:00
2006-10-26 22:22:10 +04:00
if ( lp - > snapshot ) {
if ( ! activate_lv_excl ( cmd , lv ) ) {
2003-07-05 02:34:56 +04:00
log_error ( " Aborting. Failed to activate snapshot "
2007-11-12 16:34:14 +03:00
" exception store. " ) ;
goto revert_new_lv ;
2006-10-26 22:22:10 +04:00
}
} else if ( ! activate_lv ( cmd , lv ) ) {
2007-11-12 16:34:14 +03:00
if ( lp - > zero ) {
log_error ( " Aborting. Failed to activate new LV to wipe "
" the start of it. " ) ;
2008-06-05 17:38:30 +04:00
goto deactivate_and_revert_new_lv ;
2007-11-12 16:34:14 +03:00
}
2006-10-26 22:22:10 +04:00
log_error ( " Failed to activate new LV. " ) ;
2002-03-04 18:25:52 +03:00
return 0 ;
2002-11-18 17:04:08 +03:00
}
2002-03-04 18:25:52 +03:00
2007-11-12 16:34:14 +03:00
if ( ! lp - > zero & & ! lp - > snapshot )
2002-11-18 17:04:08 +03:00
log_error ( " WARNING: \" %s \" not zeroed " , lv - > name ) ;
2007-11-12 16:34:14 +03:00
else if ( ! set_lv ( cmd , lv , UINT64_C ( 0 ) , 0 ) ) {
log_error ( " Aborting. Failed to wipe %s. " ,
lp - > snapshot ? " snapshot exception store " :
" start of new LV " ) ;
goto deactivate_and_revert_new_lv ;
2002-11-18 17:04:08 +03:00
}
2002-03-04 18:25:52 +03:00
if ( lp - > snapshot ) {
2003-09-16 20:08:05 +04:00
/* Reset permission after zeroing */
if ( ! ( lp - > permission & LVM_WRITE ) )
lv - > status & = ~ LVM_WRITE ;
2006-10-26 22:22:10 +04:00
2007-07-17 20:13:12 +04:00
/* COW area must be deactivated if origin is not active */
if ( ! origin_active & & ! deactivate_lv ( cmd , lv ) ) {
log_error ( " Aborting. Couldn't deactivate snapshot "
2007-11-12 16:34:14 +03:00
" COW area. Manual intervention required. " ) ;
2007-07-17 20:13:12 +04:00
return 0 ;
}
2006-10-26 22:22:10 +04:00
/* cow LV remains active and becomes snapshot LV */
2002-03-26 18:01:57 +03:00
2007-11-02 23:40:05 +03:00
if ( ! vg_add_snapshot ( NULL , org , lv , NULL ,
2005-04-07 16:39:44 +04:00
org - > le_count , lp - > chunk_size ) ) {
2007-11-12 16:34:14 +03:00
log_error ( " Couldn't create snapshot. " ) ;
2002-03-04 18:25:52 +03:00
return 0 ;
}
/* store vg on disk(s) */
2005-10-28 18:38:20 +04:00
if ( ! vg_write ( vg ) )
2007-11-12 16:34:14 +03:00
return_0 ;
2005-10-28 18:38:20 +04:00
if ( ! suspend_lv ( cmd , org ) ) {
log_error ( " Failed to suspend origin %s " , org - > name ) ;
2005-11-13 01:00:50 +03:00
vg_revert ( vg ) ;
2005-10-28 18:38:20 +04:00
return 0 ;
}
if ( ! vg_commit ( vg ) )
2007-11-12 16:34:14 +03:00
return_0 ;
2002-03-04 18:25:52 +03:00
2005-08-15 16:00:04 +04:00
if ( ! resume_lv ( cmd , org ) ) {
2002-03-26 18:01:57 +03:00
log_error ( " Problem reactivating origin %s " , org - > name ) ;
2002-03-04 18:25:52 +03:00
return 0 ;
2002-03-26 18:01:57 +03:00
}
2002-03-04 18:25:52 +03:00
}
2003-07-05 02:34:56 +04:00
/* FIXME out of sequence */
2002-01-07 14:12:11 +03:00
backup ( vg ) ;
2002-03-04 18:25:52 +03:00
2002-01-30 18:04:48 +03:00
log_print ( " Logical volume \" %s \" created " , lv - > name ) ;
2001-11-14 17:12:01 +03:00
2002-03-04 18:25:52 +03:00
/*
* FIXME : as a sanity check we could try reading the
* last block of the device ?
*/
2002-02-15 14:53:22 +03:00
return 1 ;
2005-06-01 20:51:55 +04:00
2007-11-12 16:34:14 +03:00
deactivate_and_revert_new_lv :
if ( ! deactivate_lv ( cmd , lv ) ) {
log_error ( " Unable to deactivate failed new LV. "
" Manual intervention required. " ) ;
return 0 ;
}
revert_new_lv :
/* FIXME Better to revert to backup of metadata? */
2007-11-13 00:50:21 +03:00
if ( ! lv_remove ( lv ) | | ! vg_write ( vg ) | | ( backup ( vg ) , ! vg_commit ( vg ) ) )
2007-11-12 16:34:14 +03:00
log_error ( " Manual intervention may be required to remove "
" abandoned LV(s) before retrying. " ) ;
return 0 ;
2002-02-15 14:53:22 +03:00
}
2001-11-06 22:02:26 +03:00
2002-02-15 14:53:22 +03:00
int lvcreate ( struct cmd_context * cmd , int argc , char * * argv )
{
2007-11-15 05:20:03 +03:00
int r = ECMD_PROCESSED ;
2002-02-15 14:53:22 +03:00
struct lvcreate_params lp ;
2007-11-15 05:20:03 +03:00
struct volume_group * vg ;
2002-02-15 14:53:22 +03:00
2002-02-21 22:04:37 +03:00
memset ( & lp , 0 , sizeof ( lp ) ) ;
2006-04-19 19:33:07 +04:00
if ( ! _lvcreate_params ( & lp , cmd , argc , argv ) )
2003-10-22 02:06:07 +04:00
return EINVALID_CMD_LINE ;
2002-02-15 14:53:22 +03:00
2007-11-15 05:20:03 +03:00
log_verbose ( " Finding volume group \" %s \" " , lp . vg_name ) ;
if ( ! ( vg = vg_lock_and_read ( cmd , lp . vg_name , NULL , LCK_VG_WRITE ,
CLUSTERED | EXPORTED_VG | LVM_WRITE ,
CORRECT_INCONSISTENT ) ) )
2003-10-22 02:06:07 +04:00
return ECMD_FAILED ;
2002-02-15 14:53:22 +03:00
2007-11-15 05:20:03 +03:00
if ( ! _lvcreate ( cmd , vg , & lp ) )
r = ECMD_FAILED ;
2002-02-11 18:42:34 +03:00
2002-03-11 18:08:39 +03:00
unlock_vg ( cmd , lp . vg_name ) ;
2002-02-15 14:53:22 +03:00
return r ;
2001-11-06 22:02:26 +03:00
}