2010-03-18 12:19:30 +03:00
/*
* Copyright ( C ) 2009 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
*/
2010-06-21 19:56:57 +04:00
# include "clvmd-common.h"
2010-03-18 12:19:30 +03:00
# include <pthread.h>
# include "locking.h"
# include "clvm.h"
# include "clvmd-comms.h"
# include "lvm-functions.h"
# include "clvmd.h"
2010-06-21 19:56:57 +04:00
# include <sys/un.h>
# include <sys/socket.h>
# include <fcntl.h>
2010-07-28 18:01:40 +04:00
static const char SINGLENODE_CLVMD_SOCKNAME [ ] = DEFAULT_RUN_DIR " /clvmd_singlenode.sock " ;
2010-03-18 12:19:30 +03:00
static int listen_fd = - 1 ;
2011-03-24 13:45:00 +03:00
static int * _locks = NULL ;
static char * * _resources = NULL ;
2010-03-18 12:19:30 +03:00
2010-08-03 17:06:35 +04:00
static void close_comms ( void )
2010-07-28 18:01:40 +04:00
{
if ( listen_fd ! = - 1 & & close ( listen_fd ) )
stack ;
( void ) unlink ( SINGLENODE_CLVMD_SOCKNAME ) ;
listen_fd = - 1 ;
}
2010-08-03 17:06:35 +04:00
static int init_comms ( void )
2010-03-18 12:19:30 +03:00
{
2010-03-26 18:45:36 +03:00
struct sockaddr_un addr ;
2010-07-28 18:01:40 +04:00
mode_t old_mask ;
close_comms ( ) ;
2010-12-13 13:43:56 +03:00
( void ) dm_prepare_selinux_context ( SINGLENODE_CLVMD_SOCKNAME , S_IFSOCK ) ;
2010-07-28 18:01:40 +04:00
old_mask = umask ( 0077 ) ;
2010-03-18 12:19:30 +03:00
2010-03-26 18:45:36 +03:00
listen_fd = socket ( PF_UNIX , SOCK_STREAM , 0 ) ;
if ( listen_fd < 0 ) {
DEBUGLOG ( " Can't create local socket: %s \n " , strerror ( errno ) ) ;
2010-07-28 18:01:40 +04:00
goto error ;
2010-03-26 18:45:36 +03:00
}
2010-03-18 12:19:30 +03:00
/* Set Close-on-exec */
2011-08-04 16:13:50 +04:00
if ( fcntl ( listen_fd , F_SETFD , 1 ) ) {
2011-09-29 12:57:21 +04:00
DEBUGLOG ( " Setting CLOEXEC on client fd failed: %s \n " , strerror ( errno ) ) ;
2011-08-04 16:13:50 +04:00
goto error ;
}
2010-03-18 12:19:30 +03:00
2010-03-26 18:45:36 +03:00
memset ( & addr , 0 , sizeof ( addr ) ) ;
memcpy ( addr . sun_path , SINGLENODE_CLVMD_SOCKNAME ,
sizeof ( SINGLENODE_CLVMD_SOCKNAME ) ) ;
addr . sun_family = AF_UNIX ;
if ( bind ( listen_fd , ( struct sockaddr * ) & addr , sizeof ( addr ) ) < 0 ) {
DEBUGLOG ( " Can't bind local socket: %s \n " , strerror ( errno ) ) ;
2010-07-28 18:01:40 +04:00
goto error ;
2010-03-26 18:45:36 +03:00
}
if ( listen ( listen_fd , 10 ) < 0 ) {
DEBUGLOG ( " Can't listen local socket: %s \n " , strerror ( errno ) ) ;
2010-07-28 18:01:40 +04:00
goto error ;
2010-03-26 18:45:36 +03:00
}
2010-07-28 18:01:40 +04:00
umask ( old_mask ) ;
2010-12-13 13:43:56 +03:00
( void ) dm_prepare_selinux_context ( NULL , 0 ) ;
2010-03-18 12:19:30 +03:00
return 0 ;
2010-07-28 18:01:40 +04:00
error :
umask ( old_mask ) ;
2010-12-13 13:43:56 +03:00
( void ) dm_prepare_selinux_context ( NULL , 0 ) ;
2010-07-28 18:01:40 +04:00
close_comms ( ) ;
return - 1 ;
2010-03-18 12:19:30 +03:00
}
static int _init_cluster ( void )
{
int r ;
r = init_comms ( ) ;
if ( r )
return r ;
DEBUGLOG ( " Single-node cluster initialised. \n " ) ;
return 0 ;
}
static void _cluster_closedown ( void )
{
2010-07-28 18:01:40 +04:00
close_comms ( ) ;
2010-03-18 12:19:30 +03:00
DEBUGLOG ( " cluster_closedown \n " ) ;
destroy_lvhash ( ) ;
2011-03-24 13:45:00 +03:00
dm_free ( _locks ) ;
dm_free ( _resources ) ;
_locks = NULL ;
_resources = NULL ;
2010-03-18 12:19:30 +03:00
}
static void _get_our_csid ( char * csid )
{
int nodeid = 1 ;
memcpy ( csid , & nodeid , sizeof ( int ) ) ;
}
static int _csid_from_name ( char * csid , const char * name )
{
return 1 ;
}
static int _name_from_csid ( const char * csid , char * name )
{
2010-08-17 23:25:05 +04:00
sprintf ( name , " SINGLENODE " ) ;
2010-03-18 12:19:30 +03:00
return 0 ;
}
2010-08-03 17:06:35 +04:00
static int _get_num_nodes ( void )
2010-03-18 12:19:30 +03:00
{
return 1 ;
}
/* Node is now known to be running a clvmd */
static void _add_up_node ( const char * csid )
{
}
/* Call a callback for each node, so the caller knows whether it's up or down */
static int _cluster_do_node_callback ( struct local_client * master_client ,
void ( * callback ) ( struct local_client * ,
const char * csid , int node_up ) )
{
return 0 ;
}
int _lock_file ( const char * file , uint32_t flags ) ;
static int _lock_max = 1 ;
static pthread_mutex_t _lock_mutex = PTHREAD_MUTEX_INITIALIZER ;
2011-10-11 13:05:20 +04:00
/* Using one common condition for all locks for simplicity */
static pthread_cond_t _lock_cond = PTHREAD_COND_INITIALIZER ;
2010-03-18 12:19:30 +03:00
/* Real locking */
static int _lock_resource ( const char * resource , int mode , int flags , int * lockid )
{
int * _locks_1 ;
char * * _resources_1 ;
int i , j ;
2011-11-07 21:11:23 +04:00
if ( mode = = LCK_READ ) { /* only track PREAD, aka PROTECTED READ */
DEBUGLOG ( " Not tracking CONCURRENT READ lock: %s, flags=%d, mode=%d \n " ,
resource , flags , mode ) ;
* lockid = - 1 ;
return 0 ;
}
2011-10-11 13:05:20 +04:00
DEBUGLOG ( " Locking resource %s, flags=%d, mode=%d \n " ,
2010-03-18 12:19:30 +03:00
resource , flags , mode ) ;
pthread_mutex_lock ( & _lock_mutex ) ;
2011-10-11 13:05:20 +04:00
retry :
2010-03-18 12:19:30 +03:00
/* look for an existing lock for this resource */
for ( i = 1 ; i < _lock_max ; + + i ) {
if ( ! _resources [ i ] )
break ;
if ( ! strcmp ( _resources [ i ] , resource ) ) {
2010-08-20 03:26:31 +04:00
if ( ( _locks [ i ] & LCK_TYPE_MASK ) = = LCK_WRITE | |
( _locks [ i ] & LCK_TYPE_MASK ) = = LCK_EXCL ) {
2011-10-11 13:05:20 +04:00
DEBUGLOG ( " Resource %s already write/exclusively locked... \n " , resource ) ;
2010-03-18 12:19:30 +03:00
goto maybe_retry ;
}
2010-08-20 03:26:31 +04:00
if ( ( mode & LCK_TYPE_MASK ) = = LCK_WRITE | |
( mode & LCK_TYPE_MASK ) = = LCK_EXCL ) {
2011-10-11 13:05:20 +04:00
DEBUGLOG ( " Resource %s already locked and WRITE/EXCL lock requested... \n " ,
2010-03-18 12:19:30 +03:00
resource ) ;
goto maybe_retry ;
}
}
}
if ( i = = _lock_max ) { /* out of lock slots, extend */
2011-10-11 13:05:20 +04:00
if ( ! ( _locks_1 = dm_realloc ( _locks , 2 * _lock_max * sizeof ( int ) ) ) )
goto_bad ;
2010-03-18 12:19:30 +03:00
_locks = _locks_1 ;
2011-10-11 13:05:20 +04:00
if ( ! ( _resources_1 = dm_realloc ( _resources , 2 * _lock_max * sizeof ( char * ) ) ) )
2010-03-18 12:19:30 +03:00
/* _locks may get realloc'd twice, but that should be safe */
2011-10-11 13:05:20 +04:00
goto_bad ;
2010-03-18 12:19:30 +03:00
_resources = _resources_1 ;
/* clear the new resource entries */
for ( j = _lock_max ; j < 2 * _lock_max ; + + j )
_resources [ j ] = NULL ;
_lock_max = 2 * _lock_max ;
}
/* resource is not currently locked, grab it */
2011-10-11 13:05:20 +04:00
if ( ! ( _resources [ i ] = dm_strdup ( resource ) ) )
goto_bad ;
2010-03-18 12:19:30 +03:00
* lockid = i ;
_locks [ i ] = mode ;
2011-10-11 13:05:20 +04:00
DEBUGLOG ( " Locked resource %s, lockid=%d \n " , resource , i ) ;
2010-03-18 12:19:30 +03:00
pthread_mutex_unlock ( & _lock_mutex ) ;
2011-10-11 13:05:20 +04:00
2010-03-18 12:19:30 +03:00
return 0 ;
2011-10-11 13:05:20 +04:00
maybe_retry :
2010-03-18 12:19:30 +03:00
if ( ! ( flags & LCK_NONBLOCK ) ) {
2011-10-11 13:05:20 +04:00
pthread_cond_wait ( & _lock_cond , & _lock_mutex ) ;
2010-03-18 12:19:30 +03:00
goto retry ;
}
2011-10-11 13:05:20 +04:00
bad :
DEBUGLOG ( " Failed to lock resource %s \n " , resource ) ;
pthread_mutex_unlock ( & _lock_mutex ) ;
2010-03-18 12:19:30 +03:00
return 1 ; /* fail */
}
static int _unlock_resource ( const char * resource , int lockid )
{
2011-11-07 21:11:23 +04:00
if ( lockid < 0 ) {
DEBUGLOG ( " Not tracking unlock of lockid -1: %s, lockid=%d \n " ,
resource , lockid ) ;
return 0 ;
}
2011-10-11 13:05:20 +04:00
DEBUGLOG ( " Unlocking resource %s, lockid=%d \n " , resource , lockid ) ;
pthread_mutex_lock ( & _lock_mutex ) ;
if ( ! _resources [ lockid ] ) {
pthread_mutex_unlock ( & _lock_mutex ) ;
DEBUGLOG ( " Resource %s, lockid=%d is not locked \n " , resource , lockid ) ;
2010-03-18 12:19:30 +03:00
return 1 ;
}
2011-10-11 13:05:20 +04:00
if ( strcmp ( _resources [ lockid ] , resource ) ) {
pthread_mutex_unlock ( & _lock_mutex ) ;
DEBUGLOG ( " Resource %d has wrong resource (requested %s, got %s) \n " ,
2010-03-18 12:19:30 +03:00
lockid , resource , _resources [ lockid ] ) ;
return 1 ;
}
dm_free ( _resources [ lockid ] ) ;
_resources [ lockid ] = 0 ;
2011-10-11 13:05:20 +04:00
pthread_cond_broadcast ( & _lock_cond ) ; /* wakeup waiters */
pthread_mutex_unlock ( & _lock_mutex ) ;
2010-03-18 12:19:30 +03:00
return 0 ;
}
2010-08-03 17:06:35 +04:00
static int _is_quorate ( void )
2010-03-18 12:19:30 +03:00
{
return 1 ;
}
static int _get_main_cluster_fd ( void )
{
return listen_fd ;
}
static int _cluster_fd_callback ( struct local_client * fd , char * buf , int len ,
const char * csid ,
struct local_client * * new_client )
{
return 1 ;
}
static int _cluster_send_message ( const void * buf , int msglen ,
const char * csid ,
const char * errtext )
{
return 0 ;
}
static int _get_cluster_name ( char * buf , int buflen )
{
strncpy ( buf , " localcluster " , buflen ) ;
buf [ buflen - 1 ] = 0 ;
return 0 ;
}
static struct cluster_ops _cluster_singlenode_ops = {
2011-09-25 23:37:00 +04:00
. name = " singlenode " ,
2010-03-18 12:19:30 +03:00
. cluster_init_completed = NULL ,
. cluster_send_message = _cluster_send_message ,
. name_from_csid = _name_from_csid ,
. csid_from_name = _csid_from_name ,
. get_num_nodes = _get_num_nodes ,
. cluster_fd_callback = _cluster_fd_callback ,
. get_main_cluster_fd = _get_main_cluster_fd ,
. cluster_do_node_callback = _cluster_do_node_callback ,
. is_quorate = _is_quorate ,
. get_our_csid = _get_our_csid ,
. add_up_node = _add_up_node ,
. reread_config = NULL ,
. cluster_closedown = _cluster_closedown ,
. get_cluster_name = _get_cluster_name ,
. sync_lock = _lock_resource ,
. sync_unlock = _unlock_resource ,
} ;
struct cluster_ops * init_singlenode_cluster ( void )
{
if ( ! _init_cluster ( ) )
return & _cluster_singlenode_ops ;
else
return NULL ;
}