2005-12-02 22:52:06 +03:00
/*
2012-02-08 15:29:13 +04:00
* Copyright ( C ) 2005 - 2012 Red Hat , Inc . All rights reserved .
2005-12-02 22:52:06 +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 01:15:45 +03:00
# include "lib.h"
2005-12-02 22:52:06 +03:00
# include "lvm2cmd.h"
2009-06-30 22:39:31 +04:00
# include "errors.h"
2010-01-22 01:15:45 +03:00
# include "libdevmapper-event.h"
# include "dmeventd_lvm.h"
2012-02-08 15:29:13 +04:00
# include "defaults.h"
2005-12-02 22:52:06 +03:00
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? */
2009-11-25 18:59:07 +03:00
/* FIXME Replace most syslogs with log_error() style messages and add complete context. */
/* FIXME Reformat to 80 char lines. */
2005-12-02 22:52:06 +03:00
# define ME_IGNORE 0
# define ME_INSYNC 1
# define ME_FAILURE 2
2009-11-25 18:59:07 +03:00
static int _process_status_code ( const char status_code , const char * dev_name ,
const char * dev_type , int r )
{
/*
* A = > Alive - No failures
* D = > Dead - A write failure occurred leaving mirror out - of - sync
* F = > Flush failed .
* S = > Sync - A sychronization failure occurred , mirror out - of - sync
* R = > Read - A read failure occurred , mirror data unaffected
* U = > Unclassified failure ( bug )
*/
if ( status_code = = ' F ' ) {
2010-03-30 18:39:55 +04:00
syslog ( LOG_ERR , " %s device %s flush failed. " ,
2009-11-25 18:59:07 +03:00
dev_type , dev_name ) ;
r = ME_FAILURE ;
} else if ( status_code = = ' S ' )
2010-03-30 18:39:55 +04:00
syslog ( LOG_ERR , " %s device %s sync failed. " ,
2009-11-25 18:59:07 +03:00
dev_type , dev_name ) ;
else if ( status_code = = ' R ' )
2010-03-30 18:39:55 +04:00
syslog ( LOG_ERR , " %s device %s read failed. " ,
2009-11-25 18:59:07 +03:00
dev_type , dev_name ) ;
else if ( status_code ! = ' A ' ) {
2010-03-30 18:39:55 +04:00
syslog ( LOG_ERR , " %s device %s has failed (%c). " ,
2009-11-25 18:59:07 +03:00
dev_type , dev_name , status_code ) ;
r = ME_FAILURE ;
}
return r ;
}
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 ;
2012-02-08 15:29:13 +04:00
if ( ! ( num_devs = atoi ( p ) ) | |
( num_devs > DEFAULT_MIRROR_MAX_IMAGES ) | | ( num_devs < 0 ) )
2007-01-11 23:11:19 +03:00
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
2012-02-08 15:29:13 +04:00
/* FIXME: Code differs from lib/mirror/mirrored.c */
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 + + )
2009-11-25 18:59:07 +03:00
r = _process_status_code ( dev_status_str [ i ] , args [ i ] ,
i ? " Secondary mirror " : " Primary mirror " , r ) ;
2005-12-02 22:52:06 +03:00
2007-01-11 22:52:06 +03:00
/* Check for bad disk log device */
2009-11-25 18:59:07 +03:00
if ( log_argc > 1 )
r = _process_status_code ( log_status_str [ 0 ] ,
args [ 2 + num_devs + log_argc ] ,
" Log " , r ) ;
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 :
2010-08-16 22:19:46 +04:00
dm_free ( args ) ;
2006-12-20 17:35:02 +03:00
return r ;
2012-03-10 13:32:46 +04:00
2007-01-11 22:52:06 +03:00
out_parse :
2010-08-16 22:19:46 +04:00
dm_free ( args ) ;
2007-01-11 22:52:06 +03:00
syslog ( LOG_ERR , " Unable to parse mirror status string. " ) ;
return ME_IGNORE ;
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 ] ;
2005-12-02 22:52:06 +03:00
2011-12-22 20:37:01 +04:00
if ( ! dmeventd_lvm2_command ( dmeventd_lvm2_pool ( ) , cmd_str , sizeof ( cmd_str ) ,
" lvconvert --config devices{ignore_suspended_devices=1} "
" --repair --use-policies " , device ) )
2006-12-20 17:35:02 +03:00
return - ENAMETOOLONG ; /* FIXME Replace with generic error return - reason for failure has already got logged */
2005-12-02 22:52:06 +03:00
2010-01-22 01:15:45 +03:00
r = dmeventd_lvm2_run ( cmd_str ) ;
2005-12-02 22:52:06 +03:00
2011-12-22 20:37:01 +04:00
syslog ( LOG_INFO , " Repair of mirrored device %s %s. " , device ,
2010-05-14 18:56:39 +04:00
( r = = ECMD_PROCESSED ) ? " finished successfully " : " failed " ) ;
2009-06-15 18:47:39 +04:00
2009-06-30 22:39:31 +04:00
return ( r = = ECMD_PROCESSED ) ? 0 : - 1 ;
2005-12-02 22:52:06 +03: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 ) ) ,
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
2010-01-22 01:15:45 +03:00
dmeventd_lvm2_lock ( ) ;
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 ) {
2010-03-30 18:39:55 +04:00
syslog ( LOG_INFO , " %s mapping lost. " , device ) ;
2006-12-20 17:35:02 +03:00
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 " ) ) {
2010-03-30 18:39:55 +04:00
syslog ( LOG_INFO , " %s has unmirrored portion. " , device ) ;
2005-12-02 22:52:06 +03:00
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
*/
2010-03-30 18:39:55 +04:00
syslog ( LOG_NOTICE , " %s is now in-sync. " , device ) ;
2005-12-02 22:52:06 +03:00
break ;
case ME_FAILURE :
2010-03-30 18:39:55 +04:00
syslog ( LOG_ERR , " Device failure in %s. " , device ) ;
2005-12-02 22:52:06 +03:00
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? */
2010-03-30 18:39:55 +04:00
syslog ( LOG_ERR , " Failed to remove faulty devices in %s. " ,
2005-12-02 22:52:06 +03:00
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! */
2010-03-30 18:39:55 +04:00
syslog ( LOG_INFO , " Unknown event received. " ) ;
2005-12-02 22:52:06 +03:00
}
} while ( next ) ;
2010-01-22 01:15:45 +03:00
dmeventd_lvm2_unlock ( ) ;
2005-12-02 22:52:06 +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 ) ) ,
void * * unused __attribute__ ( ( unused ) ) )
2005-12-02 22:52:06 +03:00
{
2011-12-22 20:37:01 +04:00
if ( ! dmeventd_lvm2_init ( ) )
return 0 ;
2010-03-30 18:39:55 +04:00
syslog ( LOG_INFO , " Monitoring mirror device %s for events. " , device ) ;
2011-12-22 20:37:01 +04:00
return 1 ;
2005-12-02 22:52:06 +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 ) ) ,
void * * unused __attribute__ ( ( unused ) ) )
2005-12-02 22:52:06 +03:00
{
2010-03-30 18:39:55 +04:00
syslog ( LOG_INFO , " No longer monitoring mirror device %s for events. " ,
2007-01-12 01:24:32 +03:00
device ) ;
2010-01-22 01:15:45 +03:00
dmeventd_lvm2_exit ( ) ;
2011-12-22 20:37:01 +04:00
2007-01-08 17:24:20 +03:00
return 1 ;
2005-12-02 22:52:06 +03:00
}