4 Copyright (C) Andrew Tridgell 2007
5 Copyright (C) Ronnie Sahlberg 2007
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, see <http://www.gnu.org/licenses/>.
22 #include "system/network.h"
23 #include "system/filesys.h"
24 #include "system/locale.h"
30 #include "lib/tdb_wrap/tdb_wrap.h"
31 #include "lib/util/dlinklist.h"
32 #include "lib/util/time.h"
33 #include "lib/util/debug.h"
34 #include "lib/util/samba_util.h"
36 #include "ctdb_private.h"
37 #include "ctdb_client.h"
39 #include "common/reqid.h"
40 #include "common/system.h"
41 #include "common/common.h"
42 #include "common/logging.h"
45 allocate a packet for use in client<->daemon communication
47 struct ctdb_req_header
*_ctdbd_allocate_pkt(struct ctdb_context
*ctdb
,
49 enum ctdb_operation operation
,
50 size_t length
, size_t slength
,
54 struct ctdb_req_header
*hdr
;
56 length
= MAX(length
, slength
);
57 size
= (length
+(CTDB_DS_ALIGNMENT
-1)) & ~(CTDB_DS_ALIGNMENT
-1);
59 hdr
= (struct ctdb_req_header
*)talloc_zero_size(mem_ctx
, size
);
61 DEBUG(DEBUG_ERR
,("Unable to allocate packet for operation %u of length %u\n",
62 operation
, (unsigned)length
));
65 talloc_set_name_const(hdr
, type
);
67 hdr
->operation
= operation
;
68 hdr
->ctdb_magic
= CTDB_MAGIC
;
69 hdr
->ctdb_version
= CTDB_PROTOCOL
;
70 hdr
->srcnode
= ctdb
->pnn
;
72 hdr
->generation
= ctdb
->vnn_map
->generation
;
79 local version of ctdb_call
81 int ctdb_call_local(struct ctdb_db_context
*ctdb_db
, struct ctdb_call
*call
,
82 struct ctdb_ltdb_header
*header
, TALLOC_CTX
*mem_ctx
,
83 TDB_DATA
*data
, bool updatetdb
)
85 struct ctdb_call_info
*c
;
86 struct ctdb_registered_call
*fn
;
87 struct ctdb_context
*ctdb
= ctdb_db
->ctdb
;
89 c
= talloc_zero(mem_ctx
, struct ctdb_call_info
);
90 CTDB_NO_MEMORY(ctdb
, c
);
93 c
->call_data
= &call
->call_data
;
94 c
->record_data
.dptr
= talloc_memdup(c
, data
->dptr
, data
->dsize
);
95 c
->record_data
.dsize
= data
->dsize
;
96 CTDB_NO_MEMORY(ctdb
, c
->record_data
.dptr
);
99 for (fn
=ctdb_db
->calls
;fn
;fn
=fn
->next
) {
100 if (fn
->id
== (uint32_t)call
->call_id
) {
105 ctdb_set_error(ctdb
, "Unknown call id %u\n", call
->call_id
);
110 if (fn
->fn(c
) != 0) {
111 ctdb_set_error(ctdb
, "ctdb_call %u failed\n", call
->call_id
);
116 /* we need to force the record to be written out if this was a remote access */
117 if (c
->new_data
== NULL
) {
118 c
->new_data
= &c
->record_data
;
121 if (c
->new_data
&& updatetdb
) {
122 /* XXX check that we always have the lock here? */
123 if (ctdb_ltdb_store(ctdb_db
, call
->key
, header
, *c
->new_data
) != 0) {
124 ctdb_set_error(ctdb
, "ctdb_call tdb_store failed\n");
131 call
->reply_data
= *c
->reply_data
;
133 talloc_steal(call
, call
->reply_data
.dptr
);
134 talloc_set_name_const(call
->reply_data
.dptr
, __location__
);
136 call
->reply_data
.dptr
= NULL
;
137 call
->reply_data
.dsize
= 0;
139 call
->status
= c
->status
;
148 queue a packet for sending from client to daemon
150 static int ctdb_client_queue_pkt(struct ctdb_context
*ctdb
, struct ctdb_req_header
*hdr
)
152 return ctdb_queue_send(ctdb
->daemon
.queue
, (uint8_t *)hdr
, hdr
->length
);
157 called when a CTDB_REPLY_CALL packet comes in in the client
159 This packet comes in response to a CTDB_REQ_CALL request packet. It
160 contains any reply data from the call
162 static void ctdb_client_reply_call(struct ctdb_context
*ctdb
, struct ctdb_req_header
*hdr
)
164 struct ctdb_reply_call_old
*c
= (struct ctdb_reply_call_old
*)hdr
;
165 struct ctdb_client_call_state
*state
;
167 state
= reqid_find(ctdb
->idr
, hdr
->reqid
, struct ctdb_client_call_state
);
169 DEBUG(DEBUG_ERR
,(__location__
" reqid %u not found\n", hdr
->reqid
));
173 if (hdr
->reqid
!= state
->reqid
) {
174 /* we found a record but it was the wrong one */
175 DEBUG(DEBUG_ERR
, ("Dropped client call reply with reqid:%u\n",hdr
->reqid
));
179 state
->call
->reply_data
.dptr
= c
->data
;
180 state
->call
->reply_data
.dsize
= c
->datalen
;
181 state
->call
->status
= c
->status
;
183 talloc_steal(state
, c
);
185 state
->state
= CTDB_CALL_DONE
;
187 if (state
->async
.fn
) {
188 state
->async
.fn(state
);
192 void ctdb_request_message(struct ctdb_context
*ctdb
,
193 struct ctdb_req_header
*hdr
)
195 struct ctdb_req_message_old
*c
= (struct ctdb_req_message_old
*)hdr
;
198 data
.dsize
= c
->datalen
;
199 data
.dptr
= talloc_memdup(c
, &c
->data
[0], c
->datalen
);
200 if (data
.dptr
== NULL
) {
201 DEBUG(DEBUG_ERR
, (__location__
" Memory allocation failure\n"));
205 srvid_dispatch(ctdb
->srv
, c
->srvid
, CTDB_SRVID_ALL
, data
);
208 static void ctdb_client_reply_control(struct ctdb_context
*ctdb
, struct ctdb_req_header
*hdr
);
211 this is called in the client, when data comes in from the daemon
213 void ctdb_client_read_cb(uint8_t *data
, size_t cnt
, void *args
)
215 struct ctdb_context
*ctdb
= talloc_get_type(args
, struct ctdb_context
);
216 struct ctdb_req_header
*hdr
= (struct ctdb_req_header
*)data
;
219 /* place the packet as a child of a tmp_ctx. We then use
220 talloc_free() below to free it. If any of the calls want
221 to keep it, then they will steal it somewhere else, and the
222 talloc_free() will be a no-op */
223 tmp_ctx
= talloc_new(ctdb
);
224 talloc_steal(tmp_ctx
, hdr
);
227 DEBUG(DEBUG_CRIT
,("Daemon has exited - shutting down client\n"));
231 if (cnt
< sizeof(*hdr
)) {
232 DEBUG(DEBUG_CRIT
,("Bad packet length %u in client\n", (unsigned)cnt
));
235 if (cnt
!= hdr
->length
) {
236 ctdb_set_error(ctdb
, "Bad header length %u expected %u in client\n",
237 (unsigned)hdr
->length
, (unsigned)cnt
);
241 if (hdr
->ctdb_magic
!= CTDB_MAGIC
) {
242 ctdb_set_error(ctdb
, "Non CTDB packet rejected in client\n");
246 if (hdr
->ctdb_version
!= CTDB_PROTOCOL
) {
247 ctdb_set_error(ctdb
, "Bad CTDB version 0x%x rejected in client\n", hdr
->ctdb_version
);
251 switch (hdr
->operation
) {
252 case CTDB_REPLY_CALL
:
253 ctdb_client_reply_call(ctdb
, hdr
);
256 case CTDB_REQ_MESSAGE
:
257 ctdb_request_message(ctdb
, hdr
);
260 case CTDB_REPLY_CONTROL
:
261 ctdb_client_reply_control(ctdb
, hdr
);
265 DEBUG(DEBUG_CRIT
,("bogus operation code:%u\n",hdr
->operation
));
269 talloc_free(tmp_ctx
);
273 connect to a unix domain socket
275 int ctdb_socket_connect(struct ctdb_context
*ctdb
)
277 struct sockaddr_un addr
;
280 memset(&addr
, 0, sizeof(addr
));
281 addr
.sun_family
= AF_UNIX
;
282 strncpy(addr
.sun_path
, ctdb
->daemon
.name
, sizeof(addr
.sun_path
)-1);
284 ctdb
->daemon
.sd
= socket(AF_UNIX
, SOCK_STREAM
, 0);
285 if (ctdb
->daemon
.sd
== -1) {
286 DEBUG(DEBUG_ERR
,(__location__
" Failed to open client socket. Errno:%s(%d)\n", strerror(errno
), errno
));
290 if (connect(ctdb
->daemon
.sd
, (struct sockaddr
*)&addr
, sizeof(addr
)) == -1) {
293 "Failed to connect client socket to daemon (%s)\n",
295 close(ctdb
->daemon
.sd
);
296 ctdb
->daemon
.sd
= -1;
300 ret
= set_blocking(ctdb
->daemon
.sd
, false);
304 " failed to set socket non-blocking (%s)\n",
306 close(ctdb
->daemon
.sd
);
307 ctdb
->daemon
.sd
= -1;
311 set_close_on_exec(ctdb
->daemon
.sd
);
313 ctdb
->daemon
.queue
= ctdb_queue_setup(ctdb
, ctdb
, ctdb
->daemon
.sd
,
315 ctdb_client_read_cb
, ctdb
, "to-ctdbd");
320 struct ctdb_record_handle
{
321 struct ctdb_db_context
*ctdb_db
;
324 struct ctdb_ltdb_header header
;
329 make a recv call to the local ctdb daemon - called from client context
331 This is called when the program wants to wait for a ctdb_call to complete and get the
332 results. This call will block unless the call has already completed.
334 int ctdb_call_recv(struct ctdb_client_call_state
*state
, struct ctdb_call
*call
)
340 while (state
->state
< CTDB_CALL_DONE
) {
341 tevent_loop_once(state
->ctdb_db
->ctdb
->ev
);
343 if (state
->state
!= CTDB_CALL_DONE
) {
344 DEBUG(DEBUG_ERR
,(__location__
" ctdb_call_recv failed\n"));
349 if (state
->call
->reply_data
.dsize
) {
350 call
->reply_data
.dptr
= talloc_memdup(state
->ctdb_db
,
351 state
->call
->reply_data
.dptr
,
352 state
->call
->reply_data
.dsize
);
353 call
->reply_data
.dsize
= state
->call
->reply_data
.dsize
;
355 call
->reply_data
.dptr
= NULL
;
356 call
->reply_data
.dsize
= 0;
358 call
->status
= state
->call
->status
;
368 destroy a ctdb_call in client
370 static int ctdb_client_call_destructor(struct ctdb_client_call_state
*state
)
372 reqid_remove(state
->ctdb_db
->ctdb
->idr
, state
->reqid
);
377 construct an event driven local ctdb_call
379 this is used so that locally processed ctdb_call requests are processed
380 in an event driven manner
382 static struct ctdb_client_call_state
*ctdb_client_call_local_send(struct ctdb_db_context
*ctdb_db
,
383 struct ctdb_call
*call
,
384 struct ctdb_ltdb_header
*header
,
387 struct ctdb_client_call_state
*state
;
388 struct ctdb_context
*ctdb
= ctdb_db
->ctdb
;
391 state
= talloc_zero(ctdb_db
, struct ctdb_client_call_state
);
392 CTDB_NO_MEMORY_NULL(ctdb
, state
);
393 state
->call
= talloc_zero(state
, struct ctdb_call
);
394 CTDB_NO_MEMORY_NULL(ctdb
, state
->call
);
396 talloc_steal(state
, data
->dptr
);
398 state
->state
= CTDB_CALL_DONE
;
399 *(state
->call
) = *call
;
400 state
->ctdb_db
= ctdb_db
;
402 ret
= ctdb_call_local(ctdb_db
, state
->call
, header
, state
, data
, true);
404 DEBUG(DEBUG_DEBUG
,("ctdb_call_local() failed, ignoring return code %d\n", ret
));
411 make a ctdb call to the local daemon - async send. Called from client context.
413 This constructs a ctdb_call request and queues it for processing.
414 This call never blocks.
416 struct ctdb_client_call_state
*ctdb_call_send(struct ctdb_db_context
*ctdb_db
,
417 struct ctdb_call
*call
)
419 struct ctdb_client_call_state
*state
;
420 struct ctdb_context
*ctdb
= ctdb_db
->ctdb
;
421 struct ctdb_ltdb_header header
;
425 struct ctdb_req_call_old
*c
;
427 /* if the domain socket is not yet open, open it */
428 if (ctdb
->daemon
.sd
==-1) {
429 ctdb_socket_connect(ctdb
);
432 ret
= ctdb_ltdb_lock(ctdb_db
, call
->key
);
434 DEBUG(DEBUG_ERR
,(__location__
" Failed to get chainlock\n"));
438 ret
= ctdb_ltdb_fetch(ctdb_db
, call
->key
, &header
, ctdb_db
, &data
);
440 if ((call
->flags
& CTDB_IMMEDIATE_MIGRATION
) && (header
.flags
& CTDB_REC_RO_HAVE_DELEGATIONS
)) {
444 if (ret
== 0 && header
.dmaster
== ctdb
->pnn
) {
445 state
= ctdb_client_call_local_send(ctdb_db
, call
, &header
, &data
);
446 talloc_free(data
.dptr
);
447 ctdb_ltdb_unlock(ctdb_db
, call
->key
);
451 ctdb_ltdb_unlock(ctdb_db
, call
->key
);
452 talloc_free(data
.dptr
);
454 state
= talloc_zero(ctdb_db
, struct ctdb_client_call_state
);
456 DEBUG(DEBUG_ERR
, (__location__
" failed to allocate state\n"));
459 state
->call
= talloc_zero(state
, struct ctdb_call
);
460 if (state
->call
== NULL
) {
461 DEBUG(DEBUG_ERR
, (__location__
" failed to allocate state->call\n"));
465 len
= offsetof(struct ctdb_req_call_old
, data
) + call
->key
.dsize
+ call
->call_data
.dsize
;
466 c
= ctdbd_allocate_pkt(ctdb
, state
, CTDB_REQ_CALL
, len
, struct ctdb_req_call_old
);
468 DEBUG(DEBUG_ERR
, (__location__
" failed to allocate packet\n"));
472 state
->reqid
= reqid_new(ctdb
->idr
, state
);
473 state
->ctdb_db
= ctdb_db
;
474 talloc_set_destructor(state
, ctdb_client_call_destructor
);
476 c
->hdr
.reqid
= state
->reqid
;
477 c
->flags
= call
->flags
;
478 c
->db_id
= ctdb_db
->db_id
;
479 c
->callid
= call
->call_id
;
481 c
->keylen
= call
->key
.dsize
;
482 c
->calldatalen
= call
->call_data
.dsize
;
483 memcpy(&c
->data
[0], call
->key
.dptr
, call
->key
.dsize
);
484 memcpy(&c
->data
[call
->key
.dsize
],
485 call
->call_data
.dptr
, call
->call_data
.dsize
);
486 *(state
->call
) = *call
;
487 state
->call
->call_data
.dptr
= &c
->data
[call
->key
.dsize
];
488 state
->call
->key
.dptr
= &c
->data
[0];
490 state
->state
= CTDB_CALL_WAIT
;
493 ctdb_client_queue_pkt(ctdb
, &c
->hdr
);
500 full ctdb_call. Equivalent to a ctdb_call_send() followed by a ctdb_call_recv()
502 int ctdb_call(struct ctdb_db_context
*ctdb_db
, struct ctdb_call
*call
)
504 struct ctdb_client_call_state
*state
;
506 state
= ctdb_call_send(ctdb_db
, call
);
507 return ctdb_call_recv(state
, call
);
512 tell the daemon what messaging srvid we will use, and register the message
513 handler function in the client
515 int ctdb_client_set_message_handler(struct ctdb_context
*ctdb
, uint64_t srvid
,
516 srvid_handler_fn handler
,
522 res
= ctdb_control(ctdb
, CTDB_CURRENT_NODE
, srvid
,
523 CTDB_CONTROL_REGISTER_SRVID
, 0,
524 tdb_null
, NULL
, NULL
, &status
, NULL
, NULL
);
525 if (res
!= 0 || status
!= 0) {
527 ("Failed to register srvid %llu\n",
528 (unsigned long long)srvid
));
532 /* also need to register the handler with our own ctdb structure */
533 return srvid_register(ctdb
->srv
, ctdb
, srvid
, handler
, private_data
);
537 tell the daemon we no longer want a srvid
539 int ctdb_client_remove_message_handler(struct ctdb_context
*ctdb
,
540 uint64_t srvid
, void *private_data
)
545 res
= ctdb_control(ctdb
, CTDB_CURRENT_NODE
, srvid
,
546 CTDB_CONTROL_DEREGISTER_SRVID
, 0,
547 tdb_null
, NULL
, NULL
, &status
, NULL
, NULL
);
548 if (res
!= 0 || status
!= 0) {
550 ("Failed to deregister srvid %llu\n",
551 (unsigned long long)srvid
));
555 /* also need to register the handler with our own ctdb structure */
556 srvid_deregister(ctdb
->srv
, srvid
, private_data
);
561 send a message - from client context
563 int ctdb_client_send_message(struct ctdb_context
*ctdb
, uint32_t pnn
,
564 uint64_t srvid
, TDB_DATA data
)
566 struct ctdb_req_message_old
*r
;
569 len
= offsetof(struct ctdb_req_message_old
, data
) + data
.dsize
;
570 r
= ctdbd_allocate_pkt(ctdb
, ctdb
, CTDB_REQ_MESSAGE
,
571 len
, struct ctdb_req_message_old
);
572 CTDB_NO_MEMORY(ctdb
, r
);
574 r
->hdr
.destnode
= pnn
;
576 r
->datalen
= data
.dsize
;
577 memcpy(&r
->data
[0], data
.dptr
, data
.dsize
);
579 res
= ctdb_client_queue_pkt(ctdb
, &r
->hdr
);
586 called when a control completes or timesout to invoke the callback
587 function the user provided
589 static void invoke_control_callback(struct tevent_context
*ev
,
590 struct tevent_timer
*te
,
591 struct timeval t
, void *private_data
)
593 struct ctdb_client_control_state
*state
;
594 TALLOC_CTX
*tmp_ctx
= talloc_new(NULL
);
597 state
= talloc_get_type(private_data
, struct ctdb_client_control_state
);
598 talloc_steal(tmp_ctx
, state
);
600 ret
= ctdb_control_recv(state
->ctdb
, state
, state
,
605 DEBUG(DEBUG_DEBUG
,("ctdb_control_recv() failed, ignoring return code %d\n", ret
));
608 talloc_free(tmp_ctx
);
612 called when a CTDB_REPLY_CONTROL packet comes in in the client
614 This packet comes in response to a CTDB_REQ_CONTROL request packet. It
615 contains any reply data from the control
617 static void ctdb_client_reply_control(struct ctdb_context
*ctdb
,
618 struct ctdb_req_header
*hdr
)
620 struct ctdb_reply_control_old
*c
= (struct ctdb_reply_control_old
*)hdr
;
621 struct ctdb_client_control_state
*state
;
623 state
= reqid_find(ctdb
->idr
, hdr
->reqid
, struct ctdb_client_control_state
);
625 DEBUG(DEBUG_ERR
,(__location__
" reqid %u not found\n", hdr
->reqid
));
629 if (hdr
->reqid
!= state
->reqid
) {
630 /* we found a record but it was the wrong one */
631 DEBUG(DEBUG_ERR
, ("Dropped orphaned reply control with reqid:%u\n",hdr
->reqid
));
635 state
->outdata
.dptr
= c
->data
;
636 state
->outdata
.dsize
= c
->datalen
;
637 state
->status
= c
->status
;
639 state
->errormsg
= talloc_strndup(state
,
640 (char *)&c
->data
[c
->datalen
],
644 /* state->outdata now uses resources from c so we don't want c
645 to just disappear from under us while state is still alive
647 talloc_steal(state
, c
);
649 state
->state
= CTDB_CONTROL_DONE
;
651 /* if we had a callback registered for this control, pull the response
652 and call the callback.
654 if (state
->async
.fn
) {
655 tevent_add_timer(ctdb
->ev
, state
, timeval_zero(),
656 invoke_control_callback
, state
);
662 destroy a ctdb_control in client
664 static int ctdb_client_control_destructor(struct ctdb_client_control_state
*state
)
666 reqid_remove(state
->ctdb
->idr
, state
->reqid
);
671 /* time out handler for ctdb_control */
672 static void control_timeout_func(struct tevent_context
*ev
,
673 struct tevent_timer
*te
,
674 struct timeval t
, void *private_data
)
676 struct ctdb_client_control_state
*state
= talloc_get_type(private_data
, struct ctdb_client_control_state
);
678 DEBUG(DEBUG_ERR
,(__location__
" control timed out. reqid:%u opcode:%u "
679 "dstnode:%u\n", state
->reqid
, state
->c
->opcode
,
680 state
->c
->hdr
.destnode
));
682 state
->state
= CTDB_CONTROL_TIMEOUT
;
684 /* if we had a callback registered for this control, pull the response
685 and call the callback.
687 if (state
->async
.fn
) {
688 tevent_add_timer(state
->ctdb
->ev
, state
, timeval_zero(),
689 invoke_control_callback
, state
);
693 /* async version of send control request */
694 struct ctdb_client_control_state
*ctdb_control_send(struct ctdb_context
*ctdb
,
695 uint32_t destnode
, uint64_t srvid
,
696 uint32_t opcode
, uint32_t flags
, TDB_DATA data
,
698 struct timeval
*timeout
,
701 struct ctdb_client_control_state
*state
;
703 struct ctdb_req_control_old
*c
;
710 /* if the domain socket is not yet open, open it */
711 if (ctdb
->daemon
.sd
==-1) {
712 ctdb_socket_connect(ctdb
);
715 state
= talloc_zero(mem_ctx
, struct ctdb_client_control_state
);
716 CTDB_NO_MEMORY_NULL(ctdb
, state
);
719 state
->reqid
= reqid_new(ctdb
->idr
, state
);
720 state
->state
= CTDB_CONTROL_WAIT
;
721 state
->errormsg
= NULL
;
723 talloc_set_destructor(state
, ctdb_client_control_destructor
);
725 len
= offsetof(struct ctdb_req_control_old
, data
) + data
.dsize
;
726 c
= ctdbd_allocate_pkt(ctdb
, state
, CTDB_REQ_CONTROL
,
727 len
, struct ctdb_req_control_old
);
729 CTDB_NO_MEMORY_NULL(ctdb
, c
);
730 c
->hdr
.reqid
= state
->reqid
;
731 c
->hdr
.destnode
= destnode
;
736 c
->datalen
= data
.dsize
;
738 memcpy(&c
->data
[0], data
.dptr
, data
.dsize
);
742 if (timeout
&& !timeval_is_zero(timeout
)) {
743 tevent_add_timer(ctdb
->ev
, state
, *timeout
,
744 control_timeout_func
, state
);
747 ret
= ctdb_client_queue_pkt(ctdb
, &(c
->hdr
));
753 if (flags
& CTDB_CTRL_FLAG_NOREPLY
) {
762 /* async version of receive control reply */
763 int ctdb_control_recv(struct ctdb_context
*ctdb
,
764 struct ctdb_client_control_state
*state
,
766 TDB_DATA
*outdata
, int32_t *status
, char **errormsg
)
770 if (status
!= NULL
) {
773 if (errormsg
!= NULL
) {
781 /* prevent double free of state */
782 tmp_ctx
= talloc_new(ctdb
);
783 talloc_steal(tmp_ctx
, state
);
785 /* loop one event at a time until we either timeout or the control
788 while (state
->state
== CTDB_CONTROL_WAIT
) {
789 tevent_loop_once(ctdb
->ev
);
792 if (state
->state
!= CTDB_CONTROL_DONE
) {
793 DEBUG(DEBUG_ERR
,(__location__
" ctdb_control_recv failed\n"));
794 if (state
->async
.fn
) {
795 state
->async
.fn(state
);
797 talloc_free(tmp_ctx
);
801 if (state
->errormsg
) {
802 int s
= (state
->status
== 0 ? -1 : state
->status
);
803 DEBUG(DEBUG_ERR
,("ctdb_control error: '%s'\n", state
->errormsg
));
805 (*errormsg
) = talloc_move(mem_ctx
, &state
->errormsg
);
807 if (state
->async
.fn
) {
808 state
->async
.fn(state
);
810 talloc_free(tmp_ctx
);
815 *outdata
= state
->outdata
;
816 outdata
->dptr
= talloc_memdup(mem_ctx
, outdata
->dptr
, outdata
->dsize
);
820 *status
= state
->status
;
823 if (state
->async
.fn
) {
824 state
->async
.fn(state
);
827 talloc_free(tmp_ctx
);
834 send a ctdb control message
835 timeout specifies how long we should wait for a reply.
836 if timeout is NULL we wait indefinitely
838 int ctdb_control(struct ctdb_context
*ctdb
, uint32_t destnode
, uint64_t srvid
,
839 uint32_t opcode
, uint32_t flags
, TDB_DATA data
,
840 TALLOC_CTX
*mem_ctx
, TDB_DATA
*outdata
, int32_t *status
,
841 struct timeval
*timeout
,
844 struct ctdb_client_control_state
*state
;
846 state
= ctdb_control_send(ctdb
, destnode
, srvid
, opcode
,
847 flags
, data
, mem_ctx
,
850 /* FIXME: Error conditions in ctdb_control_send return NULL without
851 * setting errormsg. So, there is no way to distinguish between success
852 * and failure when CTDB_CTRL_FLAG_NOREPLY is set */
853 if (flags
& CTDB_CTRL_FLAG_NOREPLY
) {
854 if (status
!= NULL
) {
860 return ctdb_control_recv(ctdb
, state
, mem_ctx
, outdata
, status
,
865 get vnn map from a remote node
867 int ctdb_ctrl_getvnnmap(struct ctdb_context
*ctdb
, struct timeval timeout
, uint32_t destnode
, TALLOC_CTX
*mem_ctx
, struct ctdb_vnn_map
**vnnmap
)
872 struct ctdb_vnn_map_wire
*map
;
874 ret
= ctdb_control(ctdb
, destnode
, 0,
875 CTDB_CONTROL_GETVNNMAP
, 0, tdb_null
,
876 mem_ctx
, &outdata
, &res
, &timeout
, NULL
);
877 if (ret
!= 0 || res
!= 0) {
878 DEBUG(DEBUG_ERR
,(__location__
" ctdb_control for getvnnmap failed\n"));
882 map
= (struct ctdb_vnn_map_wire
*)outdata
.dptr
;
883 if (outdata
.dsize
< offsetof(struct ctdb_vnn_map_wire
, map
) ||
884 outdata
.dsize
!= map
->size
*sizeof(uint32_t) + offsetof(struct ctdb_vnn_map_wire
, map
)) {
885 DEBUG(DEBUG_ERR
,("Bad vnn map size received in ctdb_ctrl_getvnnmap\n"));
889 (*vnnmap
) = talloc(mem_ctx
, struct ctdb_vnn_map
);
890 CTDB_NO_MEMORY(ctdb
, *vnnmap
);
891 (*vnnmap
)->generation
= map
->generation
;
892 (*vnnmap
)->size
= map
->size
;
893 (*vnnmap
)->map
= talloc_array(*vnnmap
, uint32_t, map
->size
);
895 CTDB_NO_MEMORY(ctdb
, (*vnnmap
)->map
);
896 memcpy((*vnnmap
)->map
, map
->map
, sizeof(uint32_t)*map
->size
);
897 talloc_free(outdata
.dptr
);
904 get the recovery mode of a remote node
906 struct ctdb_client_control_state
*
907 ctdb_ctrl_getrecmode_send(struct ctdb_context
*ctdb
, TALLOC_CTX
*mem_ctx
, struct timeval timeout
, uint32_t destnode
)
909 return ctdb_control_send(ctdb
, destnode
, 0,
910 CTDB_CONTROL_GET_RECMODE
, 0, tdb_null
,
911 mem_ctx
, &timeout
, NULL
);
914 int ctdb_ctrl_getrecmode_recv(struct ctdb_context
*ctdb
, TALLOC_CTX
*mem_ctx
, struct ctdb_client_control_state
*state
, uint32_t *recmode
)
919 ret
= ctdb_control_recv(ctdb
, state
, mem_ctx
, NULL
, &res
, NULL
);
921 DEBUG(DEBUG_ERR
,(__location__
" ctdb_ctrl_getrecmode_recv failed\n"));
926 *recmode
= (uint32_t)res
;
932 int ctdb_ctrl_getrecmode(struct ctdb_context
*ctdb
, TALLOC_CTX
*mem_ctx
, struct timeval timeout
, uint32_t destnode
, uint32_t *recmode
)
934 struct ctdb_client_control_state
*state
;
936 state
= ctdb_ctrl_getrecmode_send(ctdb
, mem_ctx
, timeout
, destnode
);
937 return ctdb_ctrl_getrecmode_recv(ctdb
, mem_ctx
, state
, recmode
);
944 set the recovery mode of a remote node
946 int ctdb_ctrl_setrecmode(struct ctdb_context
*ctdb
, struct timeval timeout
, uint32_t destnode
, uint32_t recmode
)
952 data
.dsize
= sizeof(uint32_t);
953 data
.dptr
= (unsigned char *)&recmode
;
955 ret
= ctdb_control(ctdb
, destnode
, 0,
956 CTDB_CONTROL_SET_RECMODE
, 0, data
,
957 NULL
, NULL
, &res
, &timeout
, NULL
);
958 if (ret
!= 0 || res
!= 0) {
959 DEBUG(DEBUG_ERR
,(__location__
" ctdb_control for setrecmode failed\n"));
969 get a list of nodes (vnn and flags ) from a remote node
971 int ctdb_ctrl_getnodemap(struct ctdb_context
*ctdb
,
972 struct timeval timeout
, uint32_t destnode
,
973 TALLOC_CTX
*mem_ctx
, struct ctdb_node_map_old
**nodemap
)
979 ret
= ctdb_control(ctdb
, destnode
, 0,
980 CTDB_CONTROL_GET_NODEMAP
, 0, tdb_null
,
981 mem_ctx
, &outdata
, &res
, &timeout
, NULL
);
982 if (ret
!= 0 || res
!= 0 || outdata
.dsize
== 0) {
983 DEBUG(DEBUG_ERR
,(__location__
" ctdb_control for getnodes failed ret:%d res:%d\n", ret
, res
));
987 *nodemap
= (struct ctdb_node_map_old
*)talloc_memdup(mem_ctx
, outdata
.dptr
, outdata
.dsize
);
988 talloc_free(outdata
.dptr
);
992 int ctdb_ctrl_get_runstate(struct ctdb_context
*ctdb
,
993 struct timeval timeout
,
1001 ret
= ctdb_control(ctdb
, destnode
, 0, CTDB_CONTROL_GET_RUNSTATE
, 0,
1002 tdb_null
, ctdb
, &outdata
, &res
, &timeout
, NULL
);
1003 if (ret
!= 0 || res
!= 0) {
1004 DEBUG(DEBUG_ERR
,("ctdb_control for get_runstate failed\n"));
1005 return ret
!= 0 ? ret
: res
;
1008 if (outdata
.dsize
!= sizeof(uint32_t)) {
1009 DEBUG(DEBUG_ERR
,("Invalid return data in get_runstate\n"));
1010 talloc_free(outdata
.dptr
);
1014 if (runstate
!= NULL
) {
1015 *runstate
= *(uint32_t *)outdata
.dptr
;
1017 talloc_free(outdata
.dptr
);
1023 get debug level on a node
1025 int ctdb_ctrl_get_debuglevel(struct ctdb_context
*ctdb
, uint32_t destnode
, int32_t *level
)
1031 ret
= ctdb_control(ctdb
, destnode
, 0, CTDB_CONTROL_GET_DEBUG
, 0, tdb_null
,
1032 ctdb
, &data
, &res
, NULL
, NULL
);
1033 if (ret
!= 0 || res
!= 0) {
1036 if (data
.dsize
!= sizeof(int32_t)) {
1037 DEBUG(DEBUG_ERR
,("Bad control reply size in ctdb_get_debuglevel (got %u)\n",
1038 (unsigned)data
.dsize
));
1041 *level
= *(int32_t *)data
.dptr
;
1042 talloc_free(data
.dptr
);
1046 /* Freeze all databases */
1047 int ctdb_ctrl_freeze(struct ctdb_context
*ctdb
, struct timeval timeout
,
1053 ret
= ctdb_control(ctdb
, destnode
, 0,
1054 CTDB_CONTROL_FREEZE
, 0, tdb_null
,
1055 NULL
, NULL
, &res
, &timeout
, NULL
);
1056 if (ret
!= 0 || res
!= 0) {
1057 DEBUG(DEBUG_ERR
, ("ctdb_ctrl_freeze_priority failed\n"));
1065 get pnn of a node, or -1
1067 int ctdb_ctrl_getpnn(struct ctdb_context
*ctdb
, struct timeval timeout
, uint32_t destnode
)
1072 ret
= ctdb_control(ctdb
, destnode
, 0,
1073 CTDB_CONTROL_GET_PNN
, 0, tdb_null
,
1074 NULL
, NULL
, &res
, &timeout
, NULL
);
1076 DEBUG(DEBUG_ERR
,(__location__
" ctdb_control for getpnn failed\n"));
1083 int ctdb_ctrl_get_public_ips_flags(struct ctdb_context
*ctdb
,
1084 struct timeval timeout
, uint32_t destnode
,
1085 TALLOC_CTX
*mem_ctx
,
1087 struct ctdb_public_ip_list_old
**ips
)
1093 ret
= ctdb_control(ctdb
, destnode
, 0,
1094 CTDB_CONTROL_GET_PUBLIC_IPS
, flags
, tdb_null
,
1095 mem_ctx
, &outdata
, &res
, &timeout
, NULL
);
1096 if (ret
!= 0 || res
!= 0) {
1097 DEBUG(DEBUG_ERR
,(__location__
1098 " ctdb_control for getpublicips failed ret:%d res:%d\n",
1103 *ips
= (struct ctdb_public_ip_list_old
*)talloc_memdup(mem_ctx
, outdata
.dptr
, outdata
.dsize
);
1104 talloc_free(outdata
.dptr
);
1109 int ctdb_ctrl_get_public_ips(struct ctdb_context
*ctdb
,
1110 struct timeval timeout
, uint32_t destnode
,
1111 TALLOC_CTX
*mem_ctx
,
1112 struct ctdb_public_ip_list_old
**ips
)
1114 return ctdb_ctrl_get_public_ips_flags(ctdb
, timeout
,
1119 int ctdb_ctrl_get_ifaces(struct ctdb_context
*ctdb
,
1120 struct timeval timeout
, uint32_t destnode
,
1121 TALLOC_CTX
*mem_ctx
,
1122 struct ctdb_iface_list_old
**_ifaces
)
1127 struct ctdb_iface_list_old
*ifaces
;
1131 ret
= ctdb_control(ctdb
, destnode
, 0,
1132 CTDB_CONTROL_GET_IFACES
, 0, tdb_null
,
1133 mem_ctx
, &outdata
, &res
, &timeout
, NULL
);
1134 if (ret
!= 0 || res
!= 0) {
1135 DEBUG(DEBUG_ERR
,(__location__
" ctdb_control for get ifaces "
1136 "failed ret:%d res:%d\n",
1141 len
= offsetof(struct ctdb_iface_list_old
, ifaces
);
1142 if (len
> outdata
.dsize
) {
1143 DEBUG(DEBUG_ERR
,(__location__
" ctdb_control for get ifaces "
1144 "returned invalid data with size %u > %u\n",
1145 (unsigned int)outdata
.dsize
,
1146 (unsigned int)len
));
1147 dump_data(DEBUG_DEBUG
, outdata
.dptr
, outdata
.dsize
);
1151 ifaces
= (struct ctdb_iface_list_old
*)outdata
.dptr
;
1152 len
+= ifaces
->num
*sizeof(struct ctdb_iface
);
1154 if (len
> outdata
.dsize
) {
1155 DEBUG(DEBUG_ERR
,(__location__
" ctdb_control for get ifaces "
1156 "returned invalid data with size %u > %u\n",
1157 (unsigned int)outdata
.dsize
,
1158 (unsigned int)len
));
1159 dump_data(DEBUG_DEBUG
, outdata
.dptr
, outdata
.dsize
);
1163 /* make sure we null terminate the returned strings */
1164 for (i
=0; i
< ifaces
->num
; i
++) {
1165 ifaces
->ifaces
[i
].name
[CTDB_IFACE_SIZE
] = '\0';
1168 *_ifaces
= (struct ctdb_iface_list_old
*)talloc_memdup(mem_ctx
,
1171 talloc_free(outdata
.dptr
);
1172 if (*_ifaces
== NULL
) {
1173 DEBUG(DEBUG_ERR
,(__location__
" ctdb_control for get ifaces "
1174 "talloc_memdup size %u failed\n",
1175 (unsigned int)outdata
.dsize
));
1185 int ctdb_ctrl_get_all_tunables(struct ctdb_context
*ctdb
,
1186 struct timeval timeout
,
1188 struct ctdb_tunable_list
*tunables
)
1194 ret
= ctdb_control(ctdb
, destnode
, 0, CTDB_CONTROL_GET_ALL_TUNABLES
, 0, tdb_null
, ctdb
,
1195 &outdata
, &res
, &timeout
, NULL
);
1196 if (ret
!= 0 || res
!= 0) {
1197 DEBUG(DEBUG_ERR
,(__location__
" ctdb_control for get all tunables failed\n"));
1201 if (outdata
.dsize
!= sizeof(*tunables
)) {
1202 DEBUG(DEBUG_ERR
,(__location__
" bad data size %u in ctdb_ctrl_get_all_tunables should be %u\n",
1203 (unsigned)outdata
.dsize
, (unsigned)sizeof(*tunables
)));
1207 *tunables
= *(struct ctdb_tunable_list
*)outdata
.dptr
;
1208 talloc_free(outdata
.dptr
);
1215 void ctdb_set_flags(struct ctdb_context
*ctdb
, unsigned flags
)
1217 ctdb
->flags
|= flags
;
1220 const char *ctdb_get_socketname(struct ctdb_context
*ctdb
)
1222 return ctdb
->daemon
.name
;
1226 return the pnn of this node
1228 uint32_t ctdb_get_pnn(struct ctdb_context
*ctdb
)
1234 callback for the async helpers used when sending the same control
1235 to multiple nodes in parallel.
1237 static void async_callback(struct ctdb_client_control_state
*state
)
1239 struct client_async_data
*data
= talloc_get_type(state
->async
.private_data
, struct client_async_data
);
1240 struct ctdb_context
*ctdb
= talloc_get_type(state
->ctdb
, struct ctdb_context
);
1244 uint32_t destnode
= state
->c
->hdr
.destnode
;
1247 outdata
.dptr
= NULL
;
1249 /* one more node has responded with recmode data */
1252 /* if we failed to push the db, then return an error and let
1253 the main loop try again.
1255 if (state
->state
!= CTDB_CONTROL_DONE
) {
1256 if ( !data
->dont_log_errors
) {
1257 DEBUG(DEBUG_ERR
,("Async operation failed with state %d, opcode:%u\n", state
->state
, data
->opcode
));
1260 if (state
->state
== CTDB_CONTROL_TIMEOUT
) {
1265 if (data
->fail_callback
) {
1266 data
->fail_callback(ctdb
, destnode
, res
, outdata
,
1267 data
->callback_data
);
1272 state
->async
.fn
= NULL
;
1274 ret
= ctdb_control_recv(ctdb
, state
, data
, &outdata
, &res
, NULL
);
1275 if ((ret
!= 0) || (res
!= 0)) {
1276 if ( !data
->dont_log_errors
) {
1277 DEBUG(DEBUG_ERR
,("Async operation failed with ret=%d res=%d opcode=%u\n", ret
, (int)res
, data
->opcode
));
1280 if (data
->fail_callback
) {
1281 data
->fail_callback(ctdb
, destnode
, res
, outdata
,
1282 data
->callback_data
);
1285 if ((ret
== 0) && (data
->callback
!= NULL
)) {
1286 data
->callback(ctdb
, destnode
, res
, outdata
,
1287 data
->callback_data
);
1292 void ctdb_client_async_add(struct client_async_data
*data
, struct ctdb_client_control_state
*state
)
1294 /* set up the callback functions */
1295 state
->async
.fn
= async_callback
;
1296 state
->async
.private_data
= data
;
1298 /* one more control to wait for to complete */
1303 /* wait for up to the maximum number of seconds allowed
1304 or until all nodes we expect a response from has replied
1306 int ctdb_client_async_wait(struct ctdb_context
*ctdb
, struct client_async_data
*data
)
1308 while (data
->count
> 0) {
1309 tevent_loop_once(ctdb
->ev
);
1311 if (data
->fail_count
!= 0) {
1312 if (!data
->dont_log_errors
) {
1313 DEBUG(DEBUG_ERR
,("Async wait failed - fail_count=%u\n",
1323 perform a simple control on the listed nodes
1324 The control cannot return data
1326 int ctdb_client_async_control(struct ctdb_context
*ctdb
,
1327 enum ctdb_controls opcode
,
1330 struct timeval timeout
,
1331 bool dont_log_errors
,
1333 client_async_callback client_callback
,
1334 client_async_callback fail_callback
,
1335 void *callback_data
)
1337 struct client_async_data
*async_data
;
1338 struct ctdb_client_control_state
*state
;
1341 async_data
= talloc_zero(ctdb
, struct client_async_data
);
1342 CTDB_NO_MEMORY_FATAL(ctdb
, async_data
);
1343 async_data
->dont_log_errors
= dont_log_errors
;
1344 async_data
->callback
= client_callback
;
1345 async_data
->fail_callback
= fail_callback
;
1346 async_data
->callback_data
= callback_data
;
1347 async_data
->opcode
= opcode
;
1349 num_nodes
= talloc_get_size(nodes
) / sizeof(uint32_t);
1351 /* loop over all nodes and send an async control to each of them */
1352 for (j
=0; j
<num_nodes
; j
++) {
1353 uint32_t pnn
= nodes
[j
];
1355 state
= ctdb_control_send(ctdb
, pnn
, srvid
, opcode
,
1356 0, data
, async_data
, &timeout
, NULL
);
1357 if (state
== NULL
) {
1358 DEBUG(DEBUG_ERR
,(__location__
" Failed to call async control %u\n", (unsigned)opcode
));
1359 talloc_free(async_data
);
1363 ctdb_client_async_add(async_data
, state
);
1366 if (ctdb_client_async_wait(ctdb
, async_data
) != 0) {
1367 talloc_free(async_data
);
1371 talloc_free(async_data
);
1375 uint32_t *list_of_vnnmap_nodes(struct ctdb_context
*ctdb
,
1376 struct ctdb_vnn_map
*vnn_map
,
1377 TALLOC_CTX
*mem_ctx
,
1380 unsigned int i
, j
, num_nodes
;
1383 for (i
=num_nodes
=0;i
<vnn_map
->size
;i
++) {
1384 if (vnn_map
->map
[i
] == ctdb
->pnn
&& !include_self
) {
1390 nodes
= talloc_array(mem_ctx
, uint32_t, num_nodes
);
1391 CTDB_NO_MEMORY_FATAL(ctdb
, nodes
);
1393 for (i
=j
=0;i
<vnn_map
->size
;i
++) {
1394 if (vnn_map
->map
[i
] == ctdb
->pnn
&& !include_self
) {
1397 nodes
[j
++] = vnn_map
->map
[i
];
1403 /* Get list of nodes not including those with flags specified by mask */
1404 static uint32_t *list_of_nodes(struct ctdb_context
*ctdb
,
1405 struct ctdb_node_map_old
*node_map
,
1406 TALLOC_CTX
*mem_ctx
,
1410 unsigned int i
, j
, num_nodes
;
1411 uint32_t exclude_pnn
;
1414 exclude_pnn
= include_self
? CTDB_UNKNOWN_PNN
: ctdb
->pnn
;
1416 for (i
=num_nodes
=0;i
<node_map
->num
;i
++) {
1417 if (node_map
->nodes
[i
].flags
& mask
) {
1420 if (node_map
->nodes
[i
].pnn
== exclude_pnn
) {
1426 nodes
= talloc_array(mem_ctx
, uint32_t, num_nodes
);
1427 CTDB_NO_MEMORY_FATAL(ctdb
, nodes
);
1429 for (i
=j
=0;i
<node_map
->num
;i
++) {
1430 if (node_map
->nodes
[i
].flags
& mask
) {
1433 if (node_map
->nodes
[i
].pnn
== exclude_pnn
) {
1436 nodes
[j
++] = node_map
->nodes
[i
].pnn
;
1442 uint32_t *list_of_active_nodes(struct ctdb_context
*ctdb
,
1443 struct ctdb_node_map_old
*node_map
,
1444 TALLOC_CTX
*mem_ctx
,
1447 return list_of_nodes(ctdb
,
1450 NODE_FLAGS_INACTIVE
,
1454 uint32_t *list_of_connected_nodes(struct ctdb_context
*ctdb
,
1455 struct ctdb_node_map_old
*node_map
,
1456 TALLOC_CTX
*mem_ctx
,
1459 return list_of_nodes(ctdb
,
1462 NODE_FLAGS_DISCONNECTED
,
1467 get capabilities of a remote node
1469 struct ctdb_client_control_state
*
1470 ctdb_ctrl_getcapabilities_send(struct ctdb_context
*ctdb
, TALLOC_CTX
*mem_ctx
, struct timeval timeout
, uint32_t destnode
)
1472 return ctdb_control_send(ctdb
, destnode
, 0,
1473 CTDB_CONTROL_GET_CAPABILITIES
, 0, tdb_null
,
1474 mem_ctx
, &timeout
, NULL
);
1477 int ctdb_ctrl_getcapabilities_recv(struct ctdb_context
*ctdb
, TALLOC_CTX
*mem_ctx
, struct ctdb_client_control_state
*state
, uint32_t *capabilities
)
1483 ret
= ctdb_control_recv(ctdb
, state
, mem_ctx
, &outdata
, &res
, NULL
);
1484 if ( (ret
!= 0) || (res
!= 0) ) {
1485 DEBUG(DEBUG_ERR
,(__location__
" ctdb_ctrl_getcapabilities_recv failed\n"));
1490 *capabilities
= *((uint32_t *)outdata
.dptr
);
1496 int ctdb_ctrl_getcapabilities(struct ctdb_context
*ctdb
, struct timeval timeout
, uint32_t destnode
, uint32_t *capabilities
)
1498 struct ctdb_client_control_state
*state
;
1499 TALLOC_CTX
*tmp_ctx
= talloc_new(NULL
);
1502 state
= ctdb_ctrl_getcapabilities_send(ctdb
, tmp_ctx
, timeout
, destnode
);
1503 ret
= ctdb_ctrl_getcapabilities_recv(ctdb
, tmp_ctx
, state
, capabilities
);
1504 talloc_free(tmp_ctx
);
1508 static void get_capabilities_callback(struct ctdb_context
*ctdb
,
1509 uint32_t node_pnn
, int32_t res
,
1510 TDB_DATA outdata
, void *callback_data
)
1512 struct ctdb_node_capabilities
*caps
=
1513 talloc_get_type(callback_data
,
1514 struct ctdb_node_capabilities
);
1516 if ( (outdata
.dsize
!= sizeof(uint32_t)) || (outdata
.dptr
== NULL
) ) {
1517 DEBUG(DEBUG_ERR
, (__location__
" Invalid length/pointer for getcap callback : %u %p\n", (unsigned)outdata
.dsize
, outdata
.dptr
));
1521 if (node_pnn
>= talloc_array_length(caps
)) {
1523 (__location__
" unexpected PNN %u\n", node_pnn
));
1527 caps
[node_pnn
].retrieved
= true;
1528 caps
[node_pnn
].capabilities
= *((uint32_t *)outdata
.dptr
);
1531 struct ctdb_node_capabilities
*
1532 ctdb_get_capabilities(struct ctdb_context
*ctdb
,
1533 TALLOC_CTX
*mem_ctx
,
1534 struct timeval timeout
,
1535 struct ctdb_node_map_old
*nodemap
)
1539 struct ctdb_node_capabilities
*ret
;
1541 nodes
= list_of_active_nodes(ctdb
, nodemap
, mem_ctx
, true);
1543 ret
= talloc_array(mem_ctx
, struct ctdb_node_capabilities
,
1545 CTDB_NO_MEMORY_NULL(ctdb
, ret
);
1546 /* Prepopulate the expected PNNs */
1547 for (i
= 0; i
< talloc_array_length(ret
); i
++) {
1548 ret
[i
].retrieved
= false;
1551 res
= ctdb_client_async_control(ctdb
, CTDB_CONTROL_GET_CAPABILITIES
,
1554 get_capabilities_callback
, NULL
,
1558 (__location__
" Failed to read node capabilities.\n"));
1566 ctdb_get_node_capabilities(struct ctdb_node_capabilities
*caps
,
1569 if (pnn
< talloc_array_length(caps
) && caps
[pnn
].retrieved
) {
1570 return &caps
[pnn
].capabilities
;
1576 bool ctdb_node_has_capabilities(struct ctdb_node_capabilities
*caps
,
1578 uint32_t capabilities_required
)
1580 uint32_t *capp
= ctdb_get_node_capabilities(caps
, pnn
);
1581 return (capp
!= NULL
) &&
1582 ((*capp
& capabilities_required
) == capabilities_required
);
1586 recovery daemon ping to main daemon
1588 int ctdb_ctrl_recd_ping(struct ctdb_context
*ctdb
)
1593 ret
= ctdb_control(ctdb
, CTDB_CURRENT_NODE
, 0, CTDB_CONTROL_RECD_PING
, 0, tdb_null
,
1594 ctdb
, NULL
, &res
, NULL
, NULL
);
1595 if (ret
!= 0 || res
!= 0) {
1596 DEBUG(DEBUG_ERR
,("Failed to send recd ping\n"));
1604 tell the main daemon how long it took to lock the reclock file
1606 int ctdb_ctrl_report_recd_lock_latency(struct ctdb_context
*ctdb
, struct timeval timeout
, double latency
)
1612 data
.dptr
= (uint8_t *)&latency
;
1613 data
.dsize
= sizeof(latency
);
1615 ret
= ctdb_control(ctdb
, CTDB_CURRENT_NODE
, 0, CTDB_CONTROL_RECD_RECLOCK_LATENCY
, 0, data
,
1616 ctdb
, NULL
, &res
, NULL
, NULL
);
1617 if (ret
!= 0 || res
!= 0) {
1618 DEBUG(DEBUG_ERR
,("Failed to send recd reclock latency\n"));
1625 int ctdb_ctrl_set_ban(struct ctdb_context
*ctdb
, struct timeval timeout
,
1626 uint32_t destnode
, struct ctdb_ban_state
*bantime
)
1632 data
.dsize
= sizeof(*bantime
);
1633 data
.dptr
= (uint8_t *)bantime
;
1635 ret
= ctdb_control(ctdb
, destnode
, 0,
1636 CTDB_CONTROL_SET_BAN_STATE
, 0, data
,
1637 NULL
, NULL
, &res
, &timeout
, NULL
);
1638 if (ret
!= 0 || res
!= 0) {
1639 DEBUG(DEBUG_ERR
,(__location__
" ctdb_control for set ban state failed\n"));
1646 struct ctdb_client_control_state
*
1647 ctdb_ctrl_updaterecord_send(struct ctdb_context
*ctdb
, TALLOC_CTX
*mem_ctx
, struct timeval timeout
, uint32_t destnode
, struct ctdb_db_context
*ctdb_db
, TDB_DATA key
, struct ctdb_ltdb_header
*header
, TDB_DATA data
)
1649 struct ctdb_client_control_state
*handle
;
1650 struct ctdb_marshall_buffer
*m
;
1651 struct ctdb_rec_data_old
*rec
;
1654 m
= talloc_zero(mem_ctx
, struct ctdb_marshall_buffer
);
1656 DEBUG(DEBUG_ERR
, ("Failed to allocate marshall buffer for update record\n"));
1660 m
->db_id
= ctdb_db
->db_id
;
1662 rec
= ctdb_marshall_record(m
, 0, key
, header
, data
);
1664 DEBUG(DEBUG_ERR
,("Failed to marshall record for update record\n"));
1668 m
= talloc_realloc_size(mem_ctx
, m
, rec
->length
+ offsetof(struct ctdb_marshall_buffer
, data
));
1670 DEBUG(DEBUG_CRIT
,(__location__
" Failed to expand recdata\n"));
1675 memcpy((uint8_t *)m
+ offsetof(struct ctdb_marshall_buffer
, data
), rec
, rec
->length
);
1678 outdata
.dptr
= (uint8_t *)m
;
1679 outdata
.dsize
= talloc_get_size(m
);
1681 handle
= ctdb_control_send(ctdb
, destnode
, 0,
1682 CTDB_CONTROL_UPDATE_RECORD
, 0, outdata
,
1683 mem_ctx
, &timeout
, NULL
);
1688 int ctdb_ctrl_updaterecord_recv(struct ctdb_context
*ctdb
, struct ctdb_client_control_state
*state
)
1693 ret
= ctdb_control_recv(ctdb
, state
, state
, NULL
, &res
, NULL
);
1694 if ( (ret
!= 0) || (res
!= 0) ){
1695 DEBUG(DEBUG_ERR
,(__location__
" ctdb_ctrl_update_record_recv failed\n"));
1703 ctdb_ctrl_updaterecord(struct ctdb_context
*ctdb
, TALLOC_CTX
*mem_ctx
, struct timeval timeout
, uint32_t destnode
, struct ctdb_db_context
*ctdb_db
, TDB_DATA key
, struct ctdb_ltdb_header
*header
, TDB_DATA data
)
1705 struct ctdb_client_control_state
*state
;
1707 state
= ctdb_ctrl_updaterecord_send(ctdb
, mem_ctx
, timeout
, destnode
, ctdb_db
, key
, header
, data
);
1708 return ctdb_ctrl_updaterecord_recv(ctdb
, state
);