2007-04-10 00:03:39 +04:00
/*
ctdb daemon code
Copyright ( C ) Andrew Tridgell 2006
2007-05-31 07:50:53 +04:00
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 2 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
2007-04-10 00:03:39 +04:00
but WITHOUT ANY WARRANTY ; without even the implied warranty of
2007-05-31 07:50:53 +04:00
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program ; if not , write to the Free Software
Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
2007-04-10 00:03:39 +04:00
*/
# include "includes.h"
# include "db_wrap.h"
# include "lib/tdb/include/tdb.h"
# include "lib/events/events.h"
# include "lib/util/dlinklist.h"
# include "system/network.h"
# include "system/filesys.h"
2007-04-17 09:33:20 +04:00
# include "system/wait.h"
2007-04-10 00:03:39 +04:00
# include "../include/ctdb.h"
# include "../include/ctdb_private.h"
2007-05-19 07:45:24 +04:00
static void daemon_incoming_packet ( void * , struct ctdb_req_header * ) ;
2007-04-19 10:27:56 +04:00
2007-06-06 15:34:36 +04:00
/*
handler for when a node changes its flags
*/
static void flag_change_handler ( struct ctdb_context * ctdb , uint64_t srvid ,
TDB_DATA data , void * private_data )
{
struct ctdb_node_flag_change * c = ( struct ctdb_node_flag_change * ) data . dptr ;
if ( data . dsize ! = sizeof ( * c ) | | ! ctdb_validate_vnn ( ctdb , c - > vnn ) ) {
DEBUG ( 0 , ( __location__ " Invalid data in ctdb_node_flag_change \n " ) ) ;
return ;
}
2007-06-07 12:13:14 +04:00
if ( ! ctdb_validate_vnn ( ctdb , c - > vnn ) ) {
DEBUG ( 0 , ( " Bad vnn %u in flag_change_handler \n " , c - > vnn ) ) ;
return ;
}
2007-06-07 09:18:55 +04:00
/* don't get the disconnected flag from the other node */
2007-06-06 15:34:36 +04:00
ctdb - > nodes [ c - > vnn ] - > flags =
2007-06-07 09:18:55 +04:00
( ctdb - > nodes [ c - > vnn ] - > flags & NODE_FLAGS_DISCONNECTED )
| ( c - > flags & ~ NODE_FLAGS_DISCONNECTED ) ;
2007-06-07 12:13:14 +04:00
DEBUG ( 2 , ( " Node flags for node %u are now 0x%x \n " , c - > vnn , ctdb - > nodes [ c - > vnn ] - > flags ) ) ;
2007-06-10 02:46:33 +04:00
/* make sure we don't hold any IPs when we shouldn't */
if ( c - > vnn = = ctdb - > vnn & &
( ctdb - > nodes [ c - > vnn ] - > flags & ( NODE_FLAGS_INACTIVE | NODE_FLAGS_BANNED ) ) ) {
ctdb_release_all_ips ( ctdb ) ;
}
2007-06-06 15:34:36 +04:00
}
2007-05-30 07:26:50 +04:00
/* called when the "startup" event script has finished */
2007-06-01 13:05:41 +04:00
static void ctdb_start_transport ( struct ctdb_context * ctdb , int status , void * p )
2007-05-30 07:26:50 +04:00
{
if ( status ! = 0 ) {
DEBUG ( 0 , ( " startup event failed! \n " ) ) ;
ctdb_fatal ( ctdb , " startup event script failed " ) ;
}
/* start the transport running */
if ( ctdb - > methods - > start ( ctdb ) ! = 0 ) {
DEBUG ( 0 , ( " transport failed to start! \n " ) ) ;
ctdb_fatal ( ctdb , " transport failed to start " ) ;
}
/* start the recovery daemon process */
if ( ctdb_start_recoverd ( ctdb ) ! = 0 ) {
DEBUG ( 0 , ( " Failed to start recovery daemon \n " ) ) ;
exit ( 11 ) ;
}
2007-05-30 08:35:22 +04:00
2007-06-06 15:34:36 +04:00
/* a handler for when nodes are disabled/enabled */
ctdb_register_message_handler ( ctdb , ctdb , CTDB_SRVID_NODE_FLAGS_CHANGED ,
flag_change_handler , NULL ) ;
2007-05-30 08:35:22 +04:00
/* start monitoring for dead nodes */
ctdb_start_monitoring ( ctdb ) ;
2007-05-30 07:26:50 +04:00
}
/* go into main ctdb loop */
2007-04-10 00:03:39 +04:00
static void ctdb_main_loop ( struct ctdb_context * ctdb )
{
2007-04-26 17:28:13 +04:00
int ret = - 1 ;
if ( strcmp ( ctdb - > transport , " tcp " ) = = 0 ) {
int ctdb_tcp_init ( struct ctdb_context * ) ;
ret = ctdb_tcp_init ( ctdb ) ;
}
2007-04-26 17:33:17 +04:00
# ifdef USE_INFINIBAND
2007-04-26 17:28:13 +04:00
if ( strcmp ( ctdb - > transport , " ib " ) = = 0 ) {
int ctdb_ibw_init ( struct ctdb_context * ) ;
ret = ctdb_ibw_init ( ctdb ) ;
}
# endif
if ( ret ! = 0 ) {
DEBUG ( 0 , ( " Failed to initialise transport '%s' \n " , ctdb - > transport ) ) ;
return ;
2007-04-20 16:26:19 +04:00
}
2007-05-30 07:26:50 +04:00
/* initialise the transport */
if ( ctdb - > methods - > initialise ( ctdb ) ! = 0 ) {
DEBUG ( 0 , ( " transport failed to initialise! \n " ) ) ;
ctdb_fatal ( ctdb , " transport failed to initialise " ) ;
2007-05-15 03:44:33 +04:00
}
2007-04-10 00:03:39 +04:00
2007-05-27 18:34:40 +04:00
/* tell all other nodes we've just started up */
ctdb_daemon_send_control ( ctdb , CTDB_BROADCAST_ALL ,
0 , CTDB_CONTROL_STARTUP , 0 ,
CTDB_CTRL_FLAG_NOREPLY ,
tdb_null , NULL , NULL ) ;
2007-06-12 13:44:54 +04:00
/* release any IPs we hold from previous runs of the daemon */
ctdb_release_all_ips ( ctdb ) ;
2007-06-06 07:45:12 +04:00
ret = ctdb_event_script_callback ( ctdb , timeval_zero ( ) , ctdb ,
2007-06-01 13:05:41 +04:00
ctdb_start_transport , NULL , " startup " ) ;
2007-05-30 07:26:50 +04:00
if ( ret ! = 0 ) {
DEBUG ( 0 , ( " Failed startup event script \n " ) ) ;
return ;
}
2007-04-10 00:03:39 +04:00
/* go into a wait loop to allow other nodes to complete */
event_loop_wait ( ctdb - > ev ) ;
2007-04-17 16:27:17 +04:00
DEBUG ( 0 , ( " event_loop_wait() returned. this should not happen \n " ) ) ;
2007-04-10 00:03:39 +04:00
exit ( 1 ) ;
}
2007-04-17 09:33:20 +04:00
static void block_signal ( int signum )
{
struct sigaction act ;
memset ( & act , 0 , sizeof ( act ) ) ;
act . sa_handler = SIG_IGN ;
sigemptyset ( & act . sa_mask ) ;
sigaddset ( & act . sa_mask , signum ) ;
sigaction ( signum , & act , NULL ) ;
}
2007-04-10 00:03:39 +04:00
2007-04-20 14:07:47 +04:00
/*
send a packet to a client
*/
static int daemon_queue_send ( struct ctdb_client * client , struct ctdb_req_header * hdr )
{
2007-05-29 06:16:59 +04:00
client - > ctdb - > statistics . client_packets_sent + + ;
2007-04-20 14:07:47 +04:00
return ctdb_queue_send ( client - > queue , ( uint8_t * ) hdr , hdr - > length ) ;
}
2007-04-11 05:58:28 +04:00
/*
message handler for when we are in daemon mode . This redirects the message
to the right client
*/
2007-04-27 18:31:45 +04:00
static void daemon_message_handler ( struct ctdb_context * ctdb , uint64_t srvid ,
2007-04-13 14:38:24 +04:00
TDB_DATA data , void * private_data )
2007-04-11 05:58:28 +04:00
{
2007-04-13 14:38:24 +04:00
struct ctdb_client * client = talloc_get_type ( private_data , struct ctdb_client ) ;
2007-04-11 05:58:28 +04:00
struct ctdb_req_message * r ;
int len ;
/* construct a message to send to the client containing the data */
len = offsetof ( struct ctdb_req_message , data ) + data . dsize ;
2007-04-28 12:50:32 +04:00
r = ctdbd_allocate_pkt ( ctdb , ctdb , CTDB_REQ_MESSAGE ,
len , struct ctdb_req_message ) ;
CTDB_NO_MEMORY_VOID ( ctdb , r ) ;
2007-04-11 07:43:15 +04:00
2007-04-11 05:58:28 +04:00
talloc_set_name_const ( r , " req_message packet " ) ;
r - > srvid = srvid ;
r - > datalen = data . dsize ;
memcpy ( & r - > data [ 0 ] , data . dptr , data . dsize ) ;
2007-04-17 04:15:44 +04:00
2007-04-20 14:07:47 +04:00
daemon_queue_send ( client , & r - > hdr ) ;
2007-04-11 05:58:28 +04:00
talloc_free ( r ) ;
}
/*
this is called when the ctdb daemon received a ctdb request to
set the srvid from the client
*/
2007-05-04 05:41:29 +04:00
int daemon_register_message_handler ( struct ctdb_context * ctdb , uint32_t client_id , uint64_t srvid )
2007-04-11 05:58:28 +04:00
{
2007-05-04 05:41:29 +04:00
struct ctdb_client * client = ctdb_reqid_find ( ctdb , client_id , struct ctdb_client ) ;
2007-04-11 05:58:28 +04:00
int res ;
2007-05-04 05:41:29 +04:00
if ( client = = NULL ) {
DEBUG ( 0 , ( " Bad client_id in daemon_request_register_message_handler \n " ) ) ;
return - 1 ;
}
res = ctdb_register_message_handler ( ctdb , client , srvid , daemon_message_handler , client ) ;
2007-04-11 05:58:28 +04:00
if ( res ! = 0 ) {
2007-05-29 07:58:41 +04:00
DEBUG ( 0 , ( __location__ " Failed to register handler %llu in daemon \n " ,
( unsigned long long ) srvid ) ) ;
2007-04-20 01:47:37 +04:00
} else {
2007-05-29 07:58:41 +04:00
DEBUG ( 2 , ( __location__ " Registered message handler for srvid=%llu \n " ,
( unsigned long long ) srvid ) ) ;
2007-04-11 05:58:28 +04:00
}
2007-06-18 21:54:06 +04:00
/* this is a hack for Samba - we now know the pid of the Samba client */
if ( ( srvid & 0xFFFFFFFF ) = = srvid & &
kill ( srvid , 0 ) = = 0 ) {
client - > pid = srvid ;
DEBUG ( 0 , ( __location__ " Registered PID %u for client %u \n " ,
( unsigned ) client - > pid , client_id ) ) ;
}
2007-05-04 05:41:29 +04:00
return res ;
}
/*
this is called when the ctdb daemon received a ctdb request to
remove a srvid from the client
*/
int daemon_deregister_message_handler ( struct ctdb_context * ctdb , uint32_t client_id , uint64_t srvid )
{
struct ctdb_client * client = ctdb_reqid_find ( ctdb , client_id , struct ctdb_client ) ;
if ( client = = NULL ) {
DEBUG ( 0 , ( " Bad client_id in daemon_request_deregister_message_handler \n " ) ) ;
return - 1 ;
}
return ctdb_deregister_message_handler ( ctdb , srvid , client ) ;
2007-04-11 05:58:28 +04:00
}
2007-04-10 00:03:39 +04:00
/*
destroy a ctdb_client
*/
static int ctdb_client_destructor ( struct ctdb_client * client )
{
2007-05-27 09:26:29 +04:00
ctdb_takeover_client_destructor_hook ( client ) ;
2007-05-04 05:41:29 +04:00
ctdb_reqid_remove ( client - > ctdb , client - > client_id ) ;
2007-05-29 06:16:59 +04:00
client - > ctdb - > statistics . num_clients - - ;
2007-04-10 00:03:39 +04:00
return 0 ;
}
2007-04-11 07:43:15 +04:00
/*
this is called when the ctdb daemon received a ctdb request message
from a local client over the unix domain socket
*/
static void daemon_request_message_from_client ( struct ctdb_client * client ,
2007-04-11 08:05:01 +04:00
struct ctdb_req_message * c )
2007-04-11 07:43:15 +04:00
{
2007-04-11 08:05:01 +04:00
TDB_DATA data ;
int res ;
/* maybe the message is for another client on this node */
2007-04-11 07:43:15 +04:00
if ( ctdb_get_vnn ( client - > ctdb ) = = c - > hdr . destnode ) {
ctdb_request_message ( client - > ctdb , ( struct ctdb_req_header * ) c ) ;
2007-04-11 08:05:01 +04:00
return ;
}
2007-04-27 17:16:17 +04:00
2007-04-11 08:05:01 +04:00
/* its for a remote node */
data . dptr = & c - > data [ 0 ] ;
data . dsize = c - > datalen ;
res = ctdb_daemon_send_message ( client - > ctdb , c - > hdr . destnode ,
c - > srvid , data ) ;
if ( res ! = 0 ) {
2007-04-17 16:27:17 +04:00
DEBUG ( 0 , ( __location__ " Failed to send message to remote node %u \n " ,
c - > hdr . destnode ) ) ;
2007-04-11 07:43:15 +04:00
}
}
2007-04-19 04:37:44 +04:00
struct daemon_call_state {
struct ctdb_client * client ;
uint32_t reqid ;
struct ctdb_call * call ;
2007-04-20 14:07:47 +04:00
struct timeval start_time ;
2007-04-19 04:37:44 +04:00
} ;
/*
complete a call from a client
*/
static void daemon_call_from_client_callback ( struct ctdb_call_state * state )
2007-04-10 00:03:39 +04:00
{
2007-04-19 04:37:44 +04:00
struct daemon_call_state * dstate = talloc_get_type ( state - > async . private_data ,
struct daemon_call_state ) ;
2007-04-11 05:01:42 +04:00
struct ctdb_reply_call * r ;
2007-04-10 00:03:39 +04:00
int res ;
2007-04-11 05:01:42 +04:00
uint32_t length ;
2007-04-19 04:37:44 +04:00
struct ctdb_client * client = dstate - > client ;
2007-04-10 00:03:39 +04:00
2007-04-19 04:37:44 +04:00
talloc_steal ( client , dstate ) ;
talloc_steal ( dstate , dstate - > call ) ;
2007-04-10 00:03:39 +04:00
2007-04-19 04:37:44 +04:00
res = ctdb_daemon_call_recv ( state , dstate - > call ) ;
2007-04-10 00:03:39 +04:00
if ( res ! = 0 ) {
2007-04-17 16:27:17 +04:00
DEBUG ( 0 , ( __location__ " ctdbd_call_recv() returned error \n " ) ) ;
2007-05-29 06:16:59 +04:00
client - > ctdb - > statistics . pending_calls - - ;
ctdb_latency ( & client - > ctdb - > statistics . max_call_latency , dstate - > start_time ) ;
2007-04-19 04:37:44 +04:00
return ;
2007-04-10 00:03:39 +04:00
}
2007-04-19 04:37:44 +04:00
length = offsetof ( struct ctdb_reply_call , data ) + dstate - > call - > reply_data . dsize ;
2007-04-28 12:50:32 +04:00
r = ctdbd_allocate_pkt ( client - > ctdb , dstate , CTDB_REPLY_CALL ,
length , struct ctdb_reply_call ) ;
2007-04-11 05:01:42 +04:00
if ( r = = NULL ) {
2007-04-17 16:27:17 +04:00
DEBUG ( 0 , ( __location__ " Failed to allocate reply_call in ctdb daemon \n " ) ) ;
2007-05-29 06:16:59 +04:00
client - > ctdb - > statistics . pending_calls - - ;
ctdb_latency ( & client - > ctdb - > statistics . max_call_latency , dstate - > start_time ) ;
2007-04-11 05:01:42 +04:00
return ;
}
2007-04-19 04:37:44 +04:00
r - > hdr . reqid = dstate - > reqid ;
r - > datalen = dstate - > call - > reply_data . dsize ;
memcpy ( & r - > data [ 0 ] , dstate - > call - > reply_data . dptr , r - > datalen ) ;
2007-04-11 05:01:42 +04:00
2007-04-20 14:07:47 +04:00
res = daemon_queue_send ( client , & r - > hdr ) ;
2007-04-11 05:01:42 +04:00
if ( res ! = 0 ) {
2007-05-12 08:34:21 +04:00
DEBUG ( 0 , ( __location__ " Failed to queue packet from daemon to client \n " ) ) ;
2007-04-10 00:03:39 +04:00
}
2007-05-29 06:16:59 +04:00
ctdb_latency ( & client - > ctdb - > statistics . max_call_latency , dstate - > start_time ) ;
2007-04-19 04:37:44 +04:00
talloc_free ( dstate ) ;
2007-05-29 06:16:59 +04:00
client - > ctdb - > statistics . pending_calls - - ;
2007-04-10 00:03:39 +04:00
}
2007-04-19 10:27:56 +04:00
2007-05-10 01:43:18 +04:00
static void daemon_request_call_from_client ( struct ctdb_client * client ,
struct ctdb_req_call * c ) ;
2007-04-19 04:37:44 +04:00
/*
this is called when the ctdb daemon received a ctdb request call
from a local client over the unix domain socket
*/
static void daemon_request_call_from_client ( struct ctdb_client * client ,
struct ctdb_req_call * c )
{
struct ctdb_call_state * state ;
struct ctdb_db_context * ctdb_db ;
struct daemon_call_state * dstate ;
struct ctdb_call * call ;
2007-04-19 10:27:56 +04:00
struct ctdb_ltdb_header header ;
TDB_DATA key , data ;
int ret ;
struct ctdb_context * ctdb = client - > ctdb ;
2007-04-19 04:37:44 +04:00
2007-05-29 06:16:59 +04:00
ctdb - > statistics . total_calls + + ;
ctdb - > statistics . pending_calls + + ;
2007-04-20 14:07:47 +04:00
2007-04-19 04:37:44 +04:00
ctdb_db = find_ctdb_db ( client - > ctdb , c - > db_id ) ;
if ( ! ctdb_db ) {
DEBUG ( 0 , ( __location__ " Unknown database in request. db_id==0x%08x " ,
c - > db_id ) ) ;
2007-05-29 06:16:59 +04:00
ctdb - > statistics . pending_calls - - ;
2007-04-19 04:37:44 +04:00
return ;
}
2007-04-19 10:27:56 +04:00
key . dptr = c - > data ;
key . dsize = c - > keylen ;
ret = ctdb_ltdb_lock_fetch_requeue ( ctdb_db , key , & header ,
( struct ctdb_req_header * ) c , & data ,
2007-05-12 12:08:50 +04:00
daemon_incoming_packet , client , True ) ;
2007-04-19 10:27:56 +04:00
if ( ret = = - 2 ) {
/* will retry later */
2007-05-29 06:16:59 +04:00
ctdb - > statistics . pending_calls - - ;
2007-04-19 10:27:56 +04:00
return ;
}
if ( ret ! = 0 ) {
DEBUG ( 0 , ( __location__ " Unable to fetch record \n " ) ) ;
2007-05-29 06:16:59 +04:00
ctdb - > statistics . pending_calls - - ;
2007-04-19 10:27:56 +04:00
return ;
}
2007-04-19 04:37:44 +04:00
dstate = talloc ( client , struct daemon_call_state ) ;
if ( dstate = = NULL ) {
2007-04-19 10:27:56 +04:00
ctdb_ltdb_unlock ( ctdb_db , key ) ;
2007-04-19 04:37:44 +04:00
DEBUG ( 0 , ( __location__ " Unable to allocate dstate \n " ) ) ;
2007-05-29 06:16:59 +04:00
ctdb - > statistics . pending_calls - - ;
2007-04-19 04:37:44 +04:00
return ;
}
2007-04-20 14:07:47 +04:00
dstate - > start_time = timeval_current ( ) ;
2007-04-19 04:37:44 +04:00
dstate - > client = client ;
dstate - > reqid = c - > hdr . reqid ;
2007-04-19 10:27:56 +04:00
talloc_steal ( dstate , data . dptr ) ;
2007-04-19 04:37:44 +04:00
call = dstate - > call = talloc_zero ( dstate , struct ctdb_call ) ;
if ( call = = NULL ) {
2007-04-19 10:27:56 +04:00
ctdb_ltdb_unlock ( ctdb_db , key ) ;
2007-04-19 04:37:44 +04:00
DEBUG ( 0 , ( __location__ " Unable to allocate call \n " ) ) ;
2007-05-29 06:16:59 +04:00
ctdb - > statistics . pending_calls - - ;
ctdb_latency ( & ctdb - > statistics . max_call_latency , dstate - > start_time ) ;
2007-04-19 04:37:44 +04:00
return ;
}
call - > call_id = c - > callid ;
2007-04-19 10:27:56 +04:00
call - > key = key ;
2007-04-19 04:37:44 +04:00
call - > call_data . dptr = c - > data + c - > keylen ;
call - > call_data . dsize = c - > calldatalen ;
2007-04-19 19:44:45 +04:00
call - > flags = c - > flags ;
2007-04-19 04:37:44 +04:00
2007-06-05 11:57:07 +04:00
if ( header . dmaster = = ctdb - > vnn ) {
2007-04-19 10:27:56 +04:00
state = ctdb_call_local_send ( ctdb_db , call , & header , & data ) ;
} else {
state = ctdb_daemon_call_send_remote ( ctdb_db , call , & header ) ;
}
ctdb_ltdb_unlock ( ctdb_db , key ) ;
2007-04-19 04:37:44 +04:00
if ( state = = NULL ) {
DEBUG ( 0 , ( __location__ " Unable to setup call send \n " ) ) ;
2007-05-29 06:16:59 +04:00
ctdb - > statistics . pending_calls - - ;
ctdb_latency ( & ctdb - > statistics . max_call_latency , dstate - > start_time ) ;
2007-04-19 04:37:44 +04:00
return ;
}
talloc_steal ( state , dstate ) ;
talloc_steal ( client , state ) ;
state - > async . fn = daemon_call_from_client_callback ;
state - > async . private_data = dstate ;
}
2007-04-10 00:03:39 +04:00
2007-04-26 16:27:49 +04:00
static void daemon_request_control_from_client ( struct ctdb_client * client ,
struct ctdb_req_control * c ) ;
2007-04-10 00:03:39 +04:00
/* data contains a packet from the client */
2007-05-19 07:45:24 +04:00
static void daemon_incoming_packet ( void * p , struct ctdb_req_header * hdr )
2007-04-10 00:03:39 +04:00
{
2007-04-19 10:27:56 +04:00
struct ctdb_client * client = talloc_get_type ( p , struct ctdb_client ) ;
2007-04-18 05:20:24 +04:00
TALLOC_CTX * tmp_ctx ;
2007-04-20 15:02:53 +04:00
struct ctdb_context * ctdb = client - > ctdb ;
2007-04-18 05:20:24 +04:00
/* place the packet as a child of a tmp_ctx. We then use
talloc_free ( ) below to free it . If any of the calls want
to keep it , then they will steal it somewhere else , and the
talloc_free ( ) will be a no - op */
tmp_ctx = talloc_new ( client ) ;
talloc_steal ( tmp_ctx , hdr ) ;
2007-04-10 00:03:39 +04:00
if ( hdr - > ctdb_magic ! = CTDB_MAGIC ) {
2007-04-17 04:15:44 +04:00
ctdb_set_error ( client - > ctdb , " Non CTDB packet rejected in daemon \n " ) ;
2007-04-11 08:05:01 +04:00
goto done ;
2007-04-10 00:03:39 +04:00
}
if ( hdr - > ctdb_version ! = CTDB_VERSION ) {
2007-04-17 04:15:44 +04:00
ctdb_set_error ( client - > ctdb , " Bad CTDB version 0x%x rejected in daemon \n " , hdr - > ctdb_version ) ;
2007-04-11 08:05:01 +04:00
goto done ;
2007-04-10 00:03:39 +04:00
}
switch ( hdr - > operation ) {
case CTDB_REQ_CALL :
2007-05-29 06:16:59 +04:00
ctdb - > statistics . client . req_call + + ;
2007-04-11 05:01:42 +04:00
daemon_request_call_from_client ( client , ( struct ctdb_req_call * ) hdr ) ;
2007-04-10 00:03:39 +04:00
break ;
2007-04-11 07:43:15 +04:00
case CTDB_REQ_MESSAGE :
2007-05-29 06:16:59 +04:00
ctdb - > statistics . client . req_message + + ;
2007-04-11 07:43:15 +04:00
daemon_request_message_from_client ( client , ( struct ctdb_req_message * ) hdr ) ;
break ;
2007-04-11 08:54:47 +04:00
2007-04-26 16:27:49 +04:00
case CTDB_REQ_CONTROL :
2007-05-29 06:16:59 +04:00
ctdb - > statistics . client . req_control + + ;
2007-04-26 16:27:49 +04:00
daemon_request_control_from_client ( client , ( struct ctdb_req_control * ) hdr ) ;
break ;
2007-04-13 03:41:15 +04:00
default :
2007-05-23 14:15:09 +04:00
DEBUG ( 0 , ( __location__ " daemon: unrecognized operation %u \n " ,
2007-04-17 16:27:17 +04:00
hdr - > operation ) ) ;
2007-04-10 00:03:39 +04:00
}
2007-04-11 08:05:01 +04:00
done :
2007-04-18 05:20:24 +04:00
talloc_free ( tmp_ctx ) ;
2007-04-10 00:03:39 +04:00
}
2007-04-20 14:07:47 +04:00
/*
called when the daemon gets a incoming packet
*/
2007-04-17 08:52:51 +04:00
static void ctdb_daemon_read_cb ( uint8_t * data , size_t cnt , void * args )
2007-04-10 00:03:39 +04:00
{
2007-04-10 02:38:29 +04:00
struct ctdb_client * client = talloc_get_type ( args , struct ctdb_client ) ;
struct ctdb_req_header * hdr ;
2007-04-11 15:17:36 +04:00
if ( cnt = = 0 ) {
talloc_free ( client ) ;
return ;
}
2007-05-29 06:16:59 +04:00
client - > ctdb - > statistics . client_packets_recv + + ;
2007-04-20 14:07:47 +04:00
2007-04-10 02:38:29 +04:00
if ( cnt < sizeof ( * hdr ) ) {
2007-04-28 13:35:49 +04:00
ctdb_set_error ( client - > ctdb , " Bad packet length %u in daemon \n " ,
( unsigned ) cnt ) ;
2007-04-10 00:03:39 +04:00
return ;
}
2007-04-10 02:38:29 +04:00
hdr = ( struct ctdb_req_header * ) data ;
if ( cnt ! = hdr - > length ) {
2007-04-26 20:31:13 +04:00
ctdb_set_error ( client - > ctdb , " Bad header length %u expected %u \n in daemon " ,
2007-04-28 13:35:49 +04:00
( unsigned ) hdr - > length , ( unsigned ) cnt ) ;
2007-04-10 00:03:39 +04:00
return ;
}
2007-04-10 02:38:29 +04:00
if ( hdr - > ctdb_magic ! = CTDB_MAGIC ) {
ctdb_set_error ( client - > ctdb , " Non CTDB packet rejected \n " ) ;
2007-04-10 00:03:39 +04:00
return ;
}
2007-04-10 02:38:29 +04:00
if ( hdr - > ctdb_version ! = CTDB_VERSION ) {
2007-04-17 04:15:44 +04:00
ctdb_set_error ( client - > ctdb , " Bad CTDB version 0x%x rejected in daemon \n " , hdr - > ctdb_version ) ;
2007-04-10 00:03:39 +04:00
return ;
}
2007-05-23 14:15:09 +04:00
DEBUG ( 3 , ( __location__ " client request %u of type %u length %u from "
" node %u to %u \n " , hdr - > reqid , hdr - > operation , hdr - > length ,
2007-04-20 14:07:47 +04:00
hdr - > srcnode , hdr - > destnode ) ) ;
2007-04-10 02:38:29 +04:00
/* it is the responsibility of the incoming packet function to free 'data' */
2007-05-19 07:45:24 +04:00
daemon_incoming_packet ( client , hdr ) ;
2007-04-10 02:38:29 +04:00
}
2007-04-10 00:03:39 +04:00
static void ctdb_accept_client ( struct event_context * ev , struct fd_event * fde ,
2007-04-13 14:38:24 +04:00
uint16_t flags , void * private_data )
2007-04-10 00:03:39 +04:00
{
struct sockaddr_in addr ;
socklen_t len ;
int fd ;
2007-04-13 14:38:24 +04:00
struct ctdb_context * ctdb = talloc_get_type ( private_data , struct ctdb_context ) ;
2007-04-10 00:03:39 +04:00
struct ctdb_client * client ;
memset ( & addr , 0 , sizeof ( addr ) ) ;
len = sizeof ( addr ) ;
fd = accept ( ctdb - > daemon . sd , ( struct sockaddr * ) & addr , & len ) ;
if ( fd = = - 1 ) {
return ;
}
2007-05-30 09:43:25 +04:00
set_nonblocking ( fd ) ;
set_close_on_exec ( fd ) ;
2007-04-10 00:03:39 +04:00
client = talloc_zero ( ctdb , struct ctdb_client ) ;
client - > ctdb = ctdb ;
client - > fd = fd ;
2007-05-04 05:41:29 +04:00
client - > client_id = ctdb_reqid_new ( ctdb , client ) ;
2007-05-29 06:16:59 +04:00
ctdb - > statistics . num_clients + + ;
2007-04-10 00:03:39 +04:00
2007-04-10 13:33:21 +04:00
client - > queue = ctdb_queue_setup ( ctdb , client , fd , CTDB_DS_ALIGNMENT ,
2007-04-17 08:52:51 +04:00
ctdb_daemon_read_cb , client ) ;
2007-04-10 00:03:39 +04:00
talloc_set_destructor ( client , ctdb_client_destructor ) ;
}
/*
create a unix domain socket and bind it
return a file descriptor open on the socket
*/
static int ux_socket_bind ( struct ctdb_context * ctdb )
{
struct sockaddr_un addr ;
ctdb - > daemon . sd = socket ( AF_UNIX , SOCK_STREAM , 0 ) ;
if ( ctdb - > daemon . sd = = - 1 ) {
return - 1 ;
}
2007-05-30 09:43:25 +04:00
set_nonblocking ( ctdb - > daemon . sd ) ;
set_close_on_exec ( ctdb - > daemon . sd ) ;
2007-05-15 03:44:33 +04:00
#if 0
/* AIX doesn't like this :( */
2007-05-13 03:20:16 +04:00
if ( fchown ( ctdb - > daemon . sd , geteuid ( ) , getegid ( ) ) ! = 0 | |
fchmod ( ctdb - > daemon . sd , 0700 ) ! = 0 ) {
DEBUG ( 0 , ( " Unable to secure ctdb socket '%s', ctdb->daemon.name \n " ) ) ;
goto failed ;
}
2007-05-15 03:44:33 +04:00
# endif
2007-05-13 03:20:16 +04:00
2007-05-30 09:43:25 +04:00
set_nonblocking ( ctdb - > daemon . sd ) ;
2007-04-10 00:03:39 +04:00
memset ( & addr , 0 , sizeof ( addr ) ) ;
addr . sun_family = AF_UNIX ;
strncpy ( addr . sun_path , ctdb - > daemon . name , sizeof ( addr . sun_path ) ) ;
if ( bind ( ctdb - > daemon . sd , ( struct sockaddr * ) & addr , sizeof ( addr ) ) = = - 1 ) {
2007-05-29 07:48:30 +04:00
DEBUG ( 0 , ( " Unable to bind on ctdb socket '%s' \n " , ctdb - > daemon . name ) ) ;
2007-05-13 03:20:16 +04:00
goto failed ;
2007-04-10 00:03:39 +04:00
}
2007-05-13 03:20:16 +04:00
if ( listen ( ctdb - > daemon . sd , 10 ) ! = 0 ) {
2007-05-29 07:48:30 +04:00
DEBUG ( 0 , ( " Unable to listen on ctdb socket '%s' \n " , ctdb - > daemon . name ) ) ;
2007-05-13 03:20:16 +04:00
goto failed ;
}
2007-04-10 00:03:39 +04:00
return 0 ;
2007-05-13 03:20:16 +04:00
failed :
close ( ctdb - > daemon . sd ) ;
ctdb - > daemon . sd = - 1 ;
return - 1 ;
2007-04-10 00:03:39 +04:00
}
2007-04-11 05:01:42 +04:00
/*
delete the socket on exit - called on destruction of autofree context
*/
static int unlink_destructor ( const char * name )
2007-04-10 02:47:39 +04:00
{
2007-04-11 05:01:42 +04:00
unlink ( name ) ;
return 0 ;
2007-04-10 02:47:39 +04:00
}
2007-04-29 18:19:40 +04:00
/*
start the protocol going as a daemon
*/
2007-05-15 03:44:33 +04:00
int ctdb_start_daemon ( struct ctdb_context * ctdb , bool do_fork )
2007-04-29 18:19:40 +04:00
{
int res ;
struct fd_event * fde ;
const char * domain_socket_name ;
/* get rid of any old sockets */
unlink ( ctdb - > daemon . name ) ;
/* create a unix domain stream socket to listen to */
res = ux_socket_bind ( ctdb ) ;
if ( res ! = 0 ) {
DEBUG ( 0 , ( __location__ " Failed to open CTDB unix domain socket \n " ) ) ;
exit ( 10 ) ;
}
2007-05-15 03:44:33 +04:00
if ( do_fork & & fork ( ) ) {
2007-04-29 18:19:40 +04:00
return 0 ;
}
tdb_reopen_all ( False ) ;
2007-05-15 03:44:33 +04:00
if ( do_fork ) {
setsid ( ) ;
}
2007-04-29 18:19:40 +04:00
block_signal ( SIGPIPE ) ;
2007-05-24 08:52:10 +04:00
/* try to set us up as realtime */
2007-06-02 02:46:49 +04:00
ctdb_set_realtime ( true ) ;
2007-05-24 08:52:10 +04:00
2007-04-29 18:19:40 +04:00
/* ensure the socket is deleted on exit of the daemon */
domain_socket_name = talloc_strdup ( talloc_autofree_context ( ) , ctdb - > daemon . name ) ;
talloc_set_destructor ( domain_socket_name , unlink_destructor ) ;
ctdb - > ev = event_context_init ( NULL ) ;
2007-05-09 03:59:23 +04:00
2007-05-23 06:23:07 +04:00
/* start frozen, then let the first election sort things out */
if ( ! ctdb_blocking_freeze ( ctdb ) ) {
DEBUG ( 0 , ( " Failed to get initial freeze \n " ) ) ;
exit ( 12 ) ;
}
/* force initial recovery for election */
ctdb - > recovery_mode = CTDB_RECOVERY_ACTIVE ;
/* now start accepting clients, only can do this once frozen */
fde = event_add_fd ( ctdb - > ev , ctdb , ctdb - > daemon . sd ,
EVENT_FD_READ | EVENT_FD_AUTOCLOSE ,
ctdb_accept_client , ctdb ) ;
2007-04-29 18:19:40 +04:00
ctdb_main_loop ( ctdb ) ;
return 0 ;
}
2007-04-28 12:50:32 +04:00
/*
allocate a packet for use in daemon < - > daemon communication
*/
struct ctdb_req_header * _ctdb_transport_allocate ( struct ctdb_context * ctdb ,
TALLOC_CTX * mem_ctx ,
enum ctdb_operation operation ,
size_t length , size_t slength ,
const char * type )
{
int size ;
struct ctdb_req_header * hdr ;
2007-05-03 07:44:27 +04:00
length = MAX ( length , slength ) ;
size = ( length + ( CTDB_DS_ALIGNMENT - 1 ) ) & ~ ( CTDB_DS_ALIGNMENT - 1 ) ;
2007-04-28 12:50:32 +04:00
hdr = ( struct ctdb_req_header * ) ctdb - > methods - > allocate_pkt ( mem_ctx , size ) ;
if ( hdr = = NULL ) {
DEBUG ( 0 , ( " Unable to allocate transport packet for operation %u of length %u \n " ,
2007-05-29 07:58:41 +04:00
operation , ( unsigned ) length ) ) ;
2007-04-28 12:50:32 +04:00
return NULL ;
}
talloc_set_name_const ( hdr , type ) ;
2007-05-03 07:44:27 +04:00
memset ( hdr , 0 , slength ) ;
hdr - > length = length ;
2007-04-28 12:50:32 +04:00
hdr - > operation = operation ;
hdr - > ctdb_magic = CTDB_MAGIC ;
hdr - > ctdb_version = CTDB_VERSION ;
hdr - > generation = ctdb - > vnn_map - > generation ;
hdr - > srcnode = ctdb - > vnn ;
return hdr ;
2007-04-10 00:03:39 +04:00
}
2007-04-26 16:27:49 +04:00
struct daemon_control_state {
2007-05-18 17:48:29 +04:00
struct daemon_control_state * next , * prev ;
2007-04-26 16:27:49 +04:00
struct ctdb_client * client ;
struct ctdb_req_control * c ;
2007-04-26 21:27:07 +04:00
uint32_t reqid ;
2007-05-18 17:48:29 +04:00
struct ctdb_node * node ;
2007-04-26 16:27:49 +04:00
} ;
/*
callback when a control reply comes in
*/
static void daemon_control_callback ( struct ctdb_context * ctdb ,
2007-05-18 17:48:29 +04:00
int32_t status , TDB_DATA data ,
2007-05-12 15:25:26 +04:00
const char * errormsg ,
2007-04-26 16:27:49 +04:00
void * private_data )
{
struct daemon_control_state * state = talloc_get_type ( private_data ,
struct daemon_control_state ) ;
struct ctdb_client * client = state - > client ;
struct ctdb_reply_control * r ;
size_t len ;
/* construct a message to send to the client containing the data */
2007-04-27 01:10:35 +04:00
len = offsetof ( struct ctdb_reply_control , data ) + data . dsize ;
2007-05-12 15:25:26 +04:00
if ( errormsg ) {
len + = strlen ( errormsg ) ;
}
2007-05-02 23:51:46 +04:00
r = ctdbd_allocate_pkt ( ctdb , state , CTDB_REPLY_CONTROL , len ,
2007-04-28 12:50:32 +04:00
struct ctdb_reply_control ) ;
CTDB_NO_MEMORY_VOID ( ctdb , r ) ;
2007-04-26 16:27:49 +04:00
2007-04-26 21:27:07 +04:00
r - > hdr . reqid = state - > reqid ;
2007-04-26 16:27:49 +04:00
r - > status = status ;
r - > datalen = data . dsize ;
2007-05-12 15:25:26 +04:00
r - > errorlen = 0 ;
2007-04-26 16:27:49 +04:00
memcpy ( & r - > data [ 0 ] , data . dptr , data . dsize ) ;
2007-05-12 15:25:26 +04:00
if ( errormsg ) {
r - > errorlen = strlen ( errormsg ) ;
memcpy ( & r - > data [ r - > datalen ] , errormsg , r - > errorlen ) ;
}
2007-04-26 16:27:49 +04:00
daemon_queue_send ( client , & r - > hdr ) ;
talloc_free ( state ) ;
}
2007-05-18 17:48:29 +04:00
/*
fail all pending controls to a disconnected node
*/
void ctdb_daemon_cancel_controls ( struct ctdb_context * ctdb , struct ctdb_node * node )
{
struct daemon_control_state * state ;
while ( ( state = node - > pending_controls ) ) {
DLIST_REMOVE ( node - > pending_controls , state ) ;
daemon_control_callback ( ctdb , ( uint32_t ) - 1 , tdb_null ,
" node is disconnected " , state ) ;
}
}
/*
destroy a daemon_control_state
*/
static int daemon_control_destructor ( struct daemon_control_state * state )
{
if ( state - > node ) {
DLIST_REMOVE ( state - > node - > pending_controls , state ) ;
}
return 0 ;
}
2007-04-26 16:27:49 +04:00
/*
this is called when the ctdb daemon received a ctdb request control
from a local client over the unix domain socket
*/
static void daemon_request_control_from_client ( struct ctdb_client * client ,
struct ctdb_req_control * c )
{
TDB_DATA data ;
int res ;
struct daemon_control_state * state ;
2007-06-02 04:03:28 +04:00
TALLOC_CTX * tmp_ctx = talloc_new ( client ) ;
2007-04-26 16:27:49 +04:00
2007-04-26 21:27:07 +04:00
if ( c - > hdr . destnode = = CTDB_CURRENT_NODE ) {
c - > hdr . destnode = client - > ctdb - > vnn ;
}
2007-04-26 16:27:49 +04:00
state = talloc ( client , struct daemon_control_state ) ;
CTDB_NO_MEMORY_VOID ( client - > ctdb , state ) ;
state - > client = client ;
state - > c = talloc_steal ( state , c ) ;
2007-04-26 21:27:07 +04:00
state - > reqid = c - > hdr . reqid ;
2007-05-18 17:48:29 +04:00
if ( ctdb_validate_vnn ( client - > ctdb , c - > hdr . destnode ) ) {
state - > node = client - > ctdb - > nodes [ c - > hdr . destnode ] ;
DLIST_ADD ( state - > node - > pending_controls , state ) ;
} else {
state - > node = NULL ;
}
talloc_set_destructor ( state , daemon_control_destructor ) ;
2007-06-02 04:03:28 +04:00
if ( c - > flags & CTDB_CTRL_FLAG_NOREPLY ) {
talloc_steal ( tmp_ctx , state ) ;
}
2007-04-26 16:27:49 +04:00
data . dptr = & c - > data [ 0 ] ;
data . dsize = c - > datalen ;
res = ctdb_daemon_send_control ( client - > ctdb , c - > hdr . destnode ,
2007-05-04 05:41:29 +04:00
c - > srvid , c - > opcode , client - > client_id ,
c - > flags ,
2007-04-30 17:31:40 +04:00
data , daemon_control_callback ,
2007-04-26 16:27:49 +04:00
state ) ;
if ( res ! = 0 ) {
DEBUG ( 0 , ( __location__ " Failed to send control to remote node %u \n " ,
c - > hdr . destnode ) ) ;
}
2007-05-18 17:48:29 +04:00
2007-06-02 04:03:28 +04:00
talloc_free ( tmp_ctx ) ;
2007-04-26 16:27:49 +04:00
}
2007-04-30 17:31:40 +04:00
/*
register a call function
*/
int ctdb_daemon_set_call ( struct ctdb_context * ctdb , uint32_t db_id ,
ctdb_fn_t fn , int id )
{
struct ctdb_registered_call * call ;
struct ctdb_db_context * ctdb_db ;
ctdb_db = find_ctdb_db ( ctdb , db_id ) ;
if ( ctdb_db = = NULL ) {
return - 1 ;
}
call = talloc ( ctdb_db , struct ctdb_registered_call ) ;
call - > fn = fn ;
call - > id = id ;
DLIST_ADD ( ctdb_db - > calls , call ) ;
return 0 ;
}
2007-06-07 16:06:19 +04:00
/*
this local messaging handler is ugly , but is needed to prevent
recursion in ctdb_send_message ( ) when the destination node is the
same as the source node
*/
struct ctdb_local_message {
struct ctdb_context * ctdb ;
uint64_t srvid ;
TDB_DATA data ;
} ;
static void ctdb_local_message_trigger ( struct event_context * ev , struct timed_event * te ,
struct timeval t , void * private_data )
{
struct ctdb_local_message * m = talloc_get_type ( private_data ,
struct ctdb_local_message ) ;
int res ;
res = ctdb_dispatch_message ( m - > ctdb , m - > srvid , m - > data ) ;
if ( res ! = 0 ) {
DEBUG ( 0 , ( __location__ " Failed to dispatch message for srvid=%llu \n " ,
( unsigned long long ) m - > srvid ) ) ;
}
talloc_free ( m ) ;
}
static int ctdb_local_message ( struct ctdb_context * ctdb , uint64_t srvid , TDB_DATA data )
{
struct ctdb_local_message * m ;
m = talloc ( ctdb , struct ctdb_local_message ) ;
CTDB_NO_MEMORY ( ctdb , m ) ;
m - > ctdb = ctdb ;
m - > srvid = srvid ;
m - > data = data ;
m - > data . dptr = talloc_memdup ( m , m - > data . dptr , m - > data . dsize ) ;
if ( m - > data . dptr = = NULL ) {
talloc_free ( m ) ;
return - 1 ;
}
/* this needs to be done as an event to prevent recursion */
event_add_timed ( ctdb - > ev , m , timeval_zero ( ) , ctdb_local_message_trigger , m ) ;
return 0 ;
}
/*
send a ctdb message
*/
int ctdb_daemon_send_message ( struct ctdb_context * ctdb , uint32_t vnn ,
uint64_t srvid , TDB_DATA data )
{
struct ctdb_req_message * r ;
int len ;
/* see if this is a message to ourselves */
if ( vnn = = ctdb - > vnn ) {
return ctdb_local_message ( ctdb , srvid , data ) ;
}
len = offsetof ( struct ctdb_req_message , data ) + data . dsize ;
r = ctdb_transport_allocate ( ctdb , ctdb , CTDB_REQ_MESSAGE , len ,
struct ctdb_req_message ) ;
CTDB_NO_MEMORY ( ctdb , r ) ;
r - > hdr . destnode = vnn ;
r - > srvid = srvid ;
r - > datalen = data . dsize ;
memcpy ( & r - > data [ 0 ] , data . dptr , data . dsize ) ;
ctdb_queue_packet ( ctdb , & r - > hdr ) ;
talloc_free ( r ) ;
return 0 ;
}