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 .
2007-08-21 00:55:30 +04:00
* Copyright ( C ) 2004 - 2007 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 ,
* Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*/
# include "tools.h"
# include "polldaemon.h"
2010-01-11 22:19:17 +03:00
# include "lvm2cmdline.h"
2004-05-05 21:56:20 +04:00
# include <signal.h>
# include <sys/wait.h>
2010-07-09 19:34:40 +04:00
static void _sigchld_handler ( int sig __attribute__ ( ( unused ) ) )
2004-05-05 21:56:20 +04:00
{
while ( wait4 ( - 1 , NULL , WNOHANG | WUNTRACED , NULL ) > 0 ) ;
}
2010-01-11 22:19:17 +03:00
/*
* returns :
* - 1 if the fork failed
* 0 if the parent
* 1 if the child
*/
2004-05-05 21:56:20 +04:00
static int _become_daemon ( struct cmd_context * cmd )
{
2012-02-28 14:06:53 +04:00
static const char devnull [ ] = " /dev/null " ;
int null_fd ;
2004-05-05 21:56:20 +04:00
pid_t pid ;
struct sigaction act = {
{ _sigchld_handler } ,
. sa_flags = SA_NOCLDSTOP ,
} ;
log_verbose ( " Forking background process " ) ;
sigaction ( SIGCHLD , & act , NULL ) ;
2011-01-12 23:42:50 +03:00
sync_local_dev_names ( cmd ) ; /* Flush ops and reset dm cookie */
2011-01-10 22:31:02 +03:00
2004-05-05 21:56:20 +04:00
if ( ( pid = fork ( ) ) = = - 1 ) {
log_error ( " fork failed: %s " , strerror ( errno ) ) ;
2010-01-11 22:19:17 +03:00
return - 1 ;
2004-05-05 21:56:20 +04:00
}
/* Parent */
if ( pid > 0 )
return 0 ;
/* Child */
if ( setsid ( ) = = - 1 )
log_error ( " Background process failed to setsid: %s " ,
strerror ( errno ) ) ;
2012-02-28 14:06:53 +04:00
/* For poll debugging it's best to disable for compilation */
# if 1
if ( ( null_fd = open ( devnull , O_RDWR ) ) = = - 1 ) {
log_sys_error ( " open " , devnull ) ;
_exit ( ECMD_FAILED ) ;
}
if ( dup2 ( null_fd , STDIN_FILENO ) | | /* reopen stdin */
dup2 ( null_fd , STDOUT_FILENO ) | | /* reopen stdout */
dup2 ( null_fd , STDERR_FILENO ) ) { /* reopen stderr */
log_sys_error ( " dup2 " , " redirect " ) ;
( void ) close ( null_fd ) ;
_exit ( ECMD_FAILED ) ;
}
2004-05-05 21:56:20 +04:00
2012-02-28 14:06:53 +04:00
if ( null_fd > STDERR_FILENO )
( void ) close ( null_fd ) ;
init_verbose ( VERBOSE_BASE_LEVEL ) ;
# endif
2010-01-09 00:53:07 +03:00
strncpy ( * cmd - > argv , " (lvm2) " , strlen ( * cmd - > argv ) ) ;
2004-05-05 21:56:20 +04:00
reset_locking ( ) ;
2011-01-05 15:59:46 +03:00
if ( ! lvmcache_init ( ) )
/* FIXME Clean up properly here */
_exit ( ECMD_FAILED ) ;
2004-05-05 21:56:20 +04:00
dev_close_all ( ) ;
return 1 ;
}
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 )
{
2010-11-30 14:53:31 +03:00
percent_t segment_percent = PERCENT_0 , overall_percent = 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 ) | |
( segment_percent = = 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 )
log_print ( " %s: %s: %.1f%% " , name , parms - > progress_title ,
2010-11-30 14:53:31 +03:00
percent_to_float ( overall_percent ) ) ;
2009-09-30 21:43:51 +04:00
else
log_verbose ( " %s: %s: %.1f%% " , name , parms - > progress_title ,
2010-11-30 14:53:31 +03:00
percent_to_float ( overall_percent ) ) ;
2009-09-30 21:43:51 +04:00
2010-11-30 14:53:31 +03:00
if ( segment_percent ! = PERCENT_100 )
2009-09-30 21:43:51 +04:00
return PROGRESS_UNFINISHED ;
2010-11-30 14:53:31 +03:00
if ( overall_percent = = 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 ;
}
2010-01-23 00:59:42 +03:00
static void _sleep_and_rescan_devices ( struct daemon_parms * parms )
{
/* FIXME Use alarm for regular intervals instead */
if ( parms - > interval & & ! parms - > aborting ) {
sleep ( parms - > interval ) ;
/* Devices might have changed while we slept */
init_full_scan_done ( 0 ) ;
}
}
2009-09-29 23:35:26 +04:00
static int _wait_for_single_lv ( struct cmd_context * cmd , const char * name , const char * uuid ,
2010-01-23 00:59:42 +03:00
struct daemon_parms * parms )
2004-05-05 21:56:20 +04:00
{
struct volume_group * vg ;
2009-09-29 23:35:26 +04:00
struct logical_volume * lv ;
2004-05-05 21:56:20 +04:00
int finished = 0 ;
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 )
_sleep_and_rescan_devices ( parms ) ;
2004-05-05 21:56:20 +04:00
/* Locks the (possibly renamed) VG again */
2009-07-01 20:59:37 +04:00
vg = parms - > poll_fns - > get_copy_vg ( cmd , name , uuid ) ;
if ( vg_read_error ( vg ) ) {
2011-08-11 00:25:29 +04:00
release_vg ( vg ) ;
2004-05-05 21:56:20 +04:00
log_error ( " ABORTING: Can't reread VG for %s " , name ) ;
/* What more could we do here? */
return 0 ;
}
2011-01-20 02:11:39 +03:00
lv = parms - > poll_fns - > get_copy_lv ( cmd , vg , name , uuid , parms - > lv_type ) ;
if ( ! lv & & parms - > lv_type = = PVMOVE ) {
log_print ( " %s: no pvmove in progress - already finished or aborted. " ,
name ) ;
2011-08-11 00:25:29 +04:00
unlock_and_release_vg ( cmd , vg , vg - > name ) ;
2011-01-20 02:11:39 +03:00
return 1 ;
}
if ( ! lv ) {
2010-01-09 00:53:07 +03:00
log_error ( " ABORTING: Can't find LV in %s for %s " ,
2004-05-05 21:56:20 +04:00
vg - > name , name ) ;
2011-08-11 00:25:29 +04:00
unlock_and_release_vg ( cmd , vg , vg - > name ) ;
2004-05-05 21:56:20 +04:00
return 0 ;
}
2009-09-29 23:35:26 +04:00
if ( ! _check_lv_status ( cmd , vg , lv , name , parms , & finished ) ) {
2011-08-11 00:25:29 +04:00
unlock_and_release_vg ( cmd , vg , vg - > name ) ;
2011-02-18 18:05:40 +03:00
return_0 ;
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
/*
* 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 " .
*/
if ( ! parms - > wait_before_testing )
_sleep_and_rescan_devices ( parms ) ;
2004-05-05 21:56:20 +04:00
}
return 1 ;
}
static int _poll_vg ( struct cmd_context * cmd , const char * vgname ,
2009-07-01 21:00:50 +04:00
struct volume_group * vg , void * handle )
2004-05-05 21:56:20 +04:00
{
struct daemon_parms * parms = ( struct daemon_parms * ) handle ;
struct lv_list * lvl ;
2009-09-29 23:35:26 +04:00
struct logical_volume * lv ;
2004-05-05 21:56:20 +04:00
const char * name ;
int finished ;
2008-11-04 01:14:30 +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 ;
2010-08-23 15:34:10 +04:00
name = parms - > poll_fns - > get_copy_name_from_lv ( lv ) ;
if ( ! name & & ! parms - > aborting )
2004-05-05 21:56:20 +04:00
continue ;
2010-08-23 15:34:10 +04:00
2008-01-30 17:00:02 +03:00
/* FIXME Need to do the activation from _set_up_pvmove here
2004-05-05 21:56:20 +04:00
* if it ' s not running and we ' re not aborting */
2009-09-29 23:35:26 +04:00
if ( _check_lv_status ( cmd , vg , lv , name , parms , & finished ) & &
! finished )
2004-05-05 21:56:20 +04:00
parms - > outstanding_count + + ;
}
return ECMD_PROCESSED ;
}
static void _poll_for_all_vgs ( struct cmd_context * cmd ,
struct daemon_parms * parms )
{
while ( 1 ) {
parms - > outstanding_count = 0 ;
2009-07-01 21:00:50 +04:00
process_each_vg ( cmd , 0 , NULL , READ_FOR_UPDATE , parms , _poll_vg ) ;
2004-05-05 21:56:20 +04:00
if ( ! parms - > outstanding_count )
break ;
sleep ( parms - > interval ) ;
}
}
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 .
*/
2009-06-01 18:43:27 +04:00
int poll_daemon ( struct cmd_context * cmd , const char * name , const char * uuid ,
unsigned background ,
2011-09-06 22:49:31 +04:00
uint64_t lv_type , struct poll_functions * poll_fns ,
2007-12-22 15:13:29 +03:00
const char * progress_title )
2004-05-05 21:56:20 +04:00
{
struct daemon_parms parms ;
2010-01-11 22:19:17 +03:00
int daemon_mode = 0 ;
int ret = ECMD_PROCESSED ;
2010-01-23 00:59:42 +03:00
sign_t interval_sign ;
2004-05-05 21:56:20 +04:00
2009-11-03 18:50:42 +03:00
parms . aborting = arg_is_set ( cmd , abort_ARG ) ;
2004-05-05 21:56:20 +04:00
parms . background = background ;
2010-01-23 00:59:42 +03:00
interval_sign = arg_sign_value ( cmd , interval_ARG , 0 ) ;
if ( interval_sign = = SIGN_MINUS )
log_error ( " Argument to --interval cannot be negative " ) ;
2010-04-13 05:43:56 +04:00
parms . interval = arg_uint_value ( cmd , interval_ARG ,
find_config_tree_int ( cmd , " activation/polling_interval " ,
DEFAULT_INTERVAL ) ) ;
2010-01-23 00:59:42 +03:00
parms . wait_before_testing = ( interval_sign = = SIGN_PLUS ) ;
2004-05-05 21:56:20 +04:00
parms . progress_display = 1 ;
2007-12-22 15:13:29 +03:00
parms . progress_title = progress_title ;
2004-05-05 21:56:20 +04:00
parms . lv_type = lv_type ;
parms . poll_fns = poll_fns ;
if ( parms . interval & & ! parms . aborting )
2010-01-23 00:59:42 +03:00
log_verbose ( " Checking progress %s waiting every %u seconds " ,
( parms . wait_before_testing ? " after " : " before " ) ,
2004-05-05 21:56:20 +04:00
parms . interval ) ;
if ( ! parms . interval ) {
parms . progress_display = 0 ;
/* FIXME Disabled multiple-copy wait_event */
if ( ! name )
2010-04-13 05:43:56 +04:00
parms . interval = find_config_tree_int ( cmd , " activation/polling_interval " ,
DEFAULT_INTERVAL ) ;
2004-05-05 21:56:20 +04:00
}
if ( parms . background ) {
2010-01-11 22:19:17 +03:00
daemon_mode = _become_daemon ( cmd ) ;
if ( daemon_mode = = 0 )
return ECMD_PROCESSED ; /* Parent */
else if ( daemon_mode = = 1 )
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? */
}
2009-09-29 23:35:26 +04:00
/*
* Process one specific task or all incomplete tasks ?
*/
2004-05-05 21:56:20 +04:00
if ( name ) {
2009-09-29 23:35:26 +04:00
if ( ! _wait_for_single_lv ( cmd , name , uuid , & 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
}
2004-05-05 21:56:20 +04:00
} else
_poll_for_all_vgs ( cmd , & parms ) ;
2010-01-11 22:19:17 +03:00
if ( parms . background & & daemon_mode = = 1 ) {
/*
* 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 ) ) ;
}
return ret ;
2004-05-05 21:56:20 +04:00
}