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 ) ) {
2011-08-11 00:25:29 +04:00
release_vg ( 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
}
2013-07-09 14:01:25 +04:00
/* Select bigger pool metadata spare volume */
static int _vgmerge_select_pool_metadata_spare ( struct cmd_context * cmd ,
struct volume_group * vg_to ,
struct volume_group * vg_from )
{
struct volume_group * svg ;
if ( ! vg_to - > pool_metadata_spare_lv | |
! vg_from - > pool_metadata_spare_lv )
return 1 ; /* no problem */
/* Drop smaller pool metadata spare */
svg = ( vg_to - > pool_metadata_spare_lv - > le_count <
vg_from - > pool_metadata_spare_lv - > le_count ) ? vg_to : vg_from ;
vg_remove_pool_metadata_spare ( svg ) ;
/* Re-test lv name compatibility */
if ( ! vgs_are_compatible ( cmd , vg_from , vg_to ) )
return_0 ;
return 1 ;
}
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 ) {
2013-07-01 13:27:22 +04:00
if ( ! ( vg_from = _vgmerge_vg_read ( cmd , vg_name_from ) ) )
return_ECMD_FAILED ;
if ( ! ( vg_to = _vgmerge_vg_read ( cmd , vg_name_to ) ) ) {
2011-08-11 00:25:29 +04:00
unlock_and_release_vg ( cmd , vg_from , vg_name_from ) ;
2013-07-01 13:27:22 +04:00
return_ECMD_FAILED ;
2009-09-03 01:28:43 +04:00
}
} else {
2013-07-01 13:27:22 +04:00
if ( ! ( vg_to = _vgmerge_vg_read ( cmd , vg_name_to ) ) )
return_ECMD_FAILED ;
2009-09-03 01:28:43 +04:00
2013-07-01 13:27:22 +04:00
if ( ! ( vg_from = _vgmerge_vg_read ( cmd , vg_name_from ) ) ) {
2011-08-11 00:25:29 +04:00
unlock_and_release_vg ( cmd , vg_to , vg_name_to ) ;
2013-07-01 13:27:22 +04:00
return_ECMD_FAILED ;
2009-09-03 01:28:43 +04:00
}
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
2012-03-02 01:16:44 +04:00
if ( ! drop_cached_metadata ( vg_from ) )
stack ;
2008-06-06 23:32:35 +04:00
2013-07-09 14:01:25 +04:00
if ( ! _vgmerge_select_pool_metadata_spare ( cmd , vg_to , vg_from ) )
goto_bad ;
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 ;
2010-07-09 19:34:40 +04: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
2010-12-14 20:51:09 +03:00
dm_list_iterate_items ( lvl1 , & vg_from - > lvs ) {
lvl1 - > lv - > vg = vg_to ;
2014-07-03 22:06:04 +04:00
lvl1 - > lv - > lvid . id [ 0 ] = lvl1 - > lv - > vg - > id ;
2010-12-14 20:51:09 +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
}
2010-06-29 00:39:08 +04:00
while ( ! dm_list_empty ( & vg_from - > fid - > metadata_areas_ignored ) ) {
struct dm_list * mdah = vg_from - > fid - > metadata_areas_ignored . n ;
dm_list_move ( & vg_to - > fid - > metadata_areas_ignored , mdah ) ;
}
2013-07-09 14:01:25 +04:00
if ( ! vg_to - > pool_metadata_spare_lv )
vg_to - > pool_metadata_spare_lv =
vg_from - > pool_metadata_spare_lv ;
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 ) ;
config: add silent mode
Accept -q as the short form of --quiet.
Suppress non-essential standard output if -q is given twice.
Treat log/silent in lvm.conf as equivalent to -qq.
Review all log_print messages and change some to
log_print_unless_silent.
When silent, the following commands still produce output:
dumpconfig, lvdisplay, lvmdiskscan, lvs, pvck, pvdisplay,
pvs, version, vgcfgrestore -l, vgdisplay, vgs.
[Needs checking.]
Non-essential messages are shifted from log level 4 to log level 5
for syslog and lvm2_log_fn purposes.
2012-08-25 23:35:48 +04:00
log_print_unless_silent ( " Volume group \" %s \" successfully merged into \" %s \" " ,
vg_from - > name , vg_to - > name ) ;
2009-04-10 14:01:38 +04:00
r = ECMD_PROCESSED ;
bad :
2011-03-30 18:35:00 +04:00
/*
* Note : as vg_to is referencing moved elements from vg_from
2011-08-11 00:25:29 +04:00
* the order of release_vg calls is mandatory .
2011-03-30 18:35:00 +04:00
*/
2011-08-11 00:25:29 +04:00
unlock_and_release_vg ( cmd , vg_to , vg_name_to ) ;
unlock_and_release_vg ( cmd , vg_from , vg_name_from ) ;
2011-03-30 18:35:00 +04:00
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 )
{
2011-02-18 17:47:28 +03:00
const 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 ;
}