2005-10-31 05:37:29 +03:00
/*
* Copyright ( C ) 2001 - 2004 Sistina Software , Inc . All rights reserved .
* 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
* of the GNU General Public License v .2 .
*
* You should have received a copy of the GNU General Public License
* 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 ;
} ;
static int _pvresize_single ( struct cmd_context * cmd ,
struct volume_group * vg ,
struct physical_volume * pv ,
void * handle )
{
struct pv_list * pvl ;
int consistent = 1 ;
uint64_t size = 0 ;
uint32_t new_pe_count = 0 ;
struct list mdas ;
const char * pv_name = dev_name ( pv - > dev ) ;
struct pvresize_params * params = ( struct pvresize_params * ) handle ;
const char * vg_name ;
list_init ( & mdas ) ;
params - > total + + ;
if ( ! * pv - > vg_name ) {
vg_name = ORPHAN ;
if ( ! lock_vol ( cmd , vg_name , LCK_VG_WRITE ) ) {
log_error ( " Can't get lock for orphans " ) ;
return ECMD_FAILED ;
}
if ( ! ( pv = pv_read ( cmd , pv_name , & mdas , NULL , 1 ) ) ) {
unlock_vg ( cmd , vg_name ) ;
log_error ( " Unable to read PV \" %s \" " , pv_name ) ;
return ECMD_FAILED ;
}
/* FIXME Create function to test compatibility properly */
if ( list_size ( & mdas ) > 1 ) {
log_error ( " %s: too many metadata areas for pvresize " ,
pv_name ) ;
unlock_vg ( cmd , vg_name ) ;
return ECMD_FAILED ;
}
} else {
vg_name = pv - > vg_name ;
if ( ! lock_vol ( cmd , vg_name , LCK_VG_WRITE ) ) {
log_error ( " Can't get lock for %s " , pv - > vg_name ) ;
return ECMD_FAILED ;
}
2006-04-13 01:23:04 +04:00
if ( ! ( vg = vg_read ( cmd , vg_name , NULL , & consistent ) ) ) {
2005-10-31 05:37:29 +03:00
unlock_vg ( cmd , vg_name ) ;
log_error ( " Unable to find volume group of \" %s \" " ,
pv_name ) ;
return ECMD_FAILED ;
}
2006-09-02 05:18:17 +04:00
if ( ( vg - > status & CLUSTERED ) & & ! locking_is_clustered ( ) & &
! lockingfailed ( ) ) {
unlock_vg ( cmd , vg_name ) ;
log_error ( " Skipping clustered volume group %s " , vg - > name ) ;
return ECMD_FAILED ;
}
2005-10-31 05:37:29 +03:00
if ( vg - > status & EXPORTED_VG ) {
unlock_vg ( cmd , vg_name ) ;
log_error ( " Volume group \" %s \" is exported " , vg - > name ) ;
return ECMD_FAILED ;
}
if ( ! ( vg - > status & LVM_WRITE ) ) {
unlock_vg ( cmd , pv - > vg_name ) ;
log_error ( " Volume group \" %s \" is read-only " , vg - > name ) ;
return ECMD_FAILED ;
}
if ( ! ( pvl = find_pv_in_vg ( vg , pv_name ) ) ) {
unlock_vg ( cmd , vg_name ) ;
log_error ( " Unable to find \" %s \" in volume group \" %s \" " ,
pv_name , vg - > name ) ;
return ECMD_FAILED ;
}
pv = pvl - > pv ;
if ( ! archive ( vg ) )
return ECMD_FAILED ;
}
if ( ! ( pv - > fmt - > features & FMT_RESIZE_PV ) ) {
log_error ( " Physical volume %s format does not support resizing. " ,
pv_name ) ;
unlock_vg ( cmd , vg_name ) ;
return ECMD_FAILED ;
}
/* Get new size */
if ( ! dev_get_size ( pv - > dev , & size ) ) {
log_error ( " %s: Couldn't get size. " , pv_name ) ;
unlock_vg ( cmd , vg_name ) ;
return ECMD_FAILED ;
}
if ( params - > new_size ) {
if ( params - > new_size > size )
log_print ( " WARNING: %s: Overriding real size. "
" You could lose data. " , pv_name ) ;
log_verbose ( " %s: Pretending size is % " PRIu64 " not % " PRIu64
" sectors. " , pv_name , params - > new_size , pv - > size ) ;
size = params - > new_size ;
}
if ( size < PV_MIN_SIZE ) {
log_error ( " %s: Size must exceed minimum of %ld sectors. " ,
pv_name , PV_MIN_SIZE ) ;
unlock_vg ( cmd , vg_name ) ;
return ECMD_FAILED ;
}
if ( size < pv - > pe_start ) {
log_error ( " %s: Size must exceed physical extent start of "
" % " PRIu64 " sectors. " , pv_name , pv - > pe_start ) ;
unlock_vg ( cmd , vg_name ) ;
return ECMD_FAILED ;
}
pv - > size = size ;
if ( vg ) {
pv - > size - = pv - > pe_start ;
new_pe_count = pv - > size / vg - > extent_size ;
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 ) ;
unlock_vg ( cmd , vg_name ) ;
return ECMD_FAILED ;
}
if ( ! pv_resize ( pv , vg , new_pe_count ) ) {
stack ;
unlock_vg ( cmd , vg_name ) ;
return ECMD_FAILED ;
}
}
log_verbose ( " Resizing volume \" %s \" to % " PRIu64 " sectors. " ,
pv_name , pv - > size ) ;
log_verbose ( " Updating physical volume \" %s \" " , pv_name ) ;
if ( * pv - > vg_name ) {
if ( ! vg_write ( vg ) | | ! vg_commit ( vg ) ) {
unlock_vg ( cmd , pv - > vg_name ) ;
log_error ( " Failed to store physical volume \" %s \" in "
" volume group \" %s \" " , pv_name , vg - > name ) ;
return ECMD_FAILED ;
}
backup ( vg ) ;
unlock_vg ( cmd , vg_name ) ;
} else {
if ( ! ( pv_write ( cmd , pv , NULL , INT64_C ( - 1 ) ) ) ) {
unlock_vg ( cmd , ORPHAN ) ;
log_error ( " Failed to store physical volume \" %s \" " ,
pv_name ) ;
return ECMD_FAILED ;
}
unlock_vg ( cmd , vg_name ) ;
}
log_print ( " Physical volume \" %s \" changed " , pv_name ) ;
params - > done + + ;
return 1 ;
}
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 ,
UINT64_C ( 0 ) ) * 2 ;
params . done = 0 ;
params . total = 0 ;
ret = process_each_pv ( cmd , argc , argv , NULL , & params , _pvresize_single ) ;
log_print ( " %d physical volume(s) resized / %d physical volume(s) "
" not resized " , params . done , params . total - params . done ) ;
return ret ;
}