2001-11-27 20:02:24 +03:00
/*
2004-03-30 23:35:44 +04:00
* Copyright ( C ) 2001 - 2004 Sistina Software , Inc . All rights reserved .
* Copyright ( C ) 2004 Red Hat , Inc . All rights reserved .
2001-11-27 20:02:24 +03:00
*
2004-03-30 23:35:44 +04:00
* This file is part of LVM2 .
2001-11-27 20:02:24 +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-27 20:02:24 +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-27 20:02:24 +03:00
*/
# include "tools.h"
2002-12-20 02:25:55 +03:00
static int _vgmerge_single ( struct cmd_context * cmd , const char * vg_name_to ,
const char * vg_name_from )
2001-11-27 20:02:24 +03:00
{
struct volume_group * vg_to , * vg_from ;
2003-10-16 00:02:46 +04:00
struct lv_list * lvl1 , * lvl2 ;
2005-10-25 23:08:21 +04:00
struct pv_list * pvl ;
2002-01-11 02:21:07 +03:00
int active ;
2002-11-18 17:04:08 +03:00
int consistent = 1 ;
2001-11-27 20:02:24 +03:00
if ( ! strcmp ( vg_name_to , vg_name_from ) ) {
2002-01-30 18:04:48 +03:00
log_error ( " Duplicate volume group name \" %s \" " , vg_name_from ) ;
2001-11-27 20:02:24 +03:00
return ECMD_FAILED ;
}
2002-01-30 18:04:48 +03:00
log_verbose ( " Checking for volume group \" %s \" " , vg_name_to ) ;
2002-02-27 15:26:41 +03:00
if ( ! lock_vol ( cmd , vg_name_to , LCK_VG_WRITE ) ) {
2002-02-11 18:42:34 +03:00
log_error ( " Can't get lock for %s " , vg_name_to ) ;
return ECMD_FAILED ;
}
2002-11-18 17:04:08 +03:00
if ( ! ( vg_to = vg_read ( cmd , vg_name_to , & consistent ) ) | | ! consistent ) {
2002-01-30 18:04:48 +03:00
log_error ( " Volume group \" %s \" doesn't exist " , vg_name_to ) ;
2002-03-11 18:08:39 +03:00
unlock_vg ( cmd , vg_name_to ) ;
2001-11-27 20:02:24 +03:00
return ECMD_FAILED ;
}
2002-02-12 00:00:35 +03:00
if ( vg_to - > status & EXPORTED_VG ) {
log_error ( " Volume group \" %s \" is exported " , vg_to - > name ) ;
2002-03-11 18:08:39 +03:00
unlock_vg ( cmd , vg_name_to ) ;
2002-02-12 00:00:35 +03:00
return ECMD_FAILED ;
}
2002-01-29 20:23:33 +03:00
if ( ! ( vg_to - > status & LVM_WRITE ) ) {
2002-01-30 18:04:48 +03:00
log_error ( " Volume group \" %s \" is read-only " , vg_to - > name ) ;
2002-03-11 18:08:39 +03:00
unlock_vg ( cmd , vg_name_to ) ;
2002-01-29 20:23:33 +03:00
return ECMD_FAILED ;
}
2002-01-30 18:04:48 +03:00
log_verbose ( " Checking for volume group \" %s \" " , vg_name_from ) ;
2002-02-27 15:26:41 +03:00
if ( ! lock_vol ( cmd , vg_name_from , LCK_VG_WRITE | LCK_NONBLOCK ) ) {
2002-02-11 18:42:34 +03:00
log_error ( " Can't get lock for %s " , vg_name_from ) ;
2002-03-11 18:08:39 +03:00
unlock_vg ( cmd , vg_name_to ) ;
2002-02-11 18:42:34 +03:00
return ECMD_FAILED ;
}
2002-11-18 17:04:08 +03:00
consistent = 1 ;
if ( ! ( vg_from = vg_read ( cmd , vg_name_from , & consistent ) ) | | ! consistent ) {
2002-01-30 18:04:48 +03:00
log_error ( " Volume group \" %s \" doesn't exist " , vg_name_from ) ;
2002-02-11 18:42:34 +03:00
goto error ;
2001-11-27 20:02:24 +03:00
}
2002-02-12 00:00:35 +03:00
if ( vg_from - > status & EXPORTED_VG ) {
log_error ( " Volume group \" %s \" is exported " , vg_from - > name ) ;
goto error ;
}
2002-01-29 20:23:33 +03:00
if ( ! ( vg_from - > status & LVM_WRITE ) ) {
2002-01-30 18:04:48 +03:00
log_error ( " Volume group \" %s \" is read-only " , vg_from - > name ) ;
2002-02-11 18:42:34 +03:00
goto error ;
2002-01-29 20:23:33 +03:00
}
2002-01-11 02:21:07 +03:00
if ( ( active = lvs_in_vg_activated ( vg_from ) ) ) {
2002-01-30 18:04:48 +03:00
log_error ( " Logical volumes in \" %s \" must be inactive " ,
2002-01-11 02:21:07 +03:00
vg_name_from ) ;
2002-02-11 18:42:34 +03:00
goto error ;
2001-11-27 20:02:24 +03:00
}
/* Check compatibility */
if ( vg_to - > extent_size ! = vg_from - > extent_size ) {
log_error ( " Extent sizes differ: %d (%s) and %d (%s) " ,
vg_to - > extent_size , vg_to - > name ,
vg_from - > extent_size , vg_from - > name ) ;
2002-02-11 18:42:34 +03:00
goto error ;
2001-11-27 20:02:24 +03:00
}
2003-11-06 23:33:34 +03:00
if ( vg_to - > max_pv & &
( vg_to - > max_pv < vg_to - > pv_count + vg_from - > pv_count ) ) {
2001-11-27 20:02:24 +03:00
log_error ( " Maximum number of physical volumes (%d) exceeded "
2002-01-30 18:04:48 +03:00
" for \" %s \" and \" %s \" " , vg_to - > max_pv , vg_to - > name ,
2001-11-27 20:02:24 +03:00
vg_from - > name ) ;
2002-02-11 18:42:34 +03:00
goto error ;
2001-11-27 20:02:24 +03:00
}
2003-11-06 23:33:34 +03:00
if ( vg_to - > max_lv & &
( vg_to - > max_lv < vg_to - > lv_count + vg_from - > lv_count ) ) {
2001-11-27 20:02:24 +03:00
log_error ( " Maximum number of logical volumes (%d) exceeded "
2002-01-30 18:04:48 +03:00
" for \" %s \" and \" %s \" " , vg_to - > max_lv , vg_to - > name ,
2001-11-27 20:02:24 +03:00
vg_from - > name ) ;
2002-02-11 18:42:34 +03:00
goto error ;
2001-11-27 20:02:24 +03:00
}
/* Check no conflicts with LV names */
2003-10-16 00:02:46 +04:00
list_iterate_items ( lvl1 , & vg_to - > lvs ) {
char * name1 = lvl1 - > lv - > name ;
list_iterate_items ( lvl2 , & vg_from - > lvs ) {
char * name2 = lvl2 - > lv - > name ;
2002-01-21 19:49:32 +03:00
2001-11-27 20:02:24 +03:00
if ( ! strcmp ( name1 , name2 ) ) {
2002-01-30 20:25:51 +03:00
log_error ( " Duplicate logical volume "
2002-01-30 18:04:48 +03:00
" name \" %s \" "
" in \" %s \" and \" %s \" " ,
2002-02-12 00:00:35 +03:00
name1 , vg_to - > name , vg_from - > name ) ;
2002-02-11 18:42:34 +03:00
goto error ;
2001-11-27 20:02:24 +03:00
}
}
}
2005-10-25 23:08:21 +04:00
/* Check no PVs are constructed from either VG */
list_iterate_items ( pvl , & vg_to - > pvs ) {
if ( pv_uses_vg ( cmd , pvl - > pv , vg_from ) ) {
log_error ( " Physical volume %s might be constructed "
" from same volume group %s. " ,
dev_name ( pvl - > pv - > dev ) , vg_from - > name ) ;
goto error ;
}
}
list_iterate_items ( pvl , & vg_from - > pvs ) {
if ( pv_uses_vg ( cmd , pvl - > pv , vg_to ) ) {
log_error ( " Physical volume %s might be constructed "
" from same volume group %s. " ,
dev_name ( pvl - > pv - > dev ) , vg_to - > name ) ;
goto error ;
}
}
2001-11-27 20:02:24 +03:00
/* FIXME List arg: vg_show_with_pv_and_lv(vg_to); */
2002-01-09 16:17:14 +03:00
if ( ! archive ( vg_from ) | | ! archive ( vg_to ) )
2002-02-11 18:42:34 +03:00
goto error ;
2002-01-09 16:17:14 +03:00
2001-11-27 20:02:24 +03:00
/* Merge volume groups */
while ( ! list_empty ( & vg_from - > pvs ) ) {
2001-11-28 16:45:50 +03:00
struct list * pvh = vg_from - > pvs . n ;
struct physical_volume * pv ;
list_del ( pvh ) ;
list_add ( & vg_to - > pvs , pvh ) ;
2002-01-21 19:05:23 +03:00
pv = list_item ( pvh , struct pv_list ) - > pv ;
2005-10-17 03:03:59 +04:00
pv - > vg_name = dm_pool_strdup ( cmd - > mem , vg_to - > name ) ;
2001-11-27 20:02:24 +03:00
}
vg_to - > pv_count + = vg_from - > pv_count ;
2005-05-19 20:48:51 +04:00
/* Fix up LVIDs */
list_iterate_items ( lvl1 , & vg_to - > lvs ) {
union lvid * lvid1 = & lvl1 - > lv - > lvid ;
char uuid [ 64 ] ;
list_iterate_items ( lvl2 , & vg_from - > lvs ) {
union lvid * lvid2 = & lvl2 - > lv - > lvid ;
if ( id_equal ( & lvid1 - > id [ 1 ] , & lvid2 - > id [ 1 ] ) ) {
if ( ! id_create ( & lvid2 - > id [ 1 ] ) ) {
log_error ( " Failed to generate new "
" random LVID for %s " ,
lvl2 - > lv - > name ) ;
goto error ;
}
if ( ! id_write_format ( & lvid2 - > id [ 1 ] , uuid ,
sizeof ( uuid ) ) ) {
stack ;
goto error ;
}
log_verbose ( " Changed LVID for %s to %s " ,
lvl2 - > lv - > name , uuid ) ;
}
}
}
2001-11-27 20:02:24 +03:00
while ( ! list_empty ( & vg_from - > lvs ) ) {
2001-11-28 16:45:50 +03:00
struct list * lvh = vg_from - > lvs . n ;
list_del ( lvh ) ;
list_add ( & vg_to - > lvs , lvh ) ;
2001-11-27 20:02:24 +03:00
}
2002-11-18 17:04:08 +03:00
while ( ! list_empty ( & vg_from - > fid - > metadata_areas ) ) {
struct list * mdah = vg_from - > fid - > metadata_areas . n ;
list_del ( mdah ) ;
list_add ( & vg_to - > fid - > metadata_areas , mdah ) ;
}
2001-11-27 20:02:24 +03:00
vg_to - > lv_count + = vg_from - > lv_count ;
vg_to - > extent_count + = vg_from - > extent_count ;
vg_to - > free_count + = vg_from - > free_count ;
/* store it on disks */
log_verbose ( " Writing out updated volume group " ) ;
2003-07-05 02:34:56 +04:00
if ( ! vg_write ( vg_to ) | | ! vg_commit ( vg_to ) ) {
2002-02-11 18:42:34 +03:00
goto error ;
2001-11-27 20:02:24 +03:00
}
/* FIXME Remove /dev/vgfrom */
2002-01-07 14:12:11 +03:00
backup ( vg_to ) ;
2002-01-01 00:27:39 +03:00
2002-03-11 18:08:39 +03:00
unlock_vg ( cmd , vg_name_from ) ;
unlock_vg ( cmd , vg_name_to ) ;
2002-02-11 18:42:34 +03:00
2002-01-30 18:04:48 +03:00
log_print ( " Volume group \" %s \" successfully merged into \" %s \" " ,
2001-11-27 20:02:24 +03:00
vg_from - > name , vg_to - > name ) ;
2003-10-22 02:06:07 +04:00
return ECMD_PROCESSED ;
2002-02-11 18:42:34 +03:00
error :
2002-03-11 18:08:39 +03:00
unlock_vg ( cmd , vg_name_from ) ;
unlock_vg ( cmd , vg_name_to ) ;
2002-02-11 18:42:34 +03:00
return ECMD_FAILED ;
2001-11-27 20:02:24 +03:00
}
2002-11-18 17:04:08 +03:00
int vgmerge ( struct cmd_context * cmd , int argc , char * * argv )
{
char * vg_name_to ;
int opt = 0 ;
int ret = 0 , ret_max = 0 ;
if ( argc < 2 ) {
log_error ( " Please enter 2 or more volume groups to merge " ) ;
return EINVALID_CMD_LINE ;
}
vg_name_to = argv [ 0 ] ;
argc - - ;
argv + + ;
for ( ; opt < argc ; opt + + ) {
2002-12-20 02:25:55 +03:00
ret = _vgmerge_single ( cmd , vg_name_to , argv [ opt ] ) ;
2002-11-18 17:04:08 +03:00
if ( ret > ret_max )
ret_max = ret ;
}
return ret_max ;
}