2006-11-27 13:38:13 +03:00
/*
2006-11-28 09:56:10 +03:00
ctdb main protocol code
2006-11-27 13:38:13 +03:00
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 ,
2006-11-27 13:38:13 +03: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/>.
2006-11-27 13:38:13 +03:00
*/
# include "includes.h"
2007-01-23 03:38:45 +03:00
# include "lib/tdb/include/tdb.h"
2006-11-27 13:38:13 +03:00
# include "lib/events/events.h"
2007-01-23 03:38:45 +03:00
# include "lib/util/dlinklist.h"
2006-11-27 13:38:13 +03:00
# include "system/network.h"
# include "system/filesys.h"
2007-01-23 03:38:45 +03:00
# include "../include/ctdb_private.h"
2006-11-27 13:38:13 +03:00
/*
choose the transport we will use
*/
int ctdb_set_transport ( struct ctdb_context * ctdb , const char * transport )
{
2007-04-20 16:26:19 +04:00
ctdb - > transport = talloc_strdup ( ctdb , transport ) ;
return 0 ;
2006-11-27 13:38:13 +03:00
}
2007-06-02 05:36:42 +04:00
/*
choose the recovery lock file
*/
int ctdb_set_recovery_lock_file ( struct ctdb_context * ctdb , const char * file )
{
ctdb - > recovery_lock_file = talloc_strdup ( ctdb , file ) ;
return 0 ;
}
2007-04-30 00:42:23 +04:00
/*
choose the logfile location
*/
int ctdb_set_logfile ( struct ctdb_context * ctdb , const char * logfile )
{
ctdb - > logfile = talloc_strdup ( ctdb , logfile ) ;
2007-06-01 13:05:41 +04:00
if ( ctdb - > logfile ! = NULL & & strcmp ( logfile , " - " ) ! = 0 ) {
2007-04-30 00:42:23 +04:00
int fd ;
fd = open ( ctdb - > logfile , O_WRONLY | O_APPEND | O_CREAT , 0666 ) ;
if ( fd = = - 1 ) {
2007-06-03 12:59:27 +04:00
printf ( " Failed to open logfile %s \n " , ctdb - > logfile ) ;
2007-04-30 00:42:23 +04:00
abort ( ) ;
}
2007-06-03 12:59:27 +04:00
close ( 1 ) ;
close ( 2 ) ;
2007-04-30 00:42:23 +04:00
if ( fd ! = 1 ) {
dup2 ( fd , 1 ) ;
close ( fd ) ;
}
2007-05-29 06:49:25 +04:00
/* also catch stderr of subcommands to the log file */
dup2 ( 1 , 2 ) ;
2007-04-30 00:42:23 +04:00
}
return 0 ;
}
2006-11-27 13:38:13 +03:00
2007-04-18 18:36:22 +04:00
/*
set the directory for the local databases
*/
2007-04-19 03:14:25 +04:00
int ctdb_set_tdb_dir ( struct ctdb_context * ctdb , const char * dir )
2007-04-18 18:36:22 +04:00
{
2007-05-01 00:34:55 +04:00
ctdb - > db_directory = talloc_strdup ( ctdb , dir ) ;
2007-04-19 03:14:25 +04:00
if ( ctdb - > db_directory = = NULL ) {
return - 1 ;
}
return 0 ;
2007-04-18 18:36:22 +04:00
}
2007-09-21 06:24:02 +04:00
/*
set the directory for the persistent databases
*/
int ctdb_set_tdb_dir_persistent ( struct ctdb_context * ctdb , const char * dir )
{
ctdb - > db_directory_persistent = talloc_strdup ( ctdb , dir ) ;
if ( ctdb - > db_directory_persistent = = NULL ) {
return - 1 ;
}
return 0 ;
}
2006-11-27 13:38:13 +03:00
/*
add a node to the list of active nodes
*/
static int ctdb_add_node ( struct ctdb_context * ctdb , char * nstr )
{
2006-11-28 09:56:10 +03:00
struct ctdb_node * node , * * nodep ;
nodep = talloc_realloc ( ctdb , ctdb - > nodes , struct ctdb_node * , ctdb - > num_nodes + 1 ) ;
CTDB_NO_MEMORY ( ctdb , nodep ) ;
ctdb - > nodes = nodep ;
nodep = & ctdb - > nodes [ ctdb - > num_nodes ] ;
( * nodep ) = talloc_zero ( ctdb - > nodes , struct ctdb_node ) ;
CTDB_NO_MEMORY ( ctdb , * nodep ) ;
node = * nodep ;
2006-11-27 13:38:13 +03:00
if ( ctdb_parse_address ( ctdb , node , nstr , & node - > address ) ! = 0 ) {
return - 1 ;
}
node - > ctdb = ctdb ;
2006-11-28 06:15:46 +03:00
node - > name = talloc_asprintf ( node , " %s:%u " ,
node - > address . address ,
node - > address . port ) ;
2007-05-18 17:23:36 +04:00
/* this assumes that the nodes are kept in sorted order, and no gaps */
2007-09-04 03:50:07 +04:00
node - > pnn = ctdb - > num_nodes ;
2006-11-27 13:38:13 +03:00
2007-06-07 09:18:55 +04:00
/* nodes start out disconnected */
node - > flags | = NODE_FLAGS_DISCONNECTED ;
2007-05-01 00:34:55 +04:00
if ( ctdb - > address . address & &
ctdb_same_address ( & ctdb - > address , & node - > address ) ) {
2007-09-04 04:06:36 +04:00
ctdb - > pnn = node - > pnn ;
2007-06-07 09:18:55 +04:00
node - > flags & = ~ NODE_FLAGS_DISCONNECTED ;
2006-11-28 09:56:10 +03:00
}
ctdb - > num_nodes + + ;
2007-05-18 13:19:35 +04:00
node - > dead_count = 0 ;
2006-11-28 09:56:10 +03:00
2006-11-27 13:38:13 +03:00
return 0 ;
}
/*
setup the node list from a file
*/
int ctdb_set_nlist ( struct ctdb_context * ctdb , const char * nlist )
{
char * * lines ;
int nlines ;
int i ;
2007-05-23 08:35:19 +04:00
talloc_free ( ctdb - > node_list_file ) ;
ctdb - > node_list_file = talloc_strdup ( ctdb , nlist ) ;
2006-11-27 13:38:13 +03:00
lines = file_lines_load ( nlist , & nlines , ctdb ) ;
if ( lines = = NULL ) {
ctdb_set_error ( ctdb , " Failed to load nlist '%s' \n " , nlist ) ;
return - 1 ;
}
2007-05-29 10:23:47 +04:00
while ( nlines > 0 & & strcmp ( lines [ nlines - 1 ] , " " ) = = 0 ) {
nlines - - ;
}
2006-11-27 13:38:13 +03:00
for ( i = 0 ; i < nlines ; i + + ) {
if ( ctdb_add_node ( ctdb , lines [ i ] ) ! = 0 ) {
talloc_free ( lines ) ;
return - 1 ;
}
}
2007-05-10 01:55:46 +04:00
/* initialize the vnn mapping table now that we have num_nodes setup */
2007-05-10 02:13:19 +04:00
ctdb - > vnn_map = talloc ( ctdb , struct ctdb_vnn_map ) ;
CTDB_NO_MEMORY ( ctdb , ctdb - > vnn_map ) ;
2007-08-22 06:38:31 +04:00
ctdb - > vnn_map - > generation = INVALID_GENERATION ;
2007-05-10 01:55:46 +04:00
ctdb - > vnn_map - > size = ctdb - > num_nodes ;
2007-05-10 02:13:19 +04:00
ctdb - > vnn_map - > map = talloc_array ( ctdb - > vnn_map , uint32_t , ctdb - > vnn_map - > size ) ;
CTDB_NO_MEMORY ( ctdb , ctdb - > vnn_map - > map ) ;
for ( i = 0 ; i < ctdb - > vnn_map - > size ; i + + ) {
ctdb - > vnn_map - > map [ i ] = i ;
2007-05-10 01:55:46 +04:00
}
2006-11-27 13:38:13 +03:00
talloc_free ( lines ) ;
return 0 ;
}
2007-05-25 11:04:13 +04:00
2006-11-27 13:38:13 +03:00
/*
setup the local node address
*/
int ctdb_set_address ( struct ctdb_context * ctdb , const char * address )
{
2006-11-28 09:56:10 +03:00
if ( ctdb_parse_address ( ctdb , ctdb , address , & ctdb - > address ) ! = 0 ) {
return - 1 ;
}
ctdb - > name = talloc_asprintf ( ctdb , " %s:%u " ,
ctdb - > address . address ,
ctdb - > address . port ) ;
return 0 ;
2006-11-27 13:38:13 +03:00
}
2007-04-26 16:27:49 +04:00
2007-05-17 17:23:41 +04:00
/*
2007-06-18 21:54:06 +04:00
return the number of active nodes
2007-05-17 17:23:41 +04:00
*/
2007-06-18 21:54:06 +04:00
uint32_t ctdb_get_num_active_nodes ( struct ctdb_context * ctdb )
2007-05-17 17:23:41 +04:00
{
int i ;
uint32_t count = 0 ;
for ( i = 0 ; i < ctdb - > vnn_map - > size ; i + + ) {
2007-06-05 11:43:19 +04:00
struct ctdb_node * node = ctdb - > nodes [ ctdb - > vnn_map - > map [ i ] ] ;
2007-06-18 21:54:06 +04:00
if ( ! ( node - > flags & NODE_FLAGS_INACTIVE ) ) {
2007-05-17 17:23:41 +04:00
count + + ;
}
}
return count ;
}
2007-02-09 04:45:58 +03:00
2006-11-27 13:38:13 +03:00
/*
2007-05-19 07:45:24 +04:00
called when we need to process a packet . This can be a requeued packet
after a lockwait , or a real packet from another node
2006-11-27 13:38:13 +03:00
*/
2007-05-19 07:45:24 +04:00
void ctdb_input_pkt ( struct ctdb_context * ctdb , struct ctdb_req_header * hdr )
2006-11-27 13:38:13 +03:00
{
2007-04-18 05:20:24 +04:00
TALLOC_CTX * tmp_ctx ;
/* place the packet as a child of the 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 only free the tmp_ctx */
tmp_ctx = talloc_new ( ctdb ) ;
talloc_steal ( tmp_ctx , hdr ) ;
2007-02-07 05:26:07 +03:00
2007-05-23 14:15:09 +04:00
DEBUG ( 3 , ( __location__ " ctdb request %u of type %u length %u from "
" node %u to %u \n " , hdr - > reqid , hdr - > operation , hdr - > length ,
2007-04-17 19:59:39 +04:00
hdr - > srcnode , hdr - > destnode ) ) ;
2007-04-17 16:13:06 +04:00
2006-12-01 07:45:24 +03:00
switch ( hdr - > operation ) {
case CTDB_REQ_CALL :
2007-05-12 13:54:40 +04:00
case CTDB_REPLY_CALL :
case CTDB_REQ_DMASTER :
case CTDB_REPLY_DMASTER :
2007-08-22 06:53:24 +04:00
/* we dont allow these calls when banned */
2007-09-04 04:06:36 +04:00
if ( ctdb - > nodes [ ctdb - > pnn ] - > flags & NODE_FLAGS_BANNED ) {
2007-08-22 06:53:24 +04:00
DEBUG ( 0 , ( __location__ " ctdb operation %u "
" request %u "
" length %u from node %u to %u while node "
" is banned \n " ,
hdr - > operation , hdr - > reqid ,
hdr - > length ,
hdr - > srcnode , hdr - > destnode ) ) ;
goto done ;
}
2007-05-12 13:54:40 +04:00
/* for ctdb_call inter-node operations verify that the
remote node that sent us the call is running in the
same generation instance as this node
2007-04-27 19:48:31 +04:00
*/
if ( ctdb - > vnn_map - > generation ! = hdr - > generation ) {
2007-07-11 02:41:29 +04:00
DEBUG ( 0 , ( __location__ " ctdb operation %u "
" request %u "
2007-05-23 14:15:09 +04:00
" length %u from node %u to %u had an "
" invalid generation id:%u while our "
" generation id is:%u \n " ,
2007-07-11 02:41:29 +04:00
hdr - > operation , hdr - > reqid ,
hdr - > length ,
2007-05-23 14:15:09 +04:00
hdr - > srcnode , hdr - > destnode ,
hdr - > generation , ctdb - > vnn_map - > generation ) ) ;
2007-05-12 13:54:40 +04:00
goto done ;
2007-04-29 16:51:56 +04:00
}
2007-05-12 13:54:40 +04:00
}
2007-04-29 16:51:56 +04:00
2007-05-12 13:54:40 +04:00
switch ( hdr - > operation ) {
case CTDB_REQ_CALL :
2007-05-29 06:16:59 +04:00
ctdb - > statistics . node . req_call + + ;
2006-12-01 07:45:24 +03:00
ctdb_request_call ( ctdb , hdr ) ;
break ;
case CTDB_REPLY_CALL :
2007-05-29 06:16:59 +04:00
ctdb - > statistics . node . reply_call + + ;
2006-12-01 07:45:24 +03:00
ctdb_reply_call ( ctdb , hdr ) ;
break ;
2006-12-18 06:27:20 +03:00
case CTDB_REPLY_ERROR :
2007-05-29 06:16:59 +04:00
ctdb - > statistics . node . reply_error + + ;
2006-12-18 06:27:20 +03:00
ctdb_reply_error ( ctdb , hdr ) ;
break ;
2006-12-18 08:01:11 +03:00
case CTDB_REQ_DMASTER :
2007-05-29 06:16:59 +04:00
ctdb - > statistics . node . req_dmaster + + ;
2006-12-18 08:01:11 +03:00
ctdb_request_dmaster ( ctdb , hdr ) ;
break ;
case CTDB_REPLY_DMASTER :
2007-05-29 06:16:59 +04:00
ctdb - > statistics . node . reply_dmaster + + ;
2006-12-18 08:01:11 +03:00
ctdb_reply_dmaster ( ctdb , hdr ) ;
break ;
2007-02-09 01:42:04 +03:00
case CTDB_REQ_MESSAGE :
2007-05-29 06:16:59 +04:00
ctdb - > statistics . node . req_message + + ;
2007-02-09 01:42:04 +03:00
ctdb_request_message ( ctdb , hdr ) ;
break ;
2007-04-26 16:27:49 +04:00
case CTDB_REQ_CONTROL :
2007-05-29 06:16:59 +04:00
ctdb - > statistics . node . req_control + + ;
2007-04-26 16:27:49 +04:00
ctdb_request_control ( ctdb , hdr ) ;
break ;
case CTDB_REPLY_CONTROL :
2007-05-29 06:16:59 +04:00
ctdb - > statistics . node . reply_control + + ;
2007-04-26 16:27:49 +04:00
ctdb_reply_control ( ctdb , hdr ) ;
break ;
2007-05-18 13:19:35 +04:00
case CTDB_REQ_KEEPALIVE :
2007-05-29 06:16:59 +04:00
ctdb - > statistics . keepalive_packets_recv + + ;
2007-05-18 13:19:35 +04:00
break ;
2006-12-01 07:45:24 +03:00
default :
2007-05-23 14:15:09 +04:00
DEBUG ( 0 , ( " %s: Packet with unknown operation %u \n " ,
2007-04-17 16:13:06 +04:00
__location__ , hdr - > operation ) ) ;
2006-12-01 07:45:24 +03:00
break ;
}
2007-04-18 05:20:24 +04:00
done :
talloc_free ( tmp_ctx ) ;
2006-11-27 13:38:13 +03:00
}
2007-05-19 07:45:24 +04:00
2006-11-28 03:51:33 +03:00
/*
2006-11-28 09:56:10 +03:00
called by the transport layer when a node is dead
2006-11-28 03:51:33 +03:00
*/
2007-05-19 10:59:10 +04:00
void ctdb_node_dead ( struct ctdb_node * node )
2006-11-28 03:51:33 +03:00
{
2007-06-07 09:18:55 +04:00
if ( node - > flags & NODE_FLAGS_DISCONNECTED ) {
2007-05-30 08:35:22 +04:00
DEBUG ( 1 , ( " %s: node %s is already marked disconnected: %u connected \n " ,
node - > ctdb - > name , node - > name ,
node - > ctdb - > num_connected ) ) ;
return ;
}
2006-12-01 00:58:08 +03:00
node - > ctdb - > num_connected - - ;
2007-06-07 09:18:55 +04:00
node - > flags | = NODE_FLAGS_DISCONNECTED ;
2007-05-19 08:04:48 +04:00
node - > rx_cnt = 0 ;
2007-05-19 11:21:58 +04:00
node - > dead_count = 0 ;
2007-05-23 14:15:09 +04:00
DEBUG ( 1 , ( " %s: node %s is dead: %u connected \n " ,
2007-04-17 16:13:06 +04:00
node - > ctdb - > name , node - > name , node - > ctdb - > num_connected ) ) ;
2007-05-18 17:48:29 +04:00
ctdb_daemon_cancel_controls ( node - > ctdb , node ) ;
2006-11-28 03:51:33 +03:00
}
2006-11-28 06:15:46 +03:00
/*
2007-02-07 05:26:07 +03:00
called by the transport layer when a node is connected
2006-11-28 06:15:46 +03:00
*/
2007-05-19 11:21:58 +04:00
void ctdb_node_connected ( struct ctdb_node * node )
2006-11-28 06:15:46 +03:00
{
2007-06-07 09:18:55 +04:00
if ( ! ( node - > flags & NODE_FLAGS_DISCONNECTED ) ) {
2007-05-30 08:35:22 +04:00
DEBUG ( 1 , ( " %s: node %s is already marked connected: %u connected \n " ,
node - > ctdb - > name , node - > name ,
node - > ctdb - > num_connected ) ) ;
return ;
}
2006-12-01 00:58:08 +03:00
node - > ctdb - > num_connected + + ;
2007-05-19 11:21:58 +04:00
node - > dead_count = 0 ;
2007-06-07 09:18:55 +04:00
node - > flags & = ~ NODE_FLAGS_DISCONNECTED ;
2007-05-23 14:15:09 +04:00
DEBUG ( 1 , ( " %s: connected to %s - %u connected \n " ,
2007-04-17 16:13:06 +04:00
node - > ctdb - > name , node - > name , node - > ctdb - > num_connected ) ) ;
2006-12-01 00:58:08 +03:00
}
2007-04-20 11:58:37 +04:00
struct queue_next {
struct ctdb_context * ctdb ;
struct ctdb_req_header * hdr ;
} ;
/*
trigered when a deferred packet is due
*/
static void queue_next_trigger ( struct event_context * ev , struct timed_event * te ,
struct timeval t , void * private_data )
{
struct queue_next * q = talloc_get_type ( private_data , struct queue_next ) ;
2007-05-19 07:45:24 +04:00
ctdb_input_pkt ( q - > ctdb , q - > hdr ) ;
2007-05-23 14:06:37 +04:00
talloc_free ( q ) ;
2007-04-20 11:58:37 +04:00
}
/*
defer a packet , so it is processed on the next event loop
this is used for sending packets to ourselves
*/
static void ctdb_defer_packet ( struct ctdb_context * ctdb , struct ctdb_req_header * hdr )
{
struct queue_next * q ;
q = talloc ( ctdb , struct queue_next ) ;
if ( q = = NULL ) {
DEBUG ( 0 , ( __location__ " Failed to allocate deferred packet \n " ) ) ;
return ;
}
q - > ctdb = ctdb ;
q - > hdr = talloc_memdup ( ctdb , hdr , hdr - > length ) ;
if ( q - > hdr = = NULL ) {
DEBUG ( 0 , ( " Error copying deferred packet to self \n " ) ) ;
return ;
}
2007-04-22 16:26:45 +04:00
#if 0
/* use this to put packets directly into our recv function */
2007-05-19 07:45:24 +04:00
ctdb_input_pkt ( q - > ctdb , q - > hdr ) ;
2007-04-22 16:26:45 +04:00
# else
2007-04-20 11:58:37 +04:00
event_add_timed ( ctdb - > ev , q , timeval_zero ( ) , queue_next_trigger , q ) ;
2007-04-22 16:26:45 +04:00
# endif
2007-04-20 11:58:37 +04:00
}
2007-04-30 17:31:40 +04:00
/*
broadcast a packet to all nodes
*/
2007-06-09 15:58:50 +04:00
static void ctdb_broadcast_packet_all ( struct ctdb_context * ctdb ,
struct ctdb_req_header * hdr )
2007-04-30 17:31:40 +04:00
{
int i ;
2007-06-02 07:16:11 +04:00
for ( i = 0 ; i < ctdb - > num_nodes ; i + + ) {
2007-09-04 03:50:07 +04:00
hdr - > destnode = ctdb - > nodes [ i ] - > pnn ;
2007-04-30 17:31:40 +04:00
ctdb_queue_packet ( ctdb , hdr ) ;
}
}
2007-05-05 07:17:26 +04:00
/*
broadcast a packet to all nodes in the current vnnmap
*/
2007-06-09 15:58:50 +04:00
static void ctdb_broadcast_packet_vnnmap ( struct ctdb_context * ctdb ,
struct ctdb_req_header * hdr )
2007-05-05 07:17:26 +04:00
{
int i ;
for ( i = 0 ; i < ctdb - > vnn_map - > size ; i + + ) {
hdr - > destnode = ctdb - > vnn_map - > map [ i ] ;
ctdb_queue_packet ( ctdb , hdr ) ;
}
}
2007-06-09 15:58:50 +04:00
/*
broadcast a packet to all connected nodes
*/
static void ctdb_broadcast_packet_connected ( struct ctdb_context * ctdb ,
struct ctdb_req_header * hdr )
{
int i ;
for ( i = 0 ; i < ctdb - > num_nodes ; i + + ) {
if ( ! ( ctdb - > nodes [ i ] - > flags & NODE_FLAGS_DISCONNECTED ) ) {
2007-09-04 03:50:07 +04:00
hdr - > destnode = ctdb - > nodes [ i ] - > pnn ;
2007-06-09 15:58:50 +04:00
ctdb_queue_packet ( ctdb , hdr ) ;
}
}
}
2007-02-09 01:42:04 +03:00
/*
queue a packet or die
*/
void ctdb_queue_packet ( struct ctdb_context * ctdb , struct ctdb_req_header * hdr )
{
struct ctdb_node * node ;
2007-04-30 17:31:40 +04:00
2007-05-05 07:17:26 +04:00
switch ( hdr - > destnode ) {
case CTDB_BROADCAST_ALL :
ctdb_broadcast_packet_all ( ctdb , hdr ) ;
return ;
case CTDB_BROADCAST_VNNMAP :
ctdb_broadcast_packet_vnnmap ( ctdb , hdr ) ;
2007-04-30 17:31:40 +04:00
return ;
2007-06-09 15:58:50 +04:00
case CTDB_BROADCAST_CONNECTED :
ctdb_broadcast_packet_connected ( ctdb , hdr ) ;
return ;
2007-04-30 17:31:40 +04:00
}
2007-05-29 06:16:59 +04:00
ctdb - > statistics . node_packets_sent + + ;
2007-04-26 17:38:33 +04:00
2007-09-04 04:09:58 +04:00
if ( ! ctdb_validate_pnn ( ctdb , hdr - > destnode ) ) {
2007-04-26 17:38:33 +04:00
DEBUG ( 0 , ( __location__ " cant send to node %u that does not exist \n " ,
hdr - > destnode ) ) ;
return ;
}
2007-02-09 01:42:04 +03:00
node = ctdb - > nodes [ hdr - > destnode ] ;
2007-04-26 17:38:33 +04:00
2007-09-04 04:06:36 +04:00
if ( hdr - > destnode = = ctdb - > pnn ) {
2007-04-20 11:58:37 +04:00
ctdb_defer_packet ( ctdb , hdr ) ;
2007-05-19 04:27:17 +04:00
} else {
node - > tx_cnt + + ;
if ( ctdb - > methods - > queue_pkt ( node , ( uint8_t * ) hdr , hdr - > length ) ! = 0 ) {
ctdb_fatal ( ctdb , " Unable to queue packet \n " ) ;
}
2007-02-09 01:42:04 +03:00
}
}