ctdb-daemon: Check packet generation against database generation
authorAmitay Isaacs <amitay@gmail.com>
Tue, 15 Sep 2015 06:50:19 +0000 (16:50 +1000)
committerAmitay Isaacs <amitay@samba.org>
Wed, 7 Oct 2015 12:53:27 +0000 (14:53 +0200)
CTDB verifies the generation in the packet header matches that of the
current generation.  However, that check now needs to be done where
database context is available.  So add in the check in handlers for
database requests (CTDB_REQ_CALL, CTDB_REQ_DMASTER, CTDB_REPLY_DMASTER
and CTDB_REPLY_CALL).

Signed-off-by: Amitay Isaacs <amitay@gmail.com>
Reviewed-by: Martin Schwenke <martin@meltin.net>
ctdb/server/ctdb_call.c
ctdb/server/ctdb_server.c

index 39aac7e800370ba6ee8d82c9b0f221779284741a..4a59094ee702fe559f6334c1071d16e4248f3ca5 100644 (file)
@@ -569,6 +569,23 @@ void ctdb_request_dmaster(struct ctdb_context *ctdb, struct ctdb_req_header *hdr
        size_t len;
        int ret;
 
+       ctdb_db = find_ctdb_db(ctdb, c->db_id);
+       if (!ctdb_db) {
+               ctdb_send_error(ctdb, hdr, -1,
+                               "Unknown database in request. db_id==0x%08x",
+                               c->db_id);
+               return;
+       }
+
+       if (hdr->generation != ctdb_db->generation) {
+               DEBUG(DEBUG_DEBUG,
+                     ("ctdb operation %u request %u from node %u to %u had an"
+                      " invalid generation:%u while our generation is:%u\n",
+                      hdr->operation, hdr->reqid, hdr->srcnode, hdr->destnode,
+                      hdr->generation, ctdb_db->generation));
+               return;
+       }
+
        key.dptr = c->data;
        key.dsize = c->keylen;
        data.dptr = c->data + c->keylen;
@@ -580,14 +597,6 @@ void ctdb_request_dmaster(struct ctdb_context *ctdb, struct ctdb_req_header *hdr
                       sizeof(record_flags));
        }
 
-       ctdb_db = find_ctdb_db(ctdb, c->db_id);
-       if (!ctdb_db) {
-               ctdb_send_error(ctdb, hdr, -1,
-                               "Unknown database in request. db_id==0x%08x",
-                               c->db_id);
-               return;
-       }
-
        dmaster_defer_setup(ctdb_db, hdr, key);
 
        /* fetch the current record */
@@ -616,7 +625,7 @@ void ctdb_request_dmaster(struct ctdb_context *ctdb, struct ctdb_req_header *hdr
        if (header.dmaster != hdr->srcnode) {
                DEBUG(DEBUG_ALERT,("pnn %u dmaster request for new-dmaster %u from non-master %u real-dmaster=%u key %08x dbid 0x%08x gen=%u curgen=%u c->rsn=%llu header.rsn=%llu reqid=%u keyval=0x%08x\n",
                         ctdb->pnn, c->dmaster, hdr->srcnode, header.dmaster, ctdb_hash(&key),
-                        ctdb_db->db_id, hdr->generation, ctdb->vnn_map->generation,
+                        ctdb_db->db_id, hdr->generation, ctdb_db->generation,
                         (unsigned long long)c->rsn, (unsigned long long)header.rsn, c->hdr.reqid,
                         (key.dsize >= 4)?(*(uint32_t *)key.dptr):0));
                if (header.rsn != 0 || header.dmaster != ctdb->pnn) {
@@ -631,7 +640,7 @@ void ctdb_request_dmaster(struct ctdb_context *ctdb, struct ctdb_req_header *hdr
        if (header.rsn > c->rsn) {
                DEBUG(DEBUG_ALERT,("pnn %u dmaster request with older RSN new-dmaster %u from %u real-dmaster=%u key %08x dbid 0x%08x gen=%u curgen=%u c->rsn=%llu header.rsn=%llu reqid=%u\n",
                         ctdb->pnn, c->dmaster, hdr->srcnode, header.dmaster, ctdb_hash(&key),
-                        ctdb_db->db_id, hdr->generation, ctdb->vnn_map->generation,
+                        ctdb_db->db_id, hdr->generation, ctdb_db->generation,
                         (unsigned long long)c->rsn, (unsigned long long)header.rsn, c->hdr.reqid));
        }
 
@@ -871,7 +880,6 @@ void ctdb_request_call(struct ctdb_context *ctdb, struct ctdb_req_header *hdr)
                return;
        }
 
-
        ctdb_db = find_ctdb_db(ctdb, c->db_id);
        if (!ctdb_db) {
                ctdb_send_error(ctdb, hdr, -1,
@@ -880,6 +888,15 @@ void ctdb_request_call(struct ctdb_context *ctdb, struct ctdb_req_header *hdr)
                return;
        }
 
+       if (hdr->generation != ctdb_db->generation) {
+               DEBUG(DEBUG_DEBUG,
+                     ("ctdb operation %u request %u from node %u to %u had an"
+                      " invalid generation:%u while our generation is:%u\n",
+                      hdr->operation, hdr->reqid, hdr->srcnode, hdr->destnode,
+                      hdr->generation, ctdb_db->generation));
+               return;
+       }
+
        call = talloc(hdr, struct ctdb_call);
        CTDB_NO_MEMORY_FATAL(ctdb, call);
 
@@ -1154,6 +1171,15 @@ void ctdb_reply_call(struct ctdb_context *ctdb, struct ctdb_req_header *hdr)
                return;
        }
 
+       if (hdr->generation != state->generation) {
+               DEBUG(DEBUG_DEBUG,
+                     ("ctdb operation %u request %u from node %u to %u had an"
+                      " invalid generation:%u while our generation is:%u\n",
+                      hdr->operation, hdr->reqid, hdr->srcnode, hdr->destnode,
+                      hdr->generation, state->generation));
+               return;
+       }
+
 
        /* read only delegation processing */
        /* If we got a FETCH_WITH_HEADER we should check if this is a ro
@@ -1248,7 +1274,16 @@ void ctdb_reply_dmaster(struct ctdb_context *ctdb, struct ctdb_req_header *hdr)
                DEBUG(DEBUG_ERR,("Unknown db_id 0x%x in ctdb_reply_dmaster\n", c->db_id));
                return;
        }
-       
+
+       if (hdr->generation != ctdb_db->generation) {
+               DEBUG(DEBUG_DEBUG,
+                     ("ctdb operation %u request %u from node %u to %u had an"
+                      " invalid generation:%u while our generation is:%u\n",
+                      hdr->operation, hdr->reqid, hdr->srcnode, hdr->destnode,
+                      hdr->generation, ctdb_db->generation));
+               return;
+       }
+
        key.dptr = c->data;
        key.dsize = c->keylen;
        data.dptr = &c->data[key.dsize];
index 81ef361b225e30c393dbffac97272da138499865..75aec16f7677793aec9ad4e9c514422631ceb975 100644 (file)
@@ -215,22 +215,11 @@ void ctdb_input_pkt(struct ctdb_context *ctdb, struct ctdb_req_header *hdr)
                        goto done;
                }
 
-               /* for ctdb_call inter-node operations verify that the
-                  remote node that sent us the call is running in the
-                  same generation instance as this node
-               */
-               if (ctdb->vnn_map->generation != hdr->generation) {
-                       DEBUG(DEBUG_DEBUG,(__location__ " ctdb operation %u"
-                               " request %u"
-                               " length %u from node %u to %u had an"
-                               " invalid generation id:%u while our"
-                               " generation id is:%u\n", 
-                                hdr->operation, hdr->reqid,
-                                hdr->length, 
-                                hdr->srcnode, hdr->destnode, 
-                                hdr->generation, ctdb->vnn_map->generation));
-                       goto done;
-               }
+               /* Push the check for generation in the handlers for these
+                * operations.  Check database generation instead of global
+                * generation.  Since the database context is not available
+                * here, push the check in the operations.
+                */
        }
 
        switch (hdr->operation) {