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 ;
2012-04-24 16:16:40 +04:00
static struct dm_hash_table * _locks ;
static int _lockid ;
struct lock {
int lockid ;
int mode ;
int excl ;
} ;
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-07-28 18:01:40 +04:00
mode_t old_mask ;
2012-06-21 23:19:28 +04:00
struct sockaddr_un addr = { . sun_family = AF_UNIX } ;
if ( ! dm_strncpy ( addr . sun_path , SINGLENODE_CLVMD_SOCKNAME ,
sizeof ( addr . sun_path ) ) ) {
DEBUGLOG ( " %s: singlenode socket name too long. " ,
SINGLENODE_CLVMD_SOCKNAME ) ;
return - 1 ;
}
2010-07-28 18:01:40 +04:00
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
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 ;
2012-04-24 16:16:40 +04:00
if ( ! ( _locks = dm_hash_create ( 128 ) ) ) {
DEBUGLOG ( " Failed to allocate single-node hash table. \n " ) ;
return 1 ;
}
2010-03-18 12:19:30 +03:00
r = init_comms ( ) ;
2012-04-24 16:16:40 +04:00
if ( r ) {
dm_hash_destroy ( _locks ) ;
2010-03-18 12:19:30 +03:00
return r ;
2012-04-24 16:16:40 +04:00
}
2010-03-18 12:19:30 +03:00
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 ( ) ;
2012-04-24 16:16:40 +04:00
dm_hash_destroy ( _locks ) ;
2011-03-24 13:45:00 +03:00
_locks = NULL ;
2012-04-24 16:16:40 +04:00
_lockid = 0 ;
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 )
{
2012-12-14 17:01:19 +04:00
strcpy ( 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 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 )
{
2012-04-24 16:16:40 +04:00
struct lock * lck ;
2011-11-07 21:11:23 +04:00
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 ) ;
2012-04-24 16:16:40 +04:00
mode & = LCK_TYPE_MASK ;
2010-03-18 12:19:30 +03:00
pthread_mutex_lock ( & _lock_mutex ) ;
2011-10-11 13:05:20 +04:00
retry :
2012-04-24 16:16:40 +04:00
if ( ! ( lck = dm_hash_lookup ( _locks , resource ) ) ) {
/* Add new locked resource */
if ( ! ( lck = dm_zalloc ( sizeof ( struct lock ) ) ) | |
! dm_hash_insert ( _locks , resource , lck ) )
goto bad ;
lck - > lockid = + + _lockid ;
goto out ;
2010-03-18 12:19:30 +03:00
}
2012-04-24 16:16:40 +04:00
/* Update/convert lock */
if ( flags = = LCKF_CONVERT ) {
if ( lck - > excl )
mode = LCK_EXCL ;
} else if ( ( lck - > mode = = LCK_WRITE ) | | ( lck - > mode = = LCK_EXCL ) ) {
DEBUGLOG ( " Resource %s already %s locked (%d)... \n " , resource ,
( lck - > mode = = LCK_WRITE ) ? " write " : " exclusively " , lck - > lockid ) ;
goto maybe_retry ;
} else if ( lck - > mode > mode ) {
DEBUGLOG ( " Resource %s already locked and %s lock requested... \n " ,
resource ,
( mode = = LCK_READ ) ? " READ " :
( mode = = LCK_WRITE ) ? " WRITE " : " EXCLUSIVE " ) ;
goto maybe_retry ;
2010-03-18 12:19:30 +03:00
}
2012-04-24 16:16:40 +04:00
out :
* lockid = lck - > lockid ;
lck - > mode = mode ;
lck - > excl | = ( mode = = LCK_EXCL ) ;
DEBUGLOG ( " Locked resource %s, lockid=%d, mode=%d \n " , resource , lck - > lockid , mode ) ;
pthread_cond_broadcast ( & _lock_cond ) ; /* wakeup waiters */
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 ) ;
2012-04-24 16:16:40 +04:00
DEBUGLOG ( " Resource %s RETRYING lock... \n " , resource ) ;
2010-03-18 12:19:30 +03:00
goto retry ;
}
2011-10-11 13:05:20 +04:00
bad :
pthread_mutex_unlock ( & _lock_mutex ) ;
2013-04-18 20:01:52 +04:00
DEBUGLOG ( " Failed to lock resource %s \n " , resource ) ;
2010-03-18 12:19:30 +03:00
return 1 ; /* fail */
}
static int _unlock_resource ( const char * resource , int lockid )
{
2012-04-24 16:16:40 +04:00
struct lock * lck ;
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 ) ;
2012-04-24 16:16:40 +04:00
if ( ! ( lck = dm_hash_lookup ( _locks , resource ) ) ) {
2011-10-11 13:05:20 +04:00
pthread_mutex_unlock ( & _lock_mutex ) ;
2012-04-24 16:16:40 +04:00
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
2012-04-24 16:16:40 +04:00
if ( lck - > lockid ! = lockid ) {
2011-10-11 13:05:20 +04:00
pthread_mutex_unlock ( & _lock_mutex ) ;
2012-04-24 16:16:40 +04:00
DEBUGLOG ( " Resource %s has wrong lockid %d, expected %d. \n " ,
resource , lck - > lockid , lockid ) ;
2010-03-18 12:19:30 +03:00
return 1 ;
}
2012-04-24 16:16:40 +04:00
dm_hash_remove ( _locks , resource ) ;
2011-10-11 13:05:20 +04:00
pthread_cond_broadcast ( & _lock_cond ) ; /* wakeup waiters */
pthread_mutex_unlock ( & _lock_mutex ) ;
2013-04-18 20:01:52 +04:00
dm_free ( lck ) ;
2011-10-11 13:05:20 +04:00
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 )
{
2012-12-14 17:01:19 +04:00
return dm_strncpy ( buf , " localcluster " , buflen ) ? 0 : 1 ;
2010-03-18 12:19:30 +03:00
}
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 ;
2013-04-18 20:01:52 +04:00
return NULL ;
2010-03-18 12:19:30 +03:00
}