2005-10-31 05:37:29 +03:00
/*
2008-01-30 17:00:02 +03:00
* Copyright ( C ) 2001 - 2004 Sistina Software , Inc . All rights reserved .
2005-10-31 05:37:29 +03:00
* Copyright ( C ) 2004 - 2005 Red Hat , Inc . All rights reserved .
* Copyright ( C ) 2005 Zak Kipling . All rights reserved .
*
* This file is part of LVM2 .
*
* 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 .
2005-10-31 05:37:29 +03:00
*
2007-08-21 00:55:30 +04:00
* You should have received a copy of the GNU Lesser General Public License
2005-10-31 05:37:29 +03:00
* along with this program ; if not , write to the Free Software Foundation ,
* Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*/
# include "tools.h"
struct pvresize_params {
uint64_t new_size ;
unsigned done ;
unsigned total ;
} ;
2007-11-17 00:16:20 +03:00
static int _pv_resize_single ( struct cmd_context * cmd ,
struct volume_group * vg ,
struct physical_volume * pv ,
const uint64_t new_size )
2007-11-16 01:11:18 +03:00
{
struct pv_list * pvl ;
uint64_t size = 0 ;
uint32_t new_pe_count = 0 ;
2009-04-10 14:01:38 +04:00
int r = 0 ;
2008-11-04 01:14:30 +03:00
struct dm_list mdas ;
2007-11-16 01:11:18 +03:00
const char * pv_name = pv_dev_name ( pv ) ;
const char * vg_name ;
2008-09-12 19:26:45 +04:00
struct lvmcache_info * info ;
int mda_count = 0 ;
2009-04-10 14:01:38 +04:00
struct volume_group * old_vg = vg ;
2007-11-16 01:11:18 +03:00
2008-11-04 01:14:30 +03:00
dm_list_init ( & mdas ) ;
2007-11-16 01:11:18 +03:00
if ( is_orphan_vg ( pv_vg_name ( pv ) ) ) {
vg_name = VG_ORPHANS ;
if ( ! lock_vol ( cmd , vg_name , LCK_VG_WRITE ) ) {
log_error ( " Can't get lock for orphans " ) ;
return 0 ;
}
2009-02-26 02:29:06 +03:00
if ( ! ( pv = pv_read ( cmd , pv_name , & mdas , NULL , 1 , 0 ) ) ) {
2007-11-16 01:11:18 +03:00
unlock_vg ( cmd , vg_name ) ;
log_error ( " Unable to read PV \" %s \" " , pv_name ) ;
return 0 ;
}
2008-11-04 01:14:30 +03:00
mda_count = dm_list_size ( & mdas ) ;
2007-11-16 01:11:18 +03:00
} else {
vg_name = pv_vg_name ( pv ) ;
2009-07-01 20:59:37 +04:00
vg = vg_read_for_update ( cmd , vg_name , NULL , 0 ) ;
2007-11-16 01:11:18 +03:00
2009-12-11 16:11:56 +03:00
if ( vg_read_error ( vg ) ) {
vg_release ( vg ) ;
log_error ( " Unable to read volume group \" %s \" . " ,
vg_name ) ;
return 0 ;
}
2007-11-16 01:11:18 +03:00
if ( ! ( pvl = find_pv_in_vg ( vg , pv_name ) ) ) {
log_error ( " Unable to find \" %s \" in volume group \" %s \" " ,
pv_name , vg - > name ) ;
2009-04-10 14:01:38 +04:00
goto bad ;
2007-11-16 01:11:18 +03:00
}
pv = pvl - > pv ;
2008-09-12 19:26:45 +04:00
if ( ! ( info = info_from_pvid ( pv - > dev - > pvid , 0 ) ) ) {
log_error ( " Can't get info for PV %s in volume group %s " ,
pv_name , vg - > name ) ;
2009-04-10 14:01:38 +04:00
goto bad ;
2008-09-12 19:26:45 +04:00
}
2008-11-04 01:14:30 +03:00
mda_count = dm_list_size ( & info - > mdas ) ;
2008-09-12 19:26:45 +04:00
2007-11-16 01:11:18 +03:00
if ( ! archive ( vg ) )
2009-04-10 14:01:38 +04:00
goto bad ;
2007-11-16 01:11:18 +03:00
}
2008-09-12 19:26:45 +04:00
/* FIXME Create function to test compatibility properly */
if ( mda_count > 1 ) {
log_error ( " %s: too many metadata areas for pvresize " , pv_name ) ;
2009-04-10 14:01:38 +04:00
goto bad ;
2008-09-12 19:26:45 +04:00
}
2007-11-16 01:11:18 +03:00
if ( ! ( pv - > fmt - > features & FMT_RESIZE_PV ) ) {
log_error ( " Physical volume %s format does not support resizing. " ,
pv_name ) ;
2009-04-10 14:01:38 +04:00
goto bad ;
2007-11-16 01:11:18 +03:00
}
/* Get new size */
if ( ! dev_get_size ( pv_dev ( pv ) , & size ) ) {
log_error ( " %s: Couldn't get size. " , pv_name ) ;
2009-04-10 14:01:38 +04:00
goto bad ;
2007-11-16 01:11:18 +03:00
}
2009-07-07 05:18:35 +04:00
2007-11-16 01:11:18 +03:00
if ( new_size ) {
if ( new_size > size )
log_warn ( " WARNING: %s: Overriding real size. "
" You could lose data. " , pv_name ) ;
log_verbose ( " %s: Pretending size is % " PRIu64 " not % " PRIu64
" sectors. " , pv_name , new_size , pv_size ( pv ) ) ;
size = new_size ;
}
if ( size < PV_MIN_SIZE ) {
log_error ( " %s: Size must exceed minimum of %ld sectors. " ,
pv_name , PV_MIN_SIZE ) ;
2009-04-10 14:01:38 +04:00
goto bad ;
2007-11-16 01:11:18 +03:00
}
if ( size < pv_pe_start ( pv ) ) {
log_error ( " %s: Size must exceed physical extent start of "
" % " PRIu64 " sectors. " , pv_name , pv_pe_start ( pv ) ) ;
2009-04-10 14:01:38 +04:00
goto bad ;
2007-11-16 01:11:18 +03:00
}
pv - > size = size ;
if ( vg ) {
pv - > size - = pv_pe_start ( pv ) ;
new_pe_count = pv_size ( pv ) / vg - > extent_size ;
2009-07-07 05:18:35 +04:00
2007-11-16 01:11:18 +03:00
if ( ! new_pe_count ) {
log_error ( " %s: Size must leave space for at "
" least one physical extent of "
" % " PRIu32 " sectors. " , pv_name ,
pv_pe_size ( pv ) ) ;
2009-04-10 14:01:38 +04:00
goto bad ;
2007-11-16 01:11:18 +03:00
}
2009-04-10 14:01:38 +04:00
if ( ! pv_resize ( pv , vg , new_pe_count ) )
goto_bad ;
2007-11-16 01:11:18 +03:00
}
log_verbose ( " Resizing volume \" %s \" to % " PRIu64 " sectors. " ,
pv_name , pv_size ( pv ) ) ;
log_verbose ( " Updating physical volume \" %s \" " , pv_name ) ;
if ( ! is_orphan_vg ( pv_vg_name ( pv ) ) ) {
if ( ! vg_write ( vg ) | | ! vg_commit ( vg ) ) {
log_error ( " Failed to store physical volume \" %s \" in "
" volume group \" %s \" " , pv_name , vg - > name ) ;
2009-04-10 14:01:38 +04:00
goto bad ;
2007-11-16 01:11:18 +03:00
}
backup ( vg ) ;
2009-04-10 14:01:38 +04:00
} else if ( ! ( pv_write ( cmd , pv , NULL , INT64_C ( - 1 ) ) ) ) {
log_error ( " Failed to store physical volume \" %s \" " ,
pv_name ) ;
goto bad ; ;
2007-11-16 01:11:18 +03:00
}
log_print ( " Physical volume \" %s \" changed " , pv_name ) ;
2009-04-10 14:01:38 +04:00
r = 1 ;
bad :
unlock_vg ( cmd , vg_name ) ;
if ( ! old_vg )
vg_release ( vg ) ;
return r ;
2007-11-16 01:11:18 +03:00
}
2007-08-31 00:16:01 +04:00
static int _pvresize_single ( struct cmd_context * cmd ,
struct volume_group * vg ,
struct physical_volume * pv ,
void * handle )
{
struct pvresize_params * params = ( struct pvresize_params * ) handle ;
params - > total + + ;
2005-10-31 05:37:29 +03:00
2009-09-15 02:47:49 +04:00
if ( ! _pv_resize_single ( cmd , vg , pv , params - > new_size ) ) {
stack ;
2007-08-31 00:16:01 +04:00
return ECMD_FAILED ;
2009-09-15 02:47:49 +04:00
}
2007-08-31 00:16:01 +04:00
2005-10-31 05:37:29 +03:00
params - > done + + ;
2007-08-31 00:16:01 +04:00
return ECMD_PROCESSED ;
2005-10-31 05:37:29 +03:00
}
int pvresize ( struct cmd_context * cmd , int argc , char * * argv )
{
struct pvresize_params params ;
int ret ;
if ( ! argc ) {
log_error ( " Please supply physical volume(s) " ) ;
return EINVALID_CMD_LINE ;
}
if ( arg_sign_value ( cmd , physicalvolumesize_ARG , 0 ) = = SIGN_MINUS ) {
log_error ( " Physical volume size may not be negative " ) ;
return 0 ;
}
params . new_size = arg_uint64_value ( cmd , physicalvolumesize_ARG ,
2007-11-14 03:08:25 +03:00
UINT64_C ( 0 ) ) ;
2005-10-31 05:37:29 +03:00
params . done = 0 ;
params . total = 0 ;
2009-07-15 09:50:22 +04:00
ret = process_each_pv ( cmd , argc , argv , NULL , READ_FOR_UPDATE , 0 , & params ,
2007-11-14 21:41:05 +03:00
_pvresize_single ) ;
2005-10-31 05:37:29 +03:00
log_print ( " %d physical volume(s) resized / %d physical volume(s) "
" not resized " , params . done , params . total - params . done ) ;
return ret ;
}