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
2007-07-10 09:29:31 +04:00
the Free Software Foundation ; either version 3 of the License , or
2007-05-31 07:50:53 +04:00
( 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
2007-07-10 09:29:31 +04:00
along with this program ; if not , see < http : //www.gnu.org/licenses/>.
2007-04-10 00:03:39 +04:00
*/
# include "includes.h"
# include "db_wrap.h"
# include "lib/tdb/include/tdb.h"
2010-08-18 03:46:31 +04:00
# include "lib/tevent/tevent.h"
2007-04-10 00:03:39 +04:00
# 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"
2010-05-20 09:48:30 +04:00
# include "../include/ctdb_client.h"
2007-04-10 00:03:39 +04:00
# include "../include/ctdb_private.h"
2011-11-07 23:55:46 +04:00
# include "../common/rb_tree.h"
2008-04-01 08:34:54 +04:00
# include <sys/socket.h>
2007-04-10 00:03:39 +04:00
2009-12-02 05:41:04 +03:00
struct ctdb_client_pid_list {
struct ctdb_client_pid_list * next , * prev ;
struct ctdb_context * ctdb ;
pid_t pid ;
struct ctdb_client * client ;
} ;
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-09-24 04:00:14 +04:00
static void print_exit_message ( void )
{
2008-02-04 12:07:15 +03:00
DEBUG ( DEBUG_NOTICE , ( " CTDB daemon shutting down \n " ) ) ;
2007-09-24 04:00:14 +04:00
}
2011-01-14 01:46:04 +03:00
static void ctdb_time_tick ( struct event_context * ev , struct timed_event * te ,
struct timeval t , void * private_data )
{
struct ctdb_context * ctdb = talloc_get_type ( private_data , struct ctdb_context ) ;
if ( getpid ( ) ! = ctdbd_pid ) {
return ;
}
event_add_timed ( ctdb - > ev , ctdb ,
timeval_current_ofs ( 1 , 0 ) ,
ctdb_time_tick , ctdb ) ;
}
/* Used to trigger a dummy event once per second, to make
* detection of hangs more reliable .
*/
static void ctdb_start_time_tickd ( struct ctdb_context * ctdb )
{
event_add_timed ( ctdb - > ev , ctdb ,
timeval_current_ofs ( 1 , 0 ) ,
ctdb_time_tick , ctdb ) ;
}
2007-05-30 07:26:50 +04:00
/* called when the "startup" event script has finished */
2007-11-12 02:53:11 +03:00
static void ctdb_start_transport ( struct ctdb_context * ctdb )
2007-05-30 07:26:50 +04:00
{
2008-05-11 08:28:33 +04:00
if ( ctdb - > methods = = NULL ) {
DEBUG ( DEBUG_ALERT , ( __location__ " startup event finished but transport is DOWN. \n " ) ) ;
ctdb_fatal ( ctdb , " transport is not initialized but startup completed " ) ;
}
2007-05-30 07:26:50 +04:00
/* start the transport running */
if ( ctdb - > methods - > start ( ctdb ) ! = 0 ) {
2008-02-04 12:07:15 +03:00
DEBUG ( DEBUG_ALERT , ( " transport failed to start! \n " ) ) ;
2007-05-30 07:26:50 +04:00
ctdb_fatal ( ctdb , " transport failed to start " ) ;
}
/* start the recovery daemon process */
if ( ctdb_start_recoverd ( ctdb ) ! = 0 ) {
2008-02-04 12:07:15 +03:00
DEBUG ( DEBUG_ALERT , ( " Failed to start recovery daemon \n " ) ) ;
2007-05-30 07:26:50 +04:00
exit ( 11 ) ;
}
2007-05-30 08:35:22 +04:00
2007-09-24 04:00:14 +04:00
/* Make sure we log something when the daemon terminates */
atexit ( print_exit_message ) ;
2008-01-15 00:42:12 +03:00
/* start monitoring for connected/disconnected nodes */
ctdb_start_keepalive ( ctdb ) ;
/* start monitoring for node health */
2007-05-30 08:35:22 +04:00
ctdb_start_monitoring ( ctdb ) ;
2007-07-20 09:05:55 +04:00
/* start periodic update of tcp tickle lists */
ctdb_start_tcp_tickle_update ( ctdb ) ;
2008-09-09 07:44:46 +04:00
/* start listening for recovery daemon pings */
ctdb_control_recd_ping ( ctdb ) ;
2011-01-14 01:46:04 +03:00
/* start listening to timer ticks */
ctdb_start_time_tickd ( ctdb ) ;
2007-05-30 07:26:50 +04:00
}
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 )
{
2010-09-29 04:38:41 +04:00
CTDB_INCREMENT_STAT ( client - > ctdb , client_packets_sent ) ;
2009-10-21 08:20:55 +04:00
if ( hdr - > operation = = CTDB_REQ_MESSAGE ) {
if ( ctdb_queue_length ( client - > queue ) > client - > ctdb - > tunable . max_queue_depth_drop_msg ) {
2010-02-04 06:36:14 +03:00
DEBUG ( DEBUG_ERR , ( " CTDB_REQ_MESSAGE queue full - killing client connection. \n " ) ) ;
talloc_free ( client ) ;
return - 1 ;
2009-10-21 08:20:55 +04:00
}
}
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 ) {
2008-02-04 12:07:15 +03:00
DEBUG ( DEBUG_ERR , ( " Bad client_id in daemon_request_register_message_handler \n " ) ) ;
2007-05-04 05:41:29 +04:00
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 ) {
2008-02-04 12:07:15 +03:00
DEBUG ( DEBUG_ERR , ( __location__ " Failed to register handler %llu in daemon \n " ,
2007-05-29 07:58:41 +04:00
( unsigned long long ) srvid ) ) ;
2007-04-20 01:47:37 +04:00
} else {
2008-02-04 09:44:24 +03:00
DEBUG ( DEBUG_INFO , ( __location__ " Registered message handler for srvid=%llu \n " ,
2007-05-29 07:58:41 +04:00
( unsigned long long ) srvid ) ) ;
2007-04-11 05:58:28 +04:00
}
2007-06-18 21:54:06 +04:00
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 ) {
2008-02-04 12:07:15 +03:00
DEBUG ( DEBUG_ERR , ( " Bad client_id in daemon_request_deregister_message_handler \n " ) ) ;
2007-05-04 05:41:29 +04:00
return - 1 ;
}
return ctdb_deregister_message_handler ( ctdb , srvid , client ) ;
2007-04-11 05:58:28 +04:00
}
2011-10-31 16:29:13 +04:00
int daemon_check_srvids ( struct ctdb_context * ctdb , TDB_DATA indata ,
TDB_DATA * outdata )
{
uint64_t * ids ;
int i , num_ids ;
uint8_t * results ;
if ( ( indata . dsize % sizeof ( uint64_t ) ) ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Bad indata in daemon_check_srvids, "
" size=%d \n " , ( int ) indata . dsize ) ) ;
return - 1 ;
}
ids = ( uint64_t * ) indata . dptr ;
num_ids = indata . dsize / 8 ;
results = talloc_zero_array ( outdata , uint8_t , ( num_ids + 7 ) / 8 ) ;
if ( results = = NULL ) {
DEBUG ( DEBUG_ERR , ( " talloc failed in daemon_check_srvids \n " ) ) ;
return - 1 ;
}
for ( i = 0 ; i < num_ids ; i + + ) {
struct ctdb_message_list * ml ;
for ( ml = ctdb - > message_list ; ml ; ml = ml - > next ) {
if ( ml - > srvid = = ids [ i ] ) {
break ;
}
}
if ( ml ! = NULL ) {
results [ i / 8 ] | = ( 1 < < ( i % 8 ) ) ;
}
}
outdata - > dptr = ( uint8_t * ) results ;
outdata - > dsize = talloc_get_size ( results ) ;
return 0 ;
}
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 )
{
2009-07-21 13:30:38 +04:00
struct ctdb_db_context * ctdb_db ;
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 ) ;
2010-09-29 04:38:41 +04:00
CTDB_DECREMENT_STAT ( client - > ctdb , num_clients ) ;
2008-07-17 07:50:55 +04:00
if ( client - > num_persistent_updates ! = 0 ) {
DEBUG ( DEBUG_ERR , ( __location__ " Client disconnecting with %u persistent updates in flight. Starting recovery \n " , client - > num_persistent_updates ) ) ;
client - > ctdb - > recovery_mode = CTDB_RECOVERY_ACTIVE ;
}
2009-07-21 13:30:38 +04:00
ctdb_db = find_ctdb_db ( client - > ctdb , client - > db_id ) ;
if ( ctdb_db ) {
DEBUG ( DEBUG_ERR , ( __location__ " client exit while transaction "
" commit active. Forcing recovery. \n " ) ) ;
client - > ctdb - > recovery_mode = CTDB_RECOVERY_ACTIVE ;
2011-02-23 19:37:42 +03:00
/* legacy trans2 transaction state: */
2009-07-21 13:30:38 +04:00
ctdb_db - > transaction_active = false ;
2011-02-23 19:37:42 +03:00
/*
* trans3 transaction state :
*
* The destructor sets the pointer to NULL .
*/
talloc_free ( ctdb_db - > persistent_state ) ;
2009-07-21 13:30:38 +04:00
}
2008-07-17 07:50:55 +04:00
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-09-04 04:18:44 +04:00
if ( ctdb_get_pnn ( client - > ctdb ) = = c - > hdr . destnode ) {
2007-04-11 07:43:15 +04:00
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 ) {
2008-02-04 12:07:15 +03:00
DEBUG ( DEBUG_ERR , ( __location__ " Failed to send message to remote node %u \n " ,
2007-04-17 16:27:17 +04:00
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 ;
2008-11-03 13:54:52 +03:00
struct ctdb_db_context * ctdb_db = state - > ctdb_db ;
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 ) {
2008-02-04 12:07:15 +03:00
DEBUG ( DEBUG_ERR , ( __location__ " ctdbd_call_recv() returned error \n " ) ) ;
2010-09-29 04:38:41 +04:00
CTDB_DECREMENT_STAT ( client - > ctdb , pending_calls ) ;
2010-10-11 08:11:18 +04:00
CTDB_UPDATE_LATENCY ( client - > ctdb , ctdb_db , " call_from_client_cb 1 " , 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 ) {
2008-02-04 12:07:15 +03:00
DEBUG ( DEBUG_ERR , ( __location__ " Failed to allocate reply_call in ctdb daemon \n " ) ) ;
2010-09-29 04:38:41 +04:00
CTDB_DECREMENT_STAT ( client - > ctdb , pending_calls ) ;
2010-10-11 08:11:18 +04:00
CTDB_UPDATE_LATENCY ( client - > ctdb , ctdb_db , " call_from_client_cb 2 " , 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 ;
2011-07-20 09:17:29 +04:00
r - > status = dstate - > call - > status ;
2007-04-19 04:37:44 +04:00
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 ) ;
2010-02-04 06:36:14 +03:00
if ( res = = - 1 ) {
/* client is dead - return immediately */
return ;
}
2007-04-11 05:01:42 +04:00
if ( res ! = 0 ) {
2008-02-04 12:07:15 +03:00
DEBUG ( DEBUG_ERR , ( __location__ " Failed to queue packet from daemon to client \n " ) ) ;
2007-04-10 00:03:39 +04:00
}
2010-10-11 08:11:18 +04:00
CTDB_UPDATE_LATENCY ( client - > ctdb , ctdb_db , " call_from_client_cb 3 " , call_latency , dstate - > start_time ) ;
2010-09-29 04:38:41 +04:00
CTDB_DECREMENT_STAT ( client - > ctdb , pending_calls ) ;
2007-04-19 04:37:44 +04:00
talloc_free ( dstate ) ;
2007-04-10 00:03:39 +04:00
}
2008-01-16 01:44:48 +03:00
struct ctdb_daemon_packet_wrap {
struct ctdb_context * ctdb ;
uint32_t client_id ;
} ;
/*
a wrapper to catch disconnected clients
*/
static void daemon_incoming_packet_wrap ( void * p , struct ctdb_req_header * hdr )
{
struct ctdb_client * client ;
struct ctdb_daemon_packet_wrap * w = talloc_get_type ( p ,
struct ctdb_daemon_packet_wrap ) ;
if ( w = = NULL ) {
2008-02-04 12:07:15 +03:00
DEBUG ( DEBUG_CRIT , ( __location__ " Bad packet type '%s' \n " , talloc_get_name ( p ) ) ) ;
2008-01-16 01:44:48 +03:00
return ;
}
client = ctdb_reqid_find ( w - > ctdb , w - > client_id , struct ctdb_client ) ;
if ( client = = NULL ) {
2008-02-04 12:07:15 +03:00
DEBUG ( DEBUG_ERR , ( __location__ " Packet for disconnected client %u \n " ,
2008-01-16 01:44:48 +03:00
w - > client_id ) ) ;
talloc_free ( w ) ;
return ;
}
talloc_free ( w ) ;
/* process it */
daemon_incoming_packet ( client , hdr ) ;
}
2007-04-19 10:27:56 +04:00
2011-11-07 23:55:46 +04:00
struct ctdb_deferred_fetch_call {
struct ctdb_deferred_fetch_call * next , * prev ;
struct ctdb_req_call * c ;
struct ctdb_daemon_packet_wrap * w ;
} ;
struct ctdb_deferred_fetch_queue {
struct ctdb_deferred_fetch_call * deferred_calls ;
} ;
struct ctdb_deferred_requeue {
struct ctdb_deferred_fetch_call * dfc ;
struct ctdb_client * client ;
} ;
/* called from a timer event and starts reprocessing the deferred call.*/
static void reprocess_deferred_call ( struct event_context * ev , struct timed_event * te ,
struct timeval t , void * private_data )
{
struct ctdb_deferred_requeue * dfr = ( struct ctdb_deferred_requeue * ) private_data ;
struct ctdb_client * client = dfr - > client ;
talloc_steal ( client , dfr - > dfc - > c ) ;
daemon_incoming_packet ( client , ( struct ctdb_req_header * ) dfr - > dfc - > c ) ;
talloc_free ( dfr ) ;
}
/* the referral context is destroyed either after a timeout or when the initial
fetch - lock has finished .
at this stage , immediately start reprocessing the queued up deferred
calls so they get reprocessed immediately ( and since we are dmaster at
this stage , trigger the waiting smbd processes to pick up and aquire the
record right away .
*/
static int deferred_fetch_queue_destructor ( struct ctdb_deferred_fetch_queue * dfq )
{
/* need to reprocess the packets from the queue explicitely instead of
just using a normal destructor since we want , need , to
call the clients in the same oder as the requests queued up
*/
while ( dfq - > deferred_calls ! = NULL ) {
struct ctdb_client * client ;
struct ctdb_deferred_fetch_call * dfc = dfq - > deferred_calls ;
struct ctdb_deferred_requeue * dfr ;
DLIST_REMOVE ( dfq - > deferred_calls , dfc ) ;
client = ctdb_reqid_find ( dfc - > w - > ctdb , dfc - > w - > client_id , struct ctdb_client ) ;
if ( client = = NULL ) {
DEBUG ( DEBUG_ERR , ( __location__ " Packet for disconnected client %u \n " ,
dfc - > w - > client_id ) ) ;
continue ;
}
/* process it by pushing it back onto the eventloop */
dfr = talloc ( client , struct ctdb_deferred_requeue ) ;
if ( dfr = = NULL ) {
DEBUG ( DEBUG_ERR , ( " Failed to allocate deferred fetch requeue structure \n " ) ) ;
continue ;
}
dfr - > dfc = talloc_steal ( dfr , dfc ) ;
dfr - > client = client ;
event_add_timed ( dfc - > w - > ctdb - > ev , client , timeval_zero ( ) , reprocess_deferred_call , dfr ) ;
}
return 0 ;
}
/* insert the new deferral context into the rb tree.
there should never be a pre - existing context here , but check for it
warn and destroy the previous context if there is already a deferral context
for this key .
*/
static void * insert_dfq_callback ( void * parm , void * data )
{
if ( data ) {
DEBUG ( DEBUG_ERR , ( " Already have DFQ registered. Free old %p and create new %p \n " , data , parm ) ) ;
talloc_free ( data ) ;
}
return parm ;
}
/* if the original fetch-lock did not complete within a reasonable time,
free the context and context for all deferred requests to cause them to be
re - inserted into the event system .
*/
static void dfq_timeout ( struct event_context * ev , struct timed_event * te ,
struct timeval t , void * private_data )
{
talloc_free ( private_data ) ;
}
/* This function is used in the local daemon to register a KEY in a database
for being " fetched "
While the remote fetch is in - flight , any futher attempts to re - fetch the
same record will be deferred until the fetch completes .
*/
static int setup_deferred_fetch_locks ( struct ctdb_db_context * ctdb_db , struct ctdb_call * call )
{
uint32_t * k ;
struct ctdb_deferred_fetch_queue * dfq ;
k = talloc_zero_size ( call , ( ( call - > key . dsize + 3 ) & 0xfffffffc ) + 4 ) ;
if ( k = = NULL ) {
DEBUG ( DEBUG_ERR , ( " Failed to allocate key for deferred fetch \n " ) ) ;
return - 1 ;
}
k [ 0 ] = ( call - > key . dsize + 3 ) / 4 + 1 ;
memcpy ( & k [ 1 ] , call - > key . dptr , call - > key . dsize ) ;
dfq = talloc ( call , struct ctdb_deferred_fetch_queue ) ;
if ( dfq = = NULL ) {
DEBUG ( DEBUG_ERR , ( " Failed to allocate key for deferred fetch queue structure \n " ) ) ;
talloc_free ( k ) ;
return - 1 ;
}
dfq - > deferred_calls = NULL ;
trbt_insertarray32_callback ( ctdb_db - > deferred_fetch , k [ 0 ] , & k [ 0 ] , insert_dfq_callback , dfq ) ;
talloc_set_destructor ( dfq , deferred_fetch_queue_destructor ) ;
/* if the fetch havent completed in 30 seconds, just tear it all down
and let it try again as the events are reissued */
event_add_timed ( ctdb_db - > ctdb - > ev , dfq , timeval_current_ofs ( 30 , 0 ) , dfq_timeout , dfq ) ;
talloc_free ( k ) ;
return 0 ;
}
/* check if this is a duplicate request to a fetch already in-flight
if it is , make this call deferred to be reprocessed later when
the in - flight fetch completes .
*/
static int requeue_duplicate_fetch ( struct ctdb_db_context * ctdb_db , struct ctdb_client * client , TDB_DATA key , struct ctdb_req_call * c )
{
uint32_t * k ;
struct ctdb_deferred_fetch_queue * dfq ;
struct ctdb_deferred_fetch_call * dfc ;
k = talloc_zero_size ( c , ( ( key . dsize + 3 ) & 0xfffffffc ) + 4 ) ;
if ( k = = NULL ) {
DEBUG ( DEBUG_ERR , ( " Failed to allocate key for deferred fetch \n " ) ) ;
return - 1 ;
}
k [ 0 ] = ( key . dsize + 3 ) / 4 + 1 ;
memcpy ( & k [ 1 ] , key . dptr , key . dsize ) ;
dfq = trbt_lookuparray32 ( ctdb_db - > deferred_fetch , k [ 0 ] , & k [ 0 ] ) ;
if ( dfq = = NULL ) {
talloc_free ( k ) ;
return - 1 ;
}
talloc_free ( k ) ;
dfc = talloc ( dfq , struct ctdb_deferred_fetch_call ) ;
if ( dfc = = NULL ) {
DEBUG ( DEBUG_ERR , ( " Failed to allocate deferred fetch call structure \n " ) ) ;
return - 1 ;
}
dfc - > w = talloc ( dfc , struct ctdb_daemon_packet_wrap ) ;
if ( dfc - > w = = NULL ) {
DEBUG ( DEBUG_ERR , ( " Failed to allocate deferred fetch daemon packet wrap structure \n " ) ) ;
talloc_free ( dfc ) ;
return - 1 ;
}
dfc - > c = talloc_steal ( dfc , c ) ;
dfc - > w - > ctdb = ctdb_db - > ctdb ;
dfc - > w - > client_id = client - > client_id ;
DLIST_ADD_END ( dfq - > deferred_calls , dfc , NULL ) ;
return 0 ;
}
2007-05-10 01:43:18 +04:00
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 ;
2008-01-16 01:44:48 +03:00
struct ctdb_daemon_packet_wrap * w ;
2007-04-19 04:37:44 +04:00
2010-09-29 04:38:41 +04:00
CTDB_INCREMENT_STAT ( ctdb , total_calls ) ;
CTDB_DECREMENT_STAT ( ctdb , 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 ) {
2008-02-04 12:07:15 +03:00
DEBUG ( DEBUG_ERR , ( __location__ " Unknown database in request. db_id==0x%08x " ,
2007-04-19 04:37:44 +04:00
c - > db_id ) ) ;
2010-09-29 04:38:41 +04:00
CTDB_DECREMENT_STAT ( ctdb , pending_calls ) ;
2007-04-19 04:37:44 +04:00
return ;
}
2009-12-07 15:28:11 +03:00
if ( ctdb_db - > unhealthy_reason ) {
/*
* this is just a warning , as the tdb should be empty anyway ,
* and only persistent databases can be unhealthy , which doesn ' t
* use this code patch
*/
DEBUG ( DEBUG_WARNING , ( " warn: db(%s) unhealty in daemon_request_call_from_client(): %s \n " ,
ctdb_db - > db_name , ctdb_db - > unhealthy_reason ) ) ;
}
2007-04-19 10:27:56 +04:00
key . dptr = c - > data ;
key . dsize = c - > keylen ;
2008-01-16 01:44:48 +03:00
w = talloc ( ctdb , struct ctdb_daemon_packet_wrap ) ;
CTDB_NO_MEMORY_VOID ( ctdb , w ) ;
w - > ctdb = ctdb ;
w - > client_id = client - > client_id ;
2007-04-19 10:27:56 +04:00
ret = ctdb_ltdb_lock_fetch_requeue ( ctdb_db , key , & header ,
( struct ctdb_req_header * ) c , & data ,
2008-01-16 01:44:48 +03:00
daemon_incoming_packet_wrap , w , True ) ;
2007-04-19 10:27:56 +04:00
if ( ret = = - 2 ) {
/* will retry later */
2010-09-29 04:38:41 +04:00
CTDB_DECREMENT_STAT ( ctdb , pending_calls ) ;
2007-04-19 10:27:56 +04:00
return ;
}
2008-01-16 01:44:48 +03:00
talloc_free ( w ) ;
2007-04-19 10:27:56 +04:00
if ( ret ! = 0 ) {
2008-02-04 12:07:15 +03:00
DEBUG ( DEBUG_ERR , ( __location__ " Unable to fetch record \n " ) ) ;
2010-09-29 04:38:41 +04:00
CTDB_DECREMENT_STAT ( ctdb , pending_calls ) ;
2007-04-19 10:27:56 +04:00
return ;
}
2011-11-07 23:55:46 +04:00
if ( c - > flags & CTDB_IMMEDIATE_MIGRATION ) {
/* check if this fetch-lock request is a duplicate for a
request we already have in flight . If so defer it until
the first request completes .
*/
if ( requeue_duplicate_fetch ( ctdb_db , client , key , c ) = = 0 ) {
ret = ctdb_ltdb_unlock ( ctdb_db , key ) ;
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( __location__ " ctdb_ltdb_unlock() failed with error %d \n " , ret ) ) ;
}
return ;
}
}
2011-07-20 09:17:29 +04:00
/* Dont do READONLY if we dont have a tracking database */
2011-08-23 04:41:52 +04:00
if ( ( c - > flags & CTDB_WANT_READONLY ) & & ! ctdb_db - > readonly ) {
2011-07-20 09:17:29 +04:00
c - > flags & = ~ CTDB_WANT_READONLY ;
}
if ( header . flags & CTDB_REC_RO_REVOKE_COMPLETE ) {
header . flags & = ~ ( CTDB_REC_RO_HAVE_DELEGATIONS | CTDB_REC_RO_HAVE_READONLY | CTDB_REC_RO_REVOKING_READONLY | CTDB_REC_RO_REVOKE_COMPLETE ) ;
if ( ctdb_ltdb_store ( ctdb_db , key , & header , data ) ! = 0 ) {
ctdb_fatal ( ctdb , " Failed to write header with cleared REVOKE flag " ) ;
}
2011-08-17 10:14:57 +04:00
/* and clear out the tracking data */
if ( tdb_delete ( ctdb_db - > rottdb , key ) ! = 0 ) {
DEBUG ( DEBUG_ERR , ( __location__ " Failed to clear out trackingdb record \n " ) ) ;
}
2011-07-20 09:17:29 +04:00
}
/* if we are revoking, we must defer all other calls until the revoke
* had completed .
*/
if ( header . flags & CTDB_REC_RO_REVOKING_READONLY ) {
talloc_free ( data . dptr ) ;
ret = ctdb_ltdb_unlock ( ctdb_db , key ) ;
if ( ctdb_add_revoke_deferred_call ( ctdb , ctdb_db , key , ( struct ctdb_req_header * ) c , daemon_incoming_packet , client ) ! = 0 ) {
ctdb_fatal ( ctdb , " Failed to add deferred call for revoke child " ) ;
}
return ;
}
if ( ( header . dmaster = = ctdb - > pnn )
& & ( ! ( c - > flags & CTDB_WANT_READONLY ) )
& & ( header . flags & ( CTDB_REC_RO_HAVE_DELEGATIONS | CTDB_REC_RO_HAVE_READONLY ) ) ) {
header . flags | = CTDB_REC_RO_REVOKING_READONLY ;
if ( ctdb_ltdb_store ( ctdb_db , key , & header , data ) ! = 0 ) {
ctdb_fatal ( ctdb , " Failed to store record with HAVE_DELEGATIONS set " ) ;
}
ret = ctdb_ltdb_unlock ( ctdb_db , key ) ;
if ( ctdb_start_revoke_ro_record ( ctdb , ctdb_db , key , & header , data ) ! = 0 ) {
ctdb_fatal ( ctdb , " Failed to start record revoke " ) ;
}
talloc_free ( data . dptr ) ;
if ( ctdb_add_revoke_deferred_call ( ctdb , ctdb_db , key , ( struct ctdb_req_header * ) c , daemon_incoming_packet , client ) ! = 0 ) {
ctdb_fatal ( ctdb , " Failed to add deferred call for revoke child " ) ;
}
return ;
}
2007-04-19 04:37:44 +04:00
dstate = talloc ( client , struct daemon_call_state ) ;
if ( dstate = = NULL ) {
2010-06-09 08:17:35 +04:00
ret = ctdb_ltdb_unlock ( ctdb_db , key ) ;
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( __location__ " ctdb_ltdb_unlock() failed with error %d \n " , ret ) ) ;
}
2008-02-04 12:07:15 +03:00
DEBUG ( DEBUG_ERR , ( __location__ " Unable to allocate dstate \n " ) ) ;
2010-09-29 04:38:41 +04:00
CTDB_DECREMENT_STAT ( ctdb , 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 ) {
2010-06-09 08:17:35 +04:00
ret = ctdb_ltdb_unlock ( ctdb_db , key ) ;
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( __location__ " ctdb_ltdb_unlock() failed with error %d \n " , ret ) ) ;
}
2008-02-04 12:07:15 +03:00
DEBUG ( DEBUG_ERR , ( __location__ " Unable to allocate call \n " ) ) ;
2010-09-29 04:38:41 +04:00
CTDB_DECREMENT_STAT ( ctdb , pending_calls ) ;
2010-10-11 08:11:18 +04:00
CTDB_UPDATE_LATENCY ( ctdb , ctdb_db , " call_from_client 1 " , 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-09-04 04:06:36 +04:00
if ( header . dmaster = = ctdb - > pnn ) {
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 ) ;
2011-11-07 23:55:46 +04:00
if ( call - > flags & CTDB_IMMEDIATE_MIGRATION ) {
/* This request triggered a remote fetch-lock.
set up a deferral for this key so any additional
fetch - locks are deferred until the current one
finishes .
*/
setup_deferred_fetch_locks ( ctdb_db , call ) ;
}
2007-04-19 10:27:56 +04:00
}
2010-06-09 08:17:35 +04:00
ret = ctdb_ltdb_unlock ( ctdb_db , key ) ;
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( __location__ " ctdb_ltdb_unlock() failed with error %d \n " , ret ) ) ;
}
2007-04-19 10:27:56 +04:00
2007-04-19 04:37:44 +04:00
if ( state = = NULL ) {
2008-02-04 12:07:15 +03:00
DEBUG ( DEBUG_ERR , ( __location__ " Unable to setup call send \n " ) ) ;
2010-09-29 04:38:41 +04:00
CTDB_DECREMENT_STAT ( ctdb , pending_calls ) ;
2010-10-11 08:11:18 +04:00
CTDB_UPDATE_LATENCY ( ctdb , ctdb_db , " call_from_client 2 " , 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 :
2010-09-29 04:38:41 +04:00
CTDB_INCREMENT_STAT ( ctdb , 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 :
2010-09-29 04:38:41 +04:00
CTDB_INCREMENT_STAT ( ctdb , 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 :
2010-09-29 04:38:41 +04:00
CTDB_INCREMENT_STAT ( ctdb , 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 :
2008-02-04 12:07:15 +03:00
DEBUG ( DEBUG_CRIT , ( __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 ;
}
2010-09-29 04:38:41 +04:00
CTDB_INCREMENT_STAT ( client - > ctdb , 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 ;
}
2008-02-04 09:44:24 +03:00
DEBUG ( DEBUG_DEBUG , ( __location__ " client request %u of type %u length %u from "
2007-05-23 14:15:09 +04:00
" 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
2009-12-02 05:41:04 +03:00
static int ctdb_clientpid_destructor ( struct ctdb_client_pid_list * client_pid )
{
if ( client_pid - > ctdb - > client_pids ! = NULL ) {
DLIST_REMOVE ( client_pid - > ctdb - > client_pids , client_pid ) ;
}
return 0 ;
}
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
{
2008-08-19 08:58:29 +04:00
struct sockaddr_un addr ;
2007-04-10 00:03:39 +04:00
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 ;
2009-12-02 05:41:04 +03:00
struct ctdb_client_pid_list * client_pid ;
2008-04-03 03:58:51 +04:00
# ifdef _AIX
struct peercred_struct cr ;
socklen_t crl = sizeof ( struct peercred_struct ) ;
# else
2008-04-01 10:17:21 +04:00
struct ucred cr ;
socklen_t crl = sizeof ( struct ucred ) ;
2008-04-03 03:58:51 +04:00
# endif
2007-04-10 00:03:39 +04:00
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 ) ;
2009-10-15 04:24:54 +04:00
2009-10-21 08:26:24 +04:00
DEBUG ( DEBUG_DEBUG , ( __location__ " Created SOCKET FD:%d to connected child \n " , fd ) ) ;
2007-04-10 00:03:39 +04:00
client = talloc_zero ( ctdb , struct ctdb_client ) ;
2008-04-03 03:58:51 +04:00
# ifdef _AIX
if ( getsockopt ( fd , SOL_SOCKET , SO_PEERID , & cr , & crl ) = = 0 ) {
# else
2008-04-01 10:17:21 +04:00
if ( getsockopt ( fd , SOL_SOCKET , SO_PEERCRED , & cr , & crl ) = = 0 ) {
2008-04-03 03:58:51 +04:00
# endif
2009-12-02 06:51:57 +03:00
DEBUG ( DEBUG_INFO , ( " Connected client with pid:%u \n " , ( unsigned ) cr . pid ) ) ;
2008-04-01 08:34:54 +04:00
}
2007-04-10 00:03:39 +04:00
client - > ctdb = ctdb ;
client - > fd = fd ;
2007-05-04 05:41:29 +04:00
client - > client_id = ctdb_reqid_new ( ctdb , client ) ;
2009-12-02 05:17:12 +03:00
client - > pid = cr . pid ;
2009-12-02 05:41:04 +03:00
client_pid = talloc ( client , struct ctdb_client_pid_list ) ;
if ( client_pid = = NULL ) {
DEBUG ( DEBUG_ERR , ( " Failed to allocate client pid structure \n " ) ) ;
close ( fd ) ;
talloc_free ( client ) ;
return ;
}
client_pid - > ctdb = ctdb ;
client_pid - > pid = cr . pid ;
client_pid - > client = client ;
DLIST_ADD ( ctdb - > client_pids , client_pid ) ;
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 ,
2010-07-01 17:08:49 +04:00
ctdb_daemon_read_cb , client ,
" client-%u " , client - > pid ) ;
2007-04-10 00:03:39 +04:00
talloc_set_destructor ( client , ctdb_client_destructor ) ;
2009-12-02 05:41:04 +03:00
talloc_set_destructor ( client_pid , ctdb_clientpid_destructor ) ;
2010-09-29 04:38:41 +04:00
CTDB_INCREMENT_STAT ( ctdb , num_clients ) ;
2007-04-10 00:03:39 +04:00
}
/*
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_close_on_exec ( ctdb - > daemon . sd ) ;
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 ) {
2008-02-04 12:07:15 +03:00
DEBUG ( DEBUG_CRIT , ( " 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
}
2008-04-10 00:51:53 +04:00
if ( chown ( ctdb - > daemon . name , geteuid ( ) , getegid ( ) ) ! = 0 | |
chmod ( ctdb - > daemon . name , 0700 ) ! = 0 ) {
2008-04-10 03:56:49 +04:00
DEBUG ( DEBUG_CRIT , ( " Unable to secure ctdb socket '%s', ctdb->daemon.name \n " , ctdb - > daemon . name ) ) ;
2008-04-10 00:51:53 +04:00
goto failed ;
}
2009-04-06 08:00:41 +04:00
if ( listen ( ctdb - > daemon . sd , 100 ) ! = 0 ) {
2008-02-04 12:07:15 +03:00
DEBUG ( DEBUG_CRIT , ( " 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
}
2008-07-09 08:02:54 +04:00
static void sig_child_handler ( struct event_context * ev ,
struct signal_event * se , int signum , int count ,
void * dont_care ,
void * private_data )
{
// struct ctdb_context *ctdb = talloc_get_type(private_data, struct ctdb_context);
int status ;
pid_t pid = - 1 ;
while ( pid ! = 0 ) {
pid = waitpid ( - 1 , & status , WNOHANG ) ;
if ( pid = = - 1 ) {
DEBUG ( DEBUG_ERR , ( __location__ " waitpid() returned error. errno:%d \n " , errno ) ) ;
return ;
}
if ( pid > 0 ) {
DEBUG ( DEBUG_DEBUG , ( " SIGCHLD from %d \n " , ( int ) pid ) ) ;
}
}
}
2010-02-12 13:24:08 +03:00
static void ctdb_setup_event_callback ( struct ctdb_context * ctdb , int status ,
void * private_data )
{
if ( status ! = 0 ) {
ctdb_fatal ( ctdb , " Failed to run setup event \n " ) ;
return ;
}
ctdb_run_notification_script ( ctdb , " setup " ) ;
/* 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-04-29 18:19:40 +04:00
/*
start the protocol going as a daemon
*/
2010-11-10 04:59:25 +03:00
int ctdb_start_daemon ( struct ctdb_context * ctdb , bool do_fork , bool use_syslog , const char * public_address_list )
2007-04-29 18:19:40 +04:00
{
2007-09-21 06:24:02 +04:00
int res , ret = - 1 ;
2007-04-29 18:19:40 +04:00
struct fd_event * fde ;
const char * domain_socket_name ;
2008-07-09 08:02:54 +04:00
struct signal_event * se ;
2007-04-29 18:19:40 +04:00
/* 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 ) {
2008-02-04 12:07:15 +03:00
DEBUG ( DEBUG_ALERT , ( __location__ " Failed to open CTDB unix domain socket \n " ) ) ;
2007-04-29 18:19:40 +04:00
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 ( ) ;
2008-01-05 04:09:29 +03:00
close ( 0 ) ;
if ( open ( " /dev/null " , O_RDONLY ) ! = 0 ) {
2008-02-04 12:07:15 +03:00
DEBUG ( DEBUG_ALERT , ( __location__ " Failed to setup stdin on /dev/null \n " ) ) ;
2008-01-05 04:09:29 +03:00
exit ( 11 ) ;
}
2007-05-15 03:44:33 +04:00
}
2007-04-29 18:19:40 +04:00
block_signal ( SIGPIPE ) ;
2009-10-27 05:18:52 +03:00
ctdbd_pid = getpid ( ) ;
2010-12-28 15:14:23 +03:00
ctdb - > ctdbd_pid = ctdbd_pid ;
2009-10-30 11:39:11 +03:00
2009-10-27 05:18:52 +03:00
DEBUG ( DEBUG_ERR , ( " Starting CTDBD as pid : %u \n " , ctdbd_pid ) ) ;
2011-01-10 05:35:39 +03:00
if ( ctdb - > do_setsched ) {
/* try to set us up as realtime */
ctdb_set_scheduler ( ctdb ) ;
}
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 ) ;
2009-05-20 14:08:13 +04:00
if ( domain_socket_name = = NULL ) {
DEBUG ( DEBUG_ALERT , ( __location__ " talloc_strdup failed. \n " ) ) ;
exit ( 12 ) ;
}
2007-04-29 18:19:40 +04:00
ctdb - > ev = event_context_init ( NULL ) ;
2010-08-18 04:11:59 +04:00
tevent_loop_allow_nesting ( ctdb - > ev ) ;
2010-09-22 04:59:01 +04:00
ret = ctdb_init_tevent_logging ( ctdb ) ;
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ALERT , ( " Failed to initialize TEVENT logging \n " ) ) ;
exit ( 1 ) ;
}
2007-05-09 03:59:23 +04:00
2008-01-16 14:03:01 +03:00
ctdb_set_child_logging ( ctdb ) ;
2010-09-29 06:13:05 +04:00
/* initialize statistics collection */
ctdb_statistics_init ( ctdb ) ;
2007-09-21 06:24:02 +04:00
/* force initial recovery for election */
ctdb - > recovery_mode = CTDB_RECOVERY_ACTIVE ;
if ( strcmp ( ctdb - > transport , " tcp " ) = = 0 ) {
int ctdb_tcp_init ( struct ctdb_context * ) ;
ret = ctdb_tcp_init ( ctdb ) ;
}
# ifdef USE_INFINIBAND
if ( strcmp ( ctdb - > transport , " ib " ) = = 0 ) {
int ctdb_ibw_init ( struct ctdb_context * ) ;
ret = ctdb_ibw_init ( ctdb ) ;
}
# endif
if ( ret ! = 0 ) {
2008-02-04 12:07:15 +03:00
DEBUG ( DEBUG_ERR , ( " Failed to initialise transport '%s' \n " , ctdb - > transport ) ) ;
2007-09-21 06:24:02 +04:00
return - 1 ;
}
2008-05-11 08:28:33 +04:00
if ( ctdb - > methods = = NULL ) {
DEBUG ( DEBUG_ALERT , ( __location__ " Can not initialize transport. ctdb->methods is NULL \n " ) ) ;
ctdb_fatal ( ctdb , " transport is unavailable. can not initialize. " ) ;
}
2007-09-21 06:24:02 +04:00
/* initialise the transport */
if ( ctdb - > methods - > initialise ( ctdb ) ! = 0 ) {
ctdb_fatal ( ctdb , " transport failed to initialise " ) ;
}
2010-11-10 04:59:25 +03:00
if ( public_address_list ) {
ret = ctdb_set_public_addresses ( ctdb , public_address_list ) ;
if ( ret = = - 1 ) {
DEBUG ( DEBUG_ALERT , ( " Unable to setup public address list \n " ) ) ;
exit ( 1 ) ;
}
}
2007-09-21 06:24:02 +04:00
2009-11-29 14:39:23 +03:00
/* attach to existing databases */
if ( ctdb_attach_databases ( ctdb ) ! = 0 ) {
ctdb_fatal ( ctdb , " Failed to attach to databases \n " ) ;
2007-09-21 06:24:02 +04:00
}
2010-01-19 12:07:14 +03:00
ret = ctdb_event_script ( ctdb , CTDB_EVENT_INIT ) ;
if ( ret ! = 0 ) {
ctdb_fatal ( ctdb , " Failed to run init event \n " ) ;
}
ctdb_run_notification_script ( ctdb , " init " ) ;
2010-08-25 02:34:35 +04:00
/* start frozen, then let the first election sort things out */
if ( ctdb_blocking_freeze ( ctdb ) ) {
ctdb_fatal ( ctdb , " Failed to get initial freeze \n " ) ;
}
2007-05-23 06:23:07 +04:00
/* now start accepting clients, only can do this once frozen */
fde = event_add_fd ( ctdb - > ev , ctdb , ctdb - > daemon . sd ,
2010-08-18 03:46:31 +04:00
EVENT_FD_READ ,
2007-05-23 06:23:07 +04:00
ctdb_accept_client , ctdb ) ;
2010-08-18 03:46:31 +04:00
tevent_fd_set_auto_close ( fde ) ;
2007-05-23 06:23:07 +04:00
2007-09-21 06:24:02 +04:00
/* release any IPs we hold from previous runs of the daemon */
2010-11-09 07:19:06 +03:00
if ( ctdb - > tunable . disable_ip_failover = = 0 ) {
ctdb_release_all_ips ( ctdb ) ;
}
2007-04-29 18:19:40 +04:00
2007-11-12 02:53:11 +03:00
/* start the transport going */
ctdb_start_transport ( ctdb ) ;
2007-09-21 06:24:02 +04:00
2008-07-09 08:02:54 +04:00
/* set up a handler to pick up sigchld */
se = event_add_signal ( ctdb - > ev , ctdb ,
SIGCHLD , 0 ,
sig_child_handler ,
ctdb ) ;
if ( se = = NULL ) {
DEBUG ( DEBUG_CRIT , ( " Failed to set up signal handler for SIGCHLD \n " ) ) ;
exit ( 1 ) ;
}
2009-10-30 11:39:11 +03:00
2010-02-12 13:24:08 +03:00
ret = ctdb_event_script_callback ( ctdb ,
ctdb ,
ctdb_setup_event_callback ,
ctdb ,
false ,
CTDB_EVENT_SETUP ,
2011-11-05 20:26:40 +04:00
" %s " ,
2010-02-12 13:24:08 +03:00
" " ) ;
if ( ret ! = 0 ) {
DEBUG ( DEBUG_CRIT , ( " Failed to set up 'setup' event \n " ) ) ;
exit ( 1 ) ;
}
2009-10-30 11:39:11 +03:00
if ( use_syslog ) {
if ( start_syslog_daemon ( ctdb ) ) {
DEBUG ( DEBUG_CRIT , ( " Failed to start syslog daemon \n " ) ) ;
exit ( 10 ) ;
}
}
2009-12-16 13:27:20 +03:00
ctdb_lockdown_memory ( ctdb ) ;
2008-07-09 08:02:54 +04:00
2007-09-21 06:24:02 +04:00
/* go into a wait loop to allow other nodes to complete */
event_loop_wait ( ctdb - > ev ) ;
2008-02-04 12:07:15 +03:00
DEBUG ( DEBUG_CRIT , ( " event_loop_wait() returned. this should not happen \n " ) ) ;
2007-09-21 06:24:02 +04:00
exit ( 1 ) ;
2007-04-29 18:19:40 +04:00
}
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 ) ;
2008-05-11 08:28:33 +04:00
if ( ctdb - > methods = = NULL ) {
2010-10-28 06:38:34 +04:00
DEBUG ( DEBUG_INFO , ( __location__ " Unable to allocate transport packet for operation %u of length %u. Transport is DOWN. \n " ,
2008-05-11 08:28:33 +04:00
operation , ( unsigned ) length ) ) ;
return NULL ;
}
2007-04-28 12:50:32 +04:00
hdr = ( struct ctdb_req_header * ) ctdb - > methods - > allocate_pkt ( mem_ctx , size ) ;
if ( hdr = = NULL ) {
2008-02-04 12:07:15 +03:00
DEBUG ( DEBUG_ERR , ( " 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 ;
2007-09-04 04:06:36 +04:00
hdr - > srcnode = ctdb - > pnn ;
2007-04-28 12:50:32 +04:00
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 ;
2010-02-04 06:36:14 +03:00
int ret ;
2007-04-26 16:27:49 +04:00
/* 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
2010-02-04 06:36:14 +03:00
ret = daemon_queue_send ( client , & r - > hdr ) ;
if ( ret ! = - 1 ) {
talloc_free ( state ) ;
}
2007-04-26 16:27:49 +04:00
}
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 ) {
2007-09-04 04:06:36 +04:00
c - > hdr . destnode = client - > ctdb - > pnn ;
2007-04-26 21:27:07 +04:00
}
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-09-04 04:09:58 +04:00
if ( ctdb_validate_pnn ( client - > ctdb , c - > hdr . destnode ) ) {
2007-05-18 17:48:29 +04:00
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 ) {
2008-02-04 12:07:15 +03:00
DEBUG ( DEBUG_ERR , ( __location__ " Failed to send control to remote node %u \n " ,
2007-04-26 16:27:49 +04:00
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 ) {
2008-02-04 12:07:15 +03:00
DEBUG ( DEBUG_ERR , ( __location__ " Failed to dispatch message for srvid=%llu \n " ,
2007-06-07 16:06:19 +04:00
( 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
*/
2007-09-04 04:45:41 +04:00
int ctdb_daemon_send_message ( struct ctdb_context * ctdb , uint32_t pnn ,
2007-06-07 16:06:19 +04:00
uint64_t srvid , TDB_DATA data )
{
struct ctdb_req_message * r ;
int len ;
2009-06-30 06:09:28 +04:00
if ( ctdb - > methods = = NULL ) {
2010-10-28 06:38:34 +04:00
DEBUG ( DEBUG_INFO , ( __location__ " Failed to send message. Transport is DOWN \n " ) ) ;
2009-06-30 06:09:28 +04:00
return - 1 ;
}
2007-06-07 16:06:19 +04:00
/* see if this is a message to ourselves */
2007-09-04 04:45:41 +04:00
if ( pnn = = ctdb - > pnn ) {
2007-06-07 16:06:19 +04:00
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 ) ;
2007-09-04 04:45:41 +04:00
r - > hdr . destnode = pnn ;
2007-06-07 16:06:19 +04:00
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 ;
}
2009-10-23 08:24:51 +04:00
struct ctdb_client_notify_list {
struct ctdb_client_notify_list * next , * prev ;
struct ctdb_context * ctdb ;
uint64_t srvid ;
TDB_DATA data ;
} ;
static int ctdb_client_notify_destructor ( struct ctdb_client_notify_list * nl )
{
int ret ;
DEBUG ( DEBUG_ERR , ( " Sending client notify message for srvid:%llu \n " , ( unsigned long long ) nl - > srvid ) ) ;
ret = ctdb_daemon_send_message ( nl - > ctdb , CTDB_BROADCAST_CONNECTED , ( unsigned long long ) nl - > srvid , nl - > data ) ;
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Failed to send client notify message \n " ) ) ;
}
return 0 ;
}
int32_t ctdb_control_register_notify ( struct ctdb_context * ctdb , uint32_t client_id , TDB_DATA indata )
{
struct ctdb_client_notify_register * notify = ( struct ctdb_client_notify_register * ) indata . dptr ;
struct ctdb_client * client = ctdb_reqid_find ( ctdb , client_id , struct ctdb_client ) ;
struct ctdb_client_notify_list * nl ;
2010-03-30 04:57:25 +04:00
DEBUG ( DEBUG_INFO , ( " Register srvid %llu for client %d \n " , ( unsigned long long ) notify - > srvid , client_id ) ) ;
2009-10-23 08:24:51 +04:00
if ( indata . dsize < offsetof ( struct ctdb_client_notify_register , notify_data ) ) {
DEBUG ( DEBUG_ERR , ( __location__ " Too little data in control : %d \n " , ( int ) indata . dsize ) ) ;
return - 1 ;
}
if ( indata . dsize ! = ( notify - > len + offsetof ( struct ctdb_client_notify_register , notify_data ) ) ) {
DEBUG ( DEBUG_ERR , ( __location__ " Wrong amount of data in control. Got %d, expected %d \n " , ( int ) indata . dsize , ( int ) ( notify - > len + offsetof ( struct ctdb_client_notify_register , notify_data ) ) ) ) ;
return - 1 ;
}
if ( client = = NULL ) {
DEBUG ( DEBUG_ERR , ( __location__ " Could not find client parent structure. You can not send this control to a remote node \n " ) ) ;
return - 1 ;
}
for ( nl = client - > notify ; nl ; nl = nl - > next ) {
if ( nl - > srvid = = notify - > srvid ) {
break ;
}
}
if ( nl ! = NULL ) {
DEBUG ( DEBUG_ERR , ( __location__ " Notification for srvid:%llu already exists for this client \n " , ( unsigned long long ) notify - > srvid ) ) ;
return - 1 ;
}
nl = talloc ( client , struct ctdb_client_notify_list ) ;
CTDB_NO_MEMORY ( ctdb , nl ) ;
nl - > ctdb = ctdb ;
nl - > srvid = notify - > srvid ;
nl - > data . dsize = notify - > len ;
nl - > data . dptr = talloc_size ( nl , nl - > data . dsize ) ;
CTDB_NO_MEMORY ( ctdb , nl - > data . dptr ) ;
memcpy ( nl - > data . dptr , notify - > notify_data , nl - > data . dsize ) ;
DLIST_ADD ( client - > notify , nl ) ;
talloc_set_destructor ( nl , ctdb_client_notify_destructor ) ;
return 0 ;
}
int32_t ctdb_control_deregister_notify ( struct ctdb_context * ctdb , uint32_t client_id , TDB_DATA indata )
{
struct ctdb_client_notify_deregister * notify = ( struct ctdb_client_notify_deregister * ) indata . dptr ;
struct ctdb_client * client = ctdb_reqid_find ( ctdb , client_id , struct ctdb_client ) ;
struct ctdb_client_notify_list * nl ;
2010-03-30 04:57:25 +04:00
DEBUG ( DEBUG_INFO , ( " Deregister srvid %llu for client %d \n " , ( unsigned long long ) notify - > srvid , client_id ) ) ;
2009-10-23 08:24:51 +04:00
if ( client = = NULL ) {
DEBUG ( DEBUG_ERR , ( __location__ " Could not find client parent structure. You can not send this control to a remote node \n " ) ) ;
return - 1 ;
}
for ( nl = client - > notify ; nl ; nl = nl - > next ) {
if ( nl - > srvid = = notify - > srvid ) {
break ;
}
}
if ( nl = = NULL ) {
DEBUG ( DEBUG_ERR , ( __location__ " No notification for srvid:%llu found for this client \n " , ( unsigned long long ) notify - > srvid ) ) ;
return - 1 ;
}
DLIST_REMOVE ( client - > notify , nl ) ;
talloc_set_destructor ( nl , NULL ) ;
talloc_free ( nl ) ;
return 0 ;
}
2009-12-02 05:17:12 +03:00
2009-12-02 05:58:27 +03:00
struct ctdb_client * ctdb_find_client_by_pid ( struct ctdb_context * ctdb , pid_t pid )
{
struct ctdb_client_pid_list * client_pid ;
for ( client_pid = ctdb - > client_pids ; client_pid ; client_pid = client_pid - > next ) {
if ( client_pid - > pid = = pid ) {
return client_pid - > client ;
}
}
return NULL ;
}
/* This control is used by samba when probing if a process (of a samba daemon)
exists on the node .
Samba does this when it needs / wants to check if a subrecord in one of the
databases is still valied , or if it is stale and can be removed .
If the node is in unhealthy or stopped state we just kill of the samba
process holding htis sub - record and return to the calling samba that
the process does not exist .
This allows us to forcefully recall subrecords registered by samba processes
on banned and stopped nodes .
*/
int32_t ctdb_control_process_exists ( struct ctdb_context * ctdb , pid_t pid )
{
struct ctdb_client * client ;
if ( ctdb - > nodes [ ctdb - > pnn ] - > flags & ( NODE_FLAGS_BANNED | NODE_FLAGS_STOPPED ) ) {
client = ctdb_find_client_by_pid ( ctdb , pid ) ;
if ( client ! = NULL ) {
DEBUG ( DEBUG_NOTICE , ( __location__ " Killing client with pid:%d on banned/stopped node \n " , ( int ) pid ) ) ;
talloc_free ( client ) ;
}
return - 1 ;
}
return kill ( pid , 0 ) ;
}