2008-01-09 18:32:19 +03:00
/*
* Copyright ( C ) 2007 - 2008 Red Hat , Inc . All rights reserved .
*
* 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
*/
# include "libdevmapper.h"
# include "libdevmapper-event.h"
# include "lvm2cmd.h"
# include "lvm-string.h"
# include <errno.h>
# include <signal.h>
# include <string.h>
# include <stdio.h>
# include <stdlib.h>
# include <pthread.h>
# include <unistd.h>
# include <syslog.h> /* FIXME Replace syslog with multilog */
/* FIXME Missing openlog? */
/* First warning when snapshot is 80% full. */
# define WARNING_THRESH 80
/* Further warnings at 85%, 90% and 95% fullness. */
# define WARNING_STEP 5
static pthread_mutex_t _register_mutex = PTHREAD_MUTEX_INITIALIZER ;
/*
* Number of active registrations .
*/
static int _register_count = 0 ;
static struct dm_pool * _mem_pool = NULL ;
static void * _lvm_handle = NULL ;
struct snap_status {
int invalid ;
int used ;
int max ;
} ;
/*
* Currently only one event can be processed at a time .
*/
static pthread_mutex_t _event_mutex = PTHREAD_MUTEX_INITIALIZER ;
2008-01-31 15:19:36 +03:00
static void _temporary_log_fn ( int level ,
const char * file __attribute ( ( unused ) ) ,
int line __attribute ( ( unused ) ) ,
const char * format )
2008-01-09 18:32:19 +03:00
{
if ( ! strncmp ( format , " WARNING: " , 9 ) & & ( level < 5 ) )
syslog ( LOG_CRIT , " %s " , format ) ;
else
syslog ( LOG_DEBUG , " %s " , format ) ;
}
/* FIXME possibly reconcile this with target_percent when we gain
access to regular LVM library here . */
static void _parse_snapshot_params ( char * params , struct snap_status * stat )
{
char * p ;
/*
* xx / xx - - fractions used / max
* Invalid - - snapshot invalidated
* Unknown - - status unknown
*/
stat - > used = stat - > max = 0 ;
if ( ! strncmp ( params , " Invalid " , 7 ) ) {
stat - > invalid = 1 ;
return ;
}
/*
* When we return without setting non - zero max , the parent is
* responsible for reporting errors .
*/
if ( ! strncmp ( params , " Unknown " , 7 ) )
return ;
if ( ! ( p = strstr ( params , " / " ) ) )
return ;
* p = ' \0 ' ;
p + + ;
stat - > used = atoi ( params ) ;
stat - > max = atoi ( p ) ;
}
/* send unregister command to itself */
static void _unregister_self ( struct dm_task * dmt )
{
const char * name = dm_task_get_name ( dmt ) ;
struct dm_event_handler * dmevh ;
if ( ! ( dmevh = dm_event_handler_create ( ) ) )
return ;
if ( dm_event_handler_set_dev_name ( dmevh , name ) )
goto fail ;
dm_event_handler_set_event_mask ( dmevh , DM_EVENT_ALL_ERRORS | DM_EVENT_TIMEOUT ) ;
dm_event_unregister_handler ( dmevh ) ;
fail :
dm_event_handler_destroy ( dmevh ) ;
}
2008-01-31 15:19:36 +03:00
void process_event ( struct dm_task * dmt ,
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 ;
struct snap_status stat = { 0 } ;
const char * device = dm_task_get_name ( dmt ) ;
int percent , * percent_warning = ( int * ) private ;
/* No longer monitoring, waiting for remove */
if ( ! * percent_warning )
return ;
if ( pthread_mutex_trylock ( & _event_mutex ) ) {
syslog ( LOG_NOTICE , " Another thread is handling an event. Waiting... " ) ;
pthread_mutex_lock ( & _event_mutex ) ;
}
dm_get_next_target ( dmt , next , & start , & length , & target_type , & params ) ;
if ( ! target_type )
goto out ;
_parse_snapshot_params ( params , & stat ) ;
/*
* If the snapshot has been invalidated or we failed to parse
* the status string . Report the full status string to syslog .
*/
if ( stat . invalid | | ! stat . max ) {
syslog ( LOG_ERR , " Snapshot %s changed state to: %s \n " , device , params ) ;
_unregister_self ( dmt ) ;
* percent_warning = 0 ;
goto out ;
}
percent = 100 * stat . used / stat . max ;
if ( percent > = * percent_warning ) {
syslog ( LOG_WARNING , " Snapshot %s is now %i%% full. \n " , device , percent ) ;
/* Print warning on the next multiple of WARNING_STEP. */
* percent_warning = ( percent / WARNING_STEP ) * WARNING_STEP + WARNING_STEP ;
}
out :
pthread_mutex_unlock ( & _event_mutex ) ;
}
2008-01-31 15:19:36 +03:00
int register_device ( const char * device ,
const char * uuid __attribute ( ( unused ) ) ,
int major __attribute ( ( unused ) ) ,
int minor __attribute ( ( unused ) ) ,
void * * private )
2008-01-09 18:32:19 +03:00
{
int r = 0 ;
int * percent_warning = ( int * ) private ;
pthread_mutex_lock ( & _register_mutex ) ;
/*
* Need some space for allocations . 1024 should be more
* than enough for what we need ( device mapper name splitting )
*/
if ( ! _mem_pool & & ! ( _mem_pool = dm_pool_create ( " snapshot_dso " , 1024 ) ) )
goto out ;
* percent_warning = WARNING_THRESH ; /* Print warning if snapshot is full */
if ( ! _lvm_handle ) {
lvm2_log_fn ( _temporary_log_fn ) ;
if ( ! ( _lvm_handle = lvm2_init ( ) ) ) {
dm_pool_destroy ( _mem_pool ) ;
_mem_pool = NULL ;
goto out ;
}
lvm2_log_level ( _lvm_handle , LVM2_LOG_SUPPRESS ) ;
/* FIXME Temporary: move to dmeventd core */
lvm2_run ( _lvm_handle , " _memlock_inc " ) ;
}
syslog ( LOG_INFO , " Monitoring snapshot %s \n " , device ) ;
_register_count + + ;
r = 1 ;
out :
pthread_mutex_unlock ( & _register_mutex ) ;
return r ;
}
2008-01-31 15:19:36 +03:00
int unregister_device ( const char * device ,
const char * uuid __attribute ( ( unused ) ) ,
int major __attribute ( ( unused ) ) ,
int minor __attribute ( ( unused ) ) ,
void * * unused __attribute ( ( unused ) ) )
2008-01-09 18:32:19 +03:00
{
pthread_mutex_lock ( & _register_mutex ) ;
syslog ( LOG_INFO , " No longer monitoring snapshot %s \n " ,
device ) ;
if ( ! - - _register_count ) {
dm_pool_destroy ( _mem_pool ) ;
_mem_pool = NULL ;
lvm2_run ( _lvm_handle , " _memlock_dec " ) ;
lvm2_exit ( _lvm_handle ) ;
_lvm_handle = NULL ;
}
pthread_mutex_unlock ( & _register_mutex ) ;
return 1 ;
}