2001-11-13 17:17:50 +03:00
/*
2004-05-11 20:01:58 +04:00
* Copyright ( C ) 2001 - 2004 Sistina Software , Inc . All rights reserved .
2009-02-24 18:48:00 +03:00
* Copyright ( C ) 2004 - 2009 Red Hat , Inc . All rights reserved .
2001-11-13 17:17:50 +03:00
*
2004-03-30 23:35:44 +04:00
* This file is part of LVM2 .
2001-11-13 17:17:50 +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 .
2001-11-13 17:17:50 +03: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-13 17:17:50 +03:00
*/
# include "tools.h"
2004-06-15 21:23:49 +04:00
# define SIZE_BUF 128
2004-05-11 22:47:40 +04:00
struct lvresize_params {
2002-12-20 02:25:55 +03:00
const char * vg_name ;
2004-05-11 22:47:40 +04:00
const char * lv_name ;
uint32_t stripes ;
uint32_t stripe_size ;
2005-06-03 23:48:19 +04:00
uint32_t mirrors ;
2004-05-11 22:47:40 +04:00
2006-05-10 01:23:51 +04:00
const struct segment_type * segtype ;
2004-05-11 22:47:40 +04:00
/* size */
uint32_t extents ;
uint64_t size ;
sign_t sign ;
2006-09-26 13:35:43 +04:00
percent_t percent ;
2001-11-13 17:17:50 +03:00
enum {
LV_ANY = 0 ,
LV_REDUCE = 1 ,
LV_EXTEND = 2
2004-05-11 22:47:40 +04:00
} resize ;
2004-06-15 21:23:49 +04:00
int resizefs ;
int nofsck ;
2004-05-11 22:47:40 +04:00
int argc ;
char * * argv ;
} ;
2009-02-28 02:40:11 +03:00
static int _validate_stripesize ( struct cmd_context * cmd ,
const struct volume_group * vg ,
struct lvresize_params * lp )
2007-09-07 01:08:16 +04:00
{
if ( arg_sign_value ( cmd , stripesize_ARG , 0 ) = = SIGN_MINUS ) {
log_error ( " Stripesize may not be negative. " ) ;
return 0 ;
}
2007-11-14 03:08:25 +03:00
if ( arg_uint_value ( cmd , stripesize_ARG , 0 ) > STRIPE_SIZE_LIMIT * 2 ) {
2007-09-07 01:08:16 +04:00
log_error ( " Stripe size cannot be larger than %s " ,
display_size ( cmd , ( uint64_t ) STRIPE_SIZE_LIMIT ) ) ;
return 0 ;
}
if ( ! ( vg - > fid - > fmt - > features & FMT_SEGMENTS ) )
log_warn ( " Varied stripesize not supported. Ignoring. " ) ;
2007-11-14 03:08:25 +03:00
else if ( arg_uint_value ( cmd , stripesize_ARG , 0 ) > vg - > extent_size * 2 ) {
2007-09-07 01:08:16 +04:00
log_error ( " Reducing stripe size %s to maximum, "
" physical extent size %s " ,
display_size ( cmd ,
2007-11-14 03:08:25 +03:00
( uint64_t ) arg_uint_value ( cmd , stripesize_ARG , 0 ) ) ,
2007-09-07 01:08:16 +04:00
display_size ( cmd , ( uint64_t ) vg - > extent_size ) ) ;
lp - > stripe_size = vg - > extent_size ;
} else
2007-11-14 03:08:25 +03:00
lp - > stripe_size = arg_uint_value ( cmd , stripesize_ARG , 0 ) ;
2007-09-07 01:08:16 +04:00
if ( lp - > mirrors ) {
log_error ( " Mirrors and striping cannot be combined yet. " ) ;
return 0 ;
}
if ( lp - > stripe_size & ( lp - > stripe_size - 1 ) ) {
log_error ( " Stripe size must be power of 2 " ) ;
return 0 ;
}
return 1 ;
}
2009-02-28 02:40:11 +03:00
static int _request_confirmation ( struct cmd_context * cmd ,
const struct volume_group * vg ,
const struct logical_volume * lv ,
const struct lvresize_params * lp )
2007-09-07 01:08:16 +04:00
{
struct lvinfo info ;
memset ( & info , 0 , sizeof ( info ) ) ;
2007-11-12 23:51:54 +03:00
if ( ! lv_info ( cmd , lv , & info , 1 , 0 ) & & driver_version ( NULL , 0 ) ) {
2007-09-07 01:08:16 +04:00
log_error ( " lv_info failed: aborting " ) ;
return 0 ;
}
2009-02-28 02:40:11 +03:00
if ( lp - > resizefs ) {
if ( ! info . exists ) {
log_error ( " Logical volume %s must be activated "
" before resizing filesystem " , lp - > lv_name ) ;
return 0 ;
}
return 1 ;
2007-09-07 01:08:16 +04:00
}
2009-02-28 02:40:11 +03:00
if ( ! info . exists )
return 1 ;
2007-09-07 01:08:16 +04:00
2009-02-28 02:40:11 +03:00
log_warn ( " WARNING: Reducing active%s logical volume to %s " ,
info . open_count ? " and open " : " " ,
display_size ( cmd , ( uint64_t ) lp - > extents * vg - > extent_size ) ) ;
2007-09-07 01:08:16 +04:00
2009-02-28 02:40:11 +03:00
log_warn ( " THIS MAY DESTROY YOUR DATA (filesystem etc.) " ) ;
if ( ! arg_count ( cmd , force_ARG ) ) {
if ( yes_no_prompt ( " Do you really want to reduce %s? [y/n]: " ,
lp - > lv_name ) = = ' n ' ) {
2009-12-03 22:18:33 +03:00
log_error ( " Logical volume %s NOT reduced " , lp - > lv_name ) ;
2009-02-28 02:40:11 +03:00
return 0 ;
2007-09-07 01:08:16 +04:00
}
2009-02-28 02:40:11 +03:00
if ( sigint_caught ( ) )
return 0 ;
2007-09-07 01:08:16 +04:00
}
return 1 ;
}
2009-02-24 18:48:00 +03:00
enum fsadm_cmd_e { FSADM_CMD_CHECK , FSADM_CMD_RESIZE } ;
2009-02-28 02:40:11 +03:00
# define FSADM_CMD "fsadm"
# define FSADM_CMD_MAX_ARGS 6
2009-02-24 18:48:00 +03:00
2009-02-28 02:40:11 +03:00
/*
* FSADM_CMD - - dry - run - - verbose - - force check lv_path
* FSADM_CMD - - dry - run - - verbose - - force resize lv_path size
*/
2009-02-28 03:54:06 +03:00
static int _fsadm_cmd ( struct cmd_context * cmd ,
2009-02-28 02:40:11 +03:00
const struct volume_group * vg ,
const struct lvresize_params * lp ,
enum fsadm_cmd_e fcmd )
2007-09-07 01:08:16 +04:00
{
char lv_path [ PATH_MAX ] ;
char size_buf [ SIZE_BUF ] ;
2009-02-28 02:40:11 +03:00
const char * argv [ FSADM_CMD_MAX_ARGS + 2 ] ;
unsigned i = 0 ;
2009-02-24 18:48:00 +03:00
2009-02-28 02:40:11 +03:00
argv [ i + + ] = FSADM_CMD ;
2009-02-24 18:48:00 +03:00
if ( test_mode ( ) )
argv [ i + + ] = " --dry-run " ;
2009-02-28 02:40:11 +03:00
if ( verbose_level ( ) > = _LOG_NOTICE )
2009-02-24 18:48:00 +03:00
argv [ i + + ] = " --verbose " ;
if ( arg_count ( cmd , force_ARG ) )
argv [ i + + ] = " --force " ;
argv [ i + + ] = ( fcmd = = FSADM_CMD_RESIZE ) ? " resize " : " check " ;
2007-09-07 01:08:16 +04:00
2009-02-28 02:40:11 +03:00
if ( dm_snprintf ( lv_path , PATH_MAX , " %s%s/%s " , cmd - > dev_dir , lp - > vg_name ,
lp - > lv_name ) < 0 ) {
log_error ( " Couldn't create LV path for %s " , lp - > lv_name ) ;
2007-09-07 01:08:16 +04:00
return 0 ;
}
2009-02-24 18:48:00 +03:00
argv [ i + + ] = lv_path ;
2007-09-07 01:08:16 +04:00
2009-02-24 18:48:00 +03:00
if ( fcmd = = FSADM_CMD_RESIZE ) {
if ( dm_snprintf ( size_buf , SIZE_BUF , " % " PRIu64 " K " ,
( uint64_t ) lp - > extents * vg - > extent_size / 2 ) < 0 ) {
log_error ( " Couldn't generate new LV size string " ) ;
return 0 ;
}
2007-09-07 01:08:16 +04:00
2009-02-24 18:48:00 +03:00
argv [ i + + ] = size_buf ;
}
2007-09-07 01:08:16 +04:00
2009-02-24 18:48:00 +03:00
argv [ i ] = NULL ;
2009-02-28 03:54:06 +03:00
return exec_cmd ( cmd , argv ) ;
2007-09-07 01:08:16 +04:00
}
2006-04-19 19:33:07 +04:00
static int _lvresize_params ( struct cmd_context * cmd , int argc , char * * argv ,
struct lvresize_params * lp )
2004-05-11 22:47:40 +04:00
{
const char * cmd_name ;
char * st ;
2008-02-06 15:45:32 +03:00
unsigned dev_dir_found = 0 ;
2004-05-11 22:47:40 +04:00
lp - > sign = SIGN_NONE ;
lp - > resize = LV_ANY ;
2001-11-13 17:17:50 +03:00
2002-02-11 23:50:53 +03:00
cmd_name = command_name ( cmd ) ;
2001-11-13 17:17:50 +03:00
if ( ! strcmp ( cmd_name , " lvreduce " ) )
2004-05-11 22:47:40 +04:00
lp - > resize = LV_REDUCE ;
2001-11-13 17:17:50 +03:00
if ( ! strcmp ( cmd_name , " lvextend " ) )
2004-05-11 22:47:40 +04:00
lp - > resize = LV_EXTEND ;
2001-11-13 17:17:50 +03:00
2007-09-21 01:39:08 +04:00
/*
* Allow omission of extents and size if the user has given us
* one or more PVs . Most likely , the intent was " resize this
* LV the best you can with these PVs "
*/
if ( ( arg_count ( cmd , extents_ARG ) + arg_count ( cmd , size_ARG ) = = 0 ) & &
( argc > = 2 ) ) {
lp - > extents = 100 ;
lp - > percent = PERCENT_PVS ;
lp - > sign = SIGN_PLUS ;
} else if ( ( arg_count ( cmd , extents_ARG ) +
arg_count ( cmd , size_ARG ) ! = 1 ) ) {
log_error ( " Please specify either size or extents but not "
" both. " ) ;
2004-05-11 22:47:40 +04:00
return 0 ;
2001-11-13 17:17:50 +03:00
}
2002-02-12 00:00:35 +03:00
if ( arg_count ( cmd , extents_ARG ) ) {
2004-05-11 22:47:40 +04:00
lp - > extents = arg_uint_value ( cmd , extents_ARG , 0 ) ;
lp - > sign = arg_sign_value ( cmd , extents_ARG , SIGN_NONE ) ;
2006-09-26 13:35:43 +04:00
lp - > percent = arg_percent_value ( cmd , extents_ARG , PERCENT_NONE ) ;
2001-11-13 17:17:50 +03:00
}
2004-05-11 20:01:58 +04:00
/* Size returned in kilobyte units; held in sectors */
2002-02-12 00:00:35 +03:00
if ( arg_count ( cmd , size_ARG ) ) {
2007-11-14 03:08:25 +03:00
lp - > size = arg_uint64_value ( cmd , size_ARG , UINT64_C ( 0 ) ) ;
2004-05-11 22:47:40 +04:00
lp - > sign = arg_sign_value ( cmd , size_ARG , SIGN_NONE ) ;
2006-09-26 13:35:43 +04:00
lp - > percent = PERCENT_NONE ;
2001-11-13 17:17:50 +03:00
}
2004-05-11 22:47:40 +04:00
if ( lp - > resize = = LV_EXTEND & & lp - > sign = = SIGN_MINUS ) {
2001-11-13 17:17:50 +03:00
log_error ( " Negative argument not permitted - use lvreduce " ) ;
2004-05-11 22:47:40 +04:00
return 0 ;
2001-11-13 17:17:50 +03:00
}
2004-05-11 22:47:40 +04:00
if ( lp - > resize = = LV_REDUCE & & lp - > sign = = SIGN_PLUS ) {
2001-11-13 17:17:50 +03:00
log_error ( " Positive sign not permitted - use lvextend " ) ;
2004-05-11 22:47:40 +04:00
return 0 ;
2001-11-13 17:17:50 +03:00
}
2009-11-03 18:50:42 +03:00
lp - > resizefs = arg_is_set ( cmd , resizefs_ARG ) ;
lp - > nofsck = arg_is_set ( cmd , nofsck_ARG ) ;
2004-06-15 21:23:49 +04:00
2001-11-13 17:17:50 +03:00
if ( ! argc ) {
log_error ( " Please provide the logical volume name " ) ;
2004-05-11 22:47:40 +04:00
return 0 ;
2001-11-13 17:17:50 +03:00
}
2004-05-11 22:47:40 +04:00
lp - > lv_name = argv [ 0 ] ;
2001-11-13 17:17:50 +03:00
argv + + ;
argc - - ;
2008-04-10 23:59:43 +04:00
if ( ! ( lp - > lv_name = skip_dev_dir ( cmd , lp - > lv_name , & dev_dir_found ) ) | |
! ( lp - > vg_name = extract_vgname ( cmd , lp - > lv_name ) ) ) {
2001-11-13 17:17:50 +03:00
log_error ( " Please provide a volume group name " ) ;
2004-05-11 22:47:40 +04:00
return 0 ;
2001-11-13 17:17:50 +03:00
}
2008-02-06 15:45:32 +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 ) ;
2007-11-12 23:02:55 +03:00
return 0 ;
2007-11-02 23:40:05 +03:00
}
2001-11-13 17:17:50 +03:00
2004-05-11 22:47:40 +04:00
if ( ( st = strrchr ( lp - > lv_name , ' / ' ) ) )
lp - > lv_name = st + 1 ;
2001-11-13 17:17:50 +03:00
2004-05-11 22:47:40 +04:00
lp - > argc = argc ;
lp - > argv = argv ;
return 1 ;
}
2002-02-11 18:42:34 +03:00
2007-11-15 05:20:03 +03:00
static int _lvresize ( struct cmd_context * cmd , struct volume_group * vg ,
struct lvresize_params * lp )
2004-05-11 22:47:40 +04:00
{
struct logical_volume * lv ;
struct lvinfo info ;
uint32_t stripesize_extents = 0 ;
uint32_t seg_stripes = 0 , seg_stripesize = 0 , seg_size = 0 ;
2005-06-03 23:48:19 +04:00
uint32_t seg_mirrors = 0 ;
2004-05-11 22:47:40 +04:00
uint32_t extents_used = 0 ;
uint32_t size_rest ;
2007-09-21 01:39:08 +04:00
uint32_t pv_extent_count = 0 ;
2004-05-19 02:12:53 +04:00
alloc_policy_t alloc ;
2005-08-15 16:00:04 +04:00
struct logical_volume * lock_lv ;
2004-05-11 22:47:40 +04:00
struct lv_list * lvl ;
struct lv_segment * seg ;
uint32_t seg_extents ;
uint32_t sz , str ;
2008-11-04 01:14:30 +03:00
struct dm_list * pvh = NULL ;
2004-05-11 22:47:40 +04:00
2001-11-13 17:17:50 +03:00
/* does LV exist? */
2004-05-11 22:47:40 +04:00
if ( ! ( lvl = find_lv_in_vg ( vg , lp - > lv_name ) ) ) {
2001-11-13 17:17:50 +03:00
log_error ( " Logical volume %s not found in volume group %s " ,
2004-05-11 22:47:40 +04:00
lp - > lv_name , lp - > vg_name ) ;
2004-05-24 19:58:50 +04:00
return ECMD_FAILED ;
2001-11-13 17:17:50 +03:00
}
2002-04-24 22:20:51 +04:00
if ( arg_count ( cmd , stripes_ARG ) ) {
if ( vg - > fid - > fmt - > features & FMT_SEGMENTS )
2004-05-11 22:47:40 +04:00
lp - > stripes = arg_uint_value ( cmd , stripes_ARG , 1 ) ;
2002-04-24 22:20:51 +04:00
else
2007-06-28 21:33:44 +04:00
log_warn ( " Varied striping not supported. Ignoring. " ) ;
2002-04-24 22:20:51 +04:00
}
2005-06-03 23:48:19 +04:00
if ( arg_count ( cmd , mirrors_ARG ) ) {
if ( vg - > fid - > fmt - > features & FMT_SEGMENTS )
lp - > mirrors = arg_uint_value ( cmd , mirrors_ARG , 1 ) + 1 ;
else
2007-06-28 21:33:44 +04:00
log_warn ( " Mirrors not supported. Ignoring. " ) ;
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 " ) ;
2007-09-07 01:08:16 +04:00
return EINVALID_CMD_LINE ;
2005-11-29 00:00:37 +03:00
}
2005-06-03 23:48:19 +04:00
}
2009-02-28 02:40:11 +03:00
if ( arg_count ( cmd , stripesize_ARG ) & &
! _validate_stripesize ( cmd , vg , lp ) )
return EINVALID_CMD_LINE ;
2002-04-24 22:20:51 +04:00
2002-01-21 19:49:32 +03:00
lv = lvl - > lv ;
2001-11-13 17:17:50 +03:00
2003-05-06 16:10:18 +04:00
if ( lv - > status & LOCKED ) {
log_error ( " Can't resize locked LV %s " , lv - > name ) ;
2004-05-24 19:58:50 +04:00
return ECMD_FAILED ;
2003-05-06 16:10:18 +04:00
}
2008-09-18 22:51:58 +04:00
if ( lv - > status & CONVERTING ) {
log_error ( " Can't resize %s while lvconvert in progress " , lv - > name ) ;
return ECMD_FAILED ;
}
2006-05-10 01:23:51 +04:00
alloc = arg_uint_value ( cmd , alloc_ARG , lv - > alloc ) ;
2004-05-24 19:58:50 +04:00
2004-05-11 22:47:40 +04:00
if ( lp - > size ) {
if ( lp - > size % vg - > extent_size ) {
if ( lp - > sign = = SIGN_MINUS )
lp - > size - = lp - > size % vg - > extent_size ;
2001-11-13 17:17:50 +03:00
else
2004-05-11 22:47:40 +04:00
lp - > size + = vg - > extent_size -
( lp - > size % vg - > extent_size ) ;
2001-11-13 17:17:50 +03:00
log_print ( " Rounding up size to full physical extent %s " ,
2006-05-10 01:23:51 +04:00
display_size ( cmd , ( uint64_t ) lp - > size ) ) ;
2001-11-13 17:17:50 +03:00
}
2004-05-11 22:47:40 +04:00
lp - > extents = lp - > size / vg - > extent_size ;
2001-11-13 17:17:50 +03:00
}
2007-09-21 01:39:08 +04:00
if ( ! ( pvh = lp - > argc ? create_pv_list ( cmd - > mem , vg , lp - > argc ,
lp - > argv , 1 ) : & vg - > pvs ) ) {
stack ;
return ECMD_FAILED ;
}
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 ;
case PERCENT_LV :
lp - > extents = lp - > extents * lv - > le_count / 100 ;
break ;
2007-09-21 01:39:08 +04:00
case PERCENT_PVS :
2009-11-04 17:47:27 +03:00
if ( lp - > argc ) {
pv_extent_count = pv_list_extents_free ( pvh ) ;
lp - > extents = lp - > extents * pv_extent_count / 100 ;
} else
lp - > extents = lp - > extents * vg - > extent_count / 100 ;
2007-09-21 01:39:08 +04:00
break ;
2010-02-03 06:58:08 +03:00
case PERCENT_ORIGIN :
if ( ! lv_is_cow ( lv ) ) {
log_error ( " Specified LV does not have an origin LV. " ) ;
return EINVALID_CMD_LINE ;
}
lp - > extents = lp - > extents * origin_from_cow ( lv ) - > le_count / 100 ;
break ;
2006-09-26 13:35:43 +04:00
case PERCENT_NONE :
break ;
}
2004-05-11 22:47:40 +04:00
if ( lp - > sign = = SIGN_PLUS )
lp - > extents + = lv - > le_count ;
2001-11-13 17:17:50 +03:00
2004-05-11 22:47:40 +04:00
if ( lp - > sign = = SIGN_MINUS ) {
if ( lp - > extents > = lv - > le_count ) {
2001-11-13 17:17:50 +03:00
log_error ( " Unable to reduce %s below 1 extent " ,
2004-05-11 22:47:40 +04:00
lp - > lv_name ) ;
2004-05-24 19:58:50 +04:00
return EINVALID_CMD_LINE ;
2001-11-13 17:17:50 +03:00
}
2004-05-11 22:47:40 +04:00
lp - > extents = lv - > le_count - lp - > extents ;
2001-11-13 17:17:50 +03:00
}
2004-05-11 22:47:40 +04:00
if ( ! lp - > extents ) {
2001-11-13 17:17:50 +03:00
log_error ( " New size of 0 not permitted " ) ;
2004-05-24 19:58:50 +04:00
return EINVALID_CMD_LINE ;
2001-11-13 17:17:50 +03:00
}
2004-05-11 22:47:40 +04:00
if ( lp - > extents = = lv - > le_count ) {
2009-02-24 18:48:00 +03:00
if ( ! lp - > resizefs ) {
log_error ( " New size (%d extents) matches existing size "
" (%d extents) " , lp - > extents , lv - > le_count ) ;
return EINVALID_CMD_LINE ;
}
lp - > resize = LV_EXTEND ; /* lets pretend zero size extension */
2001-11-13 17:17:50 +03:00
}
2004-05-11 22:47:40 +04:00
seg_size = lp - > extents - lv - > le_count ;
2002-04-24 22:20:51 +04:00
2004-05-11 20:01:58 +04:00
/* Use segment type of last segment */
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( seg , & lv - > segments ) {
2004-05-11 22:47:40 +04:00
lp - > segtype = seg - > segtype ;
2004-05-11 20:01:58 +04:00
}
/* FIXME Support LVs with mixed segment types */
2006-05-10 01:23:51 +04:00
if ( lp - > segtype ! = arg_ptr_value ( cmd , type_ARG , lp - > segtype ) ) {
2004-05-11 22:47:40 +04:00
log_error ( " VolumeType does not match (%s) " , lp - > segtype - > name ) ;
2004-05-24 19:58:50 +04:00
return EINVALID_CMD_LINE ;
2004-05-11 20:01:58 +04:00
}
2001-11-27 16:42:37 +03:00
/* If extending, find stripes, stripesize & size of last segment */
2004-05-11 22:47:40 +04:00
if ( ( lp - > extents > lv - > le_count ) & &
! ( lp - > stripes = = 1 | | ( lp - > stripes > 1 & & lp - > stripe_size ) ) ) {
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( seg , & lv - > segments ) {
2005-05-09 20:59:01 +04:00
if ( ! seg_is_striped ( seg ) )
2004-05-11 20:01:58 +04:00
continue ;
2003-04-25 02:23:24 +04:00
2001-11-28 16:45:50 +03:00
sz = seg - > stripe_size ;
2003-04-25 02:23:24 +04:00
str = seg - > area_count ;
2001-11-27 16:42:37 +03:00
2009-02-28 02:40:11 +03:00
if ( ( seg_stripesize & & seg_stripesize ! = sz & &
! lp - > stripe_size ) | |
2004-05-11 22:47:40 +04:00
( seg_stripes & & seg_stripes ! = str & & ! lp - > stripes ) ) {
2001-11-27 16:42:37 +03:00
log_error ( " Please specify number of "
" stripes (-i) and stripesize (-I) " ) ;
2004-05-24 19:58:50 +04:00
return EINVALID_CMD_LINE ;
2001-11-27 16:42:37 +03:00
}
seg_stripesize = sz ;
seg_stripes = str ;
}
2004-05-11 22:47:40 +04:00
if ( ! lp - > stripes )
lp - > stripes = seg_stripes ;
2001-11-27 16:42:37 +03:00
2004-05-11 22:47:40 +04:00
if ( ! lp - > stripe_size & & lp - > stripes > 1 ) {
2002-04-24 22:20:51 +04:00
if ( seg_stripesize ) {
2006-04-30 02:08:43 +04:00
log_print ( " Using stripesize of last segment %s " ,
2006-05-10 01:23:51 +04:00
display_size ( cmd , ( uint64_t ) seg_stripesize ) ) ;
2004-05-11 22:47:40 +04:00
lp - > stripe_size = seg_stripesize ;
2002-04-24 22:20:51 +04:00
} else {
2004-05-24 19:58:50 +04:00
lp - > stripe_size =
2006-05-16 20:48:31 +04:00
find_config_tree_int ( cmd ,
2002-12-20 02:25:55 +03:00
" metadata/stripesize " ,
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 ) ) ;
2002-04-24 22:20:51 +04:00
}
}
2001-11-27 16:42:37 +03:00
}
2005-06-03 23:48:19 +04:00
/* If extending, find mirrors of last segment */
if ( ( lp - > extents > lv - > le_count ) ) {
2008-11-04 01:14:30 +03:00
dm_list_iterate_back_items ( seg , & lv - > segments ) {
2005-06-03 23:48:19 +04:00
if ( seg_is_mirrored ( seg ) )
2007-12-20 21:55:46 +03:00
seg_mirrors = lv_mirror_count ( seg - > lv ) ;
2005-06-03 23:48:19 +04:00
else
seg_mirrors = 0 ;
break ;
}
if ( ! arg_count ( cmd , mirrors_ARG ) & & seg_mirrors ) {
log_print ( " Extending % " PRIu32 " mirror images. " ,
seg_mirrors ) ;
lp - > mirrors = seg_mirrors ;
}
if ( ( arg_count ( cmd , mirrors_ARG ) | | seg_mirrors ) & &
( lp - > mirrors ! = seg_mirrors ) ) {
log_error ( " Cannot vary number of mirrors in LV yet. " ) ;
return EINVALID_CMD_LINE ;
}
}
2001-11-27 16:42:37 +03:00
/* If reducing, find stripes, stripesize & size of last segment */
2004-05-11 22:47:40 +04:00
if ( lp - > extents < lv - > le_count ) {
2002-04-24 22:20:51 +04:00
extents_used = 0 ;
2001-11-27 16:42:37 +03:00
2005-06-03 23:48:19 +04:00
if ( lp - > stripes | | lp - > stripe_size | | lp - > mirrors )
log_error ( " Ignoring stripes, stripesize and mirrors "
" arguments when reducing " ) ;
2001-11-27 16:42:37 +03:00
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( seg , & lv - > segments ) {
2001-11-28 16:45:50 +03:00
seg_extents = seg - > len ;
2005-05-09 20:59:01 +04:00
if ( seg_is_striped ( seg ) ) {
2003-04-25 02:23:24 +04:00
seg_stripesize = seg - > stripe_size ;
seg_stripes = seg - > area_count ;
}
2001-11-27 16:42:37 +03:00
2005-06-03 23:48:19 +04:00
if ( seg_is_mirrored ( seg ) )
2007-12-20 21:55:46 +03:00
seg_mirrors = lv_mirror_count ( seg - > lv ) ;
2005-06-03 23:48:19 +04:00
else
seg_mirrors = 0 ;
2004-05-11 22:47:40 +04:00
if ( lp - > extents < = extents_used + seg_extents )
2001-11-27 16:42:37 +03:00
break ;
extents_used + = seg_extents ;
}
2004-05-11 22:47:40 +04:00
seg_size = lp - > extents - extents_used ;
lp - > stripe_size = seg_stripesize ;
lp - > stripes = seg_stripes ;
2005-06-03 23:48:19 +04:00
lp - > mirrors = seg_mirrors ;
2001-11-27 16:42:37 +03:00
}
2004-05-11 22:47:40 +04:00
if ( lp - > stripes > 1 & & ! lp - > stripe_size ) {
2002-04-24 22:20:51 +04:00
log_error ( " Stripesize for striped segment should not be 0! " ) ;
2004-05-24 19:58:50 +04:00
return EINVALID_CMD_LINE ;
2002-05-31 23:29:43 +04:00
}
2002-11-18 17:04:08 +03:00
2004-05-11 22:47:40 +04:00
if ( ( lp - > stripes > 1 ) ) {
if ( ! ( stripesize_extents = lp - > stripe_size / vg - > extent_size ) )
2002-05-31 23:29:43 +04:00
stripesize_extents = 1 ;
2004-05-11 22:47:40 +04:00
if ( ( size_rest = seg_size % ( lp - > stripes * stripesize_extents ) ) ) {
2002-05-31 23:29:43 +04:00
log_print ( " Rounding size (%d extents) down to stripe "
" boundary size for segment (%d extents) " ,
2004-05-11 22:47:40 +04:00
lp - > extents , lp - > extents - size_rest ) ;
lp - > extents = lp - > extents - size_rest ;
2002-05-31 23:29:43 +04:00
}
2006-04-30 02:08:43 +04:00
if ( lp - > stripe_size < STRIPE_SIZE_MIN ) {
log_error ( " Invalid stripe size %s " ,
2006-05-10 01:23:51 +04:00
display_size ( cmd , ( uint64_t ) lp - > stripe_size ) ) ;
2007-09-07 01:08:16 +04:00
return EINVALID_CMD_LINE ;
2006-04-30 02:08:43 +04:00
}
2001-11-27 20:02:24 +03:00
}
2001-11-27 16:42:37 +03:00
2004-05-11 22:47:40 +04:00
if ( lp - > extents < lv - > le_count ) {
if ( lp - > resize = = LV_EXTEND ) {
2001-11-13 17:17:50 +03:00
log_error ( " New size given (%d extents) not larger "
" than existing size (%d extents) " ,
2004-05-11 22:47:40 +04:00
lp - > extents , lv - > le_count ) ;
2004-05-24 19:58:50 +04:00
return EINVALID_CMD_LINE ;
2009-02-24 18:48:00 +03:00
}
lp - > resize = LV_REDUCE ;
} else if ( lp - > extents > lv - > le_count ) {
2004-05-11 22:47:40 +04:00
if ( lp - > resize = = LV_REDUCE ) {
2001-11-13 17:17:50 +03:00
log_error ( " New size given (%d extents) not less than "
2004-05-11 22:47:40 +04:00
" existing size (%d extents) " , lp - > extents ,
2001-11-13 17:17:50 +03:00
lv - > le_count ) ;
2004-05-24 19:58:50 +04:00
return EINVALID_CMD_LINE ;
2009-02-24 18:48:00 +03:00
}
lp - > resize = LV_EXTEND ;
2001-11-13 17:17:50 +03:00
}
2005-04-07 16:17:46 +04:00
if ( lv_is_origin ( lv ) ) {
if ( lp - > resize = = LV_REDUCE ) {
log_error ( " Snapshot origin volumes cannot be reduced "
" in size yet. " ) ;
return ECMD_FAILED ;
}
memset ( & info , 0 , sizeof ( info ) ) ;
2007-11-12 23:51:54 +03:00
if ( lv_info ( cmd , lv , & info , 0 , 0 ) & & info . exists ) {
2005-04-07 16:17:46 +04:00
log_error ( " Snapshot origin volumes can be resized "
" only while inactive: try lvchange -an " ) ;
return ECMD_FAILED ;
}
}
2009-02-28 02:40:11 +03:00
if ( ( lp - > resize = = LV_REDUCE ) & & lp - > argc )
log_warn ( " Ignoring PVs on command line when reducing " ) ;
2001-11-13 17:17:50 +03:00
2009-02-28 02:40:11 +03:00
/* Request confirmation before operations that are often mistakes. */
if ( ( lp - > resizefs | | ( lp - > resize = = LV_REDUCE ) ) & &
! _request_confirmation ( cmd , vg , lv , lp ) ) {
stack ;
2009-02-28 22:43:42 +03:00
return ECMD_FAILED ;
2009-02-28 02:40:11 +03:00
}
2001-11-13 17:17:50 +03:00
2004-06-15 21:23:49 +04:00
if ( lp - > resizefs ) {
2009-02-28 02:40:11 +03:00
if ( ! lp - > nofsck & &
! _fsadm_cmd ( cmd , vg , lp , FSADM_CMD_CHECK ) ) {
2009-02-24 18:48:00 +03:00
stack ;
return ECMD_FAILED ;
}
2009-02-28 02:40:11 +03:00
if ( ( lp - > resize = = LV_REDUCE ) & &
! _fsadm_cmd ( cmd , vg , lp , FSADM_CMD_RESIZE ) ) {
2009-02-24 18:48:00 +03:00
stack ;
return ECMD_FAILED ;
}
2004-06-15 21:23:49 +04:00
}
2002-01-09 16:17:14 +03:00
2004-06-15 21:23:49 +04:00
if ( ! archive ( vg ) ) {
stack ;
return ECMD_FAILED ;
}
2001-11-13 17:17:50 +03:00
2004-06-15 21:23:49 +04:00
log_print ( " %sing logical volume %s to %s " ,
( lp - > resize = = LV_REDUCE ) ? " Reduc " : " Extend " ,
lp - > lv_name ,
2006-05-10 01:23:51 +04:00
display_size ( cmd , ( uint64_t ) lp - > extents * vg - > extent_size ) ) ;
2004-06-15 21:23:49 +04:00
if ( lp - > resize = = LV_REDUCE ) {
2005-05-09 20:59:01 +04:00
if ( ! lv_reduce ( lv , lv - > le_count - lp - > extents ) ) {
2004-05-24 19:58:50 +04:00
stack ;
return ECMD_FAILED ;
2004-05-11 22:47:40 +04:00
}
2009-02-28 02:40:11 +03:00
} else if ( ( lp - > extents > lv - > le_count ) & & /* Ensure we extend */
! lv_extend ( lv , lp - > segtype , lp - > stripes ,
2005-06-03 23:48:19 +04:00
lp - > stripe_size , lp - > mirrors ,
2005-05-09 20:59:01 +04:00
lp - > extents - lv - > le_count ,
NULL , 0u , 0u , pvh , alloc ) ) {
2004-06-15 21:23:49 +04:00
stack ;
return ECMD_FAILED ;
2001-11-13 17:17:50 +03:00
}
/* store vg on disk(s) */
2002-04-24 22:20:51 +04:00
if ( ! vg_write ( vg ) ) {
2003-07-05 02:34:56 +04:00
stack ;
2004-05-24 19:58:50 +04:00
return ECMD_FAILED ;
2002-02-21 00:30:27 +03:00
}
2001-11-13 17:17:50 +03:00
2003-07-05 02:34:56 +04:00
/* If snapshot, must suspend all associated devices */
2006-04-06 17:39:16 +04:00
if ( lv_is_cow ( lv ) )
lock_lv = origin_from_cow ( lv ) ;
2003-07-05 02:34:56 +04:00
else
2005-08-15 16:00:04 +04:00
lock_lv = lv ;
2003-07-05 02:34:56 +04:00
2005-08-15 16:00:04 +04:00
if ( ! suspend_lv ( cmd , lock_lv ) ) {
2004-05-11 22:47:40 +04:00
log_error ( " Failed to suspend %s " , lp - > lv_name ) ;
2003-07-05 02:34:56 +04:00
vg_revert ( vg ) ;
2009-04-21 18:31:57 +04:00
backup ( vg ) ;
2004-05-24 19:58:50 +04:00
return ECMD_FAILED ;
2003-07-05 02:34:56 +04:00
}
if ( ! vg_commit ( vg ) ) {
stack ;
2010-01-06 00:07:31 +03:00
if ( ! resume_lv ( cmd , lock_lv ) )
stack ;
2009-04-21 18:31:57 +04:00
backup ( vg ) ;
2004-05-24 19:58:50 +04:00
return ECMD_FAILED ;
2003-07-05 02:34:56 +04:00
}
2005-08-15 16:00:04 +04:00
if ( ! resume_lv ( cmd , lock_lv ) ) {
2004-05-11 22:47:40 +04:00
log_error ( " Problem reactivating %s " , lp - > lv_name ) ;
2009-04-21 18:31:57 +04:00
backup ( vg ) ;
2004-05-24 19:58:50 +04:00
return ECMD_FAILED ;
2002-02-21 00:30:27 +03:00
}
2001-11-13 17:17:50 +03:00
2009-04-21 18:31:57 +04:00
backup ( vg ) ;
2004-05-11 22:47:40 +04:00
log_print ( " Logical volume %s successfully resized " , lp - > lv_name ) ;
2001-11-13 17:17:50 +03:00
2009-02-28 02:40:11 +03:00
if ( lp - > resizefs & & ( lp - > resize = = LV_EXTEND ) & &
! _fsadm_cmd ( cmd , vg , lp , FSADM_CMD_RESIZE ) ) {
2009-02-24 18:48:00 +03:00
stack ;
return ECMD_FAILED ;
2004-06-15 21:23:49 +04:00
}
2003-10-22 02:06:07 +04:00
return ECMD_PROCESSED ;
2001-11-13 17:17:50 +03:00
}
2004-05-11 22:47:40 +04:00
int lvresize ( struct cmd_context * cmd , int argc , char * * argv )
{
struct lvresize_params lp ;
2007-11-15 05:20:03 +03:00
struct volume_group * vg ;
2004-05-11 22:47:40 +04:00
int r ;
memset ( & lp , 0 , sizeof ( lp ) ) ;
2006-04-19 19:33:07 +04:00
if ( ! _lvresize_params ( cmd , argc , argv , & lp ) )
2004-05-11 22:47:40 +04:00
return EINVALID_CMD_LINE ;
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 ) ;
if ( vg_read_error ( vg ) ) {
2009-07-07 05:18:35 +04:00
vg_release ( vg ) ;
2008-04-02 16:17:30 +04:00
stack ;
2004-05-11 22:47:40 +04:00
return ECMD_FAILED ;
2008-04-02 16:17:30 +04:00
}
2004-05-11 22:47:40 +04:00
2007-11-15 05:20:03 +03:00
if ( ! ( r = _lvresize ( cmd , vg , & lp ) ) )
2004-05-11 22:47:40 +04:00
stack ;
2009-05-21 07:04:52 +04:00
unlock_and_release_vg ( cmd , vg , lp . vg_name ) ;
2004-05-11 22:47:40 +04:00
return r ;
}