2001-11-27 20:02:24 +03:00
/*
* Copyright ( C ) 2001 Sistina Software
*
* LVM is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 , or ( at your option )
* any later version .
*
* LVM is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with LVM ; see the file COPYING . If not , write to
* the Free Software Foundation , 59 Temple Place - Suite 330 ,
* Boston , MA 02111 - 1307 , USA .
*
*/
# 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 ;
struct list * lvh1 , * lvh2 ;
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
}
if ( vg_to - > max_pv < vg_to - > pv_count + vg_from - > pv_count ) {
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
}
if ( vg_to - > max_lv < vg_to - > lv_count + vg_from - > lv_count ) {
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 */
list_iterate ( lvh1 , & vg_to - > lvs ) {
list_iterate ( lvh2 , & vg_from - > lvs ) {
2002-01-21 19:49:32 +03:00
char * name1 = list_item ( lvh1 ,
struct lv_list ) - > lv - > name ;
char * name2 = list_item ( lvh2 ,
struct lv_list ) - > lv - > name ;
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
}
}
}
/* 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 ;
2002-02-11 23:50:53 +03:00
pv - > vg_name = pool_strdup ( cmd - > mem , vg_to - > name ) ;
2001-11-27 20:02:24 +03:00
}
vg_to - > pv_count + = vg_from - > pv_count ;
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 ) ;
return 0 ;
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 ;
}