2003-04-30 19:28:17 +04:00
/*
2004-03-30 23:35:44 +04:00
* Copyright ( C ) 2003 - 2004 Sistina Software , Inc . All rights reserved .
* Copyright ( C ) 2004 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
* of the GNU General Public License v .2 .
2003-04-30 19:28:17 +04: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
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
/* 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 ;
lvname = arg ;
if ( ! strncmp ( lvname , cmd - > dev_dir , strlen ( cmd - > dev_dir ) ) )
lvname + = strlen ( cmd - > dev_dir ) ;
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 )
{
int consistent = 1 ;
struct volume_group * vg ;
2003-04-30 19:28:17 +04:00
2004-03-31 22:41:39 +04:00
dev_close_all ( ) ;
2003-05-06 16:20:11 +04:00
if ( ! lock_vol ( cmd , vgname , LCK_VG_WRITE ) ) {
log_error ( " Can't get lock for %s " , vgname ) ;
return NULL ;
2003-04-30 19:28:17 +04:00
}
2003-05-06 16:20:11 +04:00
if ( ! ( vg = vg_read ( cmd , vgname , & consistent ) ) | | ! consistent ) {
log_error ( " Volume group \" %s \" doesn't exist " , vgname ) ;
unlock_vg ( cmd , vgname ) ;
return NULL ;
2003-04-30 19:28:17 +04:00
}
if ( vg - > status & EXPORTED_VG ) {
2003-05-06 16:20:11 +04:00
log_error ( " Volume group \" %s \" is exported " , vgname ) ;
unlock_vg ( cmd , vgname ) ;
return NULL ;
2003-04-30 19:28:17 +04:00
}
if ( ! ( vg - > status & LVM_WRITE ) ) {
2003-05-06 16:20:11 +04:00
log_error ( " Volume group \" %s \" is read-only " , vgname ) ;
unlock_vg ( cmd , vgname ) ;
return NULL ;
2003-04-30 19:28:17 +04:00
}
2003-05-06 16:20:11 +04:00
return vg ;
}
/* Create list of PVs for allocation of replacement extents */
static struct list * _get_allocatable_pvs ( struct cmd_context * cmd , int argc ,
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
{
struct list * allocatable_pvs , * pvht , * pvh ;
struct pv_list * pvl ;
2003-04-30 19:28:17 +04:00
if ( argc ) {
if ( ! ( allocatable_pvs = create_pv_list ( cmd - > mem , vg , argc ,
2004-08-18 01:55:23 +04:00
argv , 1 ) ) ) {
2003-04-30 19:28:17 +04:00
stack ;
2003-05-06 16:20:11 +04:00
return NULL ;
2003-04-30 19:28:17 +04:00
}
} else {
if ( ! ( allocatable_pvs = clone_pv_list ( cmd - > mem , & vg - > pvs ) ) ) {
stack ;
2003-05-06 16:20:11 +04:00
return NULL ;
2003-04-30 19:28:17 +04:00
}
}
list_iterate_safe ( pvh , pvht , allocatable_pvs ) {
pvl = list_item ( pvh , struct pv_list ) ;
2004-09-14 17:59:17 +04:00
/* Don't allocate onto the PV we're clearing! */
if ( ( alloc ! = ALLOC_ANYWHERE ) & & ( pvl - > pv - > dev = = pv - > dev ) ) {
list_del ( & pvl - > list ) ;
continue ;
}
/* Remove PV if full */
if ( ( pvl - > pv - > pe_count = = pvl - > pv - > pe_alloc_count ) )
list_del ( & pvl - > list ) ;
2003-04-30 19:28:17 +04:00
}
if ( list_empty ( allocatable_pvs ) ) {
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 ;
}
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 ,
2004-08-18 02:09:02 +04:00
struct list * source_pvl ,
2003-05-06 16:20:11 +04:00
const char * lv_name ,
struct list * allocatable_pvs ,
2004-09-14 17:59:17 +04:00
alloc_policy_t alloc ,
2003-05-06 16:20:11 +04:00
struct list * * lvs_changed )
{
struct logical_volume * lv_mirr , * lv ;
2003-10-16 00:02:46 +04:00
struct lv_list * lvl ;
2003-04-30 19:28:17 +04:00
2003-07-05 02:34:56 +04:00
/* FIXME Cope with non-contiguous => splitting existing segments */
2005-06-03 18:49:51 +04:00
if ( ! ( lv_mirr = lv_create_empty ( vg - > fid , " pvmove%d " , NULL ,
2003-05-06 16:20:11 +04:00
LVM_READ | LVM_WRITE ,
2005-04-07 16:39:44 +04:00
ALLOC_CONTIGUOUS , 0 , 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 ;
}
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 */
2003-10-16 00:02:46 +04:00
list_iterate_items ( lvl , & vg - > lvs ) {
lv = lvl - > lv ;
2005-04-07 16:39:44 +04:00
if ( ( lv = = lv_mirr ) | |
( lv_name & & strcmp ( lv - > name , lv_name ) ) )
2003-04-30 19:28:17 +04:00
continue ;
2003-04-30 19:58:09 +04:00
if ( lv_is_origin ( lv ) | | lv_is_cow ( lv ) ) {
log_print ( " Skipping snapshot-related LV %s " , lv - > name ) ;
continue ;
}
2004-05-05 22:33:01 +04:00
if ( lv - > status & MIRRORED ) {
log_print ( " Skipping mirror LV %s " , lv - > name ) ;
2005-06-14 21:54:48 +04:00
continue ;
}
if ( lv - > status & MIRROR_LOG ) {
log_print ( " Skipping mirror log LV %s " , lv - > name ) ;
continue ;
}
if ( lv - > status & MIRROR_IMAGE ) {
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 ) {
log_print ( " Skipping locked LV %s " , lv - > name ) ;
continue ;
}
2004-08-18 02:09:02 +04:00
if ( ! insert_pvmove_mirrors ( cmd , lv_mirr , source_pvl , lv ,
2005-05-09 20:59:01 +04:00
allocatable_pvs , alloc ,
* lvs_changed ) ) {
2003-04-30 19:28:17 +04:00
stack ;
2003-05-06 16:20:11 +04:00
return NULL ;
2003-04-30 19:28:17 +04:00
}
}
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 ) {
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
}
2003-05-06 16:20:11 +04:00
return lv_mirr ;
}
static int _update_metadata ( struct cmd_context * cmd , struct volume_group * vg ,
struct logical_volume * lv_mirr ,
struct list * lvs_changed , int first_time )
{
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 ;
}
backup ( vg ) ;
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-04-30 19:28:17 +04:00
stack ;
2003-05-06 16:20:11 +04:00
return 0 ;
}
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 ) ) {
2003-05-06 16:20:11 +04:00
stack ;
2004-05-05 16:03:07 +04:00
resume_lvs ( cmd , lvs_changed ) ;
2003-07-05 02:34:56 +04:00
vg_revert ( vg ) ;
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
/* 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 )
2005-08-15 16:00:04 +04:00
resume_lv ( cmd , lv_mirr ) ;
2004-05-05 16:03:07 +04:00
resume_lvs ( cmd , lvs_changed ) ;
2003-05-06 16:20:11 +04:00
return 0 ;
}
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 ) {
2005-08-15 16:00:04 +04:00
if ( ! activate_lv_excl ( cmd , lv_mirr ) ) {
2004-09-14 19:23:42 +04:00
if ( ! test_mode ( ) )
log_error ( " ABORTING: Temporary mirror "
" activation failed. "
" Run pvmove --abort. " ) ;
2004-05-05 21:56:20 +04:00
/* FIXME Resume using *original* metadata here! */
2004-05-05 16:03:07 +04:00
resume_lvs ( cmd , lvs_changed ) ;
2003-05-06 16:20:11 +04:00
return 0 ;
}
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 ) ;
2004-05-05 16:03:07 +04:00
resume_lvs ( cmd , lvs_changed ) ;
2003-05-06 16:20:11 +04:00
return 0 ;
}
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 " ) ;
2003-05-06 16:20:11 +04:00
return 0 ;
}
return 1 ;
}
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 ;
2004-08-18 02:09:02 +04:00
struct list * source_pvl ;
2003-05-06 16:20:11 +04:00
struct list * allocatable_pvs ;
2004-09-14 17:59:17 +04:00
alloc_policy_t alloc ;
2003-05-06 16:20:11 +04:00
struct list * lvs_changed ;
struct physical_volume * pv ;
struct logical_volume * lv_mirr ;
int first_time = 1 ;
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 ) ) {
if ( ! ( lv_name = _extract_lvname ( cmd , pv - > vg_name ,
arg_value ( cmd , name_ARG ) ) ) ) {
stack ;
return EINVALID_CMD_LINE ;
}
}
2003-07-05 02:34:56 +04:00
/* Read VG */
2003-05-06 16:20:11 +04:00
log_verbose ( " Finding volume group \" %s \" " , pv - > vg_name ) ;
if ( ! ( vg = _get_vg ( cmd , pv - > vg_name ) ) ) {
2003-04-30 19:28:17 +04:00
stack ;
return ECMD_FAILED ;
}
2004-05-05 21:56:20 +04:00
if ( ( lv_mirr = find_pvmove_lv ( vg , pv - > dev , 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 ) ) ) {
log_error
( " ABORTING: Failed to generate list of moving LVs " ) ;
unlock_vg ( cmd , pv - > vg_name ) ;
return ECMD_FAILED ;
}
2003-04-30 19:28:17 +04:00
2003-07-05 02:34:56 +04:00
/* Ensure mirror LV is active */
2005-08-15 16:00:04 +04:00
if ( ! activate_lv_excl ( cmd , lv_mirr ) ) {
2003-05-06 16:20:11 +04:00
log_error
( " ABORTING: Temporary mirror activation failed. " ) ;
unlock_vg ( cmd , pv - > vg_name ) ;
return ECMD_FAILED ;
}
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 ,
& pv_name_arg , 0 ) ) ) {
stack ;
unlock_vg ( cmd , pv - > vg_name ) ;
return ECMD_FAILED ;
}
2003-05-06 16:20:11 +04:00
2004-09-14 17:59:17 +04:00
alloc = ( alloc_policy_t ) arg_uint_value ( cmd , alloc_ARG ,
ALLOC_INHERIT ) ;
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 ,
2004-09-14 17:59:17 +04:00
vg , pv , alloc ) ) ) {
2003-05-06 16:20:11 +04:00
stack ;
unlock_vg ( cmd , pv - > vg_name ) ;
return ECMD_FAILED ;
}
if ( ! archive ( vg ) ) {
unlock_vg ( cmd , pv - > vg_name ) ;
stack ;
return ECMD_FAILED ;
}
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 ,
2003-05-06 16:20:11 +04:00
& lvs_changed ) ) ) {
stack ;
unlock_vg ( cmd , pv - > vg_name ) ;
return ECMD_FAILED ;
}
}
2004-05-05 22:33:01 +04:00
/* Lock lvs_changed for exclusive use and activate (with old metadata) */
2004-05-05 16:03:07 +04:00
if ( ! activate_lvs_excl ( cmd , lvs_changed ) ) {
2003-05-06 16:20:11 +04:00
stack ;
2003-04-30 19:28:17 +04:00
unlock_vg ( cmd , pv - > vg_name ) ;
return ECMD_FAILED ;
}
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
( cmd , vg , lv_mirr , lvs_changed , first_time ) ) {
stack ;
unlock_vg ( cmd , pv - > vg_name ) ;
return ECMD_FAILED ;
}
2003-04-30 19:28:17 +04:00
}
2004-05-05 22:33:01 +04:00
/* LVs are all in status LOCKED */
2003-05-06 16:20:11 +04:00
unlock_vg ( cmd , pv - > vg_name ) ;
2003-04-30 19:28:17 +04:00
2003-05-06 16:20:11 +04:00
return ECMD_PROCESSED ;
}
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 ,
struct list * lvs_changed )
{
int r = 1 ;
2004-05-05 22:33:01 +04:00
/* Update metadata to remove mirror segments and break dependencies */
2003-07-05 02:34:56 +04:00
if ( ! remove_pvmove_mirrors ( vg , lv_mirr ) ) {
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 ) ;
2005-08-15 16:00:04 +04:00
resume_lv ( cmd , lv_mirr ) ;
2004-05-05 16:03:07 +04:00
resume_lvs ( cmd , lvs_changed ) ;
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 */
2004-05-05 16:03:07 +04:00
resume_lvs ( cmd , lvs_changed ) ;
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 ,
const char * name )
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
2004-05-05 21:56:20 +04:00
return _get_vg ( cmd , pv - > vg_name ) ;
2003-05-06 16:20:11 +04:00
}
2004-05-05 21:56:20 +04:00
static struct poll_functions _pvmove_fns = {
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 ,
update_metadata : _update_metadata ,
finish_copy : _finish_pvmove ,
} ;
2003-05-06 16:20:11 +04:00
int pvmove_poll ( struct cmd_context * cmd , const char * pv_name ,
unsigned background )
{
2004-05-05 21:56:20 +04:00
return poll_daemon ( cmd , pv_name , background , PVMOVE , & _pvmove_fns ) ;
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 ;
if ( argc ) {
pv_name = argv [ 0 ] ;
2004-08-18 02:09:02 +04:00
/* Drop any PE lists from PV name */
if ( ( colon = strchr ( pv_name , ' : ' ) ) ) {
2005-10-17 03:03:59 +04:00
if ( ! ( pv_name = dm_pool_strndup ( cmd - > mem , pv_name ,
2004-08-18 02:09:02 +04:00
( unsigned ) ( colon -
pv_name ) ) ) ) {
log_error ( " Failed to clone PV name " ) ;
return 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 ;
}
2004-08-18 02:09:02 +04:00
2003-05-06 16:20:11 +04:00
}
2003-04-30 19:28:17 +04:00
2003-05-06 16:20:11 +04:00
return pvmove_poll ( cmd , pv_name ,
arg_count ( cmd , background_ARG ) ? 1 : 0 ) ;
2003-04-30 19:28:17 +04:00
}