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
*/
2015-10-26 08:50:46 +03:00
# include "replace.h"
2007-04-10 00:03:39 +04:00
# include "system/network.h"
# include "system/filesys.h"
2007-04-17 09:33:20 +04:00
# include "system/wait.h"
2015-10-26 08:50:46 +03:00
# include "system/time.h"
# include <talloc.h>
/* Allow use of deprecated function tevent_loop_allow_nesting() */
# define TEVENT_DEPRECATED
# include <tevent.h>
# include <tdb.h>
# include "lib/tdb_wrap/tdb_wrap.h"
# include "lib/util/dlinklist.h"
# include "lib/util/debug.h"
# include "lib/util/samba_util.h"
2015-10-23 05:05:20 +03:00
# include "ctdb_version.h"
2015-10-26 08:50:46 +03:00
# include "ctdb_private.h"
# include "ctdb_client.h"
# include "ctdb_logging.h"
# include "common/rb_tree.h"
2015-03-17 06:30:18 +03:00
# include "common/reqid.h"
2015-10-23 06:11:53 +03:00
# include "common/system.h"
2015-10-23 06:17:34 +03:00
# include "common/common.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 ;
} ;
2013-04-15 07:32:57 +04:00
const char * ctdbd_pidfile = NULL ;
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 )
{
2013-01-10 07:39:09 +04:00
if ( debug_extra ! = NULL & & debug_extra [ 0 ] ! = ' \0 ' ) {
DEBUG ( DEBUG_NOTICE , ( " CTDB %s shutting down \n " , debug_extra ) ) ;
} else {
DEBUG ( DEBUG_NOTICE , ( " CTDB daemon shutting down \n " ) ) ;
2013-07-17 05:14:37 +04:00
/* Wait a second to allow pending log messages to be flushed */
sleep ( 1 ) ;
2013-01-10 07:39:09 +04:00
}
2007-09-24 04:00:14 +04:00
}
2011-01-14 01:46:04 +03:00
2015-10-26 08:50:09 +03:00
static void ctdb_time_tick ( struct tevent_context * ev , struct tevent_timer * te ,
2011-01-14 01:46:04 +03:00
struct timeval t , void * private_data )
{
struct ctdb_context * ctdb = talloc_get_type ( private_data , struct ctdb_context ) ;
2014-07-03 06:29:46 +04:00
if ( getpid ( ) ! = ctdb - > ctdbd_pid ) {
2011-01-14 01:46:04 +03:00
return ;
}
2015-10-26 08:50:09 +03:00
tevent_add_timer ( ctdb - > ev , ctdb ,
timeval_current_ofs ( 1 , 0 ) ,
ctdb_time_tick , ctdb ) ;
2011-01-14 01:46:04 +03:00
}
/* 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 )
{
2015-10-26 08:50:09 +03:00
tevent_add_timer ( ctdb - > ev , ctdb ,
timeval_current_ofs ( 1 , 0 ) ,
ctdb_time_tick , ctdb ) ;
2011-01-14 01:46:04 +03:00
}
2013-01-10 09:33:36 +04:00
static void ctdb_start_periodic_events ( struct ctdb_context * ctdb )
2007-05-30 07:26:50 +04:00
{
2008-01-15 00:42:12 +03:00
/* start monitoring for connected/disconnected nodes */
ctdb_start_keepalive ( 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
}
2014-06-06 08:58:17 +04:00
static void ignore_signal ( int signum )
2007-04-17 09:33:20 +04:00
{
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
*/
2015-04-08 07:38:26 +03:00
static void daemon_message_handler ( uint64_t srvid , 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 ) ;
2015-10-29 08:36:30 +03:00
struct ctdb_req_message_old * r ;
2007-04-11 05:58:28 +04:00
int len ;
/* construct a message to send to the client containing the data */
2015-10-29 08:36:30 +03:00
len = offsetof ( struct ctdb_req_message_old , data ) + data . dsize ;
2015-04-08 07:38:26 +03:00
r = ctdbd_allocate_pkt ( client - > ctdb , client - > ctdb , CTDB_REQ_MESSAGE ,
2015-10-29 08:36:30 +03:00
len , struct ctdb_req_message_old ) ;
2015-04-08 07:38:26 +03:00
CTDB_NO_MEMORY_VOID ( client - > 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
{
2015-03-17 06:30:18 +03:00
struct ctdb_client * client = reqid_find ( ctdb - > idr , 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 ;
}
2015-04-08 07:38:26 +03:00
res = srvid_register ( ctdb - > srv , 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 )
{
2015-03-17 06:30:18 +03:00
struct ctdb_client * client = reqid_find ( ctdb - > idr , client_id , struct ctdb_client ) ;
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_deregister_message_handler \n " ) ) ;
2007-05-04 05:41:29 +04:00
return - 1 ;
}
2015-04-08 07:38:26 +03:00
return srvid_deregister ( ctdb - > srv , 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 + + ) {
2015-04-08 07:38:26 +03:00
if ( srvid_exists ( ctdb - > srv , ids [ i ] ) = = 0 ) {
2011-10-31 16:29:13 +04:00
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 ) ;
2015-03-17 06:30:18 +03:00
reqid_remove ( client - > ctdb - > idr , client - > client_id ) ;
2013-04-19 07:29:04 +04:00
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
/*
* 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 ,
2015-10-29 08:36:30 +03:00
struct ctdb_req_message_old * c )
2007-04-11 07:43:15 +04:00
{
2007-04-11 08:05:01 +04:00
TDB_DATA data ;
int res ;
2012-02-13 16:24:37 +04:00
if ( c - > hdr . destnode = = CTDB_CURRENT_NODE ) {
c - > hdr . destnode = ctdb_get_pnn ( client - > ctdb ) ;
}
2007-04-11 08:05:01 +04:00
/* 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 ;
2012-01-31 10:20:35 +04:00
/* readonly request ? */
uint32_t readonly_fetch ;
uint32_t client_callid ;
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 ) ;
2015-10-29 08:29:01 +03:00
struct ctdb_reply_call_old * 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
}
2015-10-29 08:29:01 +03:00
length = offsetof ( struct ctdb_reply_call_old , data ) + dstate - > call - > reply_data . dsize ;
2012-01-31 10:20:35 +04:00
/* If the client asked for readonly FETCH, we remapped this to
FETCH_WITH_HEADER when calling the daemon . So we must
strip the extra header off the reply data before passing
it back to the client .
*/
if ( dstate - > readonly_fetch
& & dstate - > client_callid = = CTDB_FETCH_FUNC ) {
length - = sizeof ( struct ctdb_ltdb_header ) ;
}
2007-04-28 12:50:32 +04:00
r = ctdbd_allocate_pkt ( client - > ctdb , dstate , CTDB_REPLY_CALL ,
2015-10-29 08:29:01 +03:00
length , struct ctdb_reply_call_old ) ;
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 ;
2011-07-20 09:17:29 +04:00
r - > status = dstate - > call - > status ;
2012-01-31 10:20:35 +04:00
if ( dstate - > readonly_fetch
& & dstate - > client_callid = = CTDB_FETCH_FUNC ) {
/* client only asked for a FETCH so we must strip off
the extra ctdb_ltdb header
*/
r - > datalen = dstate - > call - > reply_data . dsize - sizeof ( struct ctdb_ltdb_header ) ;
memcpy ( & r - > data [ 0 ] , dstate - > call - > reply_data . dptr + sizeof ( struct ctdb_ltdb_header ) , r - > datalen ) ;
} else {
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 ) ;
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 ;
}
2015-03-17 06:30:18 +03:00
client = reqid_find ( w - > ctdb - > idr , w - > client_id , struct ctdb_client ) ;
2008-01-16 01:44:48 +03:00
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 ;
2015-10-29 08:26:29 +03:00
struct ctdb_req_call_old * c ;
2011-11-07 23:55:46 +04:00
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.*/
2015-10-26 08:50:09 +03:00
static void reprocess_deferred_call ( struct tevent_context * ev ,
struct tevent_timer * te ,
struct timeval t , void * private_data )
2011-11-07 23:55:46 +04:00
{
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 ) ;
2015-03-17 06:30:18 +03:00
client = reqid_find ( dfc - > w - > ctdb - > idr , dfc - > w - > client_id , struct ctdb_client ) ;
2011-11-07 23:55:46 +04:00
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 ;
2015-10-26 08:50:09 +03:00
tevent_add_timer ( dfc - > w - > ctdb - > ev , client , timeval_zero ( ) ,
reprocess_deferred_call , dfr ) ;
2011-11-07 23:55:46 +04:00
}
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 .
*/
2015-10-26 08:50:09 +03:00
static void dfq_timeout ( struct tevent_context * ev , struct tevent_timer * te ,
struct timeval t , void * private_data )
2011-11-07 23:55:46 +04:00
{
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 ;
2014-08-15 07:33:24 +04:00
k = ctdb_key_to_idkey ( call , call - > key ) ;
2011-11-07 23:55:46 +04:00
if ( k = = NULL ) {
DEBUG ( DEBUG_ERR , ( " Failed to allocate key for deferred fetch \n " ) ) ;
return - 1 ;
}
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 */
2015-10-26 08:50:09 +03:00
tevent_add_timer ( ctdb_db - > ctdb - > ev , dfq , timeval_current_ofs ( 30 , 0 ) ,
dfq_timeout , dfq ) ;
2011-11-07 23:55:46 +04:00
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 .
*/
2015-10-29 08:26:29 +03:00
static int requeue_duplicate_fetch ( struct ctdb_db_context * ctdb_db , struct ctdb_client * client , TDB_DATA key , struct ctdb_req_call_old * c )
2011-11-07 23:55:46 +04:00
{
uint32_t * k ;
struct ctdb_deferred_fetch_queue * dfq ;
struct ctdb_deferred_fetch_call * dfc ;
2014-08-15 07:33:24 +04:00
k = ctdb_key_to_idkey ( c , key ) ;
2011-11-07 23:55:46 +04:00
if ( k = = NULL ) {
DEBUG ( DEBUG_ERR , ( " Failed to allocate key for deferred fetch \n " ) ) ;
return - 1 ;
}
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 ,
2015-10-29 08:26:29 +03:00
struct ctdb_req_call_old * c )
2007-04-19 04:37:44 +04:00
{
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 ) ;
2014-09-09 13:01:55 +04:00
CTDB_INCREMENT_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 ,
2012-05-17 10:08:37 +04: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 ;
}
2012-03-20 04:31:59 +04:00
/* check if this fetch request is a duplicate for a
request we already have in flight . If so defer it until
the first request completes .
*/
if ( ctdb - > tunable . fetch_collapse = = 1 ) {
2011-11-07 23:55:46 +04:00
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 ) ) ;
}
2014-09-12 04:50:27 +04:00
CTDB_DECREMENT_STAT ( ctdb , pending_calls ) ;
2011-11-07 23:55:46 +04:00
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 ) {
2013-04-19 18:23:16 +04:00
header . flags & = ~ CTDB_REC_RO_FLAGS ;
2012-02-08 06:42:30 +04:00
CTDB_INCREMENT_STAT ( ctdb , total_ro_revokes ) ;
2012-02-08 08:29:27 +04:00
CTDB_INCREMENT_DB_STAT ( ctdb_db , db_ro_revokes ) ;
2011-07-20 09:17:29 +04:00
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 " ) ;
}
2014-09-12 04:50:27 +04:00
CTDB_DECREMENT_STAT ( ctdb , pending_calls ) ;
2011-07-20 09:17:29 +04:00
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 " ) ;
}
2014-09-12 04:50:27 +04:00
CTDB_DECREMENT_STAT ( ctdb , pending_calls ) ;
2011-07-20 09:17:29 +04:00
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 ;
}
2012-01-31 10:20:35 +04:00
dstate - > readonly_fetch = 0 ;
2007-04-19 04:37:44 +04:00
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
2012-01-31 10:20:35 +04:00
if ( c - > flags & CTDB_WANT_READONLY ) {
/* client wants readonly record, so translate this into a
fetch with header . remember what the client asked for
so we can remap the reply back to the proper format for
the client in the reply
*/
dstate - > client_callid = call - > call_id ;
call - > call_id = CTDB_FETCH_WITH_HEADER_FUNC ;
dstate - > readonly_fetch = 1 ;
}
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 ) ;
2012-03-20 04:31:59 +04:00
if ( ctdb - > tunable . fetch_collapse = = 1 ) {
2011-11-07 23:55:46 +04:00
/* 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 ,
2015-10-29 08:42:05 +03:00
struct ctdb_req_control_old * c ) ;
2007-04-26 16:27:49 +04:00
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
}
2014-10-21 04:53:29 +04:00
if ( hdr - > ctdb_version ! = CTDB_PROTOCOL ) {
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 ) ;
2015-10-29 08:26:29 +03:00
daemon_request_call_from_client ( client , ( struct ctdb_req_call_old * ) 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 ) ;
2015-10-29 08:36:30 +03:00
daemon_request_message_from_client ( client , ( struct ctdb_req_message_old * ) hdr ) ;
2007-04-11 07:43:15 +04:00
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 ) ;
2015-10-29 08:42:05 +03:00
daemon_request_control_from_client ( client , ( struct ctdb_req_control_old * ) hdr ) ;
2007-04-26 16:27:49 +04:00
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 ;
}
2014-10-21 04:53:29 +04:00
if ( hdr - > ctdb_version ! = CTDB_PROTOCOL ) {
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 ;
}
2015-10-26 08:50:09 +03:00
static void ctdb_accept_client ( struct tevent_context * ev ,
struct tevent_fd * fde , 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 ;
2011-11-05 22:04:40 +04:00
pid_t peer_pid = 0 ;
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 ) ;
2011-11-05 22:04:40 +04:00
if ( ctdb_get_peer_pid ( fd , & peer_pid ) = = 0 ) {
DEBUG ( DEBUG_INFO , ( " Connected client with pid:%u \n " , ( unsigned ) peer_pid ) ) ;
2008-04-01 08:34:54 +04:00
}
2007-04-10 00:03:39 +04:00
client - > ctdb = ctdb ;
client - > fd = fd ;
2015-03-17 06:30:18 +03:00
client - > client_id = reqid_new ( ctdb - > idr , client ) ;
2011-11-05 22:04:40 +04:00
client - > pid = peer_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 ;
2011-11-05 22:04:40 +04:00
client_pid - > pid = peer_pid ;
2009-12-02 05:41:04 +03:00
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 ) ;
2013-04-19 07:29:04 +04:00
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 ;
}
memset ( & addr , 0 , sizeof ( addr ) ) ;
addr . sun_family = AF_UNIX ;
2013-11-11 05:39:27 +04:00
strncpy ( addr . sun_path , ctdb - > daemon . name , sizeof ( addr . sun_path ) - 1 ) ;
2007-04-10 00:03:39 +04:00
2013-07-19 09:36:29 +04:00
/* First check if an old ctdbd might be running */
if ( connect ( ctdb - > daemon . sd ,
( struct sockaddr * ) & addr , sizeof ( addr ) ) = = 0 ) {
DEBUG ( DEBUG_CRIT ,
( " Something is already listening on ctdb socket '%s' \n " ,
ctdb - > daemon . name ) ) ;
goto failed ;
}
/* Remove any old socket */
unlink ( ctdb - > daemon . name ) ;
set_close_on_exec ( ctdb - > daemon . sd ) ;
set_nonblocking ( ctdb - > daemon . sd ) ;
2007-04-10 00:03:39 +04:00
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 ;
2013-07-19 09:36:29 +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 ;
2013-07-19 09:36:29 +04:00
}
2008-04-10 00:51:53 +04:00
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
}
2012-12-04 07:28:06 +04:00
static void initialise_node_flags ( struct ctdb_context * ctdb )
{
if ( ctdb - > pnn = = - 1 ) {
ctdb_fatal ( ctdb , " PNN is set to -1 (unknown value) " ) ;
}
ctdb - > nodes [ ctdb - > pnn ] - > flags & = ~ NODE_FLAGS_DISCONNECTED ;
/* do we start out in DISABLED mode? */
if ( ctdb - > start_as_disabled ! = 0 ) {
2015-06-17 08:05:30 +03:00
DEBUG ( DEBUG_NOTICE , ( " This node is configured to start in DISABLED state \n " ) ) ;
2012-12-04 07:28:06 +04:00
ctdb - > nodes [ ctdb - > pnn ] - > flags | = NODE_FLAGS_DISABLED ;
}
/* do we start out in STOPPED mode? */
if ( ctdb - > start_as_stopped ! = 0 ) {
2015-06-17 08:05:30 +03:00
DEBUG ( DEBUG_NOTICE , ( " This node is configured to start in STOPPED state \n " ) ) ;
2012-12-04 07:28:06 +04:00
ctdb - > nodes [ ctdb - > pnn ] - > flags | = NODE_FLAGS_STOPPED ;
}
}
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 ) {
2013-06-30 11:48:01 +04:00
ctdb_die ( ctdb , " Failed to run setup event " ) ;
2010-02-12 13:24:08 +03:00
}
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 ) ;
2013-01-10 09:33:36 +04:00
/* Start the recovery daemon */
if ( ctdb_start_recoverd ( ctdb ) ! = 0 ) {
DEBUG ( DEBUG_ALERT , ( " Failed to start recovery daemon \n " ) ) ;
exit ( 11 ) ;
}
ctdb_start_periodic_events ( ctdb ) ;
2013-12-18 08:37:11 +04:00
ctdb_wait_for_first_recovery ( ctdb ) ;
2010-02-12 13:24:08 +03:00
}
2012-06-07 09:08:15 +04:00
static struct timeval tevent_before_wait_ts ;
static struct timeval tevent_after_wait_ts ;
static void ctdb_tevent_trace ( enum tevent_trace_point tp ,
void * private_data )
{
struct timeval diff ;
struct timeval now ;
2014-07-03 06:29:46 +04:00
struct ctdb_context * ctdb =
talloc_get_type ( private_data , struct ctdb_context ) ;
2012-06-07 09:08:15 +04:00
2014-07-03 06:29:46 +04:00
if ( getpid ( ) ! = ctdb - > ctdbd_pid ) {
2012-06-07 09:08:15 +04:00
return ;
}
now = timeval_current ( ) ;
switch ( tp ) {
case TEVENT_TRACE_BEFORE_WAIT :
if ( ! timeval_is_zero ( & tevent_after_wait_ts ) ) {
diff = timeval_until ( & tevent_after_wait_ts , & now ) ;
if ( diff . tv_sec > 3 ) {
DEBUG ( DEBUG_ERR ,
( " Handling event took %ld seconds! \n " ,
2015-09-03 17:25:02 +03:00
( long ) diff . tv_sec ) ) ;
2012-06-07 09:08:15 +04:00
}
}
tevent_before_wait_ts = now ;
break ;
case TEVENT_TRACE_AFTER_WAIT :
if ( ! timeval_is_zero ( & tevent_before_wait_ts ) ) {
diff = timeval_until ( & tevent_before_wait_ts , & now ) ;
if ( diff . tv_sec > 3 ) {
DEBUG ( DEBUG_CRIT ,
( " No event for %ld seconds! \n " ,
2015-09-03 17:25:02 +03:00
( long ) diff . tv_sec ) ) ;
2012-06-07 09:08:15 +04:00
}
}
tevent_after_wait_ts = now ;
break ;
default :
/* Do nothing for future tevent trace points */ ;
}
}
2013-04-15 07:32:57 +04:00
static void ctdb_remove_pidfile ( void )
{
2014-06-30 11:22:14 +04:00
/* Only the main ctdbd's PID matches the SID */
if ( ctdbd_pidfile ! = NULL & & getsid ( 0 ) = = getpid ( ) ) {
2013-04-15 07:32:57 +04:00
if ( unlink ( ctdbd_pidfile ) = = 0 ) {
2013-04-22 07:52:04 +04:00
DEBUG ( DEBUG_NOTICE , ( " Removed PID file %s \n " ,
ctdbd_pidfile ) ) ;
2013-04-15 07:32:57 +04:00
} else {
DEBUG ( DEBUG_WARNING , ( " Failed to Remove PID file %s \n " ,
ctdbd_pidfile ) ) ;
}
}
}
static void ctdb_create_pidfile ( pid_t pid )
{
if ( ctdbd_pidfile ! = NULL ) {
FILE * fp ;
fp = fopen ( ctdbd_pidfile , " w " ) ;
if ( fp = = NULL ) {
DEBUG ( DEBUG_ALERT ,
( " Failed to open PID file %s \n " , ctdbd_pidfile ) ) ;
exit ( 11 ) ;
}
fprintf ( fp , " %d \n " , pid ) ;
fclose ( fp ) ;
2013-04-22 07:52:04 +04:00
DEBUG ( DEBUG_NOTICE , ( " Created PID file %s \n " , ctdbd_pidfile ) ) ;
2013-04-15 07:32:57 +04:00
atexit ( ctdb_remove_pidfile ) ;
}
}
2015-02-17 04:34:41 +03:00
static void ctdb_initialise_vnn_map ( struct ctdb_context * ctdb )
{
int i , j , count ;
/* initialize the vnn mapping table, skipping any deleted nodes */
ctdb - > vnn_map = talloc ( ctdb , struct ctdb_vnn_map ) ;
CTDB_NO_MEMORY_FATAL ( ctdb , ctdb - > vnn_map ) ;
count = 0 ;
for ( i = 0 ; i < ctdb - > num_nodes ; i + + ) {
if ( ( ctdb - > nodes [ i ] - > flags & NODE_FLAGS_DELETED ) = = 0 ) {
count + + ;
}
}
ctdb - > vnn_map - > generation = INVALID_GENERATION ;
ctdb - > vnn_map - > size = count ;
ctdb - > vnn_map - > map = talloc_array ( ctdb - > vnn_map , uint32_t , ctdb - > vnn_map - > size ) ;
CTDB_NO_MEMORY_FATAL ( ctdb , ctdb - > vnn_map - > map ) ;
for ( i = 0 , j = 0 ; i < ctdb - > vnn_map - > size ; i + + ) {
if ( ctdb - > nodes [ i ] - > flags & NODE_FLAGS_DELETED ) {
continue ;
}
ctdb - > vnn_map - > map [ j ] = i ;
j + + ;
}
}
2015-02-17 07:21:15 +03:00
static void ctdb_set_my_pnn ( struct ctdb_context * ctdb )
{
int nodeid ;
2015-02-20 03:47:23 +03:00
if ( ctdb - > address = = NULL ) {
2015-02-17 07:21:15 +03:00
ctdb_fatal ( ctdb ,
" Can not determine PNN - node address is not set \n " ) ;
}
2015-02-20 03:47:23 +03:00
nodeid = ctdb_ip_to_nodeid ( ctdb , ctdb - > address ) ;
2015-02-17 07:21:15 +03:00
if ( nodeid = = - 1 ) {
ctdb_fatal ( ctdb ,
" Can not determine PNN - node address not found in node list \n " ) ;
}
ctdb - > pnn = ctdb - > nodes [ nodeid ] - > pnn ;
DEBUG ( DEBUG_NOTICE , ( " PNN is %u \n " , ctdb - > pnn ) ) ;
}
2007-04-29 18:19:40 +04:00
/*
start the protocol going as a daemon
*/
2014-08-08 14:57:05 +04:00
int ctdb_start_daemon ( struct ctdb_context * ctdb , bool do_fork )
2007-04-29 18:19:40 +04:00
{
2007-09-21 06:24:02 +04:00
int res , ret = - 1 ;
2015-10-26 08:50:09 +03:00
struct tevent_fd * fde ;
2007-04-29 18:19:40 +04:00
/* create a unix domain stream socket to listen to */
res = ux_socket_bind ( ctdb ) ;
if ( res ! = 0 ) {
2013-07-19 09:36:29 +04:00
DEBUG ( DEBUG_ALERT , ( " Cannot continue. Exiting! \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 ;
}
2012-05-17 10:08:37 +04:00
tdb_reopen_all ( false ) ;
2007-04-29 18:19:40 +04:00
2007-05-15 03:44:33 +04:00
if ( do_fork ) {
2014-07-03 06:12:20 +04:00
if ( setsid ( ) = = - 1 ) {
ctdb_die ( ctdb , " Failed to setsid() \n " ) ;
}
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
}
2014-06-06 08:58:17 +04:00
ignore_signal ( SIGPIPE ) ;
2015-07-21 05:23:27 +03:00
ignore_signal ( SIGUSR1 ) ;
2007-04-29 18:19:40 +04:00
2014-07-03 06:29:46 +04:00
ctdb - > ctdbd_pid = getpid ( ) ;
2013-05-22 09:37:46 +04:00
DEBUG ( DEBUG_ERR , ( " Starting CTDBD (Version %s) as PID: %u \n " ,
2014-07-03 06:29:46 +04:00
CTDB_VERSION_STRING , ctdb - > ctdbd_pid ) ) ;
2013-04-15 07:32:57 +04:00
ctdb_create_pidfile ( ctdb - > ctdbd_pid ) ;
2009-10-27 05:18:52 +03:00
2013-07-17 05:14:37 +04:00
/* Make sure we log something when the daemon terminates.
* This must be the first exit handler to run ( so the last to
* be registered .
*/
atexit ( print_exit_message ) ;
2011-01-10 05:35:39 +03:00
if ( ctdb - > do_setsched ) {
/* try to set us up as realtime */
2014-09-12 05:22:36 +04:00
if ( ! set_scheduler ( ) ) {
exit ( 1 ) ;
}
DEBUG ( DEBUG_NOTICE , ( " Set real-time scheduler priority \n " ) ) ;
2011-01-10 05:35:39 +03:00
}
2007-05-24 08:52:10 +04:00
2015-10-26 08:50:09 +03:00
ctdb - > ev = tevent_context_init ( NULL ) ;
2010-08-18 04:11:59 +04:00
tevent_loop_allow_nesting ( ctdb - > ev ) ;
2014-07-03 06:29:46 +04:00
tevent_set_trace_callback ( ctdb - > ev , ctdb_tevent_trace , ctdb ) ;
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
2012-05-03 05:42:41 +04:00
/* set up a handler to pick up sigchld */
if ( ctdb_init_sigchld ( ctdb ) = = NULL ) {
DEBUG ( DEBUG_CRIT , ( " Failed to set up signal handler for SIGCHLD \n " ) ) ;
exit ( 1 ) ;
}
2008-01-16 14:03:01 +03:00
ctdb_set_child_logging ( ctdb ) ;
2015-04-08 07:38:26 +03:00
if ( srvid_init ( ctdb , & ctdb - > srv ) ! = 0 ) {
DEBUG ( DEBUG_CRIT , ( " Failed to setup message srvid context \n " ) ) ;
exit ( 1 ) ;
}
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 ;
2013-06-16 13:49:02 +04:00
ctdb_set_runstate ( ctdb , CTDB_RUNSTATE_INIT ) ;
ret = ctdb_event_script ( ctdb , CTDB_EVENT_INIT ) ;
if ( ret ! = 0 ) {
2013-06-30 11:43:52 +04:00
ctdb_die ( ctdb , " Failed to run init event \n " ) ;
2013-06-16 13:49:02 +04:00
}
ctdb_run_notification_script ( ctdb , " init " ) ;
2007-09-21 06:24:02 +04:00
if ( strcmp ( ctdb - > transport , " tcp " ) = = 0 ) {
ret = ctdb_tcp_init ( ctdb ) ;
}
# ifdef USE_INFINIBAND
if ( strcmp ( ctdb - > transport , " ib " ) = = 0 ) {
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. " ) ;
}
2015-02-17 07:21:15 +03:00
/* Initialise the transport. This sets the node address if it
* was not set via the command - line . */
2007-09-21 06:24:02 +04:00
if ( ctdb - > methods - > initialise ( ctdb ) ! = 0 ) {
ctdb_fatal ( ctdb , " transport failed to initialise " ) ;
}
2012-12-04 07:28:06 +04:00
2015-02-17 07:21:15 +03:00
ctdb_set_my_pnn ( ctdb ) ;
2012-12-04 07:28:06 +04:00
initialise_node_flags ( ctdb ) ;
2013-10-21 12:52:01 +04:00
if ( ctdb - > public_addresses_file ) {
2012-05-01 09:27:12 +04:00
ret = ctdb_set_public_addresses ( ctdb , true ) ;
2010-11-10 04:59:25 +03:00
if ( ret = = - 1 ) {
DEBUG ( DEBUG_ALERT , ( " Unable to setup public address list \n " ) ) ;
exit ( 1 ) ;
}
}
2015-02-17 04:34:41 +03:00
ctdb_initialise_vnn_map ( ctdb ) ;
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-08-25 02:34:35 +04:00
/* start frozen, then let the first election sort things out */
2012-06-06 10:19:10 +04:00
if ( ! ctdb_blocking_freeze ( ctdb ) ) {
2010-08-25 02:34:35 +04:00
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 */
2015-10-26 08:50:09 +03:00
fde = tevent_add_fd ( ctdb - > ev , ctdb , ctdb - > daemon . sd , TEVENT_FD_READ ,
ctdb_accept_client , ctdb ) ;
2011-08-10 19:53:56 +04:00
if ( fde = = NULL ) {
ctdb_fatal ( ctdb , " Failed to add daemon socket to event loop " ) ;
}
2010-08-18 03:46:31 +04:00
tevent_fd_set_auto_close ( fde ) ;
2007-05-23 06:23:07 +04:00
2013-01-10 09:33:36 +04:00
/* Start the transport */
if ( ctdb - > methods - > start ( ctdb ) ! = 0 ) {
DEBUG ( DEBUG_ALERT , ( " transport failed to start! \n " ) ) ;
ctdb_fatal ( ctdb , " transport failed to start " ) ;
}
/* Recovery daemon and timed events are started from the
* callback , only after the setup event completes
* successfully .
*/
ctdb_set_runstate ( ctdb , CTDB_RUNSTATE_SETUP ) ;
2010-02-12 13:24:08 +03:00
ret = ctdb_event_script_callback ( ctdb ,
ctdb ,
ctdb_setup_event_callback ,
ctdb ,
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 ) ;
}
2014-06-10 11:00:38 +04:00
lockdown_memory ( ctdb - > valgrinding ) ;
2014-06-06 09:08:22 +04:00
2007-09-21 06:24:02 +04:00
/* go into a wait loop to allow other nodes to complete */
2015-10-26 08:50:09 +03:00
tevent_loop_wait ( ctdb - > ev ) ;
2007-09-21 06:24:02 +04:00
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 ;
2014-10-21 04:53:29 +04:00
hdr - > ctdb_version = CTDB_PROTOCOL ;
2007-04-28 12:50:32 +04:00
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 ;
2015-10-29 08:42:05 +03:00
struct ctdb_req_control_old * 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 ;
2015-10-29 08:44:08 +03:00
struct ctdb_reply_control_old * r ;
2007-04-26 16:27:49 +04:00
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 */
2015-10-29 08:44:08 +03:00
len = offsetof ( struct ctdb_reply_control_old , 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 ,
2015-10-29 08:44:08 +03:00
struct ctdb_reply_control_old ) ;
2007-04-28 12:50:32 +04:00
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 ,
2015-10-29 08:42:05 +03:00
struct ctdb_req_control_old * c )
2007-04-26 16:27:49 +04:00
{
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 ;
} ;
2015-10-26 08:50:09 +03:00
static void ctdb_local_message_trigger ( struct tevent_context * ev ,
struct tevent_timer * te ,
2007-06-07 16:06:19 +04:00
struct timeval t , void * private_data )
{
2015-04-08 07:38:26 +03:00
struct ctdb_local_message * m = talloc_get_type (
private_data , struct ctdb_local_message ) ;
2007-06-07 16:06:19 +04:00
2015-04-08 07:38:26 +03:00
srvid_dispatch ( m - > ctdb - > srv , m - > srvid , CTDB_SRVID_ALL , m - > data ) ;
2007-06-07 16:06:19 +04:00
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 */
2015-10-26 08:50:09 +03:00
tevent_add_timer ( ctdb - > ev , m , timeval_zero ( ) ,
ctdb_local_message_trigger , m ) ;
2007-06-07 16:06:19 +04:00
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 )
{
2015-10-29 08:36:30 +03:00
struct ctdb_req_message_old * r ;
2007-06-07 16:06:19 +04:00
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 ) ;
}
2015-10-29 08:36:30 +03:00
len = offsetof ( struct ctdb_req_message_old , data ) + data . dsize ;
2007-06-07 16:06:19 +04:00
r = ctdb_transport_allocate ( ctdb , ctdb , CTDB_REQ_MESSAGE , len ,
2015-10-29 08:36:30 +03:00
struct ctdb_req_message_old ) ;
2007-06-07 16:06:19 +04:00
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 )
{
2015-10-28 09:43:20 +03:00
struct ctdb_notify_data_old * notify = ( struct ctdb_notify_data_old * ) indata . dptr ;
2015-03-17 06:30:18 +03:00
struct ctdb_client * client = reqid_find ( ctdb - > idr , client_id , struct ctdb_client ) ;
2009-10-23 08:24:51 +04:00
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
2015-10-28 09:43:20 +03:00
if ( indata . dsize < offsetof ( struct ctdb_notify_data_old , notify_data ) ) {
2009-10-23 08:24:51 +04:00
DEBUG ( DEBUG_ERR , ( __location__ " Too little data in control : %d \n " , ( int ) indata . dsize ) ) ;
return - 1 ;
}
2015-10-28 09:43:20 +03:00
if ( indata . dsize ! = ( notify - > len + offsetof ( struct ctdb_notify_data_old , 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_notify_data_old , notify_data ) ) ) ) ;
2009-10-23 08:24:51 +04:00
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 )
{
2015-10-28 09:47:03 +03:00
uint64_t srvid = * ( uint64_t * ) indata . dptr ;
2015-03-17 06:30:18 +03:00
struct ctdb_client * client = reqid_find ( ctdb - > idr , client_id , struct ctdb_client ) ;
2009-10-23 08:24:51 +04:00
struct ctdb_client_notify_list * nl ;
2015-10-28 09:47:03 +03:00
DEBUG ( DEBUG_INFO , ( " Deregister srvid %llu for client %d \n " , ( unsigned long long ) 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 ) {
2015-10-28 09:47:03 +03:00
if ( nl - > srvid = = srvid ) {
2009-10-23 08:24:51 +04:00
break ;
}
}
if ( nl = = NULL ) {
2015-10-28 09:47:03 +03:00
DEBUG ( DEBUG_ERR , ( __location__ " No notification for srvid:%llu found for this client \n " , ( unsigned long long ) srvid ) ) ;
2009-10-23 08:24:51 +04:00
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 ) ;
}
2013-06-19 04:58:14 +04:00
2015-02-20 13:19:01 +03:00
int ctdb_control_getnodesfile ( struct ctdb_context * ctdb , uint32_t opcode , TDB_DATA indata , TDB_DATA * outdata )
{
2015-10-29 09:22:48 +03:00
struct ctdb_node_map_old * node_map = NULL ;
2015-02-20 13:19:01 +03:00
CHECK_CONTROL_DATA_SIZE ( 0 ) ;
node_map = ctdb_read_nodes_file ( ctdb , ctdb - > nodes_file ) ;
if ( node_map = = NULL ) {
DEBUG ( DEBUG_ERR , ( " Failed to read nodes file \n " ) ) ;
return - 1 ;
}
outdata - > dptr = ( unsigned char * ) node_map ;
outdata - > dsize = talloc_get_size ( outdata - > dptr ) ;
return 0 ;
}
2013-06-19 04:58:14 +04:00
void ctdb_shutdown_sequence ( struct ctdb_context * ctdb , int exit_code )
{
2013-06-22 09:44:28 +04:00
if ( ctdb - > runstate = = CTDB_RUNSTATE_SHUTDOWN ) {
DEBUG ( DEBUG_NOTICE , ( " Already shutting down so will not proceed. \n " ) ) ;
return ;
}
2013-06-19 04:58:14 +04:00
DEBUG ( DEBUG_NOTICE , ( " Shutdown sequence commencing. \n " ) ) ;
ctdb_set_runstate ( ctdb , CTDB_RUNSTATE_SHUTDOWN ) ;
ctdb_stop_recoverd ( ctdb ) ;
ctdb_stop_keepalive ( ctdb ) ;
ctdb_stop_monitoring ( ctdb ) ;
ctdb_release_all_ips ( ctdb ) ;
ctdb_event_script ( ctdb , CTDB_EVENT_SHUTDOWN ) ;
if ( ctdb - > methods ! = NULL ) {
ctdb - > methods - > shutdown ( ctdb ) ;
}
DEBUG ( DEBUG_NOTICE , ( " Shutdown sequence complete, exiting. \n " ) ) ;
exit ( exit_code ) ;
}