2004-05-05 21:56:20 +04:00
/*
2008-01-30 17:00:02 +03:00
* Copyright ( C ) 2003 - 2004 Sistina Software , Inc . All rights reserved .
2015-03-17 20:31:41 +03:00
* Copyright ( C ) 2004 - 2015 Red Hat , Inc . All rights reserved .
2004-05-05 21:56:20 +04:00
*
* This file is part of LVM2 .
*
* 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 .
2004-05-05 21:56:20 +04:00
*
2007-08-21 00:55:30 +04:00
* You should have received a copy of the GNU Lesser General Public License
2004-05-05 21:56:20 +04:00
* along with this program ; if not , write to the Free Software Foundation ,
2016-01-21 13:49:46 +03:00
* Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA
2004-05-05 21:56:20 +04:00
*/
# include "tools.h"
2015-07-06 19:30:18 +03:00
2004-05-05 21:56:20 +04:00
# include "polldaemon.h"
2010-01-11 22:19:17 +03:00
# include "lvm2cmdline.h"
2015-05-09 02:59:18 +03:00
# include "lvmpolld-client.h"
2004-05-05 21:56:20 +04:00
2015-07-06 19:30:18 +03:00
# include <time.h>
2015-04-10 17:31:28 +03:00
# define WAIT_AT_LEAST_NANOSECS 100000
2009-09-30 21:43:51 +04:00
progress_t poll_mirror_progress ( struct cmd_context * cmd ,
struct logical_volume * lv , const char * name ,
struct daemon_parms * parms )
{
2014-06-09 14:08:27 +04:00
dm_percent_t segment_percent = DM_PERCENT_0 , overall_percent = DM_PERCENT_0 ;
2009-09-30 21:43:51 +04:00
uint32_t event_nr = 0 ;
2010-08-26 20:29:12 +04:00
if ( ! lv_is_mirrored ( lv ) | |
! lv_mirror_percent ( cmd , lv , ! parms - > interval , & segment_percent ,
2010-11-30 14:53:31 +03:00
& event_nr ) | |
2014-06-09 14:08:27 +04:00
( segment_percent = = DM_PERCENT_INVALID ) ) {
2009-09-30 21:43:51 +04:00
log_error ( " ABORTING: Mirror percentage check failed. " ) ;
return PROGRESS_CHECK_FAILED ;
}
2010-11-30 14:53:31 +03:00
overall_percent = copy_percent ( lv ) ;
2009-09-30 21:43:51 +04:00
if ( parms - > progress_display )
2017-06-24 17:22:36 +03:00
log_print_unless_silent ( " %s: %s: %s%% " , name , parms - > progress_title ,
display_percent ( cmd , overall_percent ) ) ;
2009-09-30 21:43:51 +04:00
else
2017-06-24 17:22:36 +03:00
log_verbose ( " %s: %s: %s%% " , name , parms - > progress_title ,
display_percent ( cmd , overall_percent ) ) ;
2009-09-30 21:43:51 +04:00
2014-06-09 14:08:27 +04:00
if ( segment_percent ! = DM_PERCENT_100 )
2009-09-30 21:43:51 +04:00
return PROGRESS_UNFINISHED ;
2014-06-09 14:08:27 +04:00
if ( overall_percent = = DM_PERCENT_100 )
2009-09-30 21:43:51 +04:00
return PROGRESS_FINISHED_ALL ;
return PROGRESS_FINISHED_SEGMENT ;
}
2009-09-29 23:35:26 +04:00
static int _check_lv_status ( struct cmd_context * cmd ,
struct volume_group * vg ,
struct logical_volume * lv ,
const char * name , struct daemon_parms * parms ,
int * finished )
2004-05-05 21:56:20 +04:00
{
2008-11-04 01:14:30 +03:00
struct dm_list * lvs_changed ;
2009-09-30 21:43:51 +04:00
progress_t progress ;
2004-05-05 21:56:20 +04:00
/* By default, caller should not retry */
* finished = 1 ;
if ( parms - > aborting ) {
2009-09-29 23:35:26 +04:00
if ( ! ( lvs_changed = lvs_using_lv ( cmd , vg , lv ) ) ) {
2004-05-05 21:56:20 +04:00
log_error ( " Failed to generate list of copied LVs: "
" can't abort. " ) ;
return 0 ;
}
2010-08-23 15:34:40 +04:00
if ( ! parms - > poll_fns - > finish_copy ( cmd , vg , lv , lvs_changed ) )
return_0 ;
return 1 ;
2004-05-05 21:56:20 +04:00
}
2009-09-30 22:15:06 +04:00
progress = parms - > poll_fns - > poll_progress ( cmd , lv , name , parms ) ;
2009-09-30 21:43:51 +04:00
if ( progress = = PROGRESS_CHECK_FAILED )
return_0 ;
2004-05-05 21:56:20 +04:00
2009-09-30 21:43:51 +04:00
if ( progress = = PROGRESS_UNFINISHED ) {
2004-05-05 21:56:20 +04:00
/* The only case the caller *should* try again later */
* finished = 0 ;
return 1 ;
}
2009-09-29 23:35:26 +04:00
if ( ! ( lvs_changed = lvs_using_lv ( cmd , vg , lv ) ) ) {
2004-05-05 21:56:20 +04:00
log_error ( " ABORTING: Failed to generate list of copied LVs " ) ;
return 0 ;
}
/* Finished? Or progress to next segment? */
2009-09-30 21:43:51 +04:00
if ( progress = = PROGRESS_FINISHED_ALL ) {
2009-09-29 23:35:26 +04:00
if ( ! parms - > poll_fns - > finish_copy ( cmd , vg , lv , lvs_changed ) )
2011-02-18 18:05:40 +03:00
return_0 ;
2004-05-05 21:56:20 +04:00
} else {
2010-01-09 00:53:07 +03:00
if ( parms - > poll_fns - > update_metadata & &
! parms - > poll_fns - > update_metadata ( cmd , vg , lv , lvs_changed , 0 ) ) {
2004-05-05 21:56:20 +04:00
log_error ( " ABORTING: Segment progression failed. " ) ;
2009-09-29 23:35:26 +04:00
parms - > poll_fns - > finish_copy ( cmd , vg , lv , lvs_changed ) ;
2004-05-05 21:56:20 +04:00
return 0 ;
}
* finished = 0 ; /* Another segment */
}
return 1 ;
}
2015-04-10 17:31:28 +03:00
static void _nanosleep ( unsigned secs , unsigned allow_zero_time )
{
struct timespec wtime = {
. tv_sec = secs ,
} ;
if ( ! secs & & ! allow_zero_time )
wtime . tv_nsec = WAIT_AT_LEAST_NANOSECS ;
while ( ! nanosleep ( & wtime , & wtime ) & & errno = = EINTR ) { }
}
2018-04-09 19:13:43 +03:00
static void _sleep_and_rescan_devices ( struct cmd_context * cmd , struct daemon_parms * parms )
2010-01-23 00:59:42 +03:00
{
if ( parms - > interval & & ! parms - > aborting ) {
2018-04-13 22:40:00 +03:00
/*
* FIXME : do we really need to drop everything and then rescan
* everything between each iteration ? What change exactly does
* each iteration check for , and does seeing that require
* rescanning everything ?
*/
lvmcache_destroy ( cmd , 1 , 0 ) ;
label_scan_destroy ( cmd ) ;
2015-05-19 12:37:39 +03:00
dev_close_all ( ) ;
2015-04-10 17:31:28 +03:00
_nanosleep ( parms - > interval , 1 ) ;
2018-04-09 19:13:43 +03:00
lvmcache_label_scan ( cmd ) ;
2010-01-23 00:59:42 +03:00
}
}
2015-04-10 17:36:50 +03:00
int wait_for_single_lv ( struct cmd_context * cmd , struct poll_operation_id * id ,
struct daemon_parms * parms )
2004-05-05 21:56:20 +04:00
{
2015-07-22 19:42:57 +03:00
struct volume_group * vg = NULL ;
2009-09-29 23:35:26 +04:00
struct logical_volume * lv ;
2004-05-05 21:56:20 +04:00
int finished = 0 ;
2015-07-08 15:53:23 +03:00
uint32_t lockd_state = 0 ;
2015-07-22 19:42:57 +03:00
int ret ;
2004-05-05 21:56:20 +04:00
2018-04-13 22:40:00 +03:00
if ( ! parms - > wait_before_testing )
lvmcache_label_scan ( cmd ) ;
2009-09-29 23:35:26 +04:00
/* Poll for completion */
2004-05-05 21:56:20 +04:00
while ( ! finished ) {
2010-01-23 00:59:42 +03:00
if ( parms - > wait_before_testing )
2018-04-09 19:13:43 +03:00
_sleep_and_rescan_devices ( cmd , parms ) ;
2004-05-05 21:56:20 +04:00
2015-07-22 19:42:57 +03:00
/*
* An ex VG lock is needed because the check can call finish_copy
* which writes the VG .
*/
if ( ! lockd_vg ( cmd , id - > vg_name , " ex " , 0 , & lockd_state ) ) {
2015-03-05 23:00:44 +03:00
log_error ( " ABORTING: Can't lock VG for %s. " , id - > display_name ) ;
return 0 ;
}
2004-05-05 21:56:20 +04:00
/* Locks the (possibly renamed) VG again */
2015-03-05 23:00:44 +03:00
vg = vg_read ( cmd , id - > vg_name , NULL , READ_FOR_UPDATE , lockd_state ) ;
2009-07-01 20:59:37 +04:00
if ( vg_read_error ( vg ) ) {
2004-05-05 21:56:20 +04:00
/* What more could we do here? */
2015-07-22 19:42:57 +03:00
log_error ( " ABORTING: Can't reread VG for %s. " , id - > display_name ) ;
release_vg ( vg ) ;
vg = NULL ;
ret = 0 ;
goto out ;
2004-05-05 21:56:20 +04:00
}
2015-05-19 16:08:50 +03:00
lv = find_lv ( vg , id - > lv_name ) ;
if ( lv & & id - > uuid & & strcmp ( id - > uuid , ( char * ) & lv - > lvid ) )
lv = NULL ;
if ( lv & & parms - > lv_type & & ! ( lv - > status & parms - > lv_type ) )
lv = NULL ;
2011-01-20 02:11:39 +03:00
if ( ! lv ) {
2015-05-19 18:04:29 +03:00
if ( parms - > lv_type = = PVMOVE )
log_print_unless_silent ( " %s: No pvmove in progress - already finished or aborted. " ,
id - > display_name ) ;
else
log_print_unless_silent ( " Can't find LV in %s for %s. " ,
vg - > name , id - > display_name ) ;
2015-07-22 19:42:57 +03:00
ret = 1 ;
goto out ;
2004-05-05 21:56:20 +04:00
}
2014-06-17 03:56:32 +04:00
/*
* If the LV is not active locally , the kernel cannot be
* queried for its status . We must exit in this case .
*/
if ( ! lv_is_active_locally ( lv ) ) {
2015-04-10 15:08:19 +03:00
log_print_unless_silent ( " %s: Interrupted: No longer active. " , id - > display_name ) ;
2015-07-22 19:42:57 +03:00
ret = 1 ;
goto out ;
2014-06-17 03:56:32 +04:00
}
2015-04-10 15:08:19 +03:00
if ( ! _check_lv_status ( cmd , vg , lv , id - > display_name , parms , & finished ) ) {
2015-07-22 19:42:57 +03:00
ret = 0 ;
goto_out ;
2004-05-05 21:56:20 +04:00
}
2011-08-11 00:25:29 +04:00
unlock_and_release_vg ( cmd , vg , vg - > name ) ;
2010-01-23 00:59:42 +03:00
2015-08-18 12:46:42 +03:00
if ( ! lockd_vg ( cmd , id - > vg_name , " un " , 0 , & lockd_state ) )
2015-08-18 18:39:40 +03:00
stack ;
2015-03-05 23:00:44 +03:00
2010-01-23 00:59:42 +03:00
/*
* FIXME Sleeping after testing , while preferred , also works around
* unreliable " finished " state checking in _percent_run . If the
* above _check_lv_status is deferred until after the first sleep it
* may be that a polldaemon will run without ever completing .
*
* This happens when one snapshot - merge polldaemon is racing with
* another ( polling the same LV ) . The first to see the LV status
* reach the " finished " state will alter the LV that the other
* polldaemon ( s ) are polling . These other polldaemon ( s ) can then
* continue polling an LV that doesn ' t have a " status " .
*/
2015-05-05 17:09:53 +03:00
if ( ! parms - > wait_before_testing & & ! finished )
2018-04-09 19:13:43 +03:00
_sleep_and_rescan_devices ( cmd , parms ) ;
2004-05-05 21:56:20 +04:00
}
return 1 ;
2015-07-22 19:42:57 +03:00
out :
if ( vg )
unlock_and_release_vg ( cmd , vg , vg - > name ) ;
2015-08-18 18:39:40 +03:00
if ( ! lockd_vg ( cmd , id - > vg_name , " un " , 0 , & lockd_state ) )
2015-08-18 12:46:42 +03:00
stack ;
2015-07-22 19:42:57 +03:00
return ret ;
2004-05-05 21:56:20 +04:00
}
2015-04-10 15:08:19 +03:00
struct poll_id_list {
struct dm_list list ;
struct poll_operation_id * id ;
} ;
2017-10-18 17:57:46 +03:00
static struct poll_operation_id * _copy_poll_operation_id ( struct dm_pool * mem ,
2015-04-10 15:08:19 +03:00
const struct poll_operation_id * id )
{
struct poll_operation_id * copy ;
2016-02-25 15:31:31 +03:00
if ( ! id | | ! id - > vg_name | | ! id - > lv_name | | ! id - > display_name | | ! id - > uuid ) {
2017-10-18 17:57:46 +03:00
log_error ( INTERNAL_ERROR " Wrong params for _copy_poll_operation_id. " ) ;
2016-02-25 15:31:31 +03:00
return NULL ;
}
2015-04-10 15:08:19 +03:00
2016-02-25 15:31:31 +03:00
if ( ! ( copy = dm_pool_alloc ( mem , sizeof ( * copy ) ) ) ) {
2015-04-10 15:08:19 +03:00
log_error ( " Poll operation ID allocation failed. " ) ;
return NULL ;
}
2016-02-25 15:31:31 +03:00
if ( ! ( copy - > display_name = dm_pool_strdup ( mem , id - > display_name ) ) | |
! ( copy - > lv_name = dm_pool_strdup ( mem , id - > lv_name ) ) | |
! ( copy - > vg_name = dm_pool_strdup ( mem , id - > vg_name ) ) | |
! ( copy - > uuid = dm_pool_strdup ( mem , id - > uuid ) ) ) {
2015-04-10 15:08:19 +03:00
log_error ( " Failed to copy one or more poll_operation_id members. " ) ;
2016-02-25 15:31:31 +03:00
dm_pool_free ( mem , copy ) ;
2015-04-10 15:08:19 +03:00
return NULL ;
}
return copy ;
}
2017-10-18 17:57:46 +03:00
static struct poll_id_list * _poll_id_list_create ( struct dm_pool * mem ,
const struct poll_operation_id * id )
2015-04-10 15:08:19 +03:00
{
struct poll_id_list * idl = ( struct poll_id_list * ) dm_pool_alloc ( mem , sizeof ( struct poll_id_list ) ) ;
if ( ! idl ) {
log_error ( " Poll ID list allocation failed. " ) ;
return NULL ;
}
2017-10-18 17:57:46 +03:00
if ( ! ( idl - > id = _copy_poll_operation_id ( mem , id ) ) ) {
2015-04-10 15:08:19 +03:00
dm_pool_free ( mem , idl ) ;
return NULL ;
}
return idl ;
}
2004-05-05 21:56:20 +04:00
static int _poll_vg ( struct cmd_context * cmd , const char * vgname ,
2014-11-27 17:02:13 +03:00
struct volume_group * vg , struct processing_handle * handle )
2004-05-05 21:56:20 +04:00
{
2015-03-31 12:26:53 +03:00
struct daemon_parms * parms ;
2015-03-30 17:25:04 +03:00
struct lv_list * lvl ;
2015-04-10 15:08:19 +03:00
struct dm_list idls ;
struct poll_id_list * idl ;
struct poll_operation_id id ;
2009-09-29 23:35:26 +04:00
struct logical_volume * lv ;
2004-05-05 21:56:20 +04:00
int finished ;
2015-03-31 12:26:53 +03:00
if ( ! handle | | ! ( parms = ( struct daemon_parms * ) handle - > custom_handle ) ) {
2012-06-21 14:43:31 +04:00
log_error ( INTERNAL_ERROR " Handle is undefined. " ) ;
return ECMD_FAILED ;
}
2015-04-10 15:08:19 +03:00
dm_list_init ( & idls ) ;
2015-03-30 17:25:04 +03:00
/*
2015-04-14 15:43:16 +03:00
* first iterate all LVs in a VG and collect LVs suitable
* for polling ( or an abort ) which takes place below
2015-03-30 17:25:04 +03:00
*/
dm_list_iterate_items ( lvl , & vg - > lvs ) {
2009-09-29 23:35:26 +04:00
lv = lvl - > lv ;
if ( ! ( lv - > status & parms - > lv_type ) )
2004-05-05 21:56:20 +04:00
continue ;
2015-04-10 15:08:19 +03:00
id . display_name = parms - > poll_fns - > get_copy_name_from_lv ( lv ) ;
if ( ! id . display_name & & ! parms - > aborting )
2004-05-05 21:56:20 +04:00
continue ;
2010-08-23 15:34:10 +04:00
2015-04-10 15:08:19 +03:00
if ( ! id . display_name ) {
2015-04-03 18:14:50 +03:00
log_error ( " Device name for LV %s not found in metadata. "
" (unfinished pvmove mirror removal?) " , display_lvname ( lv ) ) ;
goto err ;
}
2008-01-30 17:00:02 +03:00
/* FIXME Need to do the activation from _set_up_pvmove here
2013-09-23 22:46:28 +04:00
* if it ' s not running and we ' re not aborting . */
if ( ! lv_is_active ( lv ) ) {
2015-04-10 15:08:19 +03:00
log_print_unless_silent ( " %s: Skipping inactive LV. Try lvchange or vgchange. " , id . display_name ) ;
2013-09-23 22:46:28 +04:00
continue ;
}
2015-04-10 15:08:19 +03:00
id . lv_name = lv - > name ;
id . vg_name = vg - > name ;
id . uuid = lv - > lvid . s ;
2017-10-18 17:57:46 +03:00
idl = _poll_id_list_create ( cmd - > mem , & id ) ;
2015-04-10 15:08:19 +03:00
if ( ! idl ) {
log_error ( " Failed to create poll_id_list. " ) ;
2015-03-30 17:25:04 +03:00
goto err ;
}
2015-04-10 15:08:19 +03:00
dm_list_add ( & idls , & idl - > list ) ;
2004-05-05 21:56:20 +04:00
}
2015-04-14 15:43:16 +03:00
/* perform the poll operation on LVs collected in previous cycle */
2015-04-10 15:08:19 +03:00
dm_list_iterate_items ( idl , & idls ) {
2015-05-19 16:08:50 +03:00
if ( ! ( lv = find_lv ( vg , idl - > id - > lv_name ) ) )
continue ;
if ( idl - > id - > uuid & & strcmp ( idl - > id - > uuid , ( char * ) & lv - > lvid ) )
continue ;
if ( parms - > lv_type & & ! ( lv - > status & parms - > lv_type ) )
continue ;
if ( _check_lv_status ( cmd , vg , lv , idl - > id - > display_name , parms , & finished ) & & ! finished )
2015-04-14 15:43:16 +03:00
parms - > outstanding_count + + ;
2015-03-30 17:25:04 +03:00
}
2004-05-05 21:56:20 +04:00
2015-03-30 17:25:04 +03:00
err :
2015-04-10 15:08:19 +03:00
if ( ! dm_list_empty ( & idls ) )
dm_pool_free ( cmd - > mem , dm_list_item ( dm_list_first ( & idls ) , struct poll_id_list ) ) ;
2015-03-30 17:25:04 +03:00
return ECMD_PROCESSED ;
2004-05-05 21:56:20 +04:00
}
static void _poll_for_all_vgs ( struct cmd_context * cmd ,
2015-02-13 12:36:06 +03:00
struct processing_handle * handle )
2004-05-05 21:56:20 +04:00
{
2015-02-13 12:36:06 +03:00
struct daemon_parms * parms = ( struct daemon_parms * ) handle - > custom_handle ;
2014-11-27 17:02:13 +03:00
2004-05-05 21:56:20 +04:00
while ( 1 ) {
parms - > outstanding_count = 0 ;
2016-05-03 12:46:28 +03:00
process_each_vg ( cmd , 0 , NULL , NULL , NULL , READ_FOR_UPDATE , 0 , handle , _poll_vg ) ;
2004-05-05 21:56:20 +04:00
if ( ! parms - > outstanding_count )
break ;
2015-04-10 17:31:28 +03:00
_nanosleep ( parms - > interval , 1 ) ;
2004-05-05 21:56:20 +04:00
}
}
2015-05-09 02:59:18 +03:00
# ifdef LVMPOLLD_SUPPORT
typedef struct {
struct daemon_parms * parms ;
struct dm_list idls ;
} lvmpolld_parms_t ;
2017-10-18 17:57:46 +03:00
static int _report_progress ( struct cmd_context * cmd , struct poll_operation_id * id ,
struct daemon_parms * parms )
2015-05-09 02:59:18 +03:00
{
struct volume_group * vg ;
struct logical_volume * lv ;
2015-07-08 15:53:23 +03:00
uint32_t lockd_state = 0 ;
2015-03-05 23:00:44 +03:00
int ret ;
/*
2015-07-22 19:42:57 +03:00
* It ' s reasonable to expect a lockd_vg ( " sh " ) here , but it should
* not actually be needed , because we only report the progress on
* the same host where the pvmove / lvconvert is happening . This means
* that the local pvmove / lvconvert / lvpoll commands are updating the
* local lvmetad with the latest info they have , and we just need to
* read the latest info that they have put into lvmetad about their
* progress . No VG lock is needed to protect anything here ( we ' re
* just reading the VG ) , and no VG lock is needed to force a VG read
* from disk to get changes from other hosts , because the only change
* to the VG we ' re interested in is the change done locally .
2015-03-05 23:00:44 +03:00
*/
2015-05-09 02:59:18 +03:00
2015-03-05 23:00:44 +03:00
vg = vg_read ( cmd , id - > vg_name , NULL , 0 , lockd_state ) ;
2015-05-09 02:59:18 +03:00
if ( vg_read_error ( vg ) ) {
release_vg ( vg ) ;
log_error ( " Can't reread VG for %s " , id - > display_name ) ;
2015-03-05 23:00:44 +03:00
ret = 0 ;
goto out_ret ;
2015-05-09 02:59:18 +03:00
}
2015-05-19 16:08:50 +03:00
lv = find_lv ( vg , id - > lv_name ) ;
if ( lv & & id - > uuid & & strcmp ( id - > uuid , ( char * ) & lv - > lvid ) )
lv = NULL ;
2015-10-19 17:56:45 +03:00
/*
* CONVERTING is set only during mirror upconversion but we may need to
* read LV ' s progress info even when it ' s not converting ( linear - > mirror )
*/
if ( lv & & ( parms - > lv_type ^ CONVERTING ) & & ! ( lv - > status & parms - > lv_type ) )
2015-05-19 16:08:50 +03:00
lv = NULL ;
2015-05-09 02:59:18 +03:00
if ( ! lv ) {
2015-05-21 11:17:29 +03:00
if ( parms - > lv_type = = PVMOVE )
log_verbose ( " %s: No pvmove in progress - already finished or aborted. " ,
id - > display_name ) ;
else
log_verbose ( " Can't find LV in %s for %s. Already finished or removed. " ,
vg - > name , id - > display_name ) ;
2015-03-05 23:00:44 +03:00
ret = 1 ;
2015-05-21 11:17:29 +03:00
goto out ;
2015-05-09 02:59:18 +03:00
}
if ( ! lv_is_active_locally ( lv ) ) {
2015-05-21 11:17:29 +03:00
log_verbose ( " %s: Interrupted: No longer active. " , id - > display_name ) ;
2015-03-05 23:00:44 +03:00
ret = 1 ;
2015-05-21 11:17:29 +03:00
goto out ;
2015-05-09 02:59:18 +03:00
}
if ( parms - > poll_fns - > poll_progress ( cmd , lv , id - > display_name , parms ) = = PROGRESS_CHECK_FAILED ) {
2015-03-05 23:00:44 +03:00
ret = 0 ;
goto out ;
2015-05-09 02:59:18 +03:00
}
2015-03-05 23:00:44 +03:00
ret = 1 ;
2015-05-21 11:17:29 +03:00
out :
2015-05-09 02:59:18 +03:00
unlock_and_release_vg ( cmd , vg , vg - > name ) ;
2015-03-05 23:00:44 +03:00
out_ret :
return ret ;
2015-05-09 02:59:18 +03:00
}
static int _lvmpolld_init_poll_vg ( struct cmd_context * cmd , const char * vgname ,
struct volume_group * vg , struct processing_handle * handle )
{
int r ;
struct lv_list * lvl ;
struct logical_volume * lv ;
struct poll_id_list * idl ;
struct poll_operation_id id ;
lvmpolld_parms_t * lpdp = ( lvmpolld_parms_t * ) handle - > custom_handle ;
dm_list_iterate_items ( lvl , & vg - > lvs ) {
lv = lvl - > lv ;
if ( ! ( lv - > status & lpdp - > parms - > lv_type ) )
continue ;
id . display_name = lpdp - > parms - > poll_fns - > get_copy_name_from_lv ( lv ) ;
if ( ! id . display_name & & ! lpdp - > parms - > aborting )
continue ;
2015-08-04 10:51:16 +03:00
id . vg_name = lv - > vg - > name ;
id . lv_name = lv - > name ;
2015-07-08 16:08:39 +03:00
if ( ! * lv - > lvid . s ) {
2015-05-09 02:59:18 +03:00
log_print_unless_silent ( " Missing LV uuid within: %s/%s " , id . vg_name , id . lv_name ) ;
continue ;
}
id . uuid = lv - > lvid . s ;
r = lvmpolld_poll_init ( cmd , & id , lpdp - > parms ) ;
if ( r & & ! lpdp - > parms - > background ) {
2017-10-18 17:57:46 +03:00
if ( ! ( idl = _poll_id_list_create ( cmd - > mem , & id ) ) )
2015-05-09 02:59:18 +03:00
return ECMD_FAILED ;
dm_list_add ( & lpdp - > idls , & idl - > list ) ;
}
}
return ECMD_PROCESSED ;
}
static void _lvmpolld_poll_for_all_vgs ( struct cmd_context * cmd ,
struct daemon_parms * parms ,
struct processing_handle * handle )
{
int r ;
struct dm_list * first ;
struct poll_id_list * idl , * tlv ;
unsigned finished ;
lvmpolld_parms_t lpdp = {
. parms = parms
} ;
dm_list_init ( & lpdp . idls ) ;
handle - > custom_handle = & lpdp ;
2016-05-03 12:46:28 +03:00
process_each_vg ( cmd , 0 , NULL , NULL , NULL , 0 , 0 , handle , _lvmpolld_init_poll_vg ) ;
2015-05-09 02:59:18 +03:00
first = dm_list_first ( & lpdp . idls ) ;
while ( ! dm_list_empty ( & lpdp . idls ) ) {
dm_list_iterate_items_safe ( idl , tlv , & lpdp . idls ) {
r = lvmpolld_request_info ( idl - > id , lpdp . parms ,
& finished ) ;
if ( ! r | | finished )
dm_list_del ( & idl - > list ) ;
else if ( ! parms - > aborting )
2017-10-18 17:57:46 +03:00
_report_progress ( cmd , idl - > id , lpdp . parms ) ;
2015-05-09 02:59:18 +03:00
}
2015-05-19 12:37:39 +03:00
if ( lpdp . parms - > interval )
dev_close_all ( ) ;
2015-05-09 02:59:18 +03:00
_nanosleep ( lpdp . parms - > interval , 0 ) ;
}
if ( first )
dm_pool_free ( cmd - > mem , dm_list_item ( first , struct poll_id_list ) ) ;
}
static int _lvmpoll_daemon ( struct cmd_context * cmd , struct poll_operation_id * id ,
struct daemon_parms * parms )
{
int r ;
struct processing_handle * handle = NULL ;
unsigned finished = 0 ;
if ( parms - > aborting )
parms - > interval = 0 ;
if ( id ) {
r = lvmpolld_poll_init ( cmd , id , parms ) ;
if ( r & & ! parms - > background ) {
while ( 1 ) {
if ( ! ( r = lvmpolld_request_info ( id , parms , & finished ) ) | |
finished | |
2017-10-18 17:57:46 +03:00
( ! parms - > aborting & & ! ( r = _report_progress ( cmd , id , parms ) ) ) )
2015-05-09 02:59:18 +03:00
break ;
2015-05-19 12:37:39 +03:00
if ( parms - > interval )
dev_close_all ( ) ;
2015-05-09 02:59:18 +03:00
_nanosleep ( parms - > interval , 0 ) ;
}
}
return r ? ECMD_PROCESSED : ECMD_FAILED ;
}
2017-07-19 17:16:12 +03:00
/* process all in-flight operations */
if ( ! ( handle = init_processing_handle ( cmd , NULL ) ) ) {
log_error ( " Failed to initialize processing handle. " ) ;
return ECMD_FAILED ;
}
_lvmpolld_poll_for_all_vgs ( cmd , parms , handle ) ;
destroy_processing_handle ( cmd , handle ) ;
return ECMD_PROCESSED ;
2015-05-09 02:59:18 +03:00
}
# else
# define _lvmpoll_daemon(cmd, id, parms) (ECMD_FAILED)
# endif /* LVMPOLLD_SUPPORT */
2010-01-11 22:19:17 +03:00
/*
* Only allow * one * return from poll_daemon ( ) ( the parent ) .
* If there is a child it must exit ( ignoring the memory leak messages ) .
* - ' background ' is advisory so a child polldaemon may not be used even
* if it was requested .
*/
2015-04-10 15:08:19 +03:00
static int _poll_daemon ( struct cmd_context * cmd , struct poll_operation_id * id ,
struct daemon_parms * parms )
2004-05-05 21:56:20 +04:00
{
2015-02-13 12:36:06 +03:00
struct processing_handle * handle = NULL ;
2010-01-11 22:19:17 +03:00
int daemon_mode = 0 ;
int ret = ECMD_PROCESSED ;
2004-05-05 21:56:20 +04:00
2015-03-17 20:40:43 +03:00
if ( parms - > background ) {
2013-09-03 18:06:16 +04:00
daemon_mode = become_daemon ( cmd , 0 ) ;
2010-01-11 22:19:17 +03:00
if ( daemon_mode = = 0 )
return ECMD_PROCESSED ; /* Parent */
2017-07-19 17:16:12 +03:00
if ( daemon_mode = = 1 )
2015-03-17 20:40:43 +03:00
parms - > progress_display = 0 ; /* Child */
2004-05-05 21:56:20 +04:00
/* FIXME Use wait_event (i.e. interval = 0) and */
/* fork one daemon per copy? */
2016-04-20 01:07:22 +03:00
2016-04-21 23:58:34 +03:00
if ( ( daemon_mode = = 1 ) & & find_config_tree_bool ( cmd , global_use_lvmetad_CFG , NULL ) ) {
2016-04-20 01:07:22 +03:00
if ( ! lvmetad_connect ( cmd ) )
log_warn ( " WARNING: lvm polling process %d cannot connect to lvmetad. " , getpid ( ) ) ;
}
2004-05-05 21:56:20 +04:00
}
2009-09-29 23:35:26 +04:00
/*
* Process one specific task or all incomplete tasks ?
*/
2018-04-26 00:23:55 +03:00
/* clear lvmcache/bcache/fds from the parent */
lvmcache_destroy ( cmd , 1 , 0 ) ;
label_scan_destroy ( cmd ) ;
dev_close_all ( ) ;
2015-04-10 15:08:19 +03:00
if ( id ) {
2015-04-10 17:36:50 +03:00
if ( ! wait_for_single_lv ( cmd , id , parms ) ) {
2009-09-15 02:47:49 +04:00
stack ;
2010-01-11 22:19:17 +03:00
ret = ECMD_FAILED ;
2009-09-15 02:47:49 +04:00
}
2015-02-13 12:36:06 +03:00
} else {
2015-03-17 20:44:25 +03:00
if ( ! parms - > interval )
parms - > interval = find_config_tree_int ( cmd , activation_polling_interval_CFG , NULL ) ;
2018-04-26 00:23:55 +03:00
2016-05-31 13:24:05 +03:00
if ( ! ( handle = init_processing_handle ( cmd , NULL ) ) ) {
2015-02-13 12:36:06 +03:00
log_error ( " Failed to initialize processing handle. " ) ;
ret = ECMD_FAILED ;
} else {
2015-03-17 20:40:43 +03:00
handle - > custom_handle = parms ;
2015-02-13 12:36:06 +03:00
_poll_for_all_vgs ( cmd , handle ) ;
}
}
2004-05-05 21:56:20 +04:00
2015-03-17 20:40:43 +03:00
if ( parms - > background & & daemon_mode = = 1 ) {
2015-02-13 12:42:21 +03:00
destroy_processing_handle ( cmd , handle ) ;
2010-01-11 22:19:17 +03:00
/*
* child was successfully forked :
* background polldaemon must not return to the caller
* because it will redundantly continue performing the
* caller ' s task ( that the parent already performed )
*/
/* FIXME Attempt proper cleanup */
_exit ( lvm_return_code ( ret ) ) ;
}
2015-02-13 12:42:21 +03:00
destroy_processing_handle ( cmd , handle ) ;
2010-01-11 22:19:17 +03:00
return ret ;
2004-05-05 21:56:20 +04:00
}
2015-03-17 20:31:41 +03:00
2015-03-17 20:40:43 +03:00
static int _daemon_parms_init ( struct cmd_context * cmd , struct daemon_parms * parms ,
unsigned background , struct poll_functions * poll_fns ,
const char * progress_title , uint64_t lv_type )
{
sign_t interval_sign ;
parms - > aborting = arg_is_set ( cmd , abort_ARG ) ;
parms - > background = background ;
interval_sign = arg_sign_value ( cmd , interval_ARG , SIGN_NONE ) ;
if ( interval_sign = = SIGN_MINUS ) {
log_error ( " Argument to --interval cannot be negative. " ) ;
return 0 ;
}
parms - > interval = arg_uint_value ( cmd , interval_ARG ,
find_config_tree_int ( cmd , activation_polling_interval_CFG , NULL ) ) ;
parms - > wait_before_testing = ( interval_sign = = SIGN_PLUS ) ;
parms - > progress_title = progress_title ;
parms - > lv_type = lv_type ;
parms - > poll_fns = poll_fns ;
if ( parms - > interval & & ! parms - > aborting )
log_verbose ( " Checking progress %s waiting every %u seconds. " ,
( parms - > wait_before_testing ? " after " : " before " ) ,
parms - > interval ) ;
2015-03-17 20:44:25 +03:00
parms - > progress_display = parms - > interval ? 1 : 0 ;
2015-03-17 20:40:43 +03:00
return 1 ;
}
2015-04-10 15:08:19 +03:00
int poll_daemon ( struct cmd_context * cmd , unsigned background ,
2015-03-17 20:31:41 +03:00
uint64_t lv_type , struct poll_functions * poll_fns ,
2015-04-10 15:08:19 +03:00
const char * progress_title , struct poll_operation_id * id )
2015-03-17 20:31:41 +03:00
{
2015-03-17 20:40:43 +03:00
struct daemon_parms parms ;
if ( ! _daemon_parms_init ( cmd , & parms , background , poll_fns , progress_title , lv_type ) )
return_EINVALID_CMD_LINE ;
2015-05-09 02:59:18 +03:00
if ( lvmpolld_use ( ) )
return _lvmpoll_daemon ( cmd , id , & parms ) ;
2017-07-19 17:16:12 +03:00
/* classical polling allows only PMVOVE or 0 values */
parms . lv_type & = PVMOVE ;
return _poll_daemon ( cmd , id , & parms ) ;
2015-03-17 20:31:41 +03:00
}