2015-05-09 02:59:18 +03:00
/*
* Copyright ( C ) 2014 - 2015 Red Hat , Inc .
*
* 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 "lvmpolld-common.h"
# include "config-util.h"
# include <fcntl.h>
# include <signal.h>
static char * _construct_full_lvname ( const char * vgname , const char * lvname )
{
char * name ;
size_t l ;
l = strlen ( vgname ) + strlen ( lvname ) + 2 ; /* vg/lv and \0 */
name = ( char * ) dm_malloc ( l * sizeof ( char ) ) ;
if ( ! name )
return NULL ;
if ( dm_snprintf ( name , l , " %s/%s " , vgname , lvname ) < 0 ) {
dm_free ( name ) ;
name = NULL ;
}
return name ;
}
static char * _construct_lvm_system_dir_env ( const char * sysdir )
{
/*
* Store either " LVM_SYSTEM_DIR=/path/to... "
* - or -
* just single char to store NULL byte
*/
size_t l = sysdir ? strlen ( sysdir ) + 16 : 1 ;
char * env = ( char * ) dm_malloc ( l * sizeof ( char ) ) ;
if ( ! env )
return NULL ;
* env = ' \0 ' ;
if ( sysdir & & dm_snprintf ( env , l , " LVM_SYSTEM_DIR=%s " , sysdir ) < 0 ) {
dm_free ( env ) ;
env = NULL ;
}
return env ;
}
static const char * _get_lvid ( const char * lvmpolld_id , const char * sysdir )
{
return lvmpolld_id ? ( lvmpolld_id + ( sysdir ? strlen ( sysdir ) : 0 ) ) : NULL ;
}
char * construct_id ( const char * sysdir , const char * uuid )
{
char * id ;
int r ;
size_t l ;
l = strlen ( uuid ) + ( sysdir ? strlen ( sysdir ) : 0 ) + 1 ;
id = ( char * ) dm_malloc ( l * sizeof ( char ) ) ;
if ( ! id )
return NULL ;
r = sysdir ? dm_snprintf ( id , l , " %s%s " , sysdir , uuid ) :
dm_snprintf ( id , l , " %s " , uuid ) ;
if ( r < 0 ) {
dm_free ( id ) ;
id = NULL ;
}
return id ;
}
struct lvmpolld_lv * pdlv_create ( struct lvmpolld_state * ls , const char * id ,
const char * vgname , const char * lvname ,
const char * sysdir , enum poll_type type ,
const char * sinterval , unsigned pdtimeout ,
struct lvmpolld_store * pdst )
{
char * lvmpolld_id = dm_strdup ( id ) , /* copy */
* full_lvname = _construct_full_lvname ( vgname , lvname ) , /* copy */
* lvm_system_dir_env = _construct_lvm_system_dir_env ( sysdir ) ; /* copy */
struct lvmpolld_lv tmp = {
. ls = ls ,
. type = type ,
. lvmpolld_id = lvmpolld_id ,
. lvid = _get_lvid ( lvmpolld_id , sysdir ) ,
. lvname = full_lvname ,
. lvm_system_dir_env = lvm_system_dir_env ,
. sinterval = dm_strdup ( sinterval ) , /* copy */
. pdtimeout = pdtimeout < MIN_POLLING_TIMEOUT ? MIN_POLLING_TIMEOUT : pdtimeout ,
. cmd_state = { . retcode = - 1 , . signal = 0 } ,
. pdst = pdst ,
. init_rq_count = 1
} , * pdlv = ( struct lvmpolld_lv * ) dm_malloc ( sizeof ( struct lvmpolld_lv ) ) ;
if ( ! pdlv | | ! tmp . lvid | | ! tmp . lvname | | ! tmp . lvm_system_dir_env | | ! tmp . sinterval )
goto err ;
memcpy ( pdlv , & tmp , sizeof ( * pdlv ) ) ;
if ( pthread_mutex_init ( & pdlv - > lock , NULL ) )
goto err ;
return pdlv ;
err :
dm_free ( ( void * ) full_lvname ) ;
dm_free ( ( void * ) lvmpolld_id ) ;
dm_free ( ( void * ) lvm_system_dir_env ) ;
dm_free ( ( void * ) tmp . sinterval ) ;
dm_free ( ( void * ) pdlv ) ;
return NULL ;
}
void pdlv_destroy ( struct lvmpolld_lv * pdlv )
{
dm_free ( ( void * ) pdlv - > lvmpolld_id ) ;
dm_free ( ( void * ) pdlv - > lvname ) ;
dm_free ( ( void * ) pdlv - > sinterval ) ;
dm_free ( ( void * ) pdlv - > lvm_system_dir_env ) ;
dm_free ( ( void * ) pdlv - > cmdargv ) ;
dm_free ( ( void * ) pdlv - > cmdenvp ) ;
pthread_mutex_destroy ( & pdlv - > lock ) ;
dm_free ( ( void * ) pdlv ) ;
}
unsigned pdlv_get_polling_finished ( struct lvmpolld_lv * pdlv )
{
unsigned ret ;
pdlv_lock ( pdlv ) ;
ret = pdlv - > polling_finished ;
pdlv_unlock ( pdlv ) ;
return ret ;
}
struct lvmpolld_lv_state pdlv_get_status ( struct lvmpolld_lv * pdlv )
{
struct lvmpolld_lv_state r ;
pdlv_lock ( pdlv ) ;
r . error = pdlv_locked_error ( pdlv ) ;
r . polling_finished = pdlv_locked_polling_finished ( pdlv ) ;
r . cmd_state = pdlv_locked_cmd_state ( pdlv ) ;
pdlv_unlock ( pdlv ) ;
return r ;
}
void pdlv_set_cmd_state ( struct lvmpolld_lv * pdlv , const struct lvmpolld_cmd_stat * cmd_state )
{
pdlv_lock ( pdlv ) ;
pdlv - > cmd_state = * cmd_state ;
pdlv_unlock ( pdlv ) ;
}
void pdlv_set_error ( struct lvmpolld_lv * pdlv , unsigned error )
{
pdlv_lock ( pdlv ) ;
pdlv - > error = error ;
pdlv_unlock ( pdlv ) ;
}
void pdlv_set_polling_finished ( struct lvmpolld_lv * pdlv , unsigned finished )
{
pdlv_lock ( pdlv ) ;
pdlv - > polling_finished = finished ;
pdlv_unlock ( pdlv ) ;
}
struct lvmpolld_store * pdst_init ( const char * name )
{
struct lvmpolld_store * pdst = ( struct lvmpolld_store * ) dm_malloc ( sizeof ( struct lvmpolld_store ) ) ;
if ( ! pdst )
return NULL ;
pdst - > store = dm_hash_create ( 32 ) ;
if ( ! pdst - > store )
goto err_hash ;
if ( pthread_mutex_init ( & pdst - > lock , NULL ) )
goto err_mutex ;
pdst - > name = name ;
2015-05-11 15:19:11 +03:00
pdst - > active_polling_count = 0 ;
2015-05-09 02:59:18 +03:00
return pdst ;
err_mutex :
dm_hash_destroy ( pdst - > store ) ;
err_hash :
dm_free ( pdst ) ;
return NULL ;
}
void pdst_destroy ( struct lvmpolld_store * pdst )
{
if ( ! pdst )
return ;
dm_hash_destroy ( pdst - > store ) ;
pthread_mutex_destroy ( & pdst - > lock ) ;
dm_free ( pdst ) ;
}
void pdst_locked_lock_all_pdlvs ( const struct lvmpolld_store * pdst )
{
struct dm_hash_node * n ;
dm_hash_iterate ( n , pdst - > store )
pdlv_lock ( dm_hash_get_data ( pdst - > store , n ) ) ;
}
void pdst_locked_unlock_all_pdlvs ( const struct lvmpolld_store * pdst )
{
struct dm_hash_node * n ;
dm_hash_iterate ( n , pdst - > store )
pdlv_unlock ( dm_hash_get_data ( pdst - > store , n ) ) ;
}
static void _pdlv_locked_dump ( struct buffer * buff , const struct lvmpolld_lv * pdlv )
{
char tmp [ 1024 ] ;
const struct lvmpolld_cmd_stat * cmd_state = & pdlv - > cmd_state ;
/* pdlv-section { */
if ( dm_snprintf ( tmp , sizeof ( tmp ) , " \t %s { \n " , pdlv - > lvmpolld_id ) > 0 )
buffer_append ( buff , tmp ) ;
if ( dm_snprintf ( tmp , sizeof ( tmp ) , " \t \t lvid= \" %s \" \n " , pdlv - > lvid ) > 0 )
buffer_append ( buff , tmp ) ;
if ( dm_snprintf ( tmp , sizeof ( tmp ) , " \t \t type= \" %s \" \n " , polling_op ( pdlv - > type ) ) > 0 )
buffer_append ( buff , tmp ) ;
if ( dm_snprintf ( tmp , sizeof ( tmp ) , " \t \t lvname= \" %s \" \n " , pdlv - > lvname ) > 0 )
buffer_append ( buff , tmp ) ;
if ( dm_snprintf ( tmp , sizeof ( tmp ) , " \t \t lvmpolld_internal_timeout=%d \n " , pdlv - > pdtimeout ) > 0 )
buffer_append ( buff , tmp ) ;
if ( dm_snprintf ( tmp , sizeof ( tmp ) , " \t \t lvm_command_interval= \" %s \" \n " , pdlv - > sinterval ? : " <undefined> " ) > 0 )
buffer_append ( buff , tmp ) ;
if ( dm_snprintf ( tmp , sizeof ( tmp ) , " \t \t LVM_SYSTEM_DIR= \" %s \" \n " ,
( * pdlv - > lvm_system_dir_env ? ( pdlv - > lvm_system_dir_env + strlen ( " LVM_SYSTEM_DIR= " ) ) : " <undefined> " ) ) > 0 )
buffer_append ( buff , tmp ) ;
if ( dm_snprintf ( tmp , sizeof ( tmp ) , " \t \t lvm_command_pid=%d \n " , pdlv - > cmd_pid ) > 0 )
buffer_append ( buff , tmp ) ;
if ( dm_snprintf ( tmp , sizeof ( tmp ) , " \t \t polling_finished=%d \n " , pdlv - > polling_finished ) > 0 )
buffer_append ( buff , tmp ) ;
if ( dm_snprintf ( tmp , sizeof ( tmp ) , " \t \t error_occured=%d \n " , pdlv - > error ) > 0 )
buffer_append ( buff , tmp ) ;
if ( dm_snprintf ( tmp , sizeof ( tmp ) , " \t \t init_requests_count=%d \n " , pdlv - > init_rq_count ) > 0 )
buffer_append ( buff , tmp ) ;
/* lvm_commmand-section { */
buffer_append ( buff , " \t \t lvm_command { \n " ) ;
if ( cmd_state - > retcode = = - 1 & & ! cmd_state - > signal )
buffer_append ( buff , " \t \t \t state= \" " LVMPD_RESP_IN_PROGRESS " \" \n " ) ;
else {
buffer_append ( buff , " \t \t \t state= \" " LVMPD_RESP_FINISHED " \" \n " ) ;
if ( dm_snprintf ( tmp , sizeof ( tmp ) , " \t \t \t reason= \" %s \" \n \t \t \t value=%d \n " ,
( cmd_state - > signal ? LVMPD_REAS_SIGNAL : LVMPD_REAS_RETCODE ) ,
( cmd_state - > signal ? : cmd_state - > retcode ) ) > 0 )
buffer_append ( buff , tmp ) ;
}
buffer_append ( buff , " \t \t } \n " ) ;
/* } lvm_commmand-section */
buffer_append ( buff , " \t } \n " ) ;
/* } pdlv-section */
}
void pdst_locked_dump ( const struct lvmpolld_store * pdst , struct buffer * buff )
{
struct dm_hash_node * n ;
dm_hash_iterate ( n , pdst - > store )
_pdlv_locked_dump ( buff , dm_hash_get_data ( pdst - > store , n ) ) ;
}
void pdst_locked_send_cancel ( const struct lvmpolld_store * pdst )
{
struct lvmpolld_lv * pdlv ;
struct dm_hash_node * n ;
dm_hash_iterate ( n , pdst - > store ) {
pdlv = dm_hash_get_data ( pdst - > store , n ) ;
if ( ! pdlv_locked_polling_finished ( pdlv ) )
pthread_cancel ( pdlv - > tid ) ;
}
}
void pdst_locked_destroy_all_pdlvs ( const struct lvmpolld_store * pdst )
{
struct dm_hash_node * n ;
dm_hash_iterate ( n , pdst - > store )
pdlv_destroy ( dm_hash_get_data ( pdst - > store , n ) ) ;
}
struct lvmpolld_thread_data * lvmpolld_thread_data_constructor ( struct lvmpolld_lv * pdlv )
{
struct lvmpolld_thread_data * data = ( struct lvmpolld_thread_data * ) dm_malloc ( sizeof ( struct lvmpolld_thread_data ) ) ;
if ( ! data )
return NULL ;
data - > pdlv = NULL ;
data - > line = NULL ;
2015-07-07 15:03:15 +03:00
data - > line_size = 0 ;
2015-05-09 02:59:18 +03:00
data - > fout = data - > ferr = NULL ;
data - > outpipe [ 0 ] = data - > outpipe [ 1 ] = data - > errpipe [ 0 ] = data - > errpipe [ 1 ] = - 1 ;
if ( pipe ( data - > outpipe ) | | pipe ( data - > errpipe ) ) {
lvmpolld_thread_data_destroy ( data ) ;
return NULL ;
}
if ( fcntl ( data - > outpipe [ 0 ] , F_SETFD , FD_CLOEXEC ) | |
fcntl ( data - > outpipe [ 1 ] , F_SETFD , FD_CLOEXEC ) | |
fcntl ( data - > errpipe [ 0 ] , F_SETFD , FD_CLOEXEC ) | |
fcntl ( data - > errpipe [ 1 ] , F_SETFD , FD_CLOEXEC ) ) {
lvmpolld_thread_data_destroy ( data ) ;
return NULL ;
}
data - > pdlv = pdlv ;
return data ;
}
void lvmpolld_thread_data_destroy ( void * thread_private )
{
struct lvmpolld_thread_data * data = ( struct lvmpolld_thread_data * ) thread_private ;
if ( ! data )
return ;
if ( data - > pdlv ) {
pdst_lock ( data - > pdlv - > pdst ) ;
/*
* FIXME : skip this step if lvmpolld is activated
* by systemd .
*/
if ( ! pdlv_get_polling_finished ( data - > pdlv ) )
kill ( data - > pdlv - > cmd_pid , SIGTERM ) ;
pdlv_set_polling_finished ( data - > pdlv , 1 ) ;
pdst_locked_dec ( data - > pdlv - > pdst ) ;
pdst_unlock ( data - > pdlv - > pdst ) ;
}
2015-07-07 15:03:15 +03:00
/* may get reallocated in getline(). dm_free must not be used */
free ( data - > line ) ;
2015-05-09 02:59:18 +03:00
if ( data - > fout & & ! fclose ( data - > fout ) )
data - > outpipe [ 0 ] = - 1 ;
if ( data - > ferr & & ! fclose ( data - > ferr ) )
data - > errpipe [ 0 ] = - 1 ;
if ( data - > outpipe [ 0 ] > = 0 )
2015-07-09 16:15:15 +03:00
( void ) close ( data - > outpipe [ 0 ] ) ;
2015-05-09 02:59:18 +03:00
if ( data - > outpipe [ 1 ] > = 0 )
2015-07-09 16:15:15 +03:00
( void ) close ( data - > outpipe [ 1 ] ) ;
2015-05-09 02:59:18 +03:00
if ( data - > errpipe [ 0 ] > = 0 )
2015-07-09 16:15:15 +03:00
( void ) close ( data - > errpipe [ 0 ] ) ;
2015-05-09 02:59:18 +03:00
if ( data - > errpipe [ 1 ] > = 0 )
2015-07-09 16:15:15 +03:00
( void ) close ( data - > errpipe [ 1 ] ) ;
2015-05-09 02:59:18 +03:00
dm_free ( data ) ;
}