2002-02-11 18:42:34 +03:00
/*
* Copyright ( C ) 2001 Sistina Software ( UK ) Limited .
*
* This file is released under the LGPL .
*
*/
# include "log.h"
# include "locking.h"
# include "locking_types.h"
# include "activate.h"
# include "config.h"
# include "defaults.h"
# include "lvm-file.h"
# include "lvm-string.h"
# include "dbg_malloc.h"
# include <limits.h>
# include <unistd.h>
# include <sys/types.h>
# include <sys/stat.h>
# include <sys/file.h>
# include <fcntl.h>
# include <signal.h>
struct lock_list {
struct list list ;
int lf ;
char * res ;
} ;
static struct list _lock_list ;
static char _lock_dir [ NAME_LEN ] ;
static int _release_lock ( const char * file )
{
struct lock_list * ll ;
struct list * llh , * llt ;
list_iterate_safe ( llh , llt , & _lock_list ) {
ll = list_item ( llh , struct lock_list ) ;
if ( ! file | | ! strcmp ( ll - > res , file ) ) {
list_del ( llh ) ;
log_very_verbose ( " Unlocking %s " , ll - > res ) ;
/*
* If this is the last pid using the file , remove it
*/
if ( ! flock ( ll - > lf , LOCK_NB | LOCK_EX ) )
if ( unlink ( ll - > res ) )
log_sys_error ( " unlink " , ll - > res ) ;
if ( close ( ll - > lf ) < 0 )
log_sys_error ( " close " , ll - > res ) ;
dbg_free ( ll - > res ) ;
dbg_free ( llh ) ;
if ( file )
return 1 ;
}
}
return 0 ;
}
void fin_file_locking ( void )
{
_release_lock ( NULL ) ;
}
void _trap_ctrl_c ( int signal )
{
log_error ( " CTRL-c detected: giving up waiting for lock " ) ;
return ;
}
static void _install_ctrl_c_handler ( )
{
siginterrupt ( SIGINT , 1 ) ;
signal ( SIGINT , _trap_ctrl_c ) ;
}
static void _remove_ctrl_c_handler ( )
{
signal ( SIGINT , SIG_IGN ) ;
siginterrupt ( SIGINT , 0 ) ;
}
static int _lock_file ( const char * file , int flags )
{
int operation ;
int r = 1 ;
struct lock_list * ll ;
switch ( flags & LCK_TYPE_MASK ) {
case LCK_READ :
operation = LOCK_SH ;
break ;
case LCK_WRITE :
operation = LOCK_EX ;
break ;
case LCK_NONE :
return _release_lock ( file ) ;
default :
log_error ( " Unrecognised lock type: %d " , flags & LCK_TYPE_MASK ) ;
return 0 ;
}
if ( ! ( ll = dbg_malloc ( sizeof ( struct lock_list ) ) ) )
return 0 ;
if ( ! ( ll - > res = dbg_strdup ( file ) ) ) {
dbg_free ( ll ) ;
return 0 ;
}
log_very_verbose ( " Locking %s " , ll - > res ) ;
if ( ( ll - > lf = open ( file , O_CREAT | O_APPEND | O_RDWR , 0777 ) ) < 0 ) {
log_sys_error ( " open " , file ) ;
dbg_free ( ll - > res ) ;
dbg_free ( ll ) ;
return 0 ;
}
if ( ( flags & LCK_NONBLOCK ) )
operation | = LOCK_NB ;
else
_install_ctrl_c_handler ( ) ;
if ( flock ( ll - > lf , operation ) ) {
log_sys_error ( " flock " , ll - > res ) ;
dbg_free ( ll - > res ) ;
dbg_free ( ll ) ;
r = 0 ;
} else
list_add ( & _lock_list , & ll - > list ) ;
if ( ! ( flags & LCK_NONBLOCK ) )
_remove_ctrl_c_handler ( ) ;
return r ;
}
2002-02-25 15:56:16 +03:00
int lock_resource ( struct cmd_context * cmd , const char * resource , int flags )
2002-02-11 18:42:34 +03:00
{
char lockfile [ PATH_MAX ] ;
switch ( flags & LCK_SCOPE_MASK ) {
case LCK_VG :
if ( ! resource | | ! * resource )
lvm_snprintf ( lockfile , sizeof ( lockfile ) ,
" %s/P_orphans " , _lock_dir ) ;
else
lvm_snprintf ( lockfile , sizeof ( lockfile ) ,
" %s/V_%s " , _lock_dir , resource ) ;
2002-02-25 15:56:16 +03:00
if ( ! _lock_file ( lockfile , flags ) )
return 0 ;
2002-02-11 18:42:34 +03:00
break ;
case LCK_LV :
2002-02-21 00:30:27 +03:00
switch ( flags & LCK_TYPE_MASK ) {
case LCK_NONE :
2002-02-25 15:56:16 +03:00
if ( ! lv_resume_if_active ( cmd , resource ) )
return 0 ;
2002-02-21 00:30:27 +03:00
break ;
2002-02-27 15:26:41 +03:00
case LCK_READ :
2002-03-11 18:08:39 +03:00
if ( ! lv_activate ( cmd , resource ) )
2002-02-27 15:26:41 +03:00
return 0 ;
break ;
2002-02-21 00:30:27 +03:00
case LCK_WRITE :
2002-02-25 15:56:16 +03:00
if ( ! lv_suspend_if_active ( cmd , resource ) )
return 0 ;
2002-02-21 00:30:27 +03:00
break ;
2002-02-27 15:26:41 +03:00
case LCK_EXCL :
2002-03-11 18:08:39 +03:00
if ( ! lv_deactivate ( cmd , resource ) )
2002-02-27 15:26:41 +03:00
return 0 ;
break ;
2002-02-21 00:30:27 +03:00
default :
break ;
}
2002-02-25 15:56:16 +03:00
break ;
default :
log_error ( " Unrecognised lock scope: %d " ,
flags & LCK_SCOPE_MASK ) ;
return 0 ;
2002-02-21 00:30:27 +03:00
}
2002-02-25 15:56:16 +03:00
return 1 ;
}
2002-02-11 18:42:34 +03:00
int init_file_locking ( struct locking_type * locking , struct config_file * cf )
{
locking - > lock_resource = lock_resource ;
locking - > fin_locking = fin_file_locking ;
/* Get lockfile directory from config file */
strncpy ( _lock_dir , find_config_str ( cf - > root , " global/locking_dir " ,
' / ' , DEFAULT_LOCK_DIR ) ,
sizeof ( _lock_dir ) ) ;
if ( ! create_dir ( _lock_dir ) )
return 0 ;
list_init ( & _lock_list ) ;
return 1 ;
}