ctdb-server: Implement CTDB_CONTROL_START_IPREALLOCATE
authorVinit Agnihotri <vagnihotri@ddn.com>
Thu, 26 Oct 2023 06:55:17 +0000 (23:55 -0700)
committerVolker Lendecke <vl@samba.org>
Wed, 6 Mar 2024 06:05:38 +0000 (06:05 +0000)
Trigger a "startipreallocate" event, but only if in RUNNING runstate.
"startipreallocate" is intended to allow an NFS server to be put into
grace on all nodes before any locks are released as part of releaseip
during failover.  If node A is leader and initiates a takeover run
then node B may be connected/active but may not have completed
startup.  In this case, the attempt to put NFS-Ganesha into grace on
node B will fail, startipreallocate will fail, and the node will be
banned.

Signed-off-by: Vinit Agnihotri <vagnihotri@ddn.com>
Reviewed-by: Martin Schwenke <mschwenke@ddn.com>
Reviewed-by: Volker Lendecke <vl@samba.org>
ctdb/include/ctdb_private.h
ctdb/server/ctdb_control.c
ctdb/server/ctdb_takeover.c
ctdb/tests/src/fake_ctdbd.c

index 802781237781e907f9ea6671dfe7a8b443c2a3c7..cee95792ead462ee6f24cfae1e8a12520c683d00 100644 (file)
@@ -887,6 +887,9 @@ int32_t ctdb_control_release_ip(struct ctdb_context *ctdb,
 int32_t ctdb_control_ipreallocated(struct ctdb_context *ctdb,
                                 struct ctdb_req_control_old *c,
                                 bool *async_reply);
+int32_t ctdb_control_start_ipreallocate(struct ctdb_context *ctdb,
+                                       struct ctdb_req_control_old *c,
+                                       bool *async_reply);
 
 int ctdb_set_public_addresses(struct ctdb_context *ctdb, bool check_addresses);
 
index 422c4cf1e58eeead442df0e8e6b2ca0ba2d4a905..a51795f340a5dd9b24f1fa91afb7599b4c284250 100644 (file)
@@ -876,6 +876,10 @@ static int32_t ctdb_control_dispatch(struct ctdb_context *ctdb,
                CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_connection));
                return ctdb_control_tcp_client_passed(ctdb, client_id, indata);
 
+       case CTDB_CONTROL_START_IPREALLOCATE:
+               CHECK_CONTROL_DATA_SIZE(0);
+               return ctdb_control_start_ipreallocate(ctdb, c, async_reply);
+
        default:
                DEBUG(DEBUG_CRIT,(__location__ " Unknown CTDB control opcode %u\n", opcode));
                return -1;
index b622fafd95faa9563b7c0dac304fd864fba2b6b2..70d9b85b746a8ac01d91774737dd604e808b740f 100644 (file)
@@ -2449,6 +2449,72 @@ int32_t ctdb_control_ipreallocated(struct ctdb_context *ctdb,
 }
 
 
+struct start_ipreallocate_callback_state {
+       struct ctdb_req_control_old *c;
+};
+
+static void ctdb_start_ipreallocate_callback(struct ctdb_context *ctdb,
+                                            int status, void *p)
+{
+       struct start_ipreallocate_callback_state *state = talloc_get_type_abort(
+               p, struct start_ipreallocate_callback_state);
+
+       if (status != 0) {
+               D_ERR("\"startipreallocate\" event failed (status %d)\n",
+                     status);
+               if (status == -ETIMEDOUT) {
+                       ctdb_ban_self(ctdb);
+               }
+       }
+
+       ctdb_request_control_reply(ctdb, state->c, NULL, status, NULL);
+       talloc_free(state);
+}
+
+/* A control to run the startipreallocate event */
+int32_t ctdb_control_start_ipreallocate(struct ctdb_context *ctdb,
+                                       struct ctdb_req_control_old *c,
+                                       bool *async_reply)
+{
+       int ret;
+       struct start_ipreallocate_callback_state *state;
+
+       /* Nodes that are not RUNNING can not host IPs */
+       if (ctdb->runstate != CTDB_RUNSTATE_RUNNING) {
+               DBG_INFO("Skipping \"startipreallocate\" event, not RUNNING\n");
+               return 0;
+       }
+
+       state = talloc(ctdb, struct start_ipreallocate_callback_state);
+       if (state == NULL) {
+               DBG_ERR("Memory allocation error\n");
+               return -1;
+       }
+
+       DBG_INFO("Running \"startipreallocate\" event\n");
+
+       ret = ctdb_event_script_callback(ctdb,
+                                        state,
+                                        ctdb_start_ipreallocate_callback,
+                                        state,
+                                        CTDB_EVENT_START_IPREALLOCATE,
+                                        "%s",
+                                        "");
+
+       if (ret != 0) {
+               D_ERR("Failed to run \"startipreallocate\" event \n");
+               talloc_free(state);
+               return -1;
+       }
+
+       /* tell the control that we will be reply asynchronously */
+       state->c    = talloc_steal(state, c);
+       *async_reply = true;
+
+       return 0;
+}
+
+
 struct ctdb_reloadips_handle {
        struct ctdb_context *ctdb;
        struct ctdb_req_control_old *c;
index 0d430a37834a71f1b6350c32302a532c2ad8b6a7..a569b0686c3479ffa7ca04f0ea0321d2f92bce4f 100644 (file)
@@ -3450,6 +3450,21 @@ done:
        client_send_control(req, header, &reply);
 }
 
+static void control_start_ipreallocate(TALLOC_CTX *mem_ctx,
+                                      struct tevent_req *req,
+                                      struct ctdb_req_header *header,
+                                      struct ctdb_req_control *request)
+{
+       struct ctdb_reply_control reply;
+
+       /* Always succeed */
+       reply.rdata.opcode = request->opcode;
+       reply.status = 0;
+       reply.errmsg = NULL;
+
+       client_send_control(req, header, &reply);
+}
+
 static void control_ipreallocated(TALLOC_CTX *mem_ctx,
                                  struct tevent_req *req,
                                  struct ctdb_req_header *header,
@@ -4364,6 +4379,10 @@ static void client_process_control(struct tevent_req *req,
                control_enable_node(mem_ctx, req, &header, &request);
                break;
 
+       case CTDB_CONTROL_START_IPREALLOCATE:
+               control_start_ipreallocate(mem_ctx, req, &header, &request);
+               break;
+
        default:
                if (! (request.flags & CTDB_CTRL_FLAG_NOREPLY)) {
                        control_error(mem_ctx, req, &header, &request);