2008-01-09 18:32:19 +03:00
/*
2011-12-22 20:37:01 +04:00
* Copyright ( C ) 2007 - 2011 Red Hat , Inc . All rights reserved .
2008-01-09 18:32:19 +03: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
* of the GNU Lesser General Public License v .2 .1 .
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program ; if not , write to the Free Software Foundation ,
* Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*/
2010-01-22 03:18:37 +03:00
# include "lib.h"
2010-01-22 01:15:45 +03:00
2008-01-09 18:32:19 +03:00
# include "lvm2cmd.h"
2010-01-22 01:15:45 +03:00
# include "errors.h"
# include "libdevmapper-event.h"
# include "dmeventd_lvm.h"
2010-10-29 20:43:51 +04:00
# include <sys/wait.h>
2008-01-09 18:32:19 +03:00
# include <syslog.h> /* FIXME Replace syslog with multilog */
/* FIXME Missing openlog? */
/* First warning when snapshot is 80% full. */
# define WARNING_THRESH 80
2010-10-15 20:28:14 +04:00
/* Run a check every 5%. */
# define CHECK_STEP 5
/* Do not bother checking snapshots less than 50% full. */
# define CHECK_MINIMUM 50
2008-01-09 18:32:19 +03:00
2010-10-29 20:43:51 +04:00
# define UMOUNT_COMMAND " / bin / umount"
2011-11-21 16:31:18 +04:00
struct dso_state {
2013-05-26 19:07:08 +04:00
struct dm_pool * mem ;
2011-11-21 16:31:18 +04:00
int percent_check ;
2013-05-26 19:07:08 +04:00
uint64_t known_size ;
2011-12-22 20:37:01 +04:00
char cmd_str [ 1024 ] ;
2011-11-21 16:31:18 +04:00
} ;
2010-10-29 20:43:51 +04:00
static int _run ( const char * cmd , . . . )
{
va_list ap ;
int argc = 1 ; /* for argv[0], i.e. cmd */
int i = 0 ;
const char * * argv ;
pid_t pid = fork ( ) ;
int status ;
if ( pid = = 0 ) { /* child */
va_start ( ap , cmd ) ;
while ( va_arg ( ap , const char * ) )
+ + argc ;
va_end ( ap ) ;
/* + 1 for the terminating NULL */
argv = alloca ( sizeof ( const char * ) * ( argc + 1 ) ) ;
argv [ 0 ] = cmd ;
va_start ( ap , cmd ) ;
while ( ( argv [ + + i ] = va_arg ( ap , const char * ) ) ) ;
va_end ( ap ) ;
execvp ( cmd , ( char * * ) argv ) ;
syslog ( LOG_ERR , " Failed to execute %s: %s. \n " , cmd , strerror ( errno ) ) ;
exit ( 127 ) ;
}
if ( pid > 0 ) { /* parent */
if ( waitpid ( pid , & status , 0 ) ! = pid )
return 0 ; /* waitpid failed */
if ( ! WIFEXITED ( status ) | | WEXITSTATUS ( status ) )
return 0 ; /* the child failed */
}
if ( pid < 0 )
return 0 ; /* fork failed */
return 1 ; /* all good */
}
2011-12-22 20:37:01 +04:00
static int _extend ( const char * cmd )
2010-10-15 20:28:14 +04:00
{
2011-12-22 20:37:01 +04:00
return dmeventd_lvm2_run ( cmd ) = = ECMD_PROCESSED ;
2010-10-15 20:28:14 +04:00
}
2010-10-29 20:43:51 +04:00
static void _umount ( const char * device , int major , int minor )
{
FILE * mounts ;
char buffer [ 4096 ] ;
char * words [ 3 ] ;
struct stat st ;
if ( ! ( mounts = fopen ( " /proc/mounts " , " r " ) ) ) {
syslog ( LOG_ERR , " Could not read /proc/mounts. Not umounting %s. \n " , device ) ;
return ;
}
while ( ! feof ( mounts ) ) {
/* read a line of /proc/mounts */
if ( ! fgets ( buffer , sizeof ( buffer ) , mounts ) )
break ; /* eof, likely */
/* words[0] is the mount point and words[1] is the device path */
2012-02-13 18:17:04 +04:00
if ( dm_split_words ( buffer , 3 , 0 , words ) < 2 )
continue ;
2010-10-29 20:43:51 +04:00
/* find the major/minor of the device */
if ( stat ( words [ 0 ] , & st ) )
continue ; /* can't stat, skip this one */
if ( S_ISBLK ( st . st_mode ) & &
major ( st . st_rdev ) = = major & &
minor ( st . st_rdev ) = = minor ) {
2011-12-22 20:37:01 +04:00
syslog ( LOG_ERR , " Unmounting invalid snapshot %s from %s. \n " , device , words [ 1 ] ) ;
2010-10-29 20:43:51 +04:00
if ( ! _run ( UMOUNT_COMMAND , " -fl " , words [ 1 ] , NULL ) )
2011-12-22 20:37:01 +04:00
syslog ( LOG_ERR , " Failed to umount snapshot %s from %s: %s. \n " ,
2010-10-29 20:43:51 +04:00
device , words [ 1 ] , strerror ( errno ) ) ;
}
}
2010-11-24 00:19:45 +03:00
if ( fclose ( mounts ) )
syslog ( LOG_ERR , " Failed to close /proc/mounts. \n " ) ;
2010-10-29 20:43:51 +04:00
}
2008-01-31 15:19:36 +03:00
void process_event ( struct dm_task * dmt ,
2010-07-09 19:34:40 +04:00
enum dm_event_mask event __attribute__ ( ( unused ) ) ,
2008-01-09 18:32:19 +03:00
void * * private )
{
void * next = NULL ;
uint64_t start , length ;
char * target_type = NULL ;
char * params ;
2013-05-26 19:07:08 +04:00
struct dm_status_snapshot * status = NULL ;
2008-01-09 18:32:19 +03:00
const char * device = dm_task_get_name ( dmt ) ;
2013-05-26 19:07:08 +04:00
uint64_t percent ;
2011-11-21 16:31:18 +04:00
struct dso_state * state = * private ;
2008-01-09 18:32:19 +03:00
/* No longer monitoring, waiting for remove */
2011-11-21 16:31:18 +04:00
if ( ! state - > percent_check )
2008-01-09 18:32:19 +03:00
return ;
2010-01-22 01:15:45 +03:00
dmeventd_lvm2_lock ( ) ;
2008-01-09 18:32:19 +03:00
dm_get_next_target ( dmt , next , & start , & length , & target_type , & params ) ;
if ( ! target_type )
goto out ;
2013-05-26 19:07:08 +04:00
if ( ! dm_get_status_snapshot ( state - > mem , params , & status ) )
goto out ;
2010-10-15 20:28:14 +04:00
2013-05-26 19:07:08 +04:00
if ( status - > invalid ) {
2010-10-29 20:43:51 +04:00
struct dm_info info ;
if ( dm_task_get_info ( dmt , & info ) ) {
dmeventd_lvm2_unlock ( ) ;
_umount ( device , info . major , info . minor ) ;
2013-05-26 19:07:08 +04:00
return ;
2010-10-29 20:43:51 +04:00
} /* else; too bad, but this is best-effort thing... */
}
2011-11-21 16:31:18 +04:00
/* Snapshot size had changed. Clear the threshold. */
2013-05-26 19:07:08 +04:00
if ( state - > known_size ! = status - > total_sectors ) {
2011-11-21 16:31:18 +04:00
state - > percent_check = CHECK_MINIMUM ;
2013-05-26 19:07:08 +04:00
state - > known_size = status - > total_sectors ;
2011-11-21 16:31:18 +04:00
}
2008-01-09 18:32:19 +03:00
/*
* If the snapshot has been invalidated or we failed to parse
* the status string . Report the full status string to syslog .
*/
2013-05-26 19:07:08 +04:00
if ( status - > invalid | | ! status - > total_sectors ) {
2008-01-09 18:32:19 +03:00
syslog ( LOG_ERR , " Snapshot %s changed state to: %s \n " , device , params ) ;
2011-11-21 16:31:18 +04:00
state - > percent_check = 0 ;
2008-01-09 18:32:19 +03:00
goto out ;
}
2013-05-26 19:07:08 +04:00
percent = 100 * status - > used_sectors / status - > total_sectors ;
2011-11-21 16:31:18 +04:00
if ( percent > = state - > percent_check ) {
2010-10-15 20:28:14 +04:00
/* Usage has raised more than CHECK_STEP since the last
time . Run actions . */
2011-11-21 16:31:18 +04:00
state - > percent_check = ( percent / CHECK_STEP ) * CHECK_STEP + CHECK_STEP ;
2010-10-15 20:28:14 +04:00
if ( percent > = WARNING_THRESH ) /* Print a warning to syslog. */
syslog ( LOG_WARNING , " Snapshot %s is now %i%% full. \n " , device , percent ) ;
/* Try to extend the snapshot, in accord with user-set policies */
2011-12-22 20:37:01 +04:00
if ( ! _extend ( state - > cmd_str ) )
syslog ( LOG_ERR , " Failed to extend snapshot %s. \n " , device ) ;
2008-01-09 18:32:19 +03:00
}
2011-11-21 16:31:18 +04:00
2008-01-09 18:32:19 +03:00
out :
2013-05-26 19:07:08 +04:00
if ( status )
dm_pool_free ( state - > mem , status ) ;
2010-01-22 01:15:45 +03:00
dmeventd_lvm2_unlock ( ) ;
2008-01-09 18:32:19 +03:00
}
2008-01-31 15:19:36 +03:00
int register_device ( const char * device ,
2010-07-09 19:34:40 +04:00
const char * uuid __attribute__ ( ( unused ) ) ,
int major __attribute__ ( ( unused ) ) ,
int minor __attribute__ ( ( unused ) ) ,
2008-01-31 15:19:36 +03:00
void * * private )
2008-01-09 18:32:19 +03:00
{
2013-05-26 19:07:08 +04:00
struct dm_pool * statemem = NULL ;
2011-12-22 20:37:01 +04:00
struct dso_state * state ;
if ( ! dmeventd_lvm2_init ( ) )
goto out ;
2008-01-09 18:32:19 +03:00
2013-05-26 19:07:08 +04:00
if ( ! ( statemem = dm_pool_create ( " snapshot_state " , 512 ) ) | |
! ( state = dm_pool_zalloc ( statemem , sizeof ( * state ) ) ) )
2011-12-22 20:37:01 +04:00
goto bad ;
2011-11-21 16:31:18 +04:00
2013-05-26 19:07:08 +04:00
if ( ! dmeventd_lvm2_command ( statemem , state - > cmd_str ,
sizeof ( state - > cmd_str ) ,
2011-12-22 20:37:01 +04:00
" lvextend --use-policies " , device ) )
goto bad ;
2013-05-26 19:07:08 +04:00
state - > mem = statemem ;
2011-12-22 20:37:01 +04:00
state - > percent_check = CHECK_MINIMUM ;
* private = state ;
2008-01-09 18:32:19 +03:00
syslog ( LOG_INFO , " Monitoring snapshot %s \n " , device ) ;
2011-12-22 20:37:01 +04:00
return 1 ;
bad :
2013-05-26 19:07:08 +04:00
if ( statemem )
dm_pool_destroy ( statemem ) ;
2011-12-22 20:37:01 +04:00
dmeventd_lvm2_exit ( ) ;
out :
syslog ( LOG_ERR , " Failed to monitor snapshot %s. \n " , device ) ;
return 0 ;
2008-01-09 18:32:19 +03:00
}
2008-01-31 15:19:36 +03:00
int unregister_device ( const char * device ,
2010-07-09 19:34:40 +04:00
const char * uuid __attribute__ ( ( unused ) ) ,
int major __attribute__ ( ( unused ) ) ,
int minor __attribute__ ( ( unused ) ) ,
2011-11-21 16:31:18 +04:00
void * * private )
2008-01-09 18:32:19 +03:00
{
2011-11-21 16:31:18 +04:00
struct dso_state * state = * private ;
2011-12-22 20:37:01 +04:00
syslog ( LOG_INFO , " No longer monitoring snapshot %s \n " , device ) ;
2013-05-26 19:07:08 +04:00
dm_pool_destroy ( state - > mem ) ;
2010-01-22 01:15:45 +03:00
dmeventd_lvm2_exit ( ) ;
2011-12-22 20:37:01 +04:00
2008-01-09 18:32:19 +03:00
return 1 ;
}