2005-12-02 22:52:06 +03:00
/*
* Copyright ( C ) 2005 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>
2006-01-27 23:43:52 +03:00
# include <syslog.h> /* FIXME Replace syslog with multilog */
2006-12-20 17:35:02 +03:00
/* FIXME Missing openlog? */
2005-12-02 22:52:06 +03:00
# define ME_IGNORE 0
# define ME_INSYNC 1
# define ME_FAILURE 2
2007-01-08 17:24:20 +03:00
/*
* register_device ( ) is called first and performs initialisation .
* Only one device may be registered or unregistered at a time .
*/
static pthread_mutex_t _register_mutex = PTHREAD_MUTEX_INITIALIZER ;
2006-07-04 22:57:27 +04:00
2007-01-08 17:24:20 +03:00
/*
* Number of active registrations .
*/
2006-12-20 17:35:02 +03:00
static int _register_count = 0 ;
static struct dm_pool * _mem_pool = NULL ;
2007-01-08 17:24:20 +03:00
static void * _lvm_handle = NULL ;
/*
* Currently only one event can be processed at a time .
*/
static pthread_mutex_t _event_mutex = PTHREAD_MUTEX_INITIALIZER ;
2006-01-27 23:43:52 +03:00
2005-12-02 22:52:06 +03:00
static int _get_mirror_event ( char * params )
{
2006-12-20 17:35:02 +03:00
int i , r = ME_INSYNC ;
2007-01-08 17:24:20 +03:00
# define MAX_ARGS 30 /* should support at least 8-way mirrors */
2006-12-20 17:35:02 +03:00
/* FIXME Remove unnecessary limit. It tells you how many devices there are - use it! */
char * args [ MAX_ARGS ] ;
2005-12-02 22:52:06 +03:00
char * dev_status_str ;
char * log_status_str ;
char * sync_str ;
char * p ;
int log_argc , num_devs , num_failures = 0 ;
2006-12-20 17:35:02 +03:00
/* FIXME Remove unnecessary limit - get num_devs here */
if ( MAX_ARGS < = dm_split_words ( params , MAX_ARGS , 0 , args ) ) {
2005-12-02 22:52:06 +03:00
syslog ( LOG_ERR , " Unable to split mirror parameters: Arg list too long " ) ;
2006-12-20 17:35:02 +03:00
return - E2BIG ; /* FIXME Why? Unused */
2005-12-02 22:52:06 +03:00
}
/*
* Unused : 0 409600 mirror
* Used : 2 253 : 4 253 : 5 400 / 400 1 AA 3 cluster 253 : 3 A
*/
num_devs = atoi ( args [ 0 ] ) ;
2006-12-20 17:35:02 +03:00
/* FIXME *Now* split rest of args */
2005-12-02 22:52:06 +03:00
dev_status_str = args [ 3 + num_devs ] ;
log_argc = atoi ( args [ 4 + num_devs ] ) ;
log_status_str = args [ 4 + num_devs + log_argc ] ;
sync_str = args [ 1 + num_devs ] ;
/* Check for bad mirror devices */
2006-12-20 17:35:02 +03:00
for ( i = 0 ; i < num_devs ; i + + )
2005-12-02 22:52:06 +03:00
if ( dev_status_str [ i ] = = ' D ' ) {
syslog ( LOG_ERR , " Mirror device, %s, has failed. \n " , args [ i + 1 ] ) ;
num_failures + + ;
}
/* Check for bad log device */
if ( log_status_str [ 0 ] = = ' D ' ) {
syslog ( LOG_ERR , " Log device, %s, has failed. \n " ,
args [ 3 + num_devs + log_argc ] ) ;
num_failures + + ;
}
if ( num_failures ) {
2006-12-20 17:35:02 +03:00
r = ME_FAILURE ;
2005-12-02 22:52:06 +03:00
goto out ;
}
2006-01-27 23:48:19 +03:00
p = strstr ( sync_str , " / " ) ;
if ( p ) {
p [ 0 ] = ' \0 ' ;
if ( strcmp ( sync_str , p + 1 ) )
2006-12-20 17:35:02 +03:00
r = ME_IGNORE ;
2006-01-27 23:48:19 +03:00
p [ 0 ] = ' / ' ;
} else {
/*
* How the hell did we get this ?
* Might mean all our parameters are screwed .
*/
syslog ( LOG_ERR , " Unable to parse sync string. " ) ;
2006-12-20 17:35:02 +03:00
r = ME_IGNORE ;
2005-12-02 22:52:06 +03:00
}
out :
2006-12-20 17:35:02 +03:00
return r ;
2005-12-02 22:52:06 +03:00
}
2006-05-11 23:45:53 +04:00
static void _temporary_log_fn ( int level , const char * file ,
int line , const char * format )
2005-12-02 22:52:06 +03:00
{
2006-05-11 23:45:53 +04:00
if ( ! strncmp ( format , " WARNING: " , 9 ) & & ( level < 5 ) )
syslog ( LOG_CRIT , " %s " , format ) ;
else
syslog ( LOG_DEBUG , " %s " , format ) ;
2005-12-02 22:52:06 +03:00
}
static int _remove_failed_devices ( const char * device )
{
int r ;
2006-12-20 17:35:02 +03:00
# define CMD_SIZE 256 /* FIXME Use system restriction */
char cmd_str [ CMD_SIZE ] ;
2006-01-27 23:43:52 +03:00
char * vg = NULL , * lv = NULL , * layer = NULL ;
2005-12-02 22:52:06 +03:00
2006-12-20 17:35:02 +03:00
if ( strlen ( device ) > 200 ) /* FIXME Use real restriction */
return - ENAMETOOLONG ; /* FIXME These return code distinctions are not used so remove them! */
2005-12-02 22:52:06 +03:00
2006-12-20 17:35:02 +03:00
if ( ! dm_split_lvm_name ( _mem_pool , device , & vg , & lv , & layer ) ) {
2006-01-27 23:43:52 +03:00
syslog ( LOG_ERR , " Unable to determine VG name from %s " ,
2005-12-02 22:52:06 +03:00
device ) ;
2006-12-20 17:35:02 +03:00
return - ENOMEM ; /* FIXME Replace with generic error return - reason for failure has already got logged */
2005-12-02 22:52:06 +03:00
}
/* FIXME Is any sanity-checking required on %s? */
2006-12-20 17:35:02 +03:00
if ( CMD_SIZE < = snprintf ( cmd_str , CMD_SIZE , " vgreduce --removemissing %s " , vg ) ) {
2005-12-02 22:52:06 +03:00
/* this error should be caught above, but doesn't hurt to check again */
syslog ( LOG_ERR , " Unable to form LVM command: Device name too long " ) ;
2006-12-20 17:35:02 +03:00
dm_pool_empty ( _mem_pool ) ; /* FIXME: not safe with multiple threads */
return - ENAMETOOLONG ; /* FIXME Replace with generic error return - reason for failure has already got logged */
2005-12-02 22:52:06 +03:00
}
2007-01-08 17:24:20 +03:00
r = lvm2_run ( _lvm_handle , cmd_str ) ;
2005-12-02 22:52:06 +03:00
2006-12-20 17:35:02 +03:00
dm_pool_empty ( _mem_pool ) ; /* FIXME: not safe with multiple threads */
return ( r = = 1 ) ? 0 : - 1 ;
2005-12-02 22:52:06 +03:00
}
void process_event ( const char * device , enum dm_event_type event )
{
struct dm_task * dmt ;
void * next = NULL ;
uint64_t start , length ;
char * target_type = NULL ;
char * params ;
2007-01-08 17:24:20 +03:00
if ( pthread_mutex_trylock ( & _event_mutex ) ) {
2006-07-04 22:57:27 +04:00
syslog ( LOG_NOTICE , " Another thread is handling an event. Waiting... " ) ;
2007-01-08 17:24:20 +03:00
pthread_mutex_lock ( & _event_mutex ) ;
2006-07-04 22:57:27 +04:00
}
2005-12-02 22:52:06 +03:00
/* FIXME Move inside libdevmapper */
if ( ! ( dmt = dm_task_create ( DM_DEVICE_STATUS ) ) ) {
syslog ( LOG_ERR , " Unable to create dm_task. \n " ) ;
goto fail ;
}
if ( ! dm_task_set_name ( dmt , device ) ) {
syslog ( LOG_ERR , " Unable to set device name. \n " ) ;
goto fail ;
}
if ( ! dm_task_run ( dmt ) ) {
syslog ( LOG_ERR , " Unable to run task. \n " ) ;
goto fail ;
}
do {
next = dm_get_next_target ( dmt , next , & start , & length ,
& target_type , & params ) ;
2007-01-08 17:24:20 +03:00
if ( ! target_type ) {
2006-12-20 17:35:02 +03:00
syslog ( LOG_INFO , " %s mapping lost. \n " , device ) ;
continue ;
2007-01-08 17:24:20 +03:00
}
2006-12-20 17:35:02 +03:00
2005-12-02 22:52:06 +03:00
if ( strcmp ( target_type , " mirror " ) ) {
syslog ( LOG_INFO , " %s has unmirrored portion. \n " , device ) ;
continue ;
}
switch ( _get_mirror_event ( params ) ) {
case ME_INSYNC :
/* FIXME: all we really know is that this
_part_ of the device is in sync
Also , this is not an error
*/
syslog ( LOG_NOTICE , " %s is now in-sync \n " , device ) ;
break ;
case ME_FAILURE :
syslog ( LOG_ERR , " Device failure in %s \n " , device ) ;
if ( _remove_failed_devices ( device ) )
2006-12-20 17:35:02 +03:00
/* FIXME Why are all the error return codes unused? Get rid of them? */
2005-12-02 22:52:06 +03:00
syslog ( LOG_ERR , " Failed to remove faulty devices in %s \n " ,
device ) ;
2006-01-27 23:48:19 +03:00
/* Should check before warning user that device is now linear
2005-12-02 22:52:06 +03:00
else
syslog ( LOG_NOTICE , " %s is now a linear device. \n " ,
device ) ;
2006-01-27 23:48:19 +03:00
*/
2005-12-02 22:52:06 +03:00
break ;
case ME_IGNORE :
break ;
default :
2006-12-20 17:35:02 +03:00
/* FIXME Wrong: it can also return -E2BIG but it's never used! */
2005-12-02 22:52:06 +03:00
syslog ( LOG_INFO , " Unknown event received. \n " ) ;
}
} while ( next ) ;
fail :
if ( dmt )
dm_task_destroy ( dmt ) ;
2007-01-08 17:24:20 +03:00
pthread_mutex_unlock ( & _event_mutex ) ;
2005-12-02 22:52:06 +03:00
}
int register_device ( const char * device )
{
2007-01-08 17:24:20 +03:00
int r = 0 ;
pthread_mutex_lock ( & _register_mutex ) ;
2006-05-11 23:45:53 +04:00
syslog ( LOG_INFO , " Monitoring mirror device, %s for events \n " , device ) ;
2006-01-27 23:43:52 +03:00
/*
* Need some space for allocations . 1024 should be more
* than enough for what we need ( device mapper name splitting )
*/
2006-12-20 17:35:02 +03:00
if ( ! _mem_pool & & ! ( _mem_pool = dm_pool_create ( " mirror_dso " , 1024 ) ) )
2007-01-08 17:24:20 +03:00
goto out ;
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 " ) ;
}
2006-01-27 23:43:52 +03:00
2006-12-20 17:35:02 +03:00
_register_count + + ;
2007-01-08 17:24:20 +03:00
r = 1 ;
2005-12-02 22:52:06 +03:00
2007-01-08 17:24:20 +03:00
out :
pthread_mutex_unlock ( & _register_mutex ) ;
return r ;
2005-12-02 22:52:06 +03:00
}
int unregister_device ( const char * device )
{
2007-01-08 17:24:20 +03:00
pthread_mutex_lock ( & _register_mutex ) ;
2006-12-20 17:35:02 +03:00
if ( ! - - _register_count ) {
dm_pool_destroy ( _mem_pool ) ;
_mem_pool = NULL ;
2007-01-08 17:24:20 +03:00
lvm2_run ( _lvm_handle , " _memlock_dec " ) ;
lvm2_exit ( _lvm_handle ) ;
_lvm_handle = NULL ;
2006-01-27 23:43:52 +03:00
}
2005-12-02 22:52:06 +03:00
2007-01-08 17:24:20 +03:00
pthread_mutex_unlock ( & _register_mutex ) ;
return 1 ;
2005-12-02 22:52:06 +03:00
}