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 .
2004-03-30 23:35:44 +04:00
* Copyright ( C ) 2004 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
* of the GNU General Public License v .2 .
2001-11-13 17:17:50 +03:00
*
* You should have received a copy of the GNU 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 ;
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 ;
} ;
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 ;
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
2002-02-12 00:00:35 +03:00
if ( arg_count ( cmd , extents_ARG ) + arg_count ( cmd , size_ARG ) ! = 1 ) {
2001-11-13 17:17:50 +03:00
log_error ( " Please specify either size or extents (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 ) ;
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 ) ) {
2004-05-11 22:47:40 +04:00
lp - > size = arg_uint64_value ( cmd , size_ARG , UINT64_C ( 0 ) ) * 2 ;
lp - > sign = arg_sign_value ( cmd , size_ARG , SIGN_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
}
2004-06-15 21:23:49 +04:00
lp - > resizefs = arg_count ( cmd , resizefs_ARG ) ? 1 : 0 ;
lp - > nofsck = arg_count ( cmd , nofsck_ARG ) ? 1 : 0 ;
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 - - ;
2004-05-11 22:47:40 +04:00
if ( ! ( 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
}
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
2004-05-11 22:47:40 +04:00
static int _lvresize ( struct cmd_context * cmd , struct lvresize_params * lp )
{
struct volume_group * vg ;
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 ;
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 ;
int consistent = 1 ;
struct lv_segment * seg ;
uint32_t seg_extents ;
uint32_t sz , str ;
2004-05-24 19:58:50 +04:00
struct list * pvh = NULL ;
2004-06-15 21:23:49 +04:00
char size_buf [ SIZE_BUF ] ;
char lv_path [ PATH_MAX ] ;
2004-05-11 22:47:40 +04:00
2006-04-13 01:23:04 +04:00
if ( ! ( vg = vg_read ( cmd , lp - > vg_name , NULL , & consistent ) ) ) {
2004-05-11 22:47:40 +04:00
log_error ( " Volume group %s doesn't exist " , lp - > vg_name ) ;
2004-05-24 19:58:50 +04:00
return ECMD_FAILED ;
2001-11-13 17:17:50 +03:00
}
2002-02-12 00:00:35 +03:00
if ( vg - > status & EXPORTED_VG ) {
log_error ( " Volume group %s is exported " , vg - > name ) ;
2004-05-24 19:58:50 +04:00
return ECMD_FAILED ;
2002-02-12 00:00:35 +03:00
}
2002-01-29 20:23:33 +03:00
2002-02-12 00:00:35 +03:00
if ( ! ( vg - > status & LVM_WRITE ) ) {
2004-05-11 22:47:40 +04:00
log_error ( " Volume group %s is read-only " , lp - > vg_name ) ;
2004-05-24 19:58:50 +04:00
return ECMD_FAILED ;
2002-02-12 00:00:35 +03:00
}
2002-01-29 20:23:33 +03: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
log_print ( " Varied striping not supported. Ignoring. " ) ;
}
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
log_print ( " 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 " ) ;
return 0 ;
}
2005-06-03 23:48:19 +04:00
}
2002-04-24 22:20:51 +04:00
if ( arg_count ( cmd , stripesize_ARG ) ) {
2003-09-15 19:04:39 +04:00
if ( arg_sign_value ( cmd , stripesize_ARG , 0 ) = = SIGN_MINUS ) {
log_error ( " Stripesize may not be negative. " ) ;
2004-05-24 19:58:50 +04:00
return ECMD_FAILED ;
2003-09-15 19:04:39 +04:00
}
2006-04-30 02:08:43 +04:00
if ( arg_uint_value ( cmd , stripesize_ARG , 0 ) > STRIPE_SIZE_LIMIT ) {
log_error ( " Stripe size cannot be larger than %s " ,
2006-05-10 01:23:51 +04:00
display_size ( cmd , ( uint64_t ) STRIPE_SIZE_LIMIT ) ) ;
2006-04-30 02:08:43 +04:00
return 0 ;
}
if ( ! ( vg - > fid - > fmt - > features & FMT_SEGMENTS ) )
log_print ( " Varied stripesize not supported. Ignoring. " ) ;
else if ( arg_uint_value ( cmd , stripesize_ARG , 0 ) > vg - > extent_size ) {
log_error ( " Reducing stripe size %s to maximum, "
" physical extent size %s " ,
display_size ( cmd ,
2006-05-10 01:23:51 +04:00
( uint64_t ) arg_uint_value ( cmd , stripesize_ARG , 0 ) * 2 ) ,
display_size ( cmd , ( uint64_t ) vg - > extent_size ) ) ;
2006-04-30 02:08:43 +04:00
lp - > stripe_size = vg - > extent_size ;
} else
2004-05-11 22:47:40 +04:00
lp - > stripe_size = 2 * arg_uint_value ( cmd ,
stripesize_ARG , 0 ) ;
2006-04-30 02:08:43 +04:00
2005-06-03 23:48:19 +04:00
if ( lp - > mirrors ) {
log_error ( " Mirrors and striping cannot be combined yet. " ) ;
return ECMD_FAILED ;
}
2006-04-30 02:08:43 +04:00
if ( lp - > stripe_size & ( lp - > stripe_size - 1 ) ) {
log_error ( " Stripe size must be power of 2 " ) ;
return 0 ;
}
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
}
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
}
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 ) {
2001-11-13 17:17:50 +03:00
log_error ( " New size (%d extents) matches existing size "
2004-05-11 22:47:40 +04:00
" (%d extents) " , lp - > extents , lv - > le_count ) ;
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
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 */
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 ) ) ) {
2003-10-16 00:02:46 +04:00
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
2001-11-27 20:02:24 +03:00
if ( ( seg_stripesize & & seg_stripesize ! = sz
2004-05-11 22:47:40 +04:00
& & ! lp - > stripe_size ) | |
( 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 =
find_config_int ( cmd - > cft - > root ,
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 ) ) {
list_iterate_back_items ( seg , & lv - > segments ) {
if ( seg_is_mirrored ( seg ) )
seg_mirrors = seg - > area_count ;
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
2003-10-16 00:02:46 +04:00
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 ) )
seg_mirrors = seg - > area_count ;
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 ) ) ;
2006-04-30 02:08:43 +04:00
return 0 ;
}
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 ) {
2001-11-27 16:42:37 +03:00
log_error ( " New size (%d extents) matches existing size "
2004-05-11 22:47:40 +04:00
" (%d extents) " , lp - > extents , lv - > le_count ) ;
2004-05-24 19:58:50 +04:00
return EINVALID_CMD_LINE ;
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 ;
2001-11-13 17:17:50 +03:00
} else
2004-05-11 22:47:40 +04:00
lp - > resize = LV_REDUCE ;
2001-11-13 17:17:50 +03:00
}
2004-05-11 22:47:40 +04:00
if ( lp - > extents > lv - > le_count ) {
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 ;
2001-11-13 17:17:50 +03:00
} else
2004-05-11 22:47:40 +04:00
lp - > resize = LV_EXTEND ;
2001-11-13 17:17:50 +03:00
}
2005-06-04 02:26:09 +04:00
if ( lp - > mirrors & & activation ( ) & &
2005-10-17 22:00:02 +04:00
lv_info ( cmd , lv , & info , 0 ) & & info . exists ) {
2005-06-04 02:26:09 +04:00
log_error ( " Mirrors cannot be resized while active yet. " ) ;
return ECMD_FAILED ;
}
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 ) ) ;
2005-10-17 22:00:02 +04:00
if ( lv_info ( cmd , lv , & info , 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 ;
}
}
2004-05-11 22:47:40 +04:00
if ( lp - > resize = = LV_REDUCE ) {
if ( lp - > argc )
2001-11-13 17:17:50 +03:00
log_print ( " Ignoring PVs on command line when reducing " ) ;
2004-06-15 21:23:49 +04:00
} else if ( ! ( pvh = lp - > argc ? create_pv_list ( cmd - > mem , vg , lp - > argc ,
2004-08-18 01:55:23 +04:00
lp - > argv , 1 ) : & vg - > pvs ) ) {
2004-06-15 21:23:49 +04:00
stack ;
return ECMD_FAILED ;
}
2001-11-13 17:17:50 +03:00
2004-06-15 21:23:49 +04:00
if ( lp - > resize = = LV_REDUCE | | lp - > resizefs ) {
2002-04-24 22:20:51 +04:00
memset ( & info , 0 , sizeof ( info ) ) ;
2005-10-17 22:00:02 +04:00
if ( ! lv_info ( cmd , lv , & info , 1 ) & & driver_version ( NULL , 0 ) ) {
2002-04-24 22:20:51 +04:00
log_error ( " lv_info failed: aborting " ) ;
2004-05-24 19:58:50 +04:00
return ECMD_FAILED ;
2002-03-11 22:02:28 +03:00
}
2004-06-15 21:23:49 +04:00
if ( lp - > resizefs & & ! info . exists ) {
log_error ( " Logical volume %s must be activated "
" before resizing filesystem " , lp - > lv_name ) ;
return ECMD_FAILED ;
}
if ( info . exists & & ! lp - > resizefs & & ( lp - > resize = = LV_REDUCE ) ) {
2001-11-13 17:17:50 +03:00
log_print ( " WARNING: Reducing active%s logical volume "
2002-03-11 22:02:28 +03:00
" to %s " , info . open_count ? " and open " : " " ,
2004-05-11 22:47:40 +04:00
display_size ( cmd , ( uint64_t ) lp - > extents *
2006-05-10 01:23:51 +04:00
vg - > extent_size ) ) ;
2001-11-13 17:17:50 +03:00
log_print ( " THIS MAY DESTROY YOUR DATA "
" (filesystem etc.) " ) ;
2004-06-15 21:23:49 +04:00
if ( ! arg_count ( cmd , force_ARG ) ) {
if ( yes_no_prompt ( " Do you really want to "
" reduce %s? [y/n]: " ,
lp - > lv_name ) = = ' n ' ) {
log_print ( " Logical volume %s NOT "
" reduced " , lp - > lv_name ) ;
return ECMD_FAILED ;
}
2001-11-13 17:17:50 +03:00
}
}
2004-06-15 21:23:49 +04:00
}
2001-11-13 17:17:50 +03:00
2004-06-15 21:23:49 +04:00
if ( lp - > resizefs ) {
if ( lvm_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 ) ;
2004-05-24 19:58:50 +04:00
return ECMD_FAILED ;
2004-05-11 22:47:40 +04:00
}
2002-01-09 16:17:14 +03:00
2004-06-15 21:23:49 +04:00
if ( lvm_snprintf ( size_buf , SIZE_BUF , " % " PRIu64 ,
( uint64_t ) lp - > extents * vg - > extent_size / 2 )
< 0 ) {
log_error ( " Couldn't generate new LV size string " ) ;
2004-05-24 19:58:50 +04:00
return ECMD_FAILED ;
2004-06-15 21:23:49 +04:00
}
2001-11-13 17:17:50 +03:00
2004-06-15 21:23:49 +04:00
if ( ! lp - > nofsck ) {
if ( ! exec_cmd ( " fsadm " , " check " , lv_path , NULL ) ) {
stack ;
return ECMD_FAILED ;
}
2002-12-20 02:25:55 +03:00
}
2004-06-15 21:23:49 +04:00
if ( lp - > resize = = LV_REDUCE ) {
if ( ! exec_cmd ( " fsadm " , " resize " , lv_path , size_buf ) ) {
stack ;
return ECMD_FAILED ;
}
2004-05-11 22:47:40 +04:00
}
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
}
2005-05-09 20:59:01 +04:00
} else if ( ! 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
2002-02-12 00:00:35 +03:00
backup ( vg ) ;
2002-01-01 00:27:39 +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 ) ;
2004-05-24 19:58:50 +04:00
return ECMD_FAILED ;
2003-07-05 02:34:56 +04:00
}
if ( ! vg_commit ( vg ) ) {
stack ;
2005-08-15 16:00:04 +04:00
resume_lv ( cmd , lock_lv ) ;
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 ) ;
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
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
2004-06-15 21:23:49 +04:00
if ( lp - > resizefs & & ( lp - > resize = = LV_EXTEND ) ) {
if ( ! exec_cmd ( " fsadm " , " resize " , lv_path , size_buf ) ) {
stack ;
return ECMD_FAILED ;
}
}
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 ;
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 ) ;
if ( ! lock_vol ( cmd , lp . vg_name , LCK_VG_WRITE ) ) {
log_error ( " Can't get lock for %s " , lp . vg_name ) ;
return ECMD_FAILED ;
}
if ( ! ( r = _lvresize ( cmd , & lp ) ) )
stack ;
unlock_vg ( cmd , lp . vg_name ) ;
return r ;
}