]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
in ctdb_call_recv() we must check that state is non-NULL since
authorRonnie Sahlberg <sahlberg@ronnie>
Thu, 23 Aug 2007 01:58:09 +0000 (11:58 +1000)
committerRonnie Sahlberg <sahlberg@ronnie>
Thu, 23 Aug 2007 01:58:09 +0000 (11:58 +1000)
ctdb_call() may pass a null pointer to _recv() and this would cause a
segfault.
fortunately there appears there are no critical users for this codepath
right now so the risk was more theoretical IF clients start using this
call it coult segfault.

change ctdb_control() to become fully async so we later can make
recovery daemon do the expensive controls to nodes in parallell instead
of in sequence

(This used to be ctdb commit 379789cda6ef049f389f10136aaa1b37a4d063a9)

ctdb/client/ctdb_client.c

index 19b19f489a4c0be8390fafb0e115dd2c79803fdf..a18c567ff29b9bbd67bd64a1ed0d765abfb46ae4 100644 (file)
@@ -301,6 +301,10 @@ struct ctdb_record_handle {
 */
 int ctdb_call_recv(struct ctdb_client_call_state *state, struct ctdb_call *call)
 {
+       if (state == NULL) {
+               return -1;
+       }
+
        while (state->state < CTDB_CALL_DONE) {
                event_loop_once(state->ctdb_db->ctdb->ev);
        }
@@ -661,7 +665,7 @@ int ctdb_fetch(struct ctdb_db_context *ctdb_db, TALLOC_CTX *mem_ctx,
 }
 
 
-enum control_state {CTDB_CONTROL_WAIT, CTDB_CONTROL_DONE, CTDB_CONTROL_ERROR};
+enum control_state {CTDB_CONTROL_WAIT, CTDB_CONTROL_DONE, CTDB_CONTROL_ERROR, CTDB_CONTROL_TIMEOUT};
 
 struct ctdb_client_control_state {
        struct ctdb_context *ctdb;
@@ -711,15 +715,6 @@ static void ctdb_client_reply_control(struct ctdb_context *ctdb,
 }
 
 
-/* time out handler for ctdb_control */
-static void timeout_func(struct event_context *ev, struct timed_event *te, 
-       struct timeval t, void *private_data)
-{
-       uint32_t *timed_out = (uint32_t *)private_data;
-
-       *timed_out = 1;
-}
-
 /*
   destroy a ctdb_control in client
 */
@@ -729,22 +724,29 @@ static int ctdb_control_destructor(struct ctdb_client_control_state *state)
        return 0;
 }
 
-/*
-  send a ctdb control message
-  timeout specifies how long we should wait for a reply.
-  if timeout is NULL we wait indefinitely
- */
-int ctdb_control(struct ctdb_context *ctdb, uint32_t destnode, uint64_t srvid, 
-                uint32_t opcode, uint32_t flags, TDB_DATA data, 
-                TALLOC_CTX *mem_ctx, TDB_DATA *outdata, int32_t *status,
-                struct timeval *timeout,
-                char **errormsg)
+
+/* time out handler for ctdb_control */
+static void control_timeout_func(struct event_context *ev, struct timed_event *te, 
+       struct timeval t, void *private_data)
+{
+       struct ctdb_client_control_state *state = talloc_get_type(private_data, struct ctdb_client_control_state);
+
+       state->state = CTDB_CONTROL_TIMEOUT;
+}
+
+/* async version of send control request */
+struct ctdb_client_control_state *ctdb_control_send(struct ctdb_context *ctdb, 
+               uint32_t destnode, uint64_t srvid, 
+               uint32_t opcode, uint32_t flags, TDB_DATA data, 
+               TALLOC_CTX *mem_ctx, TDB_DATA *outdata, int32_t *status,
+               struct timeval *timeout,
+               char **errormsg)
+
 {
        struct ctdb_client_control_state *state;
        struct ctdb_req_control *c;
        size_t len;
        int ret;
-       uint32_t timed_out;
 
        if (errormsg) {
                *errormsg = NULL;
@@ -756,19 +758,19 @@ int ctdb_control(struct ctdb_context *ctdb, uint32_t destnode, uint64_t srvid,
        }
 
        state = talloc_zero(ctdb, struct ctdb_client_control_state);
-       CTDB_NO_MEMORY(ctdb, state);
+       CTDB_NO_MEMORY_NULL(ctdb, state);
 
-       state->ctdb  = ctdb;
-       state->reqid = ctdb_reqid_new(ctdb, state);
-       state->state = CTDB_CONTROL_WAIT;
-       state->errormsg = NULL;
+       state->ctdb    = ctdb;
+       state->reqid   = ctdb_reqid_new(ctdb, state);
+       state->state   = CTDB_CONTROL_WAIT;
+       state->errormsg= NULL;
 
        talloc_set_destructor(state, ctdb_control_destructor);
 
        len = offsetof(struct ctdb_req_control, data) + data.dsize;
        c = ctdbd_allocate_pkt(ctdb, state, CTDB_REQ_CONTROL, 
                               len, struct ctdb_req_control);
-       CTDB_NO_MEMORY(ctdb, c);
+       CTDB_NO_MEMORY_NULL(ctdb, c);
        
        c->hdr.reqid        = state->reqid;
        c->hdr.destnode     = destnode;
@@ -785,55 +787,94 @@ int ctdb_control(struct ctdb_context *ctdb, uint32_t destnode, uint64_t srvid,
        ret = ctdb_client_queue_pkt(ctdb, &(c->hdr));
        if (ret != 0) {
                talloc_free(state);
-               return -1;
+               return NULL;
        }
 
        if (flags & CTDB_CTRL_FLAG_NOREPLY) {
                talloc_free(state);
-               return 0;
+               return NULL;
        }
 
-       /* semi-async operation */
-       timed_out = 0;
+       /* timeout */
        if (timeout && !timeval_is_zero(timeout)) {
-               event_add_timed(ctdb->ev, state, *timeout, timeout_func, &timed_out);
+               event_add_timed(ctdb->ev, state, *timeout, control_timeout_func, state);
        }
-       while ((state->state == CTDB_CONTROL_WAIT)
-       &&      (timed_out == 0) ){
+
+       return state;
+}
+
+
+/* async version of receive control reply */
+int ctdb_control_recv(struct ctdb_context *ctdb, 
+               struct ctdb_client_control_state *state, 
+               TALLOC_CTX *mem_ctx,
+               TDB_DATA *outdata, int32_t *status, char **errormsg)
+{
+       if (state == NULL) {
+               return -1;
+       }
+
+       /* loop one event at a time until we either timeout or the control
+          completes.
+       */
+       while (state->state == CTDB_CONTROL_WAIT) {
                event_loop_once(ctdb->ev);
        }
-       if (timed_out) {
+       if (state->state != CTDB_CONTROL_DONE) {
+               DEBUG(0,(__location__ " ctdb_control_recv failed\n"));
                talloc_free(state);
+               return -1;
+       }
+
+       if (state->errormsg) {
+               DEBUG(0,("ctdb_control error: '%s'\n", state->errormsg));
                if (errormsg) {
-                       (*errormsg) = talloc_strdup(mem_ctx, "control timed out");
-               } else {
-                       DEBUG(0,("ctdb_control timed out\n"));
+                       (*errormsg) = talloc_move(mem_ctx, &state->errormsg);
                }
+               talloc_free(state);
                return -1;
        }
 
+
        if (outdata) {
                *outdata = state->outdata;
                outdata->dptr = talloc_memdup(mem_ctx, outdata->dptr, outdata->dsize);
        }
 
-       *status = state->status;
-
-       if (!errormsg && state->errormsg) {
-               DEBUG(0,("ctdb_control error: '%s'\n", state->errormsg));
+       if (status) {
+               *status = state->status;
        }
 
-       if (errormsg && state->errormsg) {
-               (*errormsg) = talloc_move(mem_ctx, &state->errormsg);
-       }
 
        talloc_free(state);
+       return 0;
+}
 
-       return 0;       
+
+
+/*
+  send a ctdb control message
+  timeout specifies how long we should wait for a reply.
+  if timeout is NULL we wait indefinitely
+ */
+int ctdb_control(struct ctdb_context *ctdb, uint32_t destnode, uint64_t srvid, 
+                uint32_t opcode, uint32_t flags, TDB_DATA data, 
+                TALLOC_CTX *mem_ctx, TDB_DATA *outdata, int32_t *status,
+                struct timeval *timeout,
+                char **errormsg)
+{
+       struct ctdb_client_control_state *state;
+
+       state = ctdb_control_send(ctdb, destnode, srvid, opcode, 
+                       flags, data, mem_ctx, outdata, status,
+                       timeout, errormsg);
+       return ctdb_control_recv(ctdb, state, mem_ctx, outdata, status, 
+                       errormsg);
 }
 
 
 
+
 /*
   a process exists call. Returns 0 if process exists, -1 otherwise
  */