]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
mds: validate the state+rank in MDS map
authorJohn Spray <john.spray@redhat.com>
Tue, 12 May 2015 16:24:58 +0000 (17:24 +0100)
committerJohn Spray <john.spray@redhat.com>
Thu, 14 May 2015 12:58:31 +0000 (13:58 +0100)
Especially:
 * once I have been assigned a rank, it
can't be taken away without restarting
the daemon.
 * once I have entered standby, I can
only go upwards through the states.

Fixes: #11481
Signed-off-by: John Spray <john.spray@redhat.com>
src/mds/MDS.cc

index 61f977ea3ae7a3ebc748f129a0bcac82af5dc02e..52ccf1f54ab2d10d466f9d4054ef92a99eac3ca4 100644 (file)
@@ -1567,11 +1567,53 @@ void MDS::handle_mds_map(MMDSMap *m)
   // see who i am
   addr = messenger->get_myaddr();
   whoami = mdsmap->get_rank_gid(mds_gid_t(monc->get_global_id()));
+  if (whoami == MDS_RANK_NONE && (
+      state == MDSMap::STATE_STANDBY_REPLAY || state == MDSMap::STATE_ONESHOT_REPLAY)) {
+    whoami = mdsmap->get_mds_info_gid(mds_gid_t(monc->get_global_id())).standby_for_rank;
+  }
+
   state = mdsmap->get_state_gid(mds_gid_t(monc->get_global_id()));
   incarnation = mdsmap->get_inc_gid(mds_gid_t(monc->get_global_id()));
   dout(10) << "map says i am " << addr << " mds." << whoami << "." << incarnation
           << " state " << ceph_mds_state_name(state) << dendl;
 
+  // Once I hold a rank it can't be taken away without
+  // restarting this daemon
+  if (whoami != oldwhoami && oldwhoami != MDS_RANK_NONE) {
+    derr << "Invalid rank transition " << oldwhoami << "->" << whoami << dendl;
+    respawn();
+  }
+
+  // Validate state transitions while I hold a rank
+  {
+    bool state_valid = true;
+    if (whoami != MDS_RANK_NONE && state != oldstate) {
+      if (oldstate == MDSMap::STATE_REPLAY) {
+        if (state != MDSMap::STATE_RESOLVE && state != MDSMap::STATE_RECONNECT) {
+          state_valid = false;
+        }
+      } else if (oldstate == MDSMap::STATE_REJOIN) {
+        if (state != MDSMap::STATE_ACTIVE
+            && state != MDSMap::STATE_CLIENTREPLAY
+            && state != MDSMap::STATE_STOPPED) {
+          state_valid = false;
+        }
+      } else if (oldstate >= MDSMap::STATE_RECONNECT && oldstate < MDSMap::STATE_ACTIVE) {
+        // Once I have entered replay, the only allowable transitions are to
+        // the next state along in the sequence.
+        if (state != oldstate + 1) {
+          state_valid = false;
+        }
+      }
+    }
+
+    if (!state_valid) {
+      derr << "Invalid state transition " << ceph_mds_state_name(oldstate)
+        << "->" << ceph_mds_state_name(state) << dendl;
+      respawn();
+    }
+  }
+
   // mark down any failed peers
   for (map<mds_gid_t,MDSMap::mds_info_t>::const_iterator p = oldmap->get_mds_info().begin();
        p != oldmap->get_mds_info().end();
@@ -1603,49 +1645,39 @@ void MDS::handle_mds_map(MMDSMap *m)
     }
   }
 
-  if (whoami < 0) {
-    if (state == MDSMap::STATE_STANDBY_REPLAY ||
-        state == MDSMap::STATE_ONESHOT_REPLAY) {
-      // fill in whoami from standby-for-rank. If we let this be changed
-      // the logic used to set it here will need to be adjusted.
-      whoami = mdsmap->get_mds_info_gid(mds_gid_t(monc->get_global_id())).standby_for_rank;
+  if (whoami == MDS_RANK_NONE) {
+    if (want_state == MDSMap::STATE_STANDBY) {
+      dout(10) << "dropped out of mdsmap, try to re-add myself" << dendl;
+      state = MDSMap::STATE_BOOT;
+      set_want_state(state);
+      goto out;
+    } else if (want_state == MDSMap::STATE_BOOT) {
+      dout(10) << "not in map yet" << dendl;
     } else {
-      if (want_state == MDSMap::STATE_STANDBY) {
-        dout(10) << "dropped out of mdsmap, try to re-add myself" << dendl;
-        state = MDSMap::STATE_BOOT;
-        set_want_state(state);
-        goto out;
+      // did i get kicked by someone else?
+      if (g_conf->mds_enforce_unique_name) {
+        if (mds_gid_t existing = mdsmap->find_mds_gid_by_name(name)) {
+          MDSMap::mds_info_t& i = mdsmap->get_info_gid(existing);
+          if (i.global_id > monc->get_global_id()) {
+            dout(1) << "handle_mds_map i (" << addr
+                    << ") dne in the mdsmap, new instance has larger gid " << i.global_id
+                    << ", suicide" << dendl;
+            // Call suicide() rather than respawn() because if someone else
+            // has taken our ID, we don't want to keep restarting and
+            // fighting them for the ID.
+            suicide();
+            goto out;
+          }
+        }
       }
-      if (want_state == MDSMap::STATE_BOOT) {
-        dout(10) << "not in map yet" << dendl;
-      } else {
-       // did i get kicked by someone else?
-       if (g_conf->mds_enforce_unique_name) {
-         if (mds_gid_t existing = mdsmap->find_mds_gid_by_name(name)) {
-           MDSMap::mds_info_t& i = mdsmap->get_info_gid(existing);
-           if (i.global_id > monc->get_global_id()) {
-             dout(1) << "handle_mds_map i (" << addr
-                     << ") dne in the mdsmap, new instance has larger gid " << i.global_id
-                     << ", suicide" << dendl;
-              // Call suicide() rather than respawn() because if someone else
-              // has taken our ID, we don't want to keep restarting and
-              // fighting them for the ID.
-             suicide();
-             goto out;
-           }
-         }
-       }
 
-        dout(1) << "handle_mds_map i (" << addr
-            << ") dne in the mdsmap, respawning myself" << dendl;
-        respawn();
-      }
-      goto out;
+      dout(1) << "handle_mds_map i (" << addr
+          << ") dne in the mdsmap, respawning myself" << dendl;
+      respawn();
     }
+    goto out;
   }
 
-  // ??
-
   if (oldwhoami != whoami || oldstate != state) {
     // update messenger.
     if (state == MDSMap::STATE_STANDBY_REPLAY || state == MDSMap::STATE_ONESHOT_REPLAY) {