2003-04-30 19:28:17 +04:00
/*
2008-01-30 17:00:02 +03:00
* Copyright ( C ) 2003 - 2004 Sistina Software , Inc . All rights reserved .
2010-01-27 16:29:11 +03:00
* Copyright ( C ) 2004 - 2010 Red Hat , Inc . All rights reserved .
2003-04-30 19:28:17 +04:00
*
2004-03-30 23:35:44 +04:00
* This file is part of LVM2 .
2003-04-30 19:28:17 +04: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 .
2003-04-30 19:28:17 +04: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
2003-04-30 19:28:17 +04:00
*/
# include "tools.h"
2004-05-05 21:56:20 +04:00
# include "polldaemon.h"
2004-09-14 17:59:17 +04:00
# include "display.h"
2003-04-30 19:28:17 +04:00
2008-04-09 16:56:34 +04:00
# define PVMOVE_FIRST_TIME 0x00000001 /* Called for first time */
static int _pvmove_target_present ( struct cmd_context * cmd , int clustered )
2008-04-07 14:23:47 +04:00
{
const struct segment_type * segtype ;
unsigned attr = 0 ;
2008-04-09 16:56:34 +04:00
int found = 1 ;
static int _clustered_found = - 1 ;
if ( clustered & & _clustered_found > = 0 )
return _clustered_found ;
2008-04-07 14:23:47 +04:00
if ( ! ( segtype = get_segtype_from_string ( cmd , " mirror " ) ) )
return_0 ;
if ( activation ( ) & & segtype - > ops - > target_present & &
2009-02-28 23:04:24 +03:00
! segtype - > ops - > target_present ( cmd , NULL , clustered ? & attr : NULL ) )
2008-04-09 16:56:34 +04:00
found = 0 ;
2008-04-07 14:23:47 +04:00
2008-04-09 16:56:34 +04:00
if ( activation ( ) & & clustered ) {
if ( found & & ( attr & MIRROR_LOG_CLUSTERED ) )
_clustered_found = found = 1 ;
else
_clustered_found = found = 0 ;
2008-04-07 14:23:47 +04:00
}
2008-04-09 16:56:34 +04:00
return found ;
}
static unsigned _pvmove_is_exclusive ( struct cmd_context * cmd ,
struct volume_group * vg )
{
2008-04-10 21:09:32 +04:00
if ( vg_is_clustered ( vg ) )
2008-04-09 16:56:34 +04:00
if ( ! _pvmove_target_present ( cmd , 1 ) )
return 1 ;
return 0 ;
2008-04-07 14:23:47 +04:00
}
2003-04-30 19:28:17 +04:00
/* Allow /dev/vgname/lvname, vgname/lvname or lvname */
static const char * _extract_lvname ( struct cmd_context * cmd , const char * vgname ,
const char * arg )
{
const char * lvname ;
/* Is an lvname supplied directly? */
if ( ! strchr ( arg , ' / ' ) )
return arg ;
2007-03-09 23:47:41 +03:00
lvname = skip_dev_dir ( cmd , arg , NULL ) ;
2003-04-30 19:28:17 +04:00
while ( * lvname = = ' / ' )
lvname + + ;
if ( ! strchr ( lvname , ' / ' ) ) {
log_error ( " --name takes a logical volume name " ) ;
return NULL ;
}
if ( strncmp ( vgname , lvname , strlen ( vgname ) ) | |
( lvname + = strlen ( vgname ) , * lvname ! = ' / ' ) ) {
log_error ( " Named LV and old PV must be in the same VG " ) ;
return NULL ;
}
while ( * lvname = = ' / ' )
lvname + + ;
if ( ! * lvname ) {
log_error ( " Incomplete LV name supplied with --name " ) ;
return NULL ;
}
return lvname ;
}
2003-05-06 16:20:11 +04:00
static struct volume_group * _get_vg ( struct cmd_context * cmd , const char * vgname )
{
2004-03-31 22:41:39 +04:00
dev_close_all ( ) ;
2009-07-01 20:59:37 +04:00
return vg_read_for_update ( cmd , vgname , NULL , 0 ) ;
2003-05-06 16:20:11 +04:00
}
/* Create list of PVs for allocation of replacement extents */
2008-11-04 01:14:30 +03:00
static struct dm_list * _get_allocatable_pvs ( struct cmd_context * cmd , int argc ,
2003-05-06 16:20:11 +04:00
char * * argv , struct volume_group * vg ,
2004-09-14 17:59:17 +04:00
struct physical_volume * pv ,
alloc_policy_t alloc )
2003-05-06 16:20:11 +04:00
{
2008-11-04 01:14:30 +03:00
struct dm_list * allocatable_pvs , * pvht , * pvh ;
2003-05-06 16:20:11 +04:00
struct pv_list * pvl ;
2008-01-30 16:19:47 +03:00
if ( argc )
allocatable_pvs = create_pv_list ( cmd - > mem , vg , argc , argv , 1 ) ;
else
allocatable_pvs = clone_pv_list ( cmd - > mem , & vg - > pvs ) ;
if ( ! allocatable_pvs )
return_NULL ;
2003-04-30 19:28:17 +04:00
2008-11-04 01:14:30 +03:00
dm_list_iterate_safe ( pvh , pvht , allocatable_pvs ) {
pvl = dm_list_item ( pvh , struct pv_list ) ;
2004-09-14 17:59:17 +04:00
/* Don't allocate onto the PV we're clearing! */
2007-06-16 02:16:55 +04:00
if ( ( alloc ! = ALLOC_ANYWHERE ) & & ( pvl - > pv - > dev = = pv_dev ( pv ) ) ) {
2008-11-04 01:14:30 +03:00
dm_list_del ( & pvl - > list ) ;
2004-09-14 17:59:17 +04:00
continue ;
}
/* Remove PV if full */
if ( ( pvl - > pv - > pe_count = = pvl - > pv - > pe_alloc_count ) )
2008-11-04 01:14:30 +03:00
dm_list_del ( & pvl - > list ) ;
2003-04-30 19:28:17 +04:00
}
2008-11-04 01:14:30 +03:00
if ( dm_list_empty ( allocatable_pvs ) ) {
2003-04-30 19:28:17 +04:00
log_error ( " No extents available for allocation " ) ;
2003-05-06 16:20:11 +04:00
return NULL ;
2003-04-30 19:28:17 +04:00
}
2003-05-06 16:20:11 +04:00
return allocatable_pvs ;
}
2007-12-20 18:42:55 +03:00
/*
* Replace any LV segments on given PV with temporary mirror .
* Returns list of LVs changed .
*/
static int _insert_pvmove_mirrors ( struct cmd_context * cmd ,
struct logical_volume * lv_mirr ,
2008-11-04 01:14:30 +03:00
struct dm_list * source_pvl ,
2007-12-20 18:42:55 +03:00
struct logical_volume * lv ,
2008-11-04 01:14:30 +03:00
struct dm_list * lvs_changed )
2007-12-20 18:42:55 +03:00
{
struct pv_list * pvl ;
uint32_t prev_le_count ;
/* Only 1 PV may feature in source_pvl */
2008-11-04 01:14:30 +03:00
pvl = dm_list_item ( source_pvl - > n , struct pv_list ) ;
2007-12-20 18:42:55 +03:00
prev_le_count = lv_mirr - > le_count ;
if ( ! insert_layer_for_segments_on_pv ( cmd , lv , lv_mirr , PVMOVE ,
pvl , lvs_changed ) )
return_0 ;
/* check if layer was inserted */
if ( lv_mirr - > le_count - prev_le_count ) {
lv - > status | = LOCKED ;
log_verbose ( " Moving %u extents of logical volume %s/%s " ,
lv_mirr - > le_count - prev_le_count ,
lv - > vg - > name , lv - > name ) ;
}
return 1 ;
}
2004-05-05 21:56:20 +04:00
/* Create new LV with mirror segments for the required copies */
2003-05-06 16:20:11 +04:00
static struct logical_volume * _set_up_pvmove_lv ( struct cmd_context * cmd ,
struct volume_group * vg ,
2008-11-04 01:14:30 +03:00
struct dm_list * source_pvl ,
2003-05-06 16:20:11 +04:00
const char * lv_name ,
2008-11-04 01:14:30 +03:00
struct dm_list * allocatable_pvs ,
2004-09-14 17:59:17 +04:00
alloc_policy_t alloc ,
2008-11-04 01:14:30 +03:00
struct dm_list * * lvs_changed )
2003-05-06 16:20:11 +04:00
{
struct logical_volume * lv_mirr , * lv ;
2003-10-16 00:02:46 +04:00
struct lv_list * lvl ;
2007-12-20 18:42:55 +03:00
uint32_t log_count = 0 ;
2008-04-04 15:59:31 +04:00
int lv_found = 0 ;
2009-12-04 17:03:18 +03:00
int lv_skipped = 0 ;
2003-04-30 19:28:17 +04:00
2003-07-05 02:34:56 +04:00
/* FIXME Cope with non-contiguous => splitting existing segments */
2007-10-11 23:20:38 +04:00
if ( ! ( lv_mirr = lv_create_empty ( " pvmove%d " , NULL ,
2003-05-06 16:20:11 +04:00
LVM_READ | LVM_WRITE ,
2009-05-14 01:28:31 +04:00
ALLOC_CONTIGUOUS , vg ) ) ) {
2003-04-30 19:28:17 +04:00
log_error ( " Creation of temporary pvmove LV failed " ) ;
2003-05-06 16:20:11 +04:00
return NULL ;
2003-04-30 19:28:17 +04:00
}
2003-05-06 16:20:11 +04:00
lv_mirr - > status | = ( PVMOVE | LOCKED ) ;
2005-10-17 03:03:59 +04:00
if ( ! ( * lvs_changed = dm_pool_alloc ( cmd - > mem , sizeof ( * * lvs_changed ) ) ) ) {
2003-05-06 16:20:11 +04:00
log_error ( " lvs_changed list struct allocation failed " ) ;
return NULL ;
}
2008-11-04 01:14:30 +03:00
dm_list_init ( * lvs_changed ) ;
2003-04-30 19:28:17 +04:00
2003-07-05 02:34:56 +04:00
/* Find segments to be moved and set up mirrors */
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( lvl , & vg - > lvs ) {
2003-10-16 00:02:46 +04:00
lv = lvl - > lv ;
2008-04-04 15:59:31 +04:00
if ( ( lv = = lv_mirr ) )
2003-04-30 19:28:17 +04:00
continue ;
2008-04-04 15:59:31 +04:00
if ( lv_name ) {
if ( strcmp ( lv - > name , lv_name ) )
continue ;
lv_found = 1 ;
}
2003-04-30 19:58:09 +04:00
if ( lv_is_origin ( lv ) | | lv_is_cow ( lv ) ) {
2009-12-04 17:03:18 +03:00
lv_skipped = 1 ;
2003-04-30 19:58:09 +04:00
log_print ( " Skipping snapshot-related LV %s " , lv - > name ) ;
continue ;
}
2004-05-05 22:33:01 +04:00
if ( lv - > status & MIRRORED ) {
2009-12-04 17:03:18 +03:00
lv_skipped = 1 ;
2004-05-05 22:33:01 +04:00
log_print ( " Skipping mirror LV %s " , lv - > name ) ;
2005-06-14 21:54:48 +04:00
continue ;
}
if ( lv - > status & MIRROR_LOG ) {
2009-12-04 17:03:18 +03:00
lv_skipped = 1 ;
2005-06-14 21:54:48 +04:00
log_print ( " Skipping mirror log LV %s " , lv - > name ) ;
continue ;
}
if ( lv - > status & MIRROR_IMAGE ) {
2009-12-04 17:03:18 +03:00
lv_skipped = 1 ;
2005-06-14 21:54:48 +04:00
log_print ( " Skipping mirror image LV %s " , lv - > name ) ;
2004-05-05 22:33:01 +04:00
continue ;
}
2003-05-06 16:20:11 +04:00
if ( lv - > status & LOCKED ) {
2009-12-04 17:03:18 +03:00
lv_skipped = 1 ;
2003-05-06 16:20:11 +04:00
log_print ( " Skipping locked LV %s " , lv - > name ) ;
continue ;
}
2007-12-20 18:42:55 +03:00
if ( ! _insert_pvmove_mirrors ( cmd , lv_mirr , source_pvl , lv ,
2008-01-30 16:19:47 +03:00
* lvs_changed ) )
return_NULL ;
2003-04-30 19:28:17 +04:00
}
2008-04-04 15:59:31 +04:00
if ( lv_name & & ! lv_found ) {
log_error ( " Logical volume %s not found. " , lv_name ) ;
return NULL ;
}
2004-05-05 22:33:01 +04:00
/* Is temporary mirror empty? */
2003-04-30 19:28:17 +04:00
if ( ! lv_mirr - > le_count ) {
2009-12-04 17:03:18 +03:00
if ( lv_skipped )
log_error ( " All data on source PV skipped. "
" It contains locked, hidden or "
" non-top level LVs only. " ) ;
2003-04-30 19:28:17 +04:00
log_error ( " No data to move for %s " , vg - > name ) ;
2003-05-06 16:20:11 +04:00
return NULL ;
2003-04-30 19:28:17 +04:00
}
2010-04-09 05:00:10 +04:00
if ( ! lv_add_mirrors ( cmd , lv_mirr , 1 , 1 , 0 , 0 , log_count ,
2007-12-20 18:42:55 +03:00
allocatable_pvs , alloc , MIRROR_BY_SEG ) ) {
log_error ( " Failed to convert pvmove LV to mirrored " ) ;
return_NULL ;
}
if ( ! split_parent_segments_for_layer ( cmd , lv_mirr ) ) {
log_error ( " Failed to split segments being moved " ) ;
return_NULL ;
}
2007-12-06 01:11:20 +03:00
2003-05-06 16:20:11 +04:00
return lv_mirr ;
}
2008-04-09 16:56:34 +04:00
static int _activate_lv ( struct cmd_context * cmd , struct logical_volume * lv_mirr ,
unsigned exclusive )
{
2010-01-06 00:08:34 +03:00
int r = 0 ;
2008-04-09 16:56:34 +04:00
if ( exclusive )
2010-01-06 00:08:34 +03:00
r = activate_lv_excl ( cmd , lv_mirr ) ;
else
r = activate_lv ( cmd , lv_mirr ) ;
if ( ! r )
stack ;
2008-04-09 16:56:34 +04:00
2010-01-06 00:08:34 +03:00
return r ;
2008-04-09 16:56:34 +04:00
}
2010-01-27 16:29:11 +03:00
static int _detach_pvmove_mirror ( struct cmd_context * cmd ,
struct logical_volume * lv_mirr )
{
struct dm_list lvs_completed ;
struct lv_list * lvl ;
/* Update metadata to remove mirror segments and break dependencies */
dm_list_init ( & lvs_completed ) ;
2010-05-24 19:32:20 +04:00
if ( ! lv_remove_mirrors ( cmd , lv_mirr , 1 , 0 , NULL , NULL , PVMOVE ) | |
2010-01-27 16:29:11 +03:00
! remove_layers_for_segments_all ( cmd , lv_mirr , PVMOVE ,
& lvs_completed ) ) {
return 0 ;
}
dm_list_iterate_items ( lvl , & lvs_completed )
/* FIXME Assumes only one pvmove at a time! */
lvl - > lv - > status & = ~ LOCKED ;
return 1 ;
}
2009-05-19 13:51:02 +04:00
2003-05-06 16:20:11 +04:00
static int _update_metadata ( struct cmd_context * cmd , struct volume_group * vg ,
struct logical_volume * lv_mirr ,
2008-11-04 01:14:30 +03:00
struct dm_list * lvs_changed , unsigned flags )
2003-05-06 16:20:11 +04:00
{
2008-04-09 16:56:34 +04:00
unsigned exclusive = _pvmove_is_exclusive ( cmd , vg ) ;
unsigned first_time = ( flags & PVMOVE_FIRST_TIME ) ? 1 : 0 ;
2009-04-21 18:31:57 +04:00
int r = 0 ;
2008-04-09 16:56:34 +04:00
2003-07-05 02:34:56 +04:00
log_verbose ( " Updating volume group metadata " ) ;
if ( ! vg_write ( vg ) ) {
log_error ( " ABORTING: Volume group metadata update failed. " ) ;
return 0 ;
}
2004-05-05 22:33:01 +04:00
/* Suspend lvs_changed */
2010-01-26 11:01:18 +03:00
if ( ! suspend_lvs ( cmd , lvs_changed ) ) {
vg_revert ( vg ) ;
2009-04-21 18:31:57 +04:00
goto_out ;
2010-01-26 11:01:18 +03:00
}
2003-05-06 16:20:11 +04:00
2004-05-05 22:33:01 +04:00
/* Suspend mirrors on subsequent calls */
2003-05-06 16:20:11 +04:00
if ( ! first_time ) {
2005-08-15 16:00:04 +04:00
if ( ! suspend_lv ( cmd , lv_mirr ) ) {
2010-01-06 00:07:31 +03:00
if ( ! resume_lvs ( cmd , lvs_changed ) )
stack ;
2003-07-05 02:34:56 +04:00
vg_revert ( vg ) ;
2009-04-21 18:31:57 +04:00
goto_out ;
2003-05-06 16:20:11 +04:00
}
2003-04-30 19:28:17 +04:00
}
2004-05-05 22:33:01 +04:00
/* Commit on-disk metadata */
2003-07-05 02:34:56 +04:00
if ( ! vg_commit ( vg ) ) {
2003-05-06 16:20:11 +04:00
log_error ( " ABORTING: Volume group metadata update failed. " ) ;
if ( ! first_time )
2010-01-06 00:07:31 +03:00
if ( ! resume_lv ( cmd , lv_mirr ) )
stack ;
if ( ! resume_lvs ( cmd , lvs_changed ) )
stack ;
2010-01-26 11:01:18 +03:00
vg_revert ( vg ) ;
2009-04-21 18:31:57 +04:00
goto out ;
2003-05-06 16:20:11 +04:00
}
2004-05-05 22:33:01 +04:00
/* Activate the temporary mirror LV */
/* Only the first mirror segment gets activated as a mirror */
2005-08-15 03:18:28 +04:00
/* FIXME: Add option to use a log */
2003-05-06 16:20:11 +04:00
if ( first_time ) {
2008-04-09 16:56:34 +04:00
if ( ! _activate_lv ( cmd , lv_mirr , exclusive ) ) {
2009-12-03 22:22:24 +03:00
if ( test_mode ( ) ) {
r = 1 ;
2009-05-19 13:51:02 +04:00
goto out ;
2009-12-03 22:22:24 +03:00
}
2009-05-19 13:51:02 +04:00
/*
2010-01-27 16:29:11 +03:00
* FIXME : review ordering of operations above ,
* temporary mirror should be preloaded in suspend .
* Also banned operation here when suspended .
2009-05-19 13:51:02 +04:00
* Nothing changed yet , try to revert pvmove .
*/
log_error ( " Temporary pvmove mirror activation failed. " ) ;
2010-01-27 16:29:11 +03:00
/* Ensure that temporary mrror is deactivate even on other nodes. */
( void ) deactivate_lv ( cmd , lv_mirr ) ;
/* Revert metadata */
if ( ! _detach_pvmove_mirror ( cmd , lv_mirr ) | |
! lv_remove ( lv_mirr ) | |
! vg_write ( vg ) | | ! vg_commit ( vg ) )
2009-05-19 13:51:02 +04:00
log_error ( " ABORTING: Restoring original configuration "
" before pvmove failed. Run pvmove --abort. " ) ;
2010-01-27 16:29:11 +03:00
/* Unsuspend LVs */
if ( ! resume_lvs ( cmd , lvs_changed ) )
stack ;
2009-04-21 18:31:57 +04:00
goto out ;
2003-05-06 16:20:11 +04:00
}
2005-08-15 16:00:04 +04:00
} else if ( ! resume_lv ( cmd , lv_mirr ) ) {
2004-05-05 16:03:07 +04:00
log_error ( " Unable to reactivate logical volume \" %s \" " ,
2003-05-06 16:20:11 +04:00
lv_mirr - > name ) ;
2010-01-06 00:07:31 +03:00
if ( ! resume_lvs ( cmd , lvs_changed ) )
stack ;
2009-04-21 18:31:57 +04:00
goto out ;
2003-05-06 16:20:11 +04:00
}
2004-05-05 22:33:01 +04:00
/* Unsuspend LVs */
2004-05-05 16:03:07 +04:00
if ( ! resume_lvs ( cmd , lvs_changed ) ) {
log_error ( " Unable to resume logical volumes " ) ;
2009-04-21 18:31:57 +04:00
goto out ;
2003-05-06 16:20:11 +04:00
}
2009-04-21 18:31:57 +04:00
r = 1 ;
out :
backup ( vg ) ;
return r ;
2003-05-06 16:20:11 +04:00
}
static int _set_up_pvmove ( struct cmd_context * cmd , const char * pv_name ,
int argc , char * * argv )
{
const char * lv_name = NULL ;
2004-08-18 02:09:02 +04:00
char * pv_name_arg ;
2003-05-06 16:20:11 +04:00
struct volume_group * vg ;
2008-11-04 01:14:30 +03:00
struct dm_list * source_pvl ;
struct dm_list * allocatable_pvs ;
2004-09-14 17:59:17 +04:00
alloc_policy_t alloc ;
2008-11-04 01:14:30 +03:00
struct dm_list * lvs_changed ;
2003-05-06 16:20:11 +04:00
struct physical_volume * pv ;
struct logical_volume * lv_mirr ;
2008-04-09 16:56:34 +04:00
unsigned first_time = 1 ;
unsigned exclusive ;
2009-04-10 14:01:38 +04:00
int r = ECMD_FAILED ;
2003-05-06 16:20:11 +04:00
2004-08-18 02:09:02 +04:00
pv_name_arg = argv [ 0 ] ;
argc - - ;
argv + + ;
2003-07-05 02:34:56 +04:00
/* Find PV (in VG) */
2004-05-05 15:04:28 +04:00
if ( ! ( pv = find_pv_by_name ( cmd , pv_name ) ) ) {
2003-05-06 16:20:11 +04:00
stack ;
return EINVALID_CMD_LINE ;
}
if ( arg_count ( cmd , name_ARG ) ) {
2007-06-16 02:16:55 +04:00
if ( ! ( lv_name = _extract_lvname ( cmd , pv_vg_name ( pv ) ,
2003-05-06 16:20:11 +04:00
arg_value ( cmd , name_ARG ) ) ) ) {
stack ;
return EINVALID_CMD_LINE ;
}
2008-04-04 15:59:31 +04:00
if ( ! validate_name ( lv_name ) ) {
log_error ( " Logical volume name %s is invalid " , lv_name ) ;
return EINVALID_CMD_LINE ;
}
2003-05-06 16:20:11 +04:00
}
2003-07-05 02:34:56 +04:00
/* Read VG */
2007-06-16 02:16:55 +04:00
log_verbose ( " Finding volume group \" %s \" " , pv_vg_name ( pv ) ) ;
2003-05-06 16:20:11 +04:00
2009-07-01 20:59:37 +04:00
vg = _get_vg ( cmd , pv_vg_name ( pv ) ) ;
if ( vg_read_error ( vg ) ) {
2009-07-07 05:18:35 +04:00
vg_release ( vg ) ;
2003-04-30 19:28:17 +04:00
stack ;
return ECMD_FAILED ;
}
2008-04-09 16:56:34 +04:00
exclusive = _pvmove_is_exclusive ( cmd , vg ) ;
2007-06-16 02:16:55 +04:00
if ( ( lv_mirr = find_pvmove_lv ( vg , pv_dev ( pv ) , PVMOVE ) ) ) {
2003-05-06 16:20:11 +04:00
log_print ( " Detected pvmove in progress for %s " , pv_name ) ;
if ( argc | | lv_name )
log_error ( " Ignoring remaining command line arguments " ) ;
2003-04-30 19:28:17 +04:00
2003-05-06 16:20:11 +04:00
if ( ! ( lvs_changed = lvs_using_lv ( cmd , vg , lv_mirr ) ) ) {
2009-07-08 22:15:51 +04:00
log_error ( " ABORTING: Failed to generate list of moving LVs " ) ;
2009-04-10 14:01:38 +04:00
goto out ;
2003-05-06 16:20:11 +04:00
}
2003-04-30 19:28:17 +04:00
2003-07-05 02:34:56 +04:00
/* Ensure mirror LV is active */
2008-04-09 16:56:34 +04:00
if ( ! _activate_lv ( cmd , lv_mirr , exclusive ) ) {
2009-07-08 22:15:51 +04:00
log_error ( " ABORTING: Temporary mirror activation failed. " ) ;
2009-04-10 14:01:38 +04:00
goto out ;
2003-05-06 16:20:11 +04:00
}
first_time = 0 ;
} else {
2004-08-18 02:09:02 +04:00
/* Determine PE ranges to be moved */
if ( ! ( source_pvl = create_pv_list ( cmd - > mem , vg , 1 ,
2009-04-10 14:01:38 +04:00
& pv_name_arg , 0 ) ) )
goto_out ;
2003-05-06 16:20:11 +04:00
2006-05-10 01:23:51 +04:00
alloc = arg_uint_value ( cmd , alloc_ARG , ALLOC_INHERIT ) ;
2004-09-14 17:59:17 +04:00
if ( alloc = = ALLOC_INHERIT )
alloc = vg - > alloc ;
2004-05-05 22:33:01 +04:00
/* Get PVs we can use for allocation */
2003-05-06 16:20:11 +04:00
if ( ! ( allocatable_pvs = _get_allocatable_pvs ( cmd , argc , argv ,
2009-04-10 14:01:38 +04:00
vg , pv , alloc ) ) )
goto_out ;
2003-05-06 16:20:11 +04:00
2009-04-10 14:01:38 +04:00
if ( ! archive ( vg ) )
goto_out ;
2003-05-06 16:20:11 +04:00
2004-08-18 02:09:02 +04:00
if ( ! ( lv_mirr = _set_up_pvmove_lv ( cmd , vg , source_pvl , lv_name ,
2004-09-14 17:59:17 +04:00
allocatable_pvs , alloc ,
2009-04-10 14:01:38 +04:00
& lvs_changed ) ) )
goto_out ;
2003-05-06 16:20:11 +04:00
}
2008-04-09 16:56:34 +04:00
/* Lock lvs_changed and activate (with old metadata) */
2009-04-10 14:01:38 +04:00
if ( ! activate_lvs ( cmd , lvs_changed , exclusive ) )
goto_out ;
2003-04-30 19:28:17 +04:00
2004-05-05 22:33:01 +04:00
/* FIXME Presence of a mirror once set PVMOVE - now remove associated logic */
/* init_pvmove(1); */
/* vg->status |= PVMOVE; */
2003-05-06 16:20:11 +04:00
if ( first_time ) {
if ( ! _update_metadata
2009-04-10 14:01:38 +04:00
( cmd , vg , lv_mirr , lvs_changed , PVMOVE_FIRST_TIME ) )
goto_out ;
2003-04-30 19:28:17 +04:00
}
2004-05-05 22:33:01 +04:00
/* LVs are all in status LOCKED */
2009-04-10 14:01:38 +04:00
r = ECMD_PROCESSED ;
out :
2009-05-21 07:04:52 +04:00
unlock_and_release_vg ( cmd , vg , pv_vg_name ( pv ) ) ;
2009-04-10 14:01:38 +04:00
return r ;
2003-05-06 16:20:11 +04:00
}
2003-04-30 19:28:17 +04:00
2003-05-06 16:20:11 +04:00
static int _finish_pvmove ( struct cmd_context * cmd , struct volume_group * vg ,
struct logical_volume * lv_mirr ,
2008-11-04 01:14:30 +03:00
struct dm_list * lvs_changed )
2003-05-06 16:20:11 +04:00
{
int r = 1 ;
2010-08-23 15:34:10 +04:00
if ( ! dm_list_empty ( lvs_changed ) & &
! _detach_pvmove_mirror ( cmd , lv_mirr ) ) {
2003-07-05 02:34:56 +04:00
log_error ( " ABORTING: Removal of temporary mirror failed " ) ;
return 0 ;
}
2004-05-05 22:33:01 +04:00
/* Store metadata without dependencies on mirror segments */
2003-07-05 02:34:56 +04:00
if ( ! vg_write ( vg ) ) {
log_error ( " ABORTING: Failed to write new data locations "
" to disk. " ) ;
return 0 ;
}
2004-05-05 22:33:01 +04:00
/* Suspend LVs changed */
2004-05-05 16:03:07 +04:00
if ( ! suspend_lvs ( cmd , lvs_changed ) ) {
2003-05-06 16:20:11 +04:00
log_error ( " Locking LVs to remove temporary mirror failed " ) ;
r = 0 ;
2003-04-30 19:28:17 +04:00
}
2004-05-05 22:33:01 +04:00
/* Suspend mirror LV to flush pending I/O */
2005-08-15 16:00:04 +04:00
if ( ! suspend_lv ( cmd , lv_mirr ) ) {
2003-05-06 16:20:11 +04:00
log_error ( " Suspension of temporary mirror LV failed " ) ;
r = 0 ;
}
2003-04-30 19:28:17 +04:00
2004-05-05 22:33:01 +04:00
/* Store metadata without dependencies on mirror segments */
2003-07-05 02:34:56 +04:00
if ( ! vg_commit ( vg ) ) {
2003-05-06 16:20:11 +04:00
log_error ( " ABORTING: Failed to write new data locations "
" to disk. " ) ;
2003-07-05 02:34:56 +04:00
vg_revert ( vg ) ;
2010-01-06 00:07:31 +03:00
if ( ! resume_lv ( cmd , lv_mirr ) )
stack ;
if ( ! resume_lvs ( cmd , lvs_changed ) )
stack ;
2003-05-06 16:20:11 +04:00
return 0 ;
2003-04-30 19:28:17 +04:00
}
2004-05-05 22:33:01 +04:00
/* Release mirror LV. (No pending I/O because it's been suspended.) */
2005-08-15 16:00:04 +04:00
if ( ! resume_lv ( cmd , lv_mirr ) ) {
2004-05-05 16:03:07 +04:00
log_error ( " Unable to reactivate logical volume \" %s \" " ,
2003-04-30 19:28:17 +04:00
lv_mirr - > name ) ;
2003-05-06 16:20:11 +04:00
r = 0 ;
2003-04-30 19:28:17 +04:00
}
2004-05-05 22:33:01 +04:00
/* Unsuspend LVs */
2010-01-06 00:07:31 +03:00
if ( ! resume_lvs ( cmd , lvs_changed ) )
stack ;
2003-11-20 19:22:04 +03:00
2004-05-05 22:33:01 +04:00
/* Deactivate mirror LV */
2005-08-15 16:00:04 +04:00
if ( ! deactivate_lv ( cmd , lv_mirr ) ) {
2003-04-30 19:28:17 +04:00
log_error ( " ABORTING: Unable to deactivate temporary logical "
" volume \" %s \" " , lv_mirr - > name ) ;
2003-05-06 16:20:11 +04:00
r = 0 ;
2003-04-30 19:28:17 +04:00
}
2003-11-20 19:22:04 +03:00
log_verbose ( " Removing temporary pvmove LV " ) ;
2005-05-09 20:59:01 +04:00
if ( ! lv_remove ( lv_mirr ) ) {
2003-04-30 19:28:17 +04:00
log_error ( " ABORTING: Removal of temporary pvmove LV failed " ) ;
2003-05-06 16:20:11 +04:00
return 0 ;
2003-04-30 19:28:17 +04:00
}
2004-05-05 22:33:01 +04:00
/* Store it on disks */
2003-04-30 19:28:17 +04:00
log_verbose ( " Writing out final volume group after pvmove " ) ;
2003-07-05 02:34:56 +04:00
if ( ! vg_write ( vg ) | | ! vg_commit ( vg ) ) {
2003-04-30 19:28:17 +04:00
log_error ( " ABORTING: Failed to write new data locations "
" to disk. " ) ;
2003-05-06 16:20:11 +04:00
return 0 ;
}
2003-07-05 02:34:56 +04:00
/* FIXME backup positioning */
2003-05-06 16:20:11 +04:00
backup ( vg ) ;
return r ;
}
2004-05-05 21:56:20 +04:00
static struct volume_group * _get_move_vg ( struct cmd_context * cmd ,
2010-02-06 01:40:49 +03:00
const char * name ,
2010-07-09 19:34:40 +04:00
const char * uuid __attribute__ ( ( unused ) ) )
2003-05-06 16:20:11 +04:00
{
struct physical_volume * pv ;
2004-05-05 21:56:20 +04:00
/* Reread all metadata in case it got changed */
if ( ! ( pv = find_pv_by_name ( cmd , name ) ) ) {
log_error ( " ABORTING: Can't reread PV %s " , name ) ;
/* What more could we do here? */
return NULL ;
2003-05-06 16:20:11 +04:00
}
2003-04-30 19:28:17 +04:00
2007-06-16 02:16:55 +04:00
return _get_vg ( cmd , pv_vg_name ( pv ) ) ;
2003-05-06 16:20:11 +04:00
}
2004-05-05 21:56:20 +04:00
static struct poll_functions _pvmove_fns = {
2006-05-10 01:23:51 +04:00
. get_copy_name_from_lv = get_pvmove_pvname_from_lv_mirr ,
. get_copy_vg = _get_move_vg ,
. get_copy_lv = find_pvmove_lv_from_pvname ,
2009-09-30 22:15:06 +04:00
. poll_progress = poll_mirror_progress ,
2006-05-10 01:23:51 +04:00
. update_metadata = _update_metadata ,
. finish_copy = _finish_pvmove ,
2004-05-05 21:56:20 +04:00
} ;
2003-05-06 16:20:11 +04:00
int pvmove_poll ( struct cmd_context * cmd , const char * pv_name ,
unsigned background )
{
2009-12-03 22:22:24 +03:00
if ( test_mode ( ) )
return ECMD_PROCESSED ;
2009-06-01 18:43:27 +04:00
return poll_daemon ( cmd , pv_name , NULL , background , PVMOVE , & _pvmove_fns ,
2007-12-22 15:13:29 +03:00
" Moved " ) ;
2003-05-06 16:20:11 +04:00
}
int pvmove ( struct cmd_context * cmd , int argc , char * * argv )
{
char * pv_name = NULL ;
2004-08-18 02:09:02 +04:00
char * colon ;
2003-05-06 16:20:11 +04:00
int ret ;
2007-12-20 18:42:55 +03:00
2008-04-09 16:56:34 +04:00
/* dm raid1 target must be present in every case */
if ( ! _pvmove_target_present ( cmd , 0 ) ) {
log_error ( " Required device-mapper target(s) not "
" detected in your kernel " ) ;
2008-04-09 16:45:32 +04:00
return ECMD_FAILED ;
}
2003-05-06 16:20:11 +04:00
if ( argc ) {
2010-09-23 16:02:33 +04:00
if ( ! ( pv_name = dm_pool_strdup ( cmd - > mem , argv [ 0 ] ) ) ) {
log_error ( " Failed to clone PV name " ) ;
return ECMD_FAILED ;
}
unescape_colons_and_at_signs ( pv_name , & colon , NULL ) ;
2004-08-18 02:09:02 +04:00
/* Drop any PE lists from PV name */
2010-09-23 16:02:33 +04:00
if ( colon )
* colon = ' \0 ' ;
2003-05-06 16:20:11 +04:00
2003-08-20 19:48:27 +04:00
if ( ! arg_count ( cmd , abort_ARG ) & &
( ret = _set_up_pvmove ( cmd , pv_name , argc , argv ) ) ! =
2004-05-05 21:56:20 +04:00
ECMD_PROCESSED ) {
2003-05-06 16:20:11 +04:00
stack ;
return ret ;
}
}
2003-04-30 19:28:17 +04:00
2009-11-03 18:50:42 +03:00
return pvmove_poll ( cmd , pv_name , arg_is_set ( cmd , background_ARG ) ) ;
2003-04-30 19:28:17 +04:00
}