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 .
2011-09-06 04:26:42 +04:00
* Copyright ( C ) 2004 - 2011 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
2009-07-26 06:31:41 +04:00
struct lvcreate_cmdline_params {
2010-11-30 14:53:31 +03:00
percent_type_t percent ;
2009-07-26 06:32:00 +04:00
uint64_t size ;
2009-07-26 06:32:50 +04:00
char * * pvs ;
int pv_count ;
2009-07-26 06:31:41 +04:00
} ;
2011-09-06 04:26:42 +04:00
static int _set_vg_name ( struct lvcreate_params * lp , const char * vg_name )
{
/* Can't do anything */
if ( ! vg_name )
return 1 ;
/* If VG name already known, ensure this 2nd copy is identical */
if ( lp - > vg_name & & strcmp ( lp - > vg_name , vg_name ) ) {
log_error ( " Inconsistent volume group names "
" given: \" %s \" and \" %s \" " ,
lp - > vg_name , vg_name ) ;
return 0 ;
}
lp - > vg_name = vg_name ;
return 1 ;
}
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 ;
2011-02-18 17:47:28 +03:00
const char * vg_name ;
2002-02-15 14:53:22 +03:00
2011-09-06 04:26:42 +04:00
lp - > pool = arg_str_value ( cmd , thinpool_ARG , NULL ) ;
/* If --thinpool contains VG name, extract it. */
if ( lp - > pool & & strchr ( lp - > pool , ' / ' ) ) {
if ( ! ( lp - > vg_name = extract_vgname ( cmd , lp - > pool ) ) )
return 0 ;
/* Strip VG from pool */
if ( ( ptr = strrchr ( lp - > pool , ( int ) ' / ' ) ) )
lp - > pool = ptr + 1 ;
}
2009-11-03 18:50:42 +03:00
lp - > lv_name = arg_str_value ( cmd , name_ARG , NULL ) ;
2002-02-15 14:53:22 +03:00
2011-09-06 04:26:42 +04:00
/* If --name contains VG name, extract it. */
if ( lp - > lv_name & & strchr ( lp - > lv_name , ' / ' ) ) {
if ( ! _set_vg_name ( lp , extract_vgname ( cmd , lp - > lv_name ) ) )
return_0 ;
/* Strip VG from lv_name */
if ( ( ptr = strrchr ( lp - > lv_name , ( int ) ' / ' ) ) )
lp - > lv_name = ptr + 1 ;
}
/* Need an origin? */
2009-05-27 20:30:29 +04:00
if ( lp - > snapshot & & ! arg_count ( cmd , virtualsize_ARG ) ) {
2011-09-06 04:26:42 +04:00
/* argv[0] might be origin or vg/origin */
2002-02-15 14:53:22 +03:00
if ( ! argc ) {
2009-07-16 00:02:46 +04:00
log_error ( " Please specify a logical volume to act as "
" the snapshot origin. " ) ;
2002-02-15 14:53:22 +03:00
return 0 ;
}
2011-09-06 04:26:42 +04:00
lp - > origin = skip_dev_dir ( cmd , argv [ 0 ] , NULL ) ;
if ( strrchr ( lp - > origin , ' / ' ) ) {
if ( ! _set_vg_name ( lp , extract_vgname ( cmd , lp - > origin ) ) )
return_0 ;
/* Strip the volume group from the origin */
if ( ( ptr = strrchr ( lp - > origin , ( int ) ' / ' ) ) )
lp - > origin = ptr + 1 ;
}
if ( ! lp - > vg_name ) {
2009-07-16 00:02:46 +04:00
log_error ( " The origin name should include the "
" volume group. " ) ;
2002-02-15 14:53:22 +03:00
return 0 ;
}
2011-09-06 04:26:42 +04:00
( * pargv ) + + , ( * pargc ) - - ;
} else if ( seg_is_thin ( lp ) & & ! lp - > pool & & argc ) {
/* argv[0] might be vg or vg/Pool */
vg_name = skip_dev_dir ( cmd , argv [ 0 ] , NULL ) ;
if ( ! strrchr ( vg_name , ' / ' ) ) {
if ( ! _set_vg_name ( lp , vg_name ) )
return_0 ;
} else {
lp - > pool = vg_name ;
if ( ! _set_vg_name ( lp , extract_vgname ( cmd , lp - > pool ) ) )
return_0 ;
if ( ! lp - > vg_name ) {
log_error ( " The pool name should include the "
" volume group. " ) ;
return 0 ;
}
2002-02-18 13:59:51 +03:00
2011-09-06 04:26:42 +04:00
/* Strip the volume group */
if ( ( ptr = strrchr ( lp - > pool , ( int ) ' / ' ) ) )
lp - > pool = ptr + 1 ;
}
( * pargv ) + + , ( * pargc ) - - ;
2002-02-15 14:53:22 +03:00
} else {
/*
2011-09-06 04:26:42 +04:00
* If VG not on command line , try environment default .
2002-02-15 14:53:22 +03:00
*/
if ( ! argc ) {
2011-09-06 04:26:42 +04:00
if ( ! lp - > vg_name & & ! ( lp - > vg_name = extract_vgname ( cmd , NULL ) ) ) {
2009-07-16 00:02:46 +04:00
log_error ( " Please provide a volume group name " ) ;
2002-02-15 14:53:22 +03:00
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 ;
}
2011-09-06 04:26:42 +04:00
if ( ! _set_vg_name ( lp , vg_name ) )
return_0 ;
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 ) {
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
}
2011-09-06 04:26:42 +04:00
if ( lp - > pool ) {
if ( ! apply_lvname_restrictions ( lp - > pool ) )
return_0 ;
if ( ! validate_name ( lp - > pool ) ) {
log_error ( " Logical volume name \" %s \" is invalid " ,
lp - > pool ) ;
return 0 ;
}
if ( lp - > lv_name & & ! strcmp ( lp - > lv_name , lp - > pool ) ) {
log_error ( " Logical volume name %s and pool name %s must be different. " ,
lp - > lv_name , lp - > pool ) ;
return 0 ;
}
}
return 1 ;
}
/*
* Normal snapshot or thinly - provisioned snapshot ?
*/
static int _determine_snapshot_type ( struct volume_group * vg ,
struct lvcreate_params * lp )
{
struct lv_list * lvl ;
if ( ! ( lvl = find_lv_in_vg ( vg , lp - > origin ) ) ) {
log_error ( " Snapshot origin LV %s not found in Volume group %s. " , lp - > origin , vg - > name ) ;
return 0 ;
}
2011-09-06 23:25:42 +04:00
if ( lv_is_thin_volume ( lvl - > lv ) ) {
2011-09-06 04:26:42 +04:00
lp - > thin = 1 ;
if ( ! ( lp - > segtype = get_segtype_from_string ( vg - > cmd , " thin " ) ) )
return_0 ;
2011-09-07 02:43:56 +04:00
lp - > pool = first_seg ( lvl - > lv ) - > pool_lv - > name ;
2011-09-06 04:26:42 +04:00
}
if ( ! lp - > thin & & ! arg_count ( vg - > cmd , extents_ARG ) & & ! arg_count ( vg - > cmd , size_ARG ) ) {
log_error ( " Please specify either size or extents with snapshots. " ) ;
return 0 ;
}
2002-02-15 14:53:22 +03:00
return 1 ;
}
2009-07-26 06:31:18 +04:00
/*
* Update extents parameters based on other parameters which affect the size
* calcuation .
* NOTE : We must do this here because of the percent_t typedef and because we
* need the vg .
*/
static int _update_extents_params ( struct volume_group * vg ,
2009-07-26 06:31:41 +04:00
struct lvcreate_params * lp ,
struct lvcreate_cmdline_params * lcp )
2009-07-26 06:31:18 +04:00
{
uint32_t pv_extent_count ;
2010-02-03 06:58:08 +03:00
struct logical_volume * origin = NULL ;
2009-07-26 06:31:18 +04:00
2009-07-26 06:32:00 +04:00
if ( lcp - > size & &
2009-07-26 06:34:09 +04:00
! ( lp - > extents = extents_from_size ( vg - > cmd , lcp - > size ,
2009-07-26 06:31:18 +04:00
vg - > extent_size ) ) )
return_0 ;
if ( lp - > voriginsize & &
2009-07-26 06:34:09 +04:00
! ( lp - > voriginextents = extents_from_size ( vg - > cmd , lp - > voriginsize ,
2009-07-26 06:31:18 +04:00
vg - > extent_size ) ) )
return_0 ;
/*
2009-07-26 06:31:41 +04:00
* Create the pv list before we parse lcp - > percent - might be
2009-07-26 06:31:18 +04:00
* PERCENT_PVSs
*/
2009-07-26 06:32:50 +04:00
if ( lcp - > pv_count ) {
2009-07-26 06:31:18 +04:00
if ( ! ( lp - > pvh = create_pv_list ( vg - > cmd - > mem , vg ,
2009-07-26 06:32:50 +04:00
lcp - > pv_count , lcp - > pvs , 1 ) ) )
2009-07-26 06:31:18 +04:00
return_0 ;
} else
lp - > pvh = & vg - > pvs ;
2009-07-26 06:31:41 +04:00
switch ( lcp - > percent ) {
2009-07-26 06:31:18 +04:00
case PERCENT_VG :
2011-09-15 19:26:40 +04:00
lp - > extents = percent_of_extents ( lp - > extents , vg - > extent_count ) ;
2009-07-26 06:31:18 +04:00
break ;
case PERCENT_FREE :
2011-09-15 19:26:40 +04:00
lp - > extents = percent_of_extents ( lp - > extents , vg - > free_count ) ;
2009-07-26 06:31:18 +04:00
break ;
case PERCENT_PVS :
2009-11-04 17:47:27 +03:00
if ( ! lcp - > pv_count )
2011-09-15 19:26:40 +04:00
lp - > extents = percent_of_extents ( lp - > extents , vg - > extent_count ) ;
2009-11-04 17:47:27 +03:00
else {
pv_extent_count = pv_list_extents_free ( lp - > pvh ) ;
2011-09-15 19:26:40 +04:00
lp - > extents = percent_of_extents ( lp - > extents , pv_extent_count ) ;
2009-07-26 06:31:18 +04:00
}
break ;
case PERCENT_LV :
log_error ( " Please express size as %%VG, %%PVS, or "
" %%FREE. " ) ;
return 0 ;
2010-02-03 06:58:08 +03:00
case PERCENT_ORIGIN :
if ( lp - > snapshot & & lp - > origin & &
! ( origin = find_lv ( vg , lp - > origin ) ) ) {
log_error ( " Couldn't find origin volume '%s'. " ,
lp - > origin ) ;
return 0 ;
}
2010-10-25 16:05:46 +04:00
if ( ! origin ) {
log_error ( INTERNAL_ERROR " Couldn't find origin volume. " ) ;
return 0 ;
}
2011-09-15 19:26:40 +04:00
lp - > extents = percent_of_extents ( lp - > extents , origin - > le_count ) ;
2010-02-03 06:58:08 +03:00
break ;
2009-07-26 06:31:18 +04:00
case PERCENT_NONE :
break ;
}
return 1 ;
}
2002-02-15 14:53:22 +03:00
static int _read_size_params ( struct lvcreate_params * lp ,
2009-07-26 06:31:41 +04:00
struct lvcreate_cmdline_params * lcp ,
2006-05-10 01:23:51 +04:00
struct cmd_context * cmd )
2002-02-15 14:53:22 +03:00
{
2011-09-06 04:26:42 +04:00
if ( arg_count ( cmd , extents_ARG ) & & arg_count ( cmd , size_ARG ) ) {
2004-05-11 20:01:58 +04:00
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
}
2011-09-06 04:26:42 +04:00
if ( ! lp - > thin & & ! lp - > snapshot & & ! arg_count ( cmd , extents_ARG ) & & ! arg_count ( cmd , size_ARG ) ) {
log_error ( " Please specify either size or extents " ) ;
return 0 ;
}
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 ) ;
2009-07-26 06:31:41 +04:00
lcp - > 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 ;
}
2009-07-26 06:32:00 +04:00
lcp - > size = arg_uint64_value ( cmd , size_ARG , UINT64_C ( 0 ) ) ;
2009-07-26 06:31:41 +04:00
lcp - > percent = PERCENT_NONE ;
2003-09-15 19:04:39 +04:00
}
2002-02-15 14:53:22 +03:00
2011-09-06 04:26:42 +04:00
/* If size/extents given with thin, then we are creating a thin pool */
if ( lp - > thin & & ( arg_count ( cmd , size_ARG ) | | arg_count ( cmd , extents_ARG ) ) )
lp - > create_thin_pool = 1 ;
2009-04-25 05:17:59 +04:00
/* Size returned in kilobyte units; held in sectors */
2009-05-27 20:30:29 +04:00
if ( arg_count ( cmd , virtualsize_ARG ) ) {
2011-09-06 04:26:42 +04:00
if ( seg_is_thin_pool ( lp ) ) {
log_error ( " Virtual size in incompatible with thin_pool segment type. " ) ;
return 0 ;
}
2009-05-27 20:30:29 +04:00
if ( arg_sign_value ( cmd , virtualsize_ARG , 0 ) = = SIGN_MINUS ) {
2009-04-25 05:17:59 +04:00
log_error ( " Negative virtual origin size is invalid " ) ;
return 0 ;
}
2009-05-27 20:30:29 +04:00
lp - > voriginsize = arg_uint64_value ( cmd , virtualsize_ARG ,
2009-04-25 05:17:59 +04:00
UINT64_C ( 0 ) ) ;
if ( ! lp - > voriginsize ) {
log_error ( " Virtual origin size may not be zero " ) ;
return 0 ;
}
2011-09-06 04:26:42 +04:00
} else {
/* No virtual size given, so no thin LV to create. */
2011-09-06 19:35:11 +04:00
if ( seg_is_thin_volume ( lp ) & & ! ( lp - > segtype = get_segtype_from_string ( cmd , " thin_pool " ) ) )
2011-09-06 04:26:42 +04:00
return_0 ;
lp - > thin = 0 ;
2009-04-25 05:17:59 +04:00
}
2002-02-15 14:53:22 +03:00
return 1 ;
}
2007-09-24 17:29:49 +04:00
/*
* Generic mirror parameter checks .
* FIXME : Should eventually be moved into lvm library .
*/
2010-07-09 19:34:40 +04: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 ;
2010-01-12 17:00:51 +03:00
int corelog = arg_count ( cmd , corelog_ARG ) ;
2007-08-02 01:01:06 +04:00
2007-08-30 23:34:19 +04:00
mirrorlog = arg_str_value ( cmd , mirrorlog_ARG ,
2010-01-12 17:00:51 +03:00
corelog ? " core " : DEFAULT_MIRRORLOG ) ;
2007-08-30 23:34:19 +04:00
2010-03-27 01:15:43 +03:00
if ( strcmp ( " core " , mirrorlog ) & & corelog ) {
log_error ( " Please use only one of --mirrorlog or --corelog " ) ;
return 0 ;
}
if ( ! strcmp ( " mirrored " , mirrorlog ) ) {
lp - > log_count = 2 ;
} else if ( ! strcmp ( " disk " , mirrorlog ) ) {
2010-01-09 01:32:35 +03:00
lp - > log_count = 1 ;
2010-01-12 17:00:51 +03:00
} else if ( ! strcmp ( " core " , mirrorlog ) )
2010-01-09 01:32:35 +03:00
lp - > log_count = 0 ;
2007-08-21 23:46:36 +04:00
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 ) ;
2009-11-03 18:50:42 +03:00
lp - > nosync = arg_is_set ( cmd , nosync_ARG ) ;
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 ;
}
2011-08-03 02:07:20 +04:00
static int _read_raid_params ( struct lvcreate_params * lp ,
struct cmd_context * cmd )
{
if ( ! segtype_is_raid ( lp - > segtype ) )
return 1 ;
if ( arg_count ( cmd , corelog_ARG ) | |
arg_count ( cmd , mirrorlog_ARG ) ) {
log_error ( " Log options not applicable to %s segtype " ,
lp - > segtype - > name ) ;
return 0 ;
}
/*
* get_stripe_params is called before _read_raid_params
* and already sets :
* lp - > stripes
* lp - > stripe_size
*
* For RAID 4 / 5 / 6 , these values must be set .
*/
if ( ! segtype_is_mirrored ( lp - > segtype ) & & ( lp - > stripes < 2 ) ) {
log_error ( " Number of stripes to %s not specified " ,
lp - > segtype - > name ) ;
return 0 ;
}
/*
* _read_mirror_params is called before _read_raid_params
* and already sets :
* lp - > nosync
* lp - > region_size
*
* But let ' s ensure that programmers don ' t reorder
* that by checking and warning if they aren ' t set .
*/
if ( ! lp - > region_size ) {
2011-09-06 04:26:42 +04:00
log_error ( INTERNAL_ERROR " region_size not set. " ) ;
return 0 ;
}
return 1 ;
}
static int _read_activation_params ( struct lvcreate_params * lp , struct cmd_context * cmd )
{
unsigned pagesize ;
lp - > activate = arg_uint_value ( cmd , available_ARG , CHANGE_AY ) ;
if ( lp - > activate = = CHANGE_AN | | lp - > activate = = CHANGE_ALN ) {
if ( lp - > zero & & ! seg_is_thin ( lp ) ) {
log_error ( " --available n requires --zero n " ) ;
return 0 ;
}
}
/*
* Read ahead .
*/
lp - > read_ahead = arg_uint_value ( cmd , readahead_ARG ,
cmd - > default_settings . read_ahead ) ;
pagesize = lvm_getpagesize ( ) > > SECTOR_SHIFT ;
if ( lp - > read_ahead ! = DM_READ_AHEAD_AUTO & &
lp - > read_ahead ! = DM_READ_AHEAD_NONE & &
lp - > read_ahead % pagesize ) {
if ( lp - > read_ahead < pagesize )
lp - > read_ahead = pagesize ;
else
lp - > read_ahead = ( lp - > read_ahead / pagesize ) * pagesize ;
log_warn ( " WARNING: Overriding readahead to %u sectors, a multiple "
" of %uK page size. " , lp - > read_ahead , pagesize > > 1 ) ;
}
/*
* Permissions .
*/
lp - > permission = arg_uint_value ( cmd , permission_ARG ,
LVM_READ | LVM_WRITE ) ;
if ( lp - > thin & & ! ( lp - > permission & LVM_WRITE ) ) {
log_error ( " Read-only thin volumes are not currently supported. " ) ;
return 0 ;
}
/* Must not zero read only volume */
if ( ! ( lp - > permission & LVM_WRITE ) )
lp - > zero = 0 ;
lp - > minor = arg_int_value ( cmd , minor_ARG , - 1 ) ;
lp - > major = arg_int_value ( cmd , major_ARG , - 1 ) ;
/* Persistent minor */
if ( arg_count ( cmd , persistent_ARG ) ) {
if ( lp - > create_thin_pool & & ! lp - > thin ) {
log_error ( " --persistent is not permitted when creating a thin pool device. " ) ;
return 0 ;
}
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 ;
}
if ( lp - > major = = - 1 ) {
log_error ( " Please specify major number with "
" --major when using -My " ) ;
return 0 ;
}
} else {
if ( ( lp - > minor ! = - 1 ) | | ( lp - > major ! = - 1 ) ) {
log_error ( " --major and --minor incompatible "
" with -Mn " ) ;
return 0 ;
}
}
} else if ( arg_count ( cmd , minor_ARG ) | | arg_count ( cmd , major_ARG ) ) {
log_error ( " --major and --minor require -My " ) ;
2011-08-03 02:07:20 +04:00
return 0 ;
}
return 1 ;
}
2009-07-26 06:31:41 +04:00
static int _lvcreate_params ( struct lvcreate_params * lp ,
struct lvcreate_cmdline_params * lcp ,
struct cmd_context * cmd ,
2006-04-19 19:33:07 +04:00
int argc , char * * argv )
2002-02-15 14:53:22 +03:00
{
2004-05-19 02:12:53 +04:00
int contiguous ;
2010-11-11 20:29:05 +03:00
struct arg_value_group_list * current_group ;
2011-08-03 02:07:20 +04:00
const char * segtype_str ;
2010-11-11 20:29:05 +03:00
const char * tag ;
2004-05-19 02:12:53 +04:00
2002-07-17 20:04:05 +04:00
memset ( lp , 0 , sizeof ( * lp ) ) ;
2009-07-26 06:31:41 +04:00
memset ( lcp , 0 , sizeof ( * lcp ) ) ;
2010-11-11 20:29:05 +03:00
dm_list_init ( & lp - > tags ) ;
2002-07-17 20:04:05 +04:00
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
*/
2011-09-06 04:26:42 +04:00
if ( arg_count ( cmd , thin_ARG ) & & arg_count ( cmd , mirrors_ARG ) ) {
log_error ( " --thin and --mirrors are incompatible. " ) ;
return 0 ;
}
/* Set default segtype */
2011-08-03 02:07:20 +04:00
if ( arg_count ( cmd , mirrors_ARG ) )
2011-08-12 06:16:46 +04:00
segtype_str = find_config_tree_str ( cmd , " global/mirror_segtype_default " , DEFAULT_MIRROR_SEGTYPE ) ;
2011-09-06 04:26:42 +04:00
else if ( arg_count ( cmd , thin_ARG ) | | arg_count ( cmd , thinpool_ARG ) )
segtype_str = " thin " ;
else
segtype_str = " striped " ;
2011-08-03 02:07:20 +04:00
lp - > segtype = get_segtype_from_string ( cmd , arg_str_value ( cmd , type_ARG , segtype_str ) ) ;
2004-05-11 20:01:58 +04:00
2011-09-08 20:41:18 +04:00
if ( seg_unknown ( lp ) ) {
log_error ( " Unable to create LV with unknown segment type %s. " , arg_str_value ( cmd , type_ARG , segtype_str ) ) ;
return 0 ;
}
2009-05-27 20:30:29 +04:00
if ( arg_count ( cmd , snapshot_ARG ) | | seg_is_snapshot ( lp ) | |
2011-09-06 04:26:42 +04:00
( ! seg_is_thin ( lp ) & & arg_count ( cmd , virtualsize_ARG ) ) )
2004-05-11 20:01:58 +04:00
lp - > snapshot = 1 ;
2011-09-06 04:26:42 +04:00
if ( seg_is_thin_pool ( lp ) ) {
if ( lp - > snapshot ) {
log_error ( " Snapshots are incompatible with thin_pool segment_type. " ) ;
return 0 ;
}
lp - > create_thin_pool = 1 ;
}
if ( seg_is_thin_volume ( lp ) )
lp - > thin = 1 ;
2005-06-01 20:51:55 +04:00
lp - > mirrors = 1 ;
2011-08-03 02:07:20 +04:00
/* Default to 2 mirrored areas if '--type mirror|raid1' */
2011-03-26 00:56:28 +03:00
if ( segtype_is_mirrored ( lp - > segtype ) )
2005-06-01 20:51:55 +04:00
lp - > mirrors = 2 ;
if ( arg_count ( cmd , mirrors_ARG ) ) {
lp - > mirrors = arg_uint_value ( cmd , mirrors_ARG , 0 ) + 1 ;
2011-09-22 19:36:21 +04:00
if ( lp - > mirrors = = 1 ) {
if ( segtype_is_mirrored ( lp - > segtype ) ) {
log_error ( " Image count for segtype \" %s \" cannot be 0. " , lp - > segtype - > name ) ;
return 0 ;
}
2005-06-01 20:51:55 +04:00
log_print ( " Redundant mirrors argument: default is 0 " ) ;
2011-09-22 19:36:21 +04:00
}
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
}
2011-09-06 04:26:42 +04:00
if ( lp - > snapshot & & arg_count ( cmd , zero_ARG ) ) {
log_error ( " -Z is incompatible with snapshots " ) ;
return 0 ;
2002-07-17 20:04:05 +04:00
}
2002-02-15 14:53:22 +03:00
2011-08-03 02:07:20 +04:00
if ( segtype_is_mirrored ( lp - > segtype ) | | segtype_is_raid ( lp - > segtype ) ) {
2005-06-01 20:51:55 +04:00
if ( lp - > snapshot ) {
log_error ( " mirrors and snapshots are currently "
" incompatible " ) ;
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
2010-05-12 01:40:11 +04:00
if ( arg_count ( cmd , mirrorlog_ARG ) ) {
log_error ( " --mirrorlog 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 & &
2009-02-28 23:04:24 +03:00
! lp - > segtype - > ops - > target_present ( cmd , 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 ;
}
2010-03-29 20:09:40 +04:00
if ( ! get_activation_monitoring_mode ( cmd , NULL ,
& lp - > activation_monitoring ) )
2010-03-24 01:30:18 +03:00
return_0 ;
2006-04-19 19:33:07 +04:00
if ( ! _lvcreate_name_params ( lp , cmd , & argc , & argv ) | |
2009-07-26 06:31:41 +04:00
! _read_size_params ( lp , lcp , cmd ) | |
2010-04-13 05:54:32 +04:00
! get_stripe_params ( cmd , & lp - > stripes , & lp - > stripe_size ) | |
2011-08-03 02:07:20 +04:00
! _read_mirror_params ( lp , cmd ) | |
! _read_raid_params ( lp , cmd ) )
2008-01-30 16:19:47 +03:00
return_0 ;
2001-11-12 22:28:50 +03:00
2011-09-06 04:26:42 +04:00
if ( lp - > snapshot & & lp - > thin & & arg_count ( cmd , chunksize_ARG ) )
log_warn ( " WARNING: Ignoring --chunksize with thin snapshots. " ) ;
else if ( lp - > thin & & ! lp - > create_thin_pool ) {
if ( arg_count ( cmd , chunksize_ARG ) )
log_warn ( " WARNING: Ignoring --chunksize when using an existing pool. " ) ;
} else if ( lp - > snapshot | | lp - > create_thin_pool ) {
if ( arg_sign_value ( cmd , chunksize_ARG , 0 ) = = SIGN_MINUS ) {
log_error ( " Negative chunk size is invalid " ) ;
return 0 ;
}
lp - > chunk_size = arg_uint_value ( cmd , chunksize_ARG , 8 ) ;
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 ;
}
log_verbose ( " Setting chunksize to %d sectors. " , lp - > chunk_size ) ;
2002-01-21 17:28:12 +03:00
2011-09-06 04:26:42 +04:00
if ( ! lp - > thin & & lp - > snapshot & & ! ( lp - > segtype = get_segtype_from_string ( cmd , " snapshot " ) ) )
return_0 ;
} else {
if ( arg_count ( cmd , chunksize_ARG ) ) {
log_error ( " -c is only available with snapshots and thin pools " ) ;
2011-06-01 23:21:03 +04:00
return 0 ;
}
}
2002-02-15 14:53:22 +03:00
/*
2011-09-06 04:26:42 +04:00
* Should we zero the lv .
2002-02-15 14:53:22 +03:00
*/
2011-09-06 04:26:42 +04:00
lp - > zero = strcmp ( arg_str_value ( cmd , zero_ARG ,
( lp - > segtype - > flags & SEG_CANNOT_BE_ZEROED ) ? " n " : " y " ) , " n " ) ;
2002-02-15 14:53:22 +03:00
2009-11-27 17:35:38 +03:00
if ( lp - > mirrors > DEFAULT_MIRROR_MAX_IMAGES ) {
log_error ( " Only up to %d images in mirror supported currently. " ,
DEFAULT_MIRROR_MAX_IMAGES ) ;
return 0 ;
}
2011-09-06 04:26:42 +04:00
if ( ! _read_activation_params ( lp , cmd ) )
return_0 ;
2002-02-15 14:53:22 +03:00
/*
2011-09-06 04:26:42 +04:00
* Allocation parameters
2002-02-15 14:53:22 +03:00
*/
2011-09-06 04:26:42 +04:00
contiguous = strcmp ( arg_str_value ( cmd , contiguous_ARG , " n " ) , " n " ) ;
2007-01-10 17:13:46 +03:00
2011-09-06 04:26:42 +04:00
lp - > alloc = contiguous ? ALLOC_CONTIGUOUS : ALLOC_INHERIT ;
2002-02-15 14:53:22 +03:00
2011-09-06 04:26:42 +04:00
lp - > alloc = arg_uint_value ( cmd , alloc_ARG , lp - > alloc ) ;
2002-02-15 14:53:22 +03:00
2011-09-06 04:26:42 +04:00
if ( contiguous & & ( lp - > alloc ! = ALLOC_CONTIGUOUS ) ) {
log_error ( " Conflicting contiguous and alloc arguments " ) ;
2008-09-24 20:32:51 +04:00
return 0 ;
2001-11-06 22:02:26 +03:00
}
2010-11-11 20:29:05 +03:00
dm_list_iterate_items ( current_group , & cmd - > arg_value_groups ) {
if ( ! grouped_arg_is_set ( current_group - > arg_values , addtag_ARG ) )
continue ;
if ( ! ( tag = grouped_arg_str_value ( current_group - > arg_values , addtag_ARG , NULL ) ) ) {
log_error ( " Failed to get tag " ) ;
return 0 ;
}
if ( ! str_list_add ( cmd - > mem , & lp - > tags , tag ) ) {
2011-09-06 04:26:42 +04:00
log_error ( " Unable to allocate memory for tag %s " , tag ) ;
2010-11-11 20:29:05 +03:00
return 0 ;
}
2011-09-06 04:26:42 +04:00
}
2009-07-26 06:30:57 +04:00
2009-07-26 06:32:50 +04:00
lcp - > pv_count = argc ;
lcp - > pvs = argv ;
2001-11-06 22:02:26 +03:00
2002-02-15 14:53:22 +03:00
return 1 ;
}
2011-09-06 04:26:42 +04:00
static int _check_thin_parameters ( struct volume_group * vg , struct lvcreate_params * lp ,
struct lvcreate_cmdline_params * lcp )
{
struct lv_list * lvl ;
if ( ! lp - > thin & & ! lp - > create_thin_pool ) {
log_error ( " Please specify device size(s). " ) ;
return 0 ;
}
if ( lp - > thin & & ! lp - > create_thin_pool ) {
if ( arg_count ( vg - > cmd , chunksize_ARG ) ) {
log_error ( " Only specify --chunksize when originally creating the thin pool. " ) ;
return 0 ;
}
if ( lcp - > pv_count ) {
log_error ( " Only specify Physical volumes when allocating the thin pool. " ) ;
return 0 ;
}
if ( arg_count ( vg - > cmd , alloc_ARG ) ) {
log_error ( " --alloc may only be specified when allocating the thin pool. " ) ;
return 0 ;
}
if ( arg_count ( vg - > cmd , stripesize_ARG ) ) {
log_error ( " --stripesize may only be specified when allocating the thin pool. " ) ;
return 0 ;
}
if ( arg_count ( vg - > cmd , stripes_ARG ) ) {
log_error ( " --stripes may only be specified when allocating the thin pool. " ) ;
return 0 ;
}
if ( arg_count ( vg - > cmd , contiguous_ARG ) ) {
log_error ( " --contiguous may only be specified when allocating the thin pool. " ) ;
return 0 ;
}
if ( arg_count ( vg - > cmd , zero_ARG ) ) {
log_error ( " --zero may only be specified when allocating the thin pool. " ) ;
return 0 ;
}
}
if ( lp - > create_thin_pool & & lp - > pool ) {
if ( find_lv_in_vg ( vg , lp - > pool ) ) {
log_error ( " Pool %s already exists in Volume group %s. " , lp - > pool , vg - > name ) ;
return 0 ;
}
} else if ( lp - > pool ) {
if ( ! ( lvl = find_lv_in_vg ( vg , lp - > pool ) ) ) {
log_error ( " Pool %s not found in Volume group %s. " , lp - > pool , vg - > name ) ;
return 0 ;
}
2011-09-06 23:25:42 +04:00
if ( ! lv_is_thin_pool ( lvl - > lv ) ) {
2011-09-06 04:26:42 +04:00
log_error ( " Logical volume %s is not a thin pool. " , lp - > pool ) ;
return 0 ;
}
} else if ( ! lp - > create_thin_pool ) {
log_error ( " Please specify name of existing pool. " ) ;
return 0 ;
}
if ( ! lp - > thin & & lp - > lv_name ) {
log_error ( " --name may only be given when creating a new thin Logical volume or snapshot. " ) ;
return 0 ;
}
if ( ! lp - > thin ) {
if ( arg_count ( vg - > cmd , readahead_ARG ) ) {
log_error ( " --readhead may only be given when creating a new thin Logical volume or snapshot. " ) ;
return 0 ;
}
if ( arg_count ( vg - > cmd , permission_ARG ) ) {
log_error ( " --permission may only be given when creating a new thin Logical volume or snapshot. " ) ;
return 0 ;
}
if ( arg_count ( vg - > cmd , persistent_ARG ) ) {
log_error ( " --persistent may only be given when creating a new thin Logical volume or snapshot. " ) ;
return 0 ;
}
}
return 1 ;
}
/*
* Ensure the set of thin parameters extracted from the command line is consistent .
*/
static int _validate_internal_thin_processing ( const struct lvcreate_params * lp )
{
int r = 1 ;
/*
The final state should be one of :
thin create_thin_pool snapshot origin pool
1 1 0 0 y / n - create new pool and a thin LV in it
1 0 0 0 y - create new thin LV in existing pool
0 1 0 0 y / n - create new pool only
1 0 1 1 y - create thin snapshot of existing thin LV
*/
if ( ! lp - > create_thin_pool & & ! lp - > pool ) {
log_error ( INTERNAL_ERROR " --thinpool not identified. " ) ;
r = 0 ;
}
if ( ( lp - > snapshot & & ! lp - > origin ) | | ( ! lp - > snapshot & & lp - > origin ) ) {
log_error ( INTERNAL_ERROR " Inconsistent snapshot and origin parameters identified. " ) ;
r = 0 ;
}
if ( lp - > snapshot & & ( lp - > create_thin_pool | | ! lp - > thin ) ) {
log_error ( INTERNAL_ERROR " Inconsistent thin and snapshot parameters identified. " ) ;
r = 0 ;
}
if ( ! lp - > thin & & ! lp - > create_thin_pool ) {
log_error ( INTERNAL_ERROR " Failed to identify what type of thin target to use. " ) ;
r = 0 ;
}
if ( seg_is_thin_pool ( lp ) & & lp - > thin ) {
log_error ( INTERNAL_ERROR " Thin volume cannot be created with thin pool segment type. " ) ;
r = 0 ;
}
return r ;
}
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 ;
2009-07-26 06:31:41 +04:00
struct lvcreate_cmdline_params lcp ;
2007-11-15 05:20:03 +03:00
struct volume_group * vg ;
2002-02-15 14:53:22 +03:00
2009-07-26 06:31:41 +04:00
if ( ! _lvcreate_params ( & lp , & lcp , 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 ) ;
2009-07-01 20:59:37 +04:00
vg = vg_read_for_update ( cmd , lp . vg_name , NULL , 0 ) ;
2009-07-07 05:18:35 +04:00
if ( vg_read_error ( vg ) ) {
2011-08-11 00:25:29 +04:00
release_vg ( vg ) ;
2009-09-15 02:47:49 +04:00
stack ;
2003-10-22 02:06:07 +04:00
return ECMD_FAILED ;
2009-07-07 05:18:35 +04:00
}
2002-02-15 14:53:22 +03:00
2011-09-07 13:25:51 +04:00
if ( lp . snapshot & & lp . origin & & ! _determine_snapshot_type ( vg , & lp ) ) {
2011-09-06 04:26:42 +04:00
r = ECMD_FAILED ;
goto_out ;
}
if ( seg_is_thin ( & lp ) & & ! _check_thin_parameters ( vg , & lp , & lcp ) ) {
r = ECMD_FAILED ;
goto_out ;
}
2009-09-15 02:47:49 +04:00
if ( ! _update_extents_params ( vg , & lp , & lcp ) ) {
2009-11-04 17:47:27 +03:00
r = ECMD_FAILED ;
goto_out ;
2009-09-15 02:47:49 +04:00
}
2009-07-26 06:31:18 +04:00
2011-09-06 04:26:42 +04:00
if ( seg_is_thin ( & lp ) & & ! _validate_internal_thin_processing ( & lp ) ) {
r = ECMD_FAILED ;
goto_out ;
}
if ( lp . create_thin_pool )
log_verbose ( " Making thin pool %s in VG %s using segtype %s " ,
lp . pool ? : " with generated name " , lp . vg_name , lp . segtype - > name ) ;
if ( lp . thin )
log_verbose ( " Making thin LV %s in pool %s in VG %s%s%s using segtype %s " ,
lp . lv_name ? : " with generated name " ,
lp . pool , lp . vg_name , lp . snapshot ? " as snapshot of " : " " ,
lp . snapshot ? lp . origin : " " , lp . segtype - > name ) ;
/* FIXME Remove when thin snapshots are supported. */
if ( lp . thin & & lp . snapshot ) {
log_error ( " Thin snapshots are not yet supported. " ) ;
r = ECMD_FAILED ;
goto_out ;
}
2009-09-15 02:47:49 +04:00
if ( ! lv_create_single ( vg , & lp ) ) {
stack ;
2007-11-15 05:20:03 +03:00
r = ECMD_FAILED ;
2009-09-15 02:47:49 +04:00
}
2009-11-04 17:47:27 +03:00
out :
2011-08-11 00:25:29 +04:00
unlock_and_release_vg ( cmd , vg , lp . vg_name ) ;
2002-02-15 14:53:22 +03:00
return r ;
2001-11-06 22:02:26 +03:00
}