]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
mon: add freeze MDS command
authorPatrick Donnelly <pdonnell@redhat.com>
Sun, 24 Feb 2019 18:52:05 +0000 (10:52 -0800)
committerPatrick Donnelly <pdonnell@redhat.com>
Thu, 28 Feb 2019 05:39:17 +0000 (21:39 -0800)
This is a new hidden command that allows us to do certain testing for race
conditions. A frozen MDS cannot change change state or be replaced by a
standby.

Signed-off-by: Patrick Donnelly <pdonnell@redhat.com>
15 files changed:
src/mds/FSMap.cc
src/mds/FSMap.h
src/mds/MDSMap.cc
src/mds/MDSMap.h
src/mds/MDSRank.cc
src/mds/mdstypes.cc
src/mds/mdstypes.h
src/mon/CMakeLists.txt
src/mon/CommandHandler.cc [new file with mode: 0644]
src/mon/CommandHandler.h [new file with mode: 0644]
src/mon/FSCommands.cc
src/mon/FSCommands.h
src/mon/MDSMonitor.cc
src/mon/MDSMonitor.h
src/mon/MonCommands.h

index 74a340fc70020180a900d719af4b530312c1fc77..e395f2dcbcc8ef3a691d8dc526839ed499acb3fb 100644 (file)
@@ -711,32 +711,40 @@ void Filesystem::print(std::ostream &out) const
   mds_map.print(out);
 }
 
-mds_gid_t FSMap::find_replacement_for(mds_role_t role, std::string_view name) const
+mds_gid_t FSMap::get_available_standby() const
 {
-  auto&& fs = get_filesystem(role.fscid);
-
-  // First see if we have a STANDBY_REPLAY
-  for (const auto& [gid, info] : fs->mds_map.mds_info) {
-    if (info.rank == role.rank && info.state == MDSMap::STATE_STANDBY_REPLAY) {
-      return gid;
-    }
-  }
-
-  // See if there are any STANDBY daemons available
   for (const auto& [gid, info] : standby_daemons) {
     ceph_assert(info.rank == MDS_RANK_NONE);
     ceph_assert(info.state == MDSMap::STATE_STANDBY);
 
-    if (info.laggy()) {
+    if (info.laggy() || info.is_frozen()) {
       continue;
     }
 
     return gid;
   }
-
   return MDS_GID_NONE;
 }
 
+mds_gid_t FSMap::find_replacement_for(mds_role_t role, std::string_view name) const
+{
+  auto&& fs = get_filesystem(role.fscid);
+
+  // First see if we have a STANDBY_REPLAY
+  for (const auto& [gid, info] : fs->mds_map.mds_info) {
+    if (info.rank == role.rank && info.state == MDSMap::STATE_STANDBY_REPLAY) {
+      if (info.is_frozen()) {
+        /* the standby-replay is frozen, do nothing! */
+        return MDS_GID_NONE;
+      } else {
+        return gid;
+      }
+    }
+  }
+
+  return get_available_standby();
+}
+
 void FSMap::sanity() const
 {
   if (legacy_client_fscid != FS_CLUSTER_ID_NONE) {
index 46f445ff4fe4d2d7e903b110178884a1f6e82020..36d024c2e36e718e31e809927b1ca6302ad9a727 100644 (file)
@@ -193,6 +193,8 @@ public:
     return result;
   }
 
+  mds_gid_t get_available_standby() const;
+
   /**
    * Resolve daemon name to GID
    */
index c29b283570aa14ce76cd2a8fda5371fbc1e6a4bd..889d35b7f1e516d327a3ad283566b6d7f43a1dd3 100644 (file)
@@ -89,6 +89,7 @@ void MDSMap::mds_info_t::dump(Formatter *f) const
   }
   f->close_section();
   f->dump_unsigned("features", mds_features);
+  f->dump_unsigned("flags", flags);
 }
 
 void MDSMap::mds_info_t::print_summary(ostream &out) const
@@ -106,6 +107,9 @@ void MDSMap::mds_info_t::print_summary(ostream &out) const
   if (!export_targets.empty()) {
     out << " export_targets=" << export_targets;
   }
+  if (is_frozen()) {
+    out << " frozen";
+  }
 }
 
 void MDSMap::mds_info_t::generate_test_instances(list<mds_info_t*>& ls)
@@ -504,7 +508,7 @@ void MDSMap::get_health_checks(health_check_map_t *checks) const
 
 void MDSMap::mds_info_t::encode_versioned(bufferlist& bl, uint64_t features) const
 {
-  __u8 v = 8;
+  __u8 v = 9;
   if (!HAVE_FEATURE(features, SERVER_NAUTILUS)) {
     v = 7;
   }
@@ -527,6 +531,7 @@ void MDSMap::mds_info_t::encode_versioned(bufferlist& bl, uint64_t features) con
   encode(mds_features, bl);
   encode(FS_CLUSTER_ID_NONE, bl); /* standby_for_fscid */
   encode(false, bl);
+  encode(flags, bl);
   ENCODE_FINISH(bl);
 }
 
@@ -579,6 +584,9 @@ void MDSMap::mds_info_t::decode(bufferlist::const_iterator& bl)
     bool standby_replay;
     decode(standby_replay, bl);
   }
+  if (struct_v >= 8) {
+    decode(flags, bl);
+  }
   DECODE_FINISH(bl);
 }
 
index 6916d0ad2bee74d01421b2bddd0ac9e9928cc675..5ba266a4294f6d3d68847b221b73e9242f0d9c19 100644 (file)
@@ -110,12 +110,24 @@ public:
     utime_t laggy_since;
     std::set<mds_rank_t> export_targets;
     uint64_t mds_features = 0;
+    uint64_t flags = 0;
+    enum mds_flags : uint64_t {
+      FROZEN = 1 << 0,
+    };
 
     mds_info_t() = default;
 
     bool laggy() const { return !(laggy_since == utime_t()); }
     void clear_laggy() { laggy_since = utime_t(); }
 
+    bool is_degraded() const {
+      return STATE_REPLAY <= state && state <= STATE_CLIENTREPLAY;
+    }
+
+    void freeze() { flags |= mds_flags::FROZEN; }
+    void unfreeze() { flags &= ~mds_flags::FROZEN; }
+    bool is_frozen() const { return flags&mds_flags::FROZEN; }
+
     const entity_addrvec_t& get_addrs() const {
       return addrs;
     }
@@ -541,29 +553,33 @@ public:
     return is_clientreplay(m) || is_active(m) || is_stopping(m);
   }
 
+  mds_gid_t get_standby_replay(mds_rank_t r) const {
+    for (auto& [gid,info] : mds_info) {
+      if (info.rank == r && info.state == STATE_STANDBY_REPLAY) {
+        return gid;
+      }
+    }
+    return MDS_GID_NONE;
+  }
+  bool has_standby_replay(mds_rank_t r) const {
+    return get_standby_replay(r) != MDS_GID_NONE;
+  }
+
   bool is_followable(mds_rank_t r) const {
-    bool has_followable_rank = false;
-    for (const auto& p : mds_info) {
-      auto& info = p.second;
-      if (info.rank == r) {
-        if (info.state == STATE_ACTIVE) {
-          has_followable_rank = true;
-        } else {
-          return false;
+    if (auto it1 = up.find(r); it1 != up.end()) {
+      if (auto it2 = mds_info.find(it1->second); it2 != mds_info.end()) {
+        auto& info = it2->second;
+        if (!info.is_degraded() && !has_standby_replay(r)) {
+          return true;
         }
       }
-      if (p.second.state == STATE_STANDBY_REPLAY) {
-        return false;
-      }
     }
-    return has_followable_rank;
+    return false;
   }
 
   bool is_laggy_gid(mds_gid_t gid) const {
-    if (!mds_info.count(gid))
-      return false;
-    std::map<mds_gid_t,mds_info_t>::const_iterator p = mds_info.find(gid);
-    return p->second.laggy();
+    auto it = mds_info.find(gid);
+    return it == mds_info.end() ? false : it->second.laggy();
   }
 
   // degraded = some recovery in process.  fixes active membership and
@@ -571,11 +587,10 @@ public:
   bool is_degraded() const {
     if (!failed.empty() || !damaged.empty())
       return true;
-    for (std::map<mds_gid_t,mds_info_t>::const_iterator p = mds_info.begin();
-        p != mds_info.end();
-        ++p)
-      if (p->second.state >= STATE_REPLAY && p->second.state <= STATE_CLIENTREPLAY)
-       return true;
+    for (const auto& p : mds_info) {
+      if (p.second.is_degraded())
+        return true;
+    }
     return false;
   }
   bool is_any_failed() const {
index ad4a4e50e80f0301ceca7c1623e6e95bf0cd0818..be90b70f57aebd49000e7844f63ea611c93873c7 100644 (file)
@@ -2393,15 +2393,7 @@ void MDSRankDispatcher::handle_mds_map(
                            std::mem_fn(&OSDMap::get_epoch)));
 
     /* Now check if we should hint to the OSD that a read may follow */
-    bool found = false;
-    for (const auto& p : mdsmap->get_mds_info()) {
-      auto& info = p.second;
-      if (info.state == MDSMap::STATE_STANDBY_REPLAY && info.rank == whoami) {
-       found = true;
-       break;
-      }
-    }
-    if (found)
+    if (mdsmap->has_standby_replay(whoami))
       mdlog->set_write_iohint(0);
     else
       mdlog->set_write_iohint(CEPH_OSD_OP_FLAG_FADVISE_DONTNEED);
index 2c671b5d0ae03bbac7db85b955bc35eb321f402f..20a2d2d5788017b1db50a5108268912247962443 100644 (file)
@@ -6,7 +6,6 @@
 #include "common/Formatter.h"
 
 const mds_gid_t MDS_GID_NONE = mds_gid_t(0);
-const mds_rank_t MDS_RANK_NONE = mds_rank_t(-1);
 
 
 /*
index 2130ace30b3ac12bb79efc93704f151106b101d0..49f6944e4bf6b695cdb54a407b525695b7d3c974 100644 (file)
 
 
 typedef int32_t mds_rank_t;
-typedef int32_t fs_cluster_id_t;
+constexpr mds_rank_t MDS_RANK_NONE = -1;
 
 BOOST_STRONG_TYPEDEF(uint64_t, mds_gid_t)
 extern const mds_gid_t MDS_GID_NONE;
-constexpr fs_cluster_id_t FS_CLUSTER_ID_NONE = {-1};
+
+typedef int32_t fs_cluster_id_t;
+constexpr fs_cluster_id_t FS_CLUSTER_ID_NONE = -1;
 // The namespace ID of the anonymous default filesystem from legacy systems
-constexpr fs_cluster_id_t FS_CLUSTER_ID_ANONYMOUS = {0};
-extern const mds_rank_t MDS_RANK_NONE;
+constexpr fs_cluster_id_t FS_CLUSTER_ID_ANONYMOUS = 0;
 
 class mds_role_t
 {
index 02b459e214bfaf6f78d232686a803590f54b8eee..23396f063bd0ab89b108bcea637259f8008669bd 100644 (file)
@@ -7,6 +7,7 @@ set(lib_mon_srcs
   PaxosService.cc
   OSDMonitor.cc
   MDSMonitor.cc
+  CommandHandler.cc
   FSCommands.cc
   MgrMonitor.cc
   MgrStatMonitor.cc
diff --git a/src/mon/CommandHandler.cc b/src/mon/CommandHandler.cc
new file mode 100644 (file)
index 0000000..903d359
--- /dev/null
@@ -0,0 +1,43 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+/*
+ * Ceph - scalable distributed file system
+ *
+ * Copyright (C) 2019 Red Hat Ltd
+ *
+ * This is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software 
+ * Foundation.  See file COPYING.
+ * 
+ */
+
+#include "CommandHandler.h"
+
+#include "common/strtol.h"
+#include "include/ceph_assert.h"
+
+#include <ostream>
+#include <string>
+#include <string_view>
+
+int CommandHandler::parse_bool(std::string_view str, bool* result, std::ostream& ss)
+{
+  ceph_assert(result != nullptr);
+
+  std::string interr;
+  int64_t n = strict_strtoll(str.data(), 10, &interr);
+
+  if (str == "false" || str == "no"
+      || (interr.length() == 0 && n == 0)) {
+    *result = false;
+    return 0;
+  } else if (str == "true" || str == "yes"
+      || (interr.length() == 0 && n == 1)) {
+    *result = true;
+    return 0;
+  } else {
+    ss << "value must be false|no|0 or true|yes|1";
+    return -EINVAL;
+  }
+}
diff --git a/src/mon/CommandHandler.h b/src/mon/CommandHandler.h
new file mode 100644 (file)
index 0000000..167b458
--- /dev/null
@@ -0,0 +1,35 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+/*
+ * Ceph - scalable distributed file system
+ *
+ * Copyright (C) 2019 Red Hat Ltd
+ *
+ * This is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software 
+ * Foundation.  See file COPYING.
+ * 
+ */
+
+
+#ifndef COMMAND_HANDLER_H_
+#define COMMAND_HANDLER_H_
+
+#include <ostream>
+#include <string_view>
+
+class CommandHandler
+{
+public:
+  /**
+   * Parse true|yes|1 style boolean string from `bool_str`
+   * `result` must be non-null.
+   * `ss` will be populated with error message on error.
+   *
+   * @return 0 on success, else -EINVAL
+   */
+  int parse_bool(std::string_view str, bool* result, std::ostream& ss);
+};
+
+#endif
index 3cc78c0f30f2902732970b0057414636a5e01ded..5dd9799c2aac67854e23ea8e2fa9c1244d76f29d 100644 (file)
@@ -974,30 +974,6 @@ FileSystemCommandHandler::load(Paxos *paxos)
   return handlers;
 }
 
-int FileSystemCommandHandler::parse_bool(
-      const std::string &bool_str,
-      bool *result,
-      std::ostream &ss)
-{
-  ceph_assert(result != nullptr);
-
-  string interr;
-  int64_t n = strict_strtoll(bool_str.c_str(), 10, &interr);
-
-  if (bool_str == "false" || bool_str == "no"
-      || (interr.length() == 0 && n == 0)) {
-    *result = false;
-    return 0;
-  } else if (bool_str == "true" || bool_str == "yes"
-      || (interr.length() == 0 && n == 1)) {
-    *result = true;
-    return 0;
-  } else {
-    ss << "value must be false|no|0 or true|yes|1";
-    return -EINVAL;
-  }
-}
-
 int FileSystemCommandHandler::_check_pool(
     OSDMap &osd_map,
     const int64_t pool_id,
index f7066c49f8635ac4cdc4414cc7a60875802423c0..69662d2b29e5c881e49f4e0ece954200806c6bb1 100644 (file)
@@ -17,6 +17,7 @@
 #define FS_COMMANDS_H_
 
 #include "Monitor.h"
+#include "CommandHandler.h"
 
 #include "osd/OSDMap.h"
 #include "mds/FSMap.h"
 #include <string>
 #include <sstream>
 
-class FileSystemCommandHandler
+class FileSystemCommandHandler : protected CommandHandler
 {
 protected:
   std::string prefix;
 
-  /**
-   * Parse true|yes|1 style boolean string from `bool_str`
-   * `result` must be non-null.
-   * `ss` will be populated with error message on error.
-   *
-   * @return 0 on success, else -EINVAL
-   */
-  int parse_bool(
-      const std::string &bool_str,
-      bool *result,
-      std::ostream &ss);
-
   /**
    * Return 0 if the pool is suitable for use with CephFS, or
    * in case of errors return a negative error code, and populate
index 521de9baa149ee0c2851cdd6bdd0e432192200a5..9739e7176eb14d4b91cff4ab15f9757d754fb220 100644 (file)
@@ -1407,6 +1407,34 @@ int MDSMonitor::filesystem_command(
       dout(1) << "repaired: no-op on rank " << role << dendl;
     }
 
+    r = 0;
+  } else if (prefix == "mds freeze") {
+    std::string who;
+    cmd_getval(g_ceph_context, cmdmap, "role_or_gid", who);
+    mds_gid_t gid = gid_from_arg(fsmap, who, ss);
+    if (gid == MDS_GID_NONE) {
+      return -EINVAL;
+    }
+
+    bool freeze = false;
+    {
+      std::string str;
+      cmd_getval(g_ceph_context, cmdmap, "val", str);
+      if ((r = parse_bool(str, &freeze, ss)) != 0) {
+        return r;
+      }
+    }
+
+    auto f = [freeze,gid,&ss](auto& info) {
+      if (freeze) {
+        ss << "freezing mds." << gid;
+        info.freeze();
+      } else {
+        ss << "unfreezing mds." << gid;
+        info.unfreeze();
+      }
+    };
+    fsmap.modify_daemon(gid, f);
     r = 0;
   } else {
     return -ENOSYS;
@@ -1794,6 +1822,7 @@ void MDSMonitor::maybe_replace_gid(FSMap &fsmap, mds_gid_t gid,
   }
   mono_time now = mono_clock::now();
   chrono::duration<double> since = now-latest_beacon;
+  const bool frozen = info.is_frozen();
   const bool may_replace = since.count() <
       std::max(g_conf()->mds_beacon_interval, g_conf()->mds_beacon_grace * 0.5);
 
@@ -1804,6 +1833,7 @@ void MDSMonitor::maybe_replace_gid(FSMap &fsmap, mds_gid_t gid,
       info.state != MDSMap::STATE_STANDBY &&
       info.state != MDSMap::STATE_STANDBY_REPLAY &&
       may_replace &&
+      !frozen &&
       !fsmap.get_filesystem(fscid)->mds_map.test_flag(CEPH_MDSMAP_NOT_JOINABLE) &&
       (sgid = fsmap.find_replacement_for({fscid, info.rank}, info.name)) != MDS_GID_NONE)
   {
@@ -1832,7 +1862,7 @@ void MDSMonitor::maybe_replace_gid(FSMap &fsmap, mds_gid_t gid,
 
     *mds_propose = true;
   } else if ((info.state == MDSMap::STATE_STANDBY_REPLAY ||
-             info.state == MDSMap::STATE_STANDBY) && may_replace) {
+             info.state == MDSMap::STATE_STANDBY) && may_replace && !frozen) {
     dout(1)  << " failing and removing " << gid << " " << info.addrs
             << " mds." << info.rank
             << "." << info.inc << " " << ceph_mds_state_name(info.state)
index 87ce40cc02200cda7f6998b58dbcf8b263cd8096..367f3c7d92e7dbaca3eb42ffd90b43be0d6cfbd3 100644 (file)
 #include "PaxosService.h"
 #include "msg/Messenger.h"
 #include "messages/MMDSBeacon.h"
+#include "CommandHandler.h"
 
 class MMonCommand;
 class MMDSLoadTargets;
 class MMDSMap;
 class FileSystemCommandHandler;
 
-class MDSMonitor : public PaxosService, public PaxosFSMap {
+class MDSMonitor : public PaxosService, public PaxosFSMap, protected CommandHandler {
  public:
   MDSMonitor(Monitor *mn, Paxos *p, string service_name);
 
index 15326c09808f1344ef20834678eb190845b2e1ef..d7a94be696fe70af2b7d8aa0ab2b217c2bfecad1 100644 (file)
@@ -322,6 +322,9 @@ COMMAND_WITH_FLAG("mds set " \
        "name=val,type=CephString "                                     \
        "name=yes_i_really_mean_it,type=CephBool,req=false",                    \
        "set mds parameter <var> to <val>", "mds", "rw", FLAG(OBSOLETE))
+COMMAND_WITH_FLAG("mds freeze name=role_or_gid,type=CephString"
+       " name=val,type=CephString",
+       "freeze MDS yes/no", "mds", "rw", FLAG(HIDDEN))
 // arbitrary limit 0-20 below; worth standing on head to make it
 // relate to actual state definitions?
 // #include "include/ceph_fs.h"