2001-11-27 20:02:24 +03:00
/*
2008-01-30 17:00:02 +03:00
* Copyright ( C ) 2001 - 2004 Sistina Software , Inc . All rights reserved .
2009-05-13 17:02:52 +04:00
* Copyright ( C ) 2004 - 2009 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
2007-08-21 00:55:30 +04:00
* of the GNU Lesser General Public License v .2 .1 .
2001-11-27 20:02:24 +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-27 20:02:24 +03:00
*/
# include "tools.h"
2009-09-03 01:28:27 +04:00
static struct volume_group * _vgmerge_vg_read ( struct cmd_context * cmd ,
const char * vg_name )
2009-09-03 01:28:10 +04:00
{
2009-09-03 01:28:27 +04:00
struct volume_group * vg ;
log_verbose ( " Checking for volume group \" %s \" " , vg_name ) ;
vg = vg_read_for_update ( cmd , vg_name , NULL , 0 ) ;
if ( vg_read_error ( vg ) ) {
vg_release ( vg ) ;
2009-09-03 01:28:10 +04:00
return NULL ;
}
2009-09-03 01:28:27 +04:00
return vg ;
2009-09-03 01:28:10 +04:00
}
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
{
2010-04-13 21:26:03 +04:00
struct pv_list * pvl , * tpvl ;
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 ;
2009-04-10 14:01:38 +04:00
int r = ECMD_FAILED ;
2009-09-03 01:27:55 +04:00
int lock_vg_from_first = 0 ;
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 ;
}
2009-09-03 01:28:43 +04:00
if ( strcmp ( vg_name_to , vg_name_from ) > 0 )
lock_vg_from_first = 1 ;
2002-01-29 20:23:33 +03:00
2009-09-03 01:28:43 +04:00
if ( lock_vg_from_first ) {
vg_from = _vgmerge_vg_read ( cmd , vg_name_from ) ;
2009-09-15 02:47:49 +04:00
if ( ! vg_from ) {
stack ;
2009-09-03 01:28:43 +04:00
return ECMD_FAILED ;
2009-09-15 02:47:49 +04:00
}
2009-09-03 01:28:43 +04:00
vg_to = _vgmerge_vg_read ( cmd , vg_name_to ) ;
if ( ! vg_to ) {
2009-09-15 02:47:49 +04:00
stack ;
2009-09-03 01:28:43 +04:00
unlock_and_release_vg ( cmd , vg_from , vg_name_from ) ;
return ECMD_FAILED ;
}
} else {
vg_to = _vgmerge_vg_read ( cmd , vg_name_to ) ;
2009-09-15 02:47:49 +04:00
if ( ! vg_to ) {
stack ;
2009-09-03 01:28:43 +04:00
return ECMD_FAILED ;
2009-09-15 02:47:49 +04:00
}
2009-09-03 01:28:43 +04:00
vg_from = _vgmerge_vg_read ( cmd , vg_name_from ) ;
if ( ! vg_from ) {
2009-09-15 02:47:49 +04:00
stack ;
2009-09-03 01:28:43 +04:00
unlock_and_release_vg ( cmd , vg_to , vg_name_to ) ;
return ECMD_FAILED ;
}
2002-02-11 18:42:34 +03:00
}
2008-01-16 22:54:39 +03:00
if ( ! vgs_are_compatible ( cmd , vg_from , vg_to ) )
2008-01-30 16:19:47 +03:00
goto_bad ;
2005-10-25 23:08:21 +04:00
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 ) )
2008-01-30 16:19:47 +03:00
goto_bad ;
2002-01-09 16:17:14 +03:00
2008-06-06 23:32:35 +04:00
drop_cached_metadata ( vg_from ) ;
2001-11-27 20:02:24 +03:00
/* Merge volume groups */
2010-04-13 21:26:03 +04:00
dm_list_iterate_items_safe ( pvl , tpvl , & vg_from - > pvs ) {
del_pvl_from_vgs ( vg_from , pvl ) ;
add_pvl_to_vgs ( vg_to , pvl ) ;
pvl - > pv - > vg_name = dm_pool_strdup ( cmd - > mem , vg_to - > name ) ;
2001-11-27 20:02:24 +03:00
}
2005-05-19 20:48:51 +04:00
/* Fix up LVIDs */
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( lvl1 , & vg_to - > lvs ) {
2005-05-19 20:48:51 +04:00
union lvid * lvid1 = & lvl1 - > lv - > lvid ;
2006-12-01 02:11:42 +03:00
char uuid [ 64 ] __attribute ( ( aligned ( 8 ) ) ) ;
2005-05-19 20:48:51 +04:00
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( lvl2 , & vg_from - > lvs ) {
2005-05-19 20:48:51 +04:00
union lvid * lvid2 = & lvl2 - > lv - > lvid ;
2008-01-30 17:00:02 +03:00
if ( id_equal ( & lvid1 - > id [ 1 ] , & lvid2 - > id [ 1 ] ) ) {
2005-05-19 20:48:51 +04:00
if ( ! id_create ( & lvid2 - > id [ 1 ] ) ) {
log_error ( " Failed to generate new "
" random LVID for %s " ,
lvl2 - > lv - > name ) ;
2008-01-30 16:19:47 +03:00
goto bad ;
2005-05-19 20:48:51 +04:00
}
2008-01-30 17:00:02 +03:00
if ( ! id_write_format ( & lvid2 - > id [ 1 ] , uuid ,
2008-01-30 16:19:47 +03:00
sizeof ( uuid ) ) )
2008-01-30 17:00:02 +03:00
goto_bad ;
2005-05-19 20:48:51 +04:00
log_verbose ( " Changed LVID for %s to %s " ,
lvl2 - > lv - > name , uuid ) ;
}
}
}
2008-01-30 17:00:02 +03:00
2008-11-04 01:14:30 +03:00
while ( ! dm_list_empty ( & vg_from - > lvs ) ) {
struct dm_list * lvh = vg_from - > lvs . n ;
2001-11-28 16:45:50 +03:00
2008-11-04 01:14:30 +03:00
dm_list_move ( & vg_to - > lvs , lvh ) ;
2001-11-27 20:02:24 +03:00
}
2002-11-18 17:04:08 +03:00
2010-06-29 00:32:44 +04:00
while ( ! dm_list_empty ( & vg_from - > fid - > metadata_areas_in_use ) ) {
struct dm_list * mdah = vg_from - > fid - > metadata_areas_in_use . n ;
2002-11-18 17:04:08 +03:00
2010-06-29 00:32:44 +04:00
dm_list_move ( & vg_to - > fid - > metadata_areas_in_use , mdah ) ;
2002-11-18 17:04:08 +03:00
}
2001-11-27 20:02:24 +03:00
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 " ) ;
2008-01-30 16:19:47 +03:00
if ( ! vg_write ( vg_to ) | | ! vg_commit ( vg_to ) )
goto_bad ;
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-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 ) ;
2009-04-10 14:01:38 +04:00
r = ECMD_PROCESSED ;
bad :
2009-09-03 01:27:55 +04:00
if ( lock_vg_from_first ) {
unlock_and_release_vg ( cmd , vg_to , vg_name_to ) ;
unlock_and_release_vg ( cmd , vg_from , vg_name_from ) ;
} else {
unlock_and_release_vg ( cmd , vg_from , vg_name_from ) ;
unlock_and_release_vg ( cmd , vg_to , vg_name_to ) ;
}
2009-04-10 14:01:38 +04:00
return r ;
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 )
{
2006-08-26 03:02:33 +04:00
char * vg_name_to , * vg_name_from ;
2002-11-18 17:04:08 +03:00
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 ;
}
2007-03-09 23:47:41 +03:00
vg_name_to = skip_dev_dir ( cmd , argv [ 0 ] , NULL ) ;
2002-11-18 17:04:08 +03:00
argc - - ;
argv + + ;
for ( ; opt < argc ; opt + + ) {
2007-03-09 23:47:41 +03:00
vg_name_from = skip_dev_dir ( cmd , argv [ opt ] , NULL ) ;
2006-08-26 03:02:33 +04:00
ret = _vgmerge_single ( cmd , vg_name_to , vg_name_from ) ;
2002-11-18 17:04:08 +03:00
if ( ret > ret_max )
ret_max = ret ;
}
return ret_max ;
}