diff options
-rw-r--r-- | ctdb/common/ctdb.c | 4 | ||||
-rw-r--r-- | ctdb/common/ctdb_call.c | 58 | ||||
-rw-r--r-- | ctdb/include/ctdb_private.h | 17 |
3 files changed, 72 insertions, 7 deletions
diff --git a/ctdb/common/ctdb.c b/ctdb/common/ctdb.c index f09f6029b1..80e4649c4d 100644 --- a/ctdb/common/ctdb.c +++ b/ctdb/common/ctdb.c @@ -177,6 +177,10 @@ static void ctdb_recv_pkt(struct ctdb_context *ctdb, uint8_t *data, uint32_t len ctdb_reply_call(ctdb, hdr); break; + case CTDB_REPLY_ERROR: + ctdb_reply_error(ctdb, hdr); + break; + default: printf("Packet with unknown operation %d\n", hdr->operation); talloc_free(hdr); diff --git a/ctdb/common/ctdb_call.c b/ctdb/common/ctdb_call.c index 74d97ee599..6349146b12 100644 --- a/ctdb/common/ctdb_call.c +++ b/ctdb/common/ctdb_call.c @@ -85,9 +85,42 @@ static int ctdb_call_local(struct ctdb_context *ctdb, TDB_DATA key, send an error reply */ static void ctdb_send_error(struct ctdb_context *ctdb, - struct ctdb_req_header *hdr, int ecode) + struct ctdb_req_header *hdr, uint32_t status, + const char *fmt, ...) { - printf("ctdb_send_error not implemented\n"); + va_list ap; + struct ctdb_reply_error *r; + char *msg; + int len; + struct ctdb_node *node; + + va_start(ap, fmt); + msg = talloc_vasprintf(ctdb, fmt, ap); + if (msg == NULL) { + /* can't send an error message, need to rely on call + timeouts instead */ + return; + } + va_end(ap); + + len = strlen(msg)+1; + r = talloc_size(ctdb, sizeof(*r) + len); + r->hdr.length = sizeof(*r) + len; + r->hdr.operation = CTDB_REPLY_ERROR; + r->hdr.destnode = hdr->srcnode; + r->hdr.srcnode = ctdb->vnn; + r->hdr.reqid = hdr->reqid; + r->status = status; + r->msglen = len; + memcpy(&r->msg[0], msg, len); + + talloc_free(msg); + + node = ctdb->nodes[hdr->srcnode]; + + ctdb->methods->queue_pkt(node, (uint8_t *)r, r->hdr.length); + + talloc_free(r); } /* @@ -122,7 +155,7 @@ void ctdb_request_call(struct ctdb_context *ctdb, struct ctdb_req_header *hdr) if the call will be answered locally */ ret = ctdb_ltdb_fetch(ctdb, key, &header, &data); if (ret != 0) { - ctdb_send_error(ctdb, hdr, ret); + ctdb_send_error(ctdb, hdr, ret, "ltdb fetch failed in ctdb_request_call"); return; } @@ -164,6 +197,7 @@ struct ctdb_call_state { enum call_state state; struct ctdb_req_call *c; struct ctdb_node *node; + const char *errmsg; TDB_DATA reply_data; }; @@ -189,6 +223,23 @@ void ctdb_reply_call(struct ctdb_context *ctdb, struct ctdb_req_header *hdr) state->state = CTDB_CALL_DONE; } + +/* + called when a CTDB_REPLY_ERROR packet comes in +*/ +void ctdb_reply_error(struct ctdb_context *ctdb, struct ctdb_req_header *hdr) +{ + struct ctdb_reply_error *c = (struct ctdb_reply_error *)hdr; + struct ctdb_call_state *state; + + state = idr_find(ctdb->idr, hdr->reqid); + + talloc_steal(state, c); + + state->state = CTDB_CALL_ERROR; + state->errmsg = (char *)c->msg; +} + /* destroy a ctdb_call */ @@ -306,6 +357,7 @@ int ctdb_call_recv(struct ctdb_call_state *state, TDB_DATA *reply_data) event_loop_once(state->node->ctdb->ev); } if (state->state != CTDB_CALL_DONE) { + ctdb_set_error(state->node->ctdb, "%s", state->errmsg); talloc_free(state); return -1; } diff --git a/ctdb/include/ctdb_private.h b/ctdb/include/ctdb_private.h index 8675dccadd..6270ac3132 100644 --- a/ctdb/include/ctdb_private.h +++ b/ctdb/include/ctdb_private.h @@ -116,11 +116,12 @@ struct ctdb_ltdb_header { operation IDs */ enum ctdb_operation { - CTDB_REQ_CALL = 0, - CTDB_REPLY_CALL = 1, + CTDB_REQ_CALL = 0, + CTDB_REPLY_CALL = 1, CTDB_REPLY_REDIRECT = 2, - CTDB_REQ_DMASTER = 3, - CTDB_REPLY_DMASTER = 4, + CTDB_REQ_DMASTER = 3, + CTDB_REPLY_DMASTER = 4, + CTDB_REPLY_ERROR = 5 }; /* @@ -148,6 +149,13 @@ struct ctdb_reply_call { uint8_t data[0]; }; +struct ctdb_reply_error { + struct ctdb_req_header hdr; + uint32_t status; + uint32_t msglen; + uint8_t msg[0]; +}; + /* internal prototypes */ void ctdb_set_error(struct ctdb_context *ctdb, const char *fmt, ...); bool ctdb_same_address(struct ctdb_address *a1, struct ctdb_address *a2); @@ -157,6 +165,7 @@ int ctdb_parse_address(struct ctdb_context *ctdb, uint32_t ctdb_hash(TDB_DATA *key); void ctdb_request_call(struct ctdb_context *ctdb, struct ctdb_req_header *hdr); void ctdb_reply_call(struct ctdb_context *ctdb, struct ctdb_req_header *hdr); +void ctdb_reply_error(struct ctdb_context *ctdb, struct ctdb_req_header *hdr); int ctdb_ltdb_fetch(struct ctdb_context *ctdb, TDB_DATA key, struct ctdb_ltdb_header *header, TDB_DATA *data); |