*/
void ctdb_recv_pkt(struct ctdb_context *ctdb, uint8_t *data, uint32_t length)
{
-- struct ctdb_req_header *hdr;
++ struct ctdb_req_header *hdr = (struct ctdb_req_header *)data;
++ 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);
if (length < sizeof(*hdr)) {
ctdb_set_error(ctdb, "Bad packet length %d\n", length);
-- return;
++ goto done;
}
-- hdr = (struct ctdb_req_header *)data;
if (length != hdr->length) {
ctdb_set_error(ctdb, "Bad header length %d expected %d\n",
hdr->length, length);
-- return;
++ goto done;
}
if (hdr->ctdb_magic != CTDB_MAGIC) {
ctdb_set_error(ctdb, "Non CTDB packet rejected\n");
-- return;
++ goto done;
}
if (hdr->ctdb_version != CTDB_VERSION) {
ctdb_set_error(ctdb, "Bad CTDB version 0x%x rejected\n", hdr->ctdb_version);
-- return;
++ goto done;
}
- DEBUG(3,(__location__ " ctdb request of type %d length %d from node %d to %d\n",
- hdr->operation, hdr->length, hdr->srcnode, hdr->destnode));
+ DEBUG(3,(__location__ " ctdb request %d of type %d length %d from "
+ "node %d to %d\n", hdr->reqid, hdr->operation, hdr->length,
+ hdr->srcnode, hdr->destnode));
switch (hdr->operation) {
case CTDB_REQ_CALL:
__location__, hdr->operation));
break;
}
-- talloc_free(hdr);
++
++done:
++ talloc_free(tmp_ctx);
}
/*
if (c->reply_data) {
call->reply_data = *c->reply_data;
talloc_steal(ctdb, call->reply_data.dptr);
++ talloc_set_name_const(call->reply_data.dptr, __location__);
} else {
call->reply_data.dptr = NULL;
call->reply_data.dsize = 0;
struct ctdb_ltdb_header header;
struct ctdb_db_context *ctdb_db;
int ret, len;
++ TALLOC_CTX *tmp_ctx;
key.dptr = c->data;
key.dsize = c->keylen;
len = offsetof(struct ctdb_reply_dmaster, data) + data.dsize;
r = ctdb->methods->allocate_pkt(ctdb, len);
CTDB_NO_MEMORY_FATAL(ctdb, r);
++
++ /* put the packet on a temporary context, allowing us to safely free
++ it below even if ctdb_reply_dmaster() has freed it already */
++ tmp_ctx = talloc_new(ctdb);
++ talloc_steal(tmp_ctx, r);
++
talloc_set_name_const(r, "reply_dmaster packet");
r->hdr.length = len;
r->hdr.ctdb_magic = CTDB_MAGIC;
ctdb_queue_packet(ctdb, &r->hdr);
}
-- talloc_free(r);
++ talloc_free(tmp_ctx);
}
state->call.reply_data.dsize = c->datalen;
state->call.status = c->status;
- talloc_steal(c, state);
-
- /* get an extra reference here - this prevents the free in ctdb_recv_pkt()
- from freeing the data */
- (void)talloc_reference(state, c);
+ talloc_steal(state, c);
- /* get an extra reference here - this prevents the free in ctdb_recv_pkt()
- from freeing the data */
- (void)talloc_reference(state, c);
-
state->state = CTDB_CALL_DONE;
if (state->async.fn) {
state->async.fn(state);
ctdb_call_local(ctdb_db, &state->call, &state->header, &data, ctdb->vnn);
++ talloc_steal(state, state->call.reply_data.dptr);
++
state->state = CTDB_CALL_DONE;
if (state->async.fn) {
state->async.fn(state);
state->ctdb_db = ctdb_db;
ret = ctdb_call_local(ctdb_db, &state->call, header, data, ctdb->vnn);
++ talloc_steal(state, state->call.reply_data.dptr);
event_add_timed(ctdb->ev, state, timeval_zero(), call_local_trigger, state);
if (ret != 0) return NULL;
if (header.dmaster == ctdb->vnn && !(ctdb->flags & CTDB_FLAG_SELF_CONNECT)) {
- return ctdb_call_local_send(ctdb_db, call, &header, &data);
- struct ctdb_call_state *result;
- result = ctdb_call_local_send(ctdb_db, call, &header, &data);
++ struct ctdb_call_state *state;
++ state = ctdb_call_local_send(ctdb_db, call, &header, &data);
+ talloc_free(data.dptr);
- return result;
++ return state;
}
talloc_free(data.dptr);
*/
int ctdb_daemon_call_recv(struct ctdb_call_state *state, struct ctdb_call *call)
{
-- struct ctdb_record_handle *rec;
++ struct ctdb_fetch_handle *rec;
while (state->state < CTDB_CALL_DONE) {
event_loop_once(state->node->ctdb->ev);
rec->header = state->header;
rec->data->dptr = talloc_steal(rec, state->call.reply_data.dptr);
rec->data->dsize = state->call.reply_data.dsize;
++ talloc_set_name_const(rec->data->dptr, __location__);
talloc_free(state);
return 0;
}
state->r = talloc_steal(state, r);
-- /* get an extra reference here - this prevents the free in ctdb_recv_pkt()
-- from freeing the data */
-- (void)talloc_reference(state, r);
--
state->state = CTDB_FETCH_LOCK_DONE;
}
static void ctdb_client_read_cb(uint8_t *data, size_t cnt, void *args)
{
struct ctdb_context *ctdb = talloc_get_type(args, struct ctdb_context);
-- struct ctdb_req_header *hdr;
++ struct ctdb_req_header *hdr = (struct ctdb_req_header *)data;
++ TALLOC_CTX *tmp_ctx;
++
++ /* 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(ctdb);
++ talloc_steal(tmp_ctx, hdr);
if (cnt < sizeof(*hdr)) {
ctdb_set_error(ctdb, "Bad packet length %d in client\n", cnt);
-- exit(1);
-- return;
++ exit(1); /* XXX - temporary for debugging */
++ goto done;
}
-- hdr = (struct ctdb_req_header *)data;
if (cnt != hdr->length) {
ctdb_set_error(ctdb, "Bad header length %d expected %d in client\n",
hdr->length, cnt);
-- return;
++ goto done;
}
if (hdr->ctdb_magic != CTDB_MAGIC) {
ctdb_set_error(ctdb, "Non CTDB packet rejected in client\n");
-- return;
++ goto done;
}
if (hdr->ctdb_version != CTDB_VERSION) {
ctdb_set_error(ctdb, "Bad CTDB version 0x%x rejected in client\n", hdr->ctdb_version);
-- return;
++ goto done;
}
switch (hdr->operation) {
default:
DEBUG(0,("bogus operation code:%d\n",hdr->operation));
}
++
++done:
++ talloc_free(tmp_ctx);
}
/*
}
++struct ctdb_record_handle {
++ struct ctdb_db_context *ctdb_db;
++ TDB_DATA key;
++ TDB_DATA *data;
++ struct ctdb_ltdb_header header;
++};
/*
make a recv call to the local ctdb daemon - called from client context
#if 0
if (header.dmaster == ctdb->vnn && !(ctdb->flags & CTDB_FLAG_SELF_CONNECT)) {
state = ctdb_call_local_send(ctdb_db, call, &header, &data);
++ talloc_free(data.dptr);
return state;
}
#endif
TDB_DATA *data)
{
struct ctdb_call *call;
-- struct ctdb_record_handle *rec;
++ struct ctdb_fetch_handle *rec;
struct ctdb_call_state *state;
-- rec = talloc(mem_ctx, struct ctdb_record_handle);
++ rec = talloc(mem_ctx, struct ctdb_fetch_handle);
CTDB_NO_MEMORY_NULL(ctdb_db->ctdb, rec);
state = ctdb_daemon_call_send_remote(ctdb_db, call, header);
state->fetch_private = rec;
++ talloc_steal(state, rec);
return state;
}
DEBUG(0,(__location__ " Failed to queue packet from daemon to client\n"));
}
talloc_free(r);
++ talloc_free(state);
}
/*
static void daemon_incoming_packet(struct ctdb_client *client, void *data, size_t nread)
{
struct ctdb_req_header *hdr = data;
++ TALLOC_CTX *tmp_ctx;
++
++ /* 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);
if (hdr->ctdb_magic != CTDB_MAGIC) {
ctdb_set_error(client->ctdb, "Non CTDB packet rejected in daemon\n");
}
done:
-- talloc_free(data);
++ talloc_free(tmp_ctx);
}
return -1;
}
-- /* we get an extra reference to the packet here, to
-- stop it being freed in the top level packet handler */
-- if (talloc_reference(ctdb_db, hdr) == NULL) {
-- talloc_free(h);
-- return -1;
-- }
--
/* now tell the caller than we will retry asynchronously */
return -2;
}
/* used for fetch_lock */
--struct ctdb_record_handle {
++struct ctdb_fetch_handle {
struct ctdb_db_context *ctdb_db;
TDB_DATA key;
TDB_DATA *data;
void talloc_report_full(const void *ptr, FILE *f);
void talloc_report(const void *ptr, FILE *f);
void talloc_enable_null_tracking(void);
++void talloc_report_null_full(void);
void talloc_disable_null_tracking(void);
void talloc_enable_leak_report(void);
void talloc_enable_leak_report_full(void);
}
}
- talloc_enable_leak_report_full();
++ /* talloc_enable_leak_report_full(); */
+
/* setup the remaining options for the main program to use */
extra_argv = poptGetArgs(pc);
if (extra_argv) {
killall -q ctdb_fetch
echo "Trying 2 nodes"
--bin/ctdb_fetch --nlist tests/nodes.txt --listen 127.0.0.2:9001 $* &
--bin/ctdb_fetch --nlist tests/nodes.txt --listen 127.0.0.1:9001 $*
++$VALGRIND bin/ctdb_fetch --nlist tests/nodes.txt --listen 127.0.0.2:9001 $* &
++$VALGRIND bin/ctdb_fetch --nlist tests/nodes.txt --listen 127.0.0.1:9001 $*
killall -q ctdb_fetch
echo "Trying 4 nodes"
--bin/ctdb_fetch --nlist tests/4nodes.txt --listen 127.0.0.4:9001 $* &
--bin/ctdb_fetch --nlist tests/4nodes.txt --listen 127.0.0.3:9001 $* &
--bin/ctdb_fetch --nlist tests/4nodes.txt --listen 127.0.0.2:9001 $* &
--bin/ctdb_fetch --nlist tests/4nodes.txt --listen 127.0.0.1:9001 $*
++$VALGRIND bin/ctdb_fetch --nlist tests/4nodes.txt --listen 127.0.0.4:9001 $* &
++$VALGRIND bin/ctdb_fetch --nlist tests/4nodes.txt --listen 127.0.0.3:9001 $* &
++$VALGRIND bin/ctdb_fetch --nlist tests/4nodes.txt --listen 127.0.0.2:9001 $* &
++$VALGRIND bin/ctdb_fetch --nlist tests/4nodes.txt --listen 127.0.0.1:9001 $*
killall -q ctdb_fetch