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 <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-11 22:52:06 +03:00
char * * args = NULL ;
2005-12-02 22:52:06 +03:00
char * dev_status_str ;
char * log_status_str ;
char * sync_str ;
2007-01-11 23:11:19 +03:00
char * p = NULL ;
2007-01-11 22:52:06 +03:00
int log_argc , num_devs ;
2005-12-02 22:52:06 +03:00
/*
2007-01-12 23:38:30 +03:00
* dm core parms : 0 409600 mirror
* Mirror core parms : 2 253 : 4 253 : 5 400 / 400
* New - style failure params : 1 AA
* New - style log params : 3 cluster 253 : 3 A
* or 3 disk 253 : 3 A
* or 1 core
2007-01-11 22:52:06 +03:00
*/
/* number of devices */
if ( ! dm_split_words ( params , 1 , 0 , & p ) )
goto out_parse ;
2007-01-11 23:11:19 +03:00
if ( ! ( num_devs = atoi ( p ) ) )
goto out_parse ;
2007-01-11 22:52:06 +03:00
p + = strlen ( p ) + 1 ;
2006-12-20 17:35:02 +03:00
2007-01-12 23:38:30 +03:00
/* devices names + "400/400" + "1 AA" + 1 or 3 log parms + NULL */
args = dm_malloc ( ( num_devs + 7 ) * sizeof ( char * ) ) ;
if ( ! args | | dm_split_words ( p , num_devs + 7 , 0 , args ) < num_devs + 5 )
2007-01-11 22:52:06 +03:00
goto out_parse ;
2006-12-20 17:35:02 +03:00
2007-01-11 22:52:06 +03:00
dev_status_str = args [ 2 + num_devs ] ;
log_argc = atoi ( args [ 3 + num_devs ] ) ;
log_status_str = args [ 3 + num_devs + log_argc ] ;
sync_str = args [ num_devs ] ;
2005-12-02 22:52:06 +03:00
/* 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 ' ) {
2007-01-11 22:52:06 +03:00
syslog ( LOG_ERR , " Mirror device, %s, has failed. \n " , args [ i ] ) ;
r = ME_FAILURE ;
2005-12-02 22:52:06 +03:00
}
2007-01-11 22:52:06 +03:00
/* Check for bad disk log device */
if ( log_argc > 1 & & log_status_str [ 0 ] = = ' D ' ) {
2005-12-02 22:52:06 +03:00
syslog ( LOG_ERR , " Log device, %s, has failed. \n " ,
2007-01-11 22:52:06 +03:00
args [ 2 + num_devs + log_argc ] ) ;
r = ME_FAILURE ;
2005-12-02 22:52:06 +03:00
}
2007-01-11 22:52:06 +03:00
if ( 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 ] = ' / ' ;
2007-01-11 22:52:06 +03:00
} else
goto out_parse ;
out :
if ( args )
dm_free ( args ) ;
2006-12-20 17:35:02 +03:00
return r ;
2007-01-11 22:52:06 +03:00
out_parse :
if ( args )
dm_free ( args ) ;
syslog ( LOG_ERR , " Unable to parse mirror status string. " ) ;
return ME_IGNORE ;
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
}
2007-01-23 20:40:40 +03:00
void process_event ( struct dm_task * dmt , enum dm_event_mask event ,
void * * unused __attribute ( ( unused ) ) )
2005-12-02 22:52:06 +03:00
{
void * next = NULL ;
uint64_t start , length ;
char * target_type = NULL ;
char * params ;
2007-01-12 01:24:32 +03:00
const char * device = dm_task_get_name ( dmt ) ;
2005-12-02 22:52:06 +03:00
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
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 :
2007-01-12 01:24:32 +03:00
/* FIXME Provide value then! */
2005-12-02 22:52:06 +03:00
syslog ( LOG_INFO , " Unknown event received. \n " ) ;
}
} while ( next ) ;
2007-01-08 17:24:20 +03:00
pthread_mutex_unlock ( & _event_mutex ) ;
2005-12-02 22:52:06 +03:00
}
2007-01-23 20:40:40 +03:00
int register_device ( const char * device , const char * uuid , int major , int minor ,
void * * unused __attribute ( ( unused ) ) )
2005-12-02 22:52:06 +03:00
{
2007-01-08 17:24:20 +03:00
int r = 0 ;
pthread_mutex_lock ( & _register_mutex ) ;
2007-01-12 01:24:32 +03: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
}
2007-01-23 20:40:40 +03:00
int unregister_device ( const char * device , const char * uuid , int major , int minor ,
void * * unused __attribute ( ( unused ) ) )
2005-12-02 22:52:06 +03:00
{
2007-01-08 17:24:20 +03:00
pthread_mutex_lock ( & _register_mutex ) ;
2007-01-12 01:24:32 +03:00
syslog ( LOG_INFO , " No longer monitoring mirror device %s for events \n " ,
device ) ;
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
}