]> git.proxmox.com Git - ceph.git/blobdiff - ceph/src/mds/FSMap.cc
update sources to ceph Nautilus 14.2.1
[ceph.git] / ceph / src / mds / FSMap.cc
index cfa1352255e546d1cfafcb76564917a3c2e3c563..e395f2dcbcc8ef3a691d8dc526839ed499acb3fb 100644 (file)
 
 #include "FSMap.h"
 
-#include <sstream>
-using std::stringstream;
+#include "common/StackStringStream.h"
 
+#include <sstream>
+#ifdef WITH_SEASTAR
+#include "crimson/common/config_proxy.h"
+#else
+#include "common/config_proxy.h"
+#endif
+#include "global/global_context.h"
 #include "mon/health_check.h"
 
+using std::stringstream;
 
 void Filesystem::dump(Formatter *f) const
 {
@@ -32,6 +39,8 @@ void Filesystem::dump(Formatter *f) const
 void FSMap::dump(Formatter *f) const
 {
   f->dump_int("epoch", epoch);
+  // Use 'default' naming to match 'set-default' CLI
+  f->dump_int("default_fscid", legacy_client_fscid);
 
   f->open_object_section("compat");
   compat.dump(f);
@@ -69,7 +78,7 @@ void FSMap::generate_test_instances(list<FSMap*>& ls)
 
   int k = 20;
   for (auto i : mds_map_instances) {
-    auto fs = std::make_shared<Filesystem>();
+    auto fs = Filesystem::create();
     fs->fscid = k++;
     fs->mds_map = *i;
     delete i;
@@ -91,11 +100,10 @@ void FSMap::print(ostream& out) const
 
   if (filesystems.empty()) {
     out << "No filesystems configured" << std::endl;
-    return;
   }
 
-  for (const auto &fs : filesystems) {
-    fs.second->print(out);
+  for (const auto& p : filesystems) {
+    p.second->print(out);
     out << " " << std::endl << " " << std::endl;  // Space out a bit
   }
 
@@ -113,23 +121,53 @@ void FSMap::print(ostream& out) const
 
 void FSMap::print_summary(Formatter *f, ostream *out) const
 {
-  map<mds_role_t,string> by_rank;
-  map<string,int> by_state;
-
   if (f) {
     f->dump_unsigned("epoch", get_epoch());
-    for (auto i : filesystems) {
-      auto fs = i.second;
+    for (const auto &p : filesystems) {
+      auto& fs = p.second;
       f->dump_unsigned("id", fs->fscid);
       f->dump_unsigned("up", fs->mds_map.up.size());
       f->dump_unsigned("in", fs->mds_map.in.size());
       f->dump_unsigned("max", fs->mds_map.max_mds);
     }
   } else {
-    for (auto i : filesystems) {
-      auto fs = i.second;
-      *out << fs->mds_map.fs_name << "-" << fs->mds_map.up.size() << "/"
-          << fs->mds_map.in.size() << "/" << fs->mds_map.max_mds << " up ";
+    auto count = filesystems.size();
+    if (count <= 3) {
+      bool first = true;
+      for (const auto& p : filesystems) {
+        const auto& fs = p.second;
+        if (!first) {
+          *out << " ";
+        }
+        if (fs->mds_map.is_degraded()) {
+          *out << fs->mds_map.fs_name << ":" << fs->mds_map.up.size() << "/" << fs->mds_map.in.size();
+        } else {
+          *out << fs->mds_map.fs_name << ":" << fs->mds_map.in.size();
+        }
+        first = false;
+      }
+    } else {
+      *out << count << " fs";
+      unsigned degraded = 0;
+      CachedStackStringStream css;
+      *css << " (degraded: ";
+      for (const auto& p : filesystems) {
+        const auto& fs = p.second;
+        if (fs->mds_map.is_degraded()) {
+          degraded++;
+          if (degraded <= 3) {
+            *css << fs->mds_map.fs_name << ":" << fs->mds_map.up.size() << "/" << fs->mds_map.in.size();
+          }
+        }
+      }
+      if (degraded > 0) {
+        if (degraded <= 3) {
+          *css << ")";
+          *out << css->strv();
+        } else {
+          *out << " (degraded: " << degraded << " fs)";
+        }
+      }
     }
   }
 
@@ -137,70 +175,77 @@ void FSMap::print_summary(Formatter *f, ostream *out) const
     f->open_array_section("by_rank");
   }
 
-  const auto all_info = get_mds_info();
-  for (const auto &p : all_info) {
-    const auto &info = p.second;
-    string s = ceph_mds_state_name(info.state);
+  std::map<MDSMap::DaemonState,unsigned> by_state;
+  std::map<mds_role_t, std::pair<MDSMap::DaemonState, std::string>> by_rank;
+  by_state[MDSMap::DaemonState::STATE_STANDBY] = standby_daemons.size();
+  for (const auto& [gid, fscid] : mds_roles) {
+    if (fscid == FS_CLUSTER_ID_NONE)
+      continue;
+
+    const auto& info = filesystems.at(fscid)->mds_map.get_info_gid(gid);
+    auto s = std::string(ceph_mds_state_name(info.state));
     if (info.laggy()) {
       s += "(laggy or crashed)";
     }
 
-    const fs_cluster_id_t fscid = mds_roles.at(info.global_id);
-
-    if (info.rank != MDS_RANK_NONE &&
-        info.state != MDSMap::STATE_STANDBY_REPLAY) {
-      if (f) {
-        f->open_object_section("mds");
-        f->dump_unsigned("filesystem_id", fscid);
-        f->dump_unsigned("rank", info.rank);
-        f->dump_string("name", info.name);
-        f->dump_string("status", s);
-        f->close_section();
-      } else {
-        by_rank[mds_role_t(fscid, info.rank)] = info.name + "=" + s;
-      }
-    } else {
-      by_state[s]++;
+    if (f) {
+      f->open_object_section("mds");
+      f->dump_unsigned("filesystem_id", fscid);
+      f->dump_unsigned("rank", info.rank);
+      f->dump_string("name", info.name);
+      f->dump_string("status", s);
+      f->dump_unsigned("gid", gid);
+      f->close_section();
+    } else if (info.state != MDSMap::DaemonState::STATE_STANDBY_REPLAY) {
+      by_rank[mds_role_t(fscid, info.rank)] = std::make_pair(info.state, info.name + "=" + s);
     }
+    by_state[info.state]++;
   }
 
   if (f) {
     f->close_section();
   } else {
-    if (!by_rank.empty()) {
+    if (0 < by_rank.size() && by_rank.size() < 5) {
       if (filesystems.size() > 1) {
         // Disambiguate filesystems
         std::map<std::string, std::string> pretty;
-        for (auto i : by_rank) {
-          const auto &fs_name = filesystems.at(i.first.fscid)->mds_map.fs_name;
-          std::ostringstream o;
-          o << "[" << fs_name << ":" << i.first.rank << "]";
-          pretty[o.str()] = i.second;
+        for (const auto& [role,status] : by_rank) {
+          const auto &fs_name = filesystems.at(role.fscid)->mds_map.fs_name;
+          CachedStackStringStream css;
+          *css << fs_name << ":" << role.rank;
+          pretty.emplace(std::piecewise_construct, std::forward_as_tuple(css->strv()), std::forward_as_tuple(status.second));
+          --by_state[status.first]; /* already printed! */
         }
         *out << " " << pretty;
       } else {
         // Omit FSCID in output when only one filesystem exists
         std::map<mds_rank_t, std::string> shortened;
-        for (auto i : by_rank) {
-          shortened[i.first.rank] = i.second;
+        for (const auto& [role,status] : by_rank) {
+          shortened[role.rank] = status.second;
+          --by_state[status.first]; /* already printed! */
         }
         *out << " " << shortened;
       }
     }
+    for (const auto& [state, count] : by_state) {
+      if (count > 0) {
+        auto s = std::string_view(ceph_mds_state_name(state));
+        *out << " " << count << " " << s;
+      }
+    }
   }
 
-  for (map<string,int>::reverse_iterator p = by_state.rbegin(); p != by_state.rend(); ++p) {
-    if (f) {
-      f->dump_unsigned(p->first.c_str(), p->second);
-    } else {
-      *out << ", " << p->second << " " << p->first;
-    }
+  if (f) {
+    const auto state = MDSMap::DaemonState::STATE_STANDBY;
+    auto&& name = ceph_mds_state_name(state);
+    auto count = standby_daemons.size();
+    f->dump_unsigned(name, count);
   }
 
   size_t failed = 0;
   size_t damaged = 0;
-  for (auto i : filesystems) {
-    auto fs = i.second;
+  for (const auto& p : filesystems) {
+    auto& fs = p.second;
     failed += fs->mds_map.failed.size();
     damaged += fs->mds_map.damaged.size();
   }
@@ -225,13 +270,12 @@ void FSMap::print_summary(Formatter *f, ostream *out) const
 }
 
 
-void FSMap::create_filesystem(boost::string_view name,
-                              int64_t metadata_pool, int64_t data_pool,
-                              uint64_t features)
+Filesystem::ref FSMap::create_filesystem(std::string_view name,
+    int64_t metadata_pool, int64_t data_pool, uint64_t features)
 {
-  auto fs = std::make_shared<Filesystem>();
+  auto fs = Filesystem::create();
   fs->mds_map.epoch = epoch;
-  fs->mds_map.fs_name = std::string(name);
+  fs->mds_map.fs_name = name;
   fs->mds_map.data_pools.push_back(data_pool);
   fs->mds_map.metadata_pool = metadata_pool;
   fs->mds_map.cas_pool = -1;
@@ -243,11 +287,11 @@ void FSMap::create_filesystem(boost::string_view name,
     fs->fscid = next_filesystem_id++;
     // ANONYMOUS is only for upgrades from legacy mdsmaps, we should
     // have initialized next_filesystem_id such that it's never used here.
-    assert(fs->fscid != FS_CLUSTER_ID_ANONYMOUS);
+    ceph_assert(fs->fscid != FS_CLUSTER_ID_ANONYMOUS);
   } else {
     // Use anon fscid because this will get thrown away when encoding
     // as legacy MDSMap for legacy mons.
-    assert(filesystems.empty());
+    ceph_assert(filesystems.empty());
     fs->fscid = FS_CLUSTER_ID_ANONYMOUS;
   }
   filesystems[fs->fscid] = fs;
@@ -257,12 +301,14 @@ void FSMap::create_filesystem(boost::string_view name,
   if (filesystems.size() == 1) {
     legacy_client_fscid = fs->fscid;
   }
+
+  return fs;
 }
 
 void FSMap::reset_filesystem(fs_cluster_id_t fscid)
 {
   auto fs = get_filesystem(fscid);
-  auto new_fs = std::make_shared<Filesystem>();
+  auto new_fs = Filesystem::create();
 
   // Populate rank 0 as existing (so don't go into CREATING)
   // but failed (so that next available MDS is assigned the rank)
@@ -337,8 +383,7 @@ void FSMap::get_health_checks(health_check_map_t *checks) const
     std::set<mds_rank_t> stuck_failed;
 
     for (const auto &rank : fs->mds_map.failed) {
-      const mds_gid_t replacement = find_replacement_for(
-          {fs->fscid, rank}, {}, g_conf->mon_force_standby_active);
+      auto&& replacement = find_replacement_for({fs->fscid, rank}, {});
       if (replacement == MDS_GID_NONE) {
         stuck_failed.insert(rank);
       }
@@ -375,20 +420,21 @@ void FSMap::encode(bufferlist& bl, uint64_t features) const
 {
   if (features & CEPH_FEATURE_SERVER_JEWEL) {
     ENCODE_START(7, 6, bl);
-    ::encode(epoch, bl);
-    ::encode(next_filesystem_id, bl);
-    ::encode(legacy_client_fscid, bl);
-    ::encode(compat, bl);
-    ::encode(enable_multiple, bl);
-    std::vector<Filesystem> fs_list;
-    for (auto i : filesystems) {
-      fs_list.push_back(*(i.second));
+    encode(epoch, bl);
+    encode(next_filesystem_id, bl);
+    encode(legacy_client_fscid, bl);
+    encode(compat, bl);
+    encode(enable_multiple, bl);
+    {
+      std::vector<Filesystem::ref> v;
+      v.reserve(filesystems.size());
+      for (auto& p : filesystems) v.emplace_back(p.second);
+      encode(v, bl, features);
     }
-    ::encode(fs_list, bl, features);
-    ::encode(mds_roles, bl);
-    ::encode(standby_daemons, bl, features);
-    ::encode(standby_epochs, bl);
-    ::encode(ever_enabled_multiple, bl);
+    encode(mds_roles, bl);
+    encode(standby_daemons, bl, features);
+    encode(standby_epochs, bl);
+    encode(ever_enabled_multiple, bl);
     ENCODE_FINISH(bl);
   } else {
     if (filesystems.empty()) {
@@ -398,7 +444,7 @@ void FSMap::encode(bufferlist& bl, uint64_t features) const
     } else {
       // MDSMonitor should never have created multiple filesystems
       // until the quorum features indicated Jewel
-      assert(filesystems.size() == 1);
+      ceph_assert(filesystems.size() == 1);
       auto fs = filesystems.begin()->second;
 
       // Take the MDSMap for the enabled filesystem, and populated its
@@ -422,7 +468,7 @@ void FSMap::encode(bufferlist& bl, uint64_t features) const
   }
 }
 
-void FSMap::decode(bufferlist::iterator& p)
+void FSMap::decode(bufferlist::const_iterator& p)
 {
   // The highest MDSMap encoding version before we changed the
   // MDSMonitor to store an FSMap instead of an MDSMap was
@@ -436,88 +482,82 @@ void FSMap::decode(bufferlist::iterator& p)
     MDSMap legacy_mds_map;
 
     // Decoding an MDSMap (upgrade)
-    ::decode(epoch, p);
-    ::decode(legacy_mds_map.flags, p);
-    ::decode(legacy_mds_map.last_failure, p);
-    ::decode(legacy_mds_map.root, p);
-    ::decode(legacy_mds_map.session_timeout, p);
-    ::decode(legacy_mds_map.session_autoclose, p);
-    ::decode(legacy_mds_map.max_file_size, p);
-    ::decode(legacy_mds_map.max_mds, p);
-    ::decode(legacy_mds_map.mds_info, p);
+    decode(epoch, p);
+    decode(legacy_mds_map.flags, p);
+    decode(legacy_mds_map.last_failure, p);
+    decode(legacy_mds_map.root, p);
+    decode(legacy_mds_map.session_timeout, p);
+    decode(legacy_mds_map.session_autoclose, p);
+    decode(legacy_mds_map.max_file_size, p);
+    decode(legacy_mds_map.max_mds, p);
+    decode(legacy_mds_map.mds_info, p);
     if (struct_v < 3) {
       __u32 n;
-      ::decode(n, p);
+      decode(n, p);
       while (n--) {
         __u32 m;
-        ::decode(m, p);
+        decode(m, p);
         legacy_mds_map.data_pools.push_back(m);
       }
       __s32 s;
-      ::decode(s, p);
+      decode(s, p);
       legacy_mds_map.cas_pool = s;
     } else {
-      ::decode(legacy_mds_map.data_pools, p);
-      ::decode(legacy_mds_map.cas_pool, p);
+      decode(legacy_mds_map.data_pools, p);
+      decode(legacy_mds_map.cas_pool, p);
     }
 
     // kclient ignores everything from here
     __u16 ev = 1;
     if (struct_v >= 2)
-      ::decode(ev, p);
+      decode(ev, p);
     if (ev >= 3)
-      ::decode(legacy_mds_map.compat, p);
+      decode(legacy_mds_map.compat, p);
     else
       legacy_mds_map.compat = MDSMap::get_compat_set_base();
     if (ev < 5) {
       __u32 n;
-      ::decode(n, p);
+      decode(n, p);
       legacy_mds_map.metadata_pool = n;
     } else {
-      ::decode(legacy_mds_map.metadata_pool, p);
+      decode(legacy_mds_map.metadata_pool, p);
     }
-    ::decode(legacy_mds_map.created, p);
-    ::decode(legacy_mds_map.modified, p);
-    ::decode(legacy_mds_map.tableserver, p);
-    ::decode(legacy_mds_map.in, p);
+    decode(legacy_mds_map.created, p);
+    decode(legacy_mds_map.modified, p);
+    decode(legacy_mds_map.tableserver, p);
+    decode(legacy_mds_map.in, p);
     std::map<mds_rank_t,int32_t> inc;  // Legacy field, parse and drop
-    ::decode(inc, p);
-    ::decode(legacy_mds_map.up, p);
-    ::decode(legacy_mds_map.failed, p);
-    ::decode(legacy_mds_map.stopped, p);
+    decode(inc, p);
+    decode(legacy_mds_map.up, p);
+    decode(legacy_mds_map.failed, p);
+    decode(legacy_mds_map.stopped, p);
     if (ev >= 4)
-      ::decode(legacy_mds_map.last_failure_osd_epoch, p);
+      decode(legacy_mds_map.last_failure_osd_epoch, p);
     if (ev >= 6) {
       if (ev < 10) {
        // previously this was a bool about snaps, not a flag map
        bool flag;
-       ::decode(flag, p);
+       decode(flag, p);
        legacy_mds_map.ever_allowed_features = flag ?
          CEPH_MDSMAP_ALLOW_SNAPS : 0;
-       ::decode(flag, p);
+       decode(flag, p);
        legacy_mds_map.explicitly_allowed_features = flag ?
          CEPH_MDSMAP_ALLOW_SNAPS : 0;
-       if (legacy_mds_map.max_mds > 1) {
-         legacy_mds_map.set_multimds_allowed();
-       }
       } else {
-       ::decode(legacy_mds_map.ever_allowed_features, p);
-       ::decode(legacy_mds_map.explicitly_allowed_features, p);
+       decode(legacy_mds_map.ever_allowed_features, p);
+       decode(legacy_mds_map.explicitly_allowed_features, p);
       }
     } else {
-      legacy_mds_map.ever_allowed_features = CEPH_MDSMAP_ALLOW_CLASSICS;
+      legacy_mds_map.ever_allowed_features = 0;
       legacy_mds_map.explicitly_allowed_features = 0;
-      if (legacy_mds_map.max_mds > 1) {
-       legacy_mds_map.set_multimds_allowed();
-      }
     }
     if (ev >= 7)
-      ::decode(legacy_mds_map.inline_data_enabled, p);
+      decode(legacy_mds_map.inline_data_enabled, p);
 
     if (ev >= 8) {
-      assert(struct_v >= 5);
-      ::decode(legacy_mds_map.enabled, p);
-      ::decode(legacy_mds_map.fs_name, p);
+      ceph_assert(struct_v >= 5);
+      decode(legacy_mds_map.enabled, p);
+      decode(legacy_mds_map.fs_name, p);
     } else {
       legacy_mds_map.fs_name = "default";
       if (epoch > 1) {
@@ -532,7 +572,7 @@ void FSMap::decode(bufferlist::iterator& p)
     }
 
     if (ev >= 9) {
-      ::decode(legacy_mds_map.damaged, p);
+      decode(legacy_mds_map.damaged, p);
     }
 
     // We're upgrading, populate filesystems from the legacy fields
@@ -546,7 +586,7 @@ void FSMap::decode(bufferlist::iterator& p)
     // Synthesise a Filesystem from legacy_mds_map, if enabled
     if (legacy_mds_map.enabled) {
       // Construct a Filesystem from the legacy MDSMap
-      auto migrate_fs = std::make_shared<Filesystem>(); 
+      auto migrate_fs = Filesystem::create();
       migrate_fs->fscid = FS_CLUSTER_ID_ANONYMOUS;
       migrate_fs->mds_map = legacy_mds_map;
       migrate_fs->mds_map.epoch = epoch;
@@ -557,22 +597,20 @@ void FSMap::decode(bufferlist::iterator& p)
 
       // Construct mds_roles, standby_daemons, and remove
       // standbys from the MDSMap in the Filesystem.
-      for (auto &p : migrate_fs->mds_map.mds_info) {
-        if (p.second.state == MDSMap::STATE_STANDBY_REPLAY) {
-          // In legacy MDSMap, standby replay daemons don't have
-          // rank set, but since FSMap they do.
-          p.second.rank = p.second.standby_for_rank;
-        }
-        if (p.second.rank == MDS_RANK_NONE) {
-          if (p.second.state != MDSMap::STATE_STANDBY) {
+      for (const auto& [gid, info] : migrate_fs->mds_map.mds_info) {
+        if (info.state == MDSMap::STATE_STANDBY_REPLAY) {
+          /* drop any legacy standby-replay daemons */
+          drop_gids.insert(gid);
+        } else if (info.rank == MDS_RANK_NONE) {
+          if (info.state != MDSMap::STATE_STANDBY) {
             // Old MDSMaps can have down:dne here, which
             // is invalid in an FSMap (#17837)
-            drop_gids.insert(p.first);
+            drop_gids.insert(gid);
           } else {
-            insert(p.second); // into standby_daemons
+            insert(info); // into standby_daemons
           }
         } else {
-          mds_roles[p.first] = migrate_fs->fscid;
+          mds_roles[gid] = migrate_fs->fscid;
         }
       }
       for (const auto &p : standby_daemons) {
@@ -591,30 +629,32 @@ void FSMap::decode(bufferlist::iterator& p)
       legacy_client_fscid = FS_CLUSTER_ID_NONE;
     }
   } else {
-    ::decode(epoch, p);
-    ::decode(next_filesystem_id, p);
-    ::decode(legacy_client_fscid, p);
-    ::decode(compat, p);
-    ::decode(enable_multiple, p);
-    std::vector<Filesystem> fs_list;
-    ::decode(fs_list, p);
-    filesystems.clear();
-    for (std::vector<Filesystem>::const_iterator fs = fs_list.begin(); fs != fs_list.end(); ++fs) {
-      filesystems[fs->fscid] = std::make_shared<Filesystem>(*fs);
+    decode(epoch, p);
+    decode(next_filesystem_id, p);
+    decode(legacy_client_fscid, p);
+    decode(compat, p);
+    decode(enable_multiple, p);
+    {
+      std::vector<Filesystem::ref> v;
+      decode(v, p);
+      filesystems.clear();
+      for (auto& ref : v) {
+        auto em = filesystems.emplace(std::piecewise_construct, std::forward_as_tuple(ref->fscid), std::forward_as_tuple(std::move(ref)));
+        ceph_assert(em.second);
+      }
     }
-
-    ::decode(mds_roles, p);
-    ::decode(standby_daemons, p);
-    ::decode(standby_epochs, p);
+    decode(mds_roles, p);
+    decode(standby_daemons, p);
+    decode(standby_epochs, p);
     if (struct_v >= 7) {
-      ::decode(ever_enabled_multiple, p);
+      decode(ever_enabled_multiple, p);
     }
   }
 
   DECODE_FINISH(p);
 }
 
-void FSMap::sanitize(std::function<bool(int64_t pool)> pool_exists)
+void FSMap::sanitize(const std::function<bool(int64_t pool)>& pool_exists)
 {
   for (auto &fs : filesystems) {
     fs.second->mds_map.sanitize(pool_exists);
@@ -624,27 +664,27 @@ void FSMap::sanitize(std::function<bool(int64_t pool)> pool_exists)
 void Filesystem::encode(bufferlist& bl, uint64_t features) const
 {
   ENCODE_START(1, 1, bl);
-  ::encode(fscid, bl);
+  encode(fscid, bl);
   bufferlist mdsmap_bl;
   mds_map.encode(mdsmap_bl, features);
-  ::encode(mdsmap_bl, bl);
+  encode(mdsmap_bl, bl);
   ENCODE_FINISH(bl);
 }
 
-void Filesystem::decode(bufferlist::iterator& p)
+void Filesystem::decode(bufferlist::const_iterator& p)
 {
   DECODE_START(1, p);
-  ::decode(fscid, p);
+  decode(fscid, p);
   bufferlist mdsmap_bl;
-  ::decode(mdsmap_bl, p);
-  bufferlist::iterator mdsmap_bl_iter = mdsmap_bl.begin();
+  decode(mdsmap_bl, p);
+  auto mdsmap_bl_iter = mdsmap_bl.cbegin();
   mds_map.decode(mdsmap_bl_iter);
   DECODE_FINISH(p);
 }
 
 int FSMap::parse_filesystem(
-      boost::string_view ns_str,
-      std::shared_ptr<const Filesystem> *result
+      std::string_view ns_str,
+      Filesystem::const_ref* result
       ) const
 {
   std::string ns_err;
@@ -671,165 +711,115 @@ void Filesystem::print(std::ostream &out) const
   mds_map.print(out);
 }
 
-mds_gid_t FSMap::find_standby_for(mds_role_t role, boost::string_view name) const
+mds_gid_t FSMap::get_available_standby() const
 {
-  mds_gid_t result = MDS_GID_NONE;
-
-  // First see if we have a STANDBY_REPLAY
-  auto fs = get_filesystem(role.fscid);
-  for (const auto &i : fs->mds_map.mds_info) {
-    const auto &info = i.second;
-    if (info.rank == role.rank && info.state == MDSMap::STATE_STANDBY_REPLAY) {
-      return info.global_id;
-    }
-  }
+  for (const auto& [gid, info] : standby_daemons) {
+    ceph_assert(info.rank == MDS_RANK_NONE);
+    ceph_assert(info.state == MDSMap::STATE_STANDBY);
 
-  // See if there are any STANDBY daemons available
-  for (const auto &i : standby_daemons) {
-    const auto &gid = i.first;
-    const auto &info = i.second;
-    assert(info.state == MDSMap::STATE_STANDBY);
-    assert(info.rank == MDS_RANK_NONE);
-
-    if (info.laggy()) {
+    if (info.laggy() || info.is_frozen()) {
       continue;
     }
 
-    // The mds_info_t may or may not tell us exactly which filesystem
-    // the standby_for_rank refers to: lookup via legacy_client_fscid
-    mds_role_t target_role = {
-      info.standby_for_fscid == FS_CLUSTER_ID_NONE ?
-        legacy_client_fscid : info.standby_for_fscid,
-      info.standby_for_rank};
-
-    if ((target_role.rank == role.rank && target_role.fscid == role.fscid)
-        || (name.length() && info.standby_for_name == name)) {
-      // It's a named standby for *me*, use it.
-      return gid;
-    } else if (
-        info.standby_for_rank < 0 && info.standby_for_name.length() == 0 &&
-        (info.standby_for_fscid == FS_CLUSTER_ID_NONE ||
-         info.standby_for_fscid == role.fscid)) {
-        // It's not a named standby for anyone, use it if we don't find
-        // a named standby for me later, unless it targets another FSCID.
-        result = gid;
-      }
+    return gid;
   }
-
-  return result;
+  return MDS_GID_NONE;
 }
 
-mds_gid_t FSMap::find_unused_for(mds_role_t role,
-                                bool force_standby_active) const {
-  for (const auto &i : standby_daemons) {
-    const auto &gid = i.first;
-    const auto &info = i.second;
-    assert(info.state == MDSMap::STATE_STANDBY);
-
-    if (info.laggy() || info.rank >= 0)
-      continue;
-
-    if (info.standby_for_fscid != FS_CLUSTER_ID_NONE &&
-        info.standby_for_fscid != role.fscid)
-      continue;
-    if (info.standby_for_rank != MDS_RANK_NONE &&
-        info.standby_for_rank != role.rank)
-      continue;
+mds_gid_t FSMap::find_replacement_for(mds_role_t role, std::string_view name) const
+{
+  auto&& fs = get_filesystem(role.fscid);
 
-    // To be considered 'unused' a daemon must either not
-    // be selected for standby-replay or the force_standby_active
-    // setting must be enabled to use replay daemons anyway.
-    if (!info.standby_replay || force_standby_active) {
-      return gid;
+  // 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 MDS_GID_NONE;
-}
 
-mds_gid_t FSMap::find_replacement_for(mds_role_t role, boost::string_view name,
-                               bool force_standby_active) const {
-  const mds_gid_t standby = find_standby_for(role, name);
-  if (standby)
-    return standby;
-  else
-    return find_unused_for(role, force_standby_active);
+  return get_available_standby();
 }
 
 void FSMap::sanity() const
 {
   if (legacy_client_fscid != FS_CLUSTER_ID_NONE) {
-    assert(filesystems.count(legacy_client_fscid) == 1);
+    ceph_assert(filesystems.count(legacy_client_fscid) == 1);
   }
 
   for (const auto &i : filesystems) {
     auto fs = i.second;
-    assert(fs->mds_map.compat.compare(compat) == 0);
-    assert(fs->fscid == i.first);
+    ceph_assert(fs->mds_map.compat.compare(compat) == 0);
+    ceph_assert(fs->fscid == i.first);
     for (const auto &j : fs->mds_map.mds_info) {
-      assert(j.second.rank != MDS_RANK_NONE);
-      assert(mds_roles.count(j.first) == 1);
-      assert(standby_daemons.count(j.first) == 0);
-      assert(standby_epochs.count(j.first) == 0);
-      assert(mds_roles.at(j.first) == i.first);
+      ceph_assert(j.second.rank != MDS_RANK_NONE);
+      ceph_assert(mds_roles.count(j.first) == 1);
+      ceph_assert(standby_daemons.count(j.first) == 0);
+      ceph_assert(standby_epochs.count(j.first) == 0);
+      ceph_assert(mds_roles.at(j.first) == i.first);
       if (j.second.state != MDSMap::STATE_STANDBY_REPLAY) {
-        assert(fs->mds_map.up.at(j.second.rank) == j.first);
-        assert(fs->mds_map.failed.count(j.second.rank) == 0);
-        assert(fs->mds_map.damaged.count(j.second.rank) == 0);
+        ceph_assert(fs->mds_map.up.at(j.second.rank) == j.first);
+        ceph_assert(fs->mds_map.failed.count(j.second.rank) == 0);
+        ceph_assert(fs->mds_map.damaged.count(j.second.rank) == 0);
       }
     }
 
     for (const auto &j : fs->mds_map.up) {
       mds_rank_t rank = j.first;
-      assert(fs->mds_map.in.count(rank) == 1);
+      ceph_assert(fs->mds_map.in.count(rank) == 1);
       mds_gid_t gid = j.second;
-      assert(fs->mds_map.mds_info.count(gid) == 1);
+      ceph_assert(fs->mds_map.mds_info.count(gid) == 1);
     }
   }
 
   for (const auto &i : standby_daemons) {
-    assert(i.second.state == MDSMap::STATE_STANDBY);
-    assert(i.second.rank == MDS_RANK_NONE);
-    assert(i.second.global_id == i.first);
-    assert(standby_epochs.count(i.first) == 1);
-    assert(mds_roles.count(i.first) == 1);
-    assert(mds_roles.at(i.first) == FS_CLUSTER_ID_NONE);
+    ceph_assert(i.second.state == MDSMap::STATE_STANDBY);
+    ceph_assert(i.second.rank == MDS_RANK_NONE);
+    ceph_assert(i.second.global_id == i.first);
+    ceph_assert(standby_epochs.count(i.first) == 1);
+    ceph_assert(mds_roles.count(i.first) == 1);
+    ceph_assert(mds_roles.at(i.first) == FS_CLUSTER_ID_NONE);
   }
 
   for (const auto &i : standby_epochs) {
-    assert(standby_daemons.count(i.first) == 1);
+    ceph_assert(standby_daemons.count(i.first) == 1);
   }
 
   for (const auto &i : mds_roles) {
     if (i.second == FS_CLUSTER_ID_NONE) {
-      assert(standby_daemons.count(i.first) == 1);
+      ceph_assert(standby_daemons.count(i.first) == 1);
     } else {
-      assert(filesystems.count(i.second) == 1);
-      assert(filesystems.at(i.second)->mds_map.mds_info.count(i.first) == 1);
+      ceph_assert(filesystems.count(i.second) == 1);
+      ceph_assert(filesystems.at(i.second)->mds_map.mds_info.count(i.first) == 1);
     }
   }
 }
 
 void FSMap::promote(
     mds_gid_t standby_gid,
-    const std::shared_ptr<Filesystem> &filesystem,
+    Filesystem& filesystem,
     mds_rank_t assigned_rank)
 {
-  assert(gid_exists(standby_gid));
+  ceph_assert(gid_exists(standby_gid));
   bool is_standby_replay = mds_roles.at(standby_gid) != FS_CLUSTER_ID_NONE;
   if (!is_standby_replay) {
-    assert(standby_daemons.count(standby_gid));
-    assert(standby_daemons.at(standby_gid).state == MDSMap::STATE_STANDBY);
+    ceph_assert(standby_daemons.count(standby_gid));
+    ceph_assert(standby_daemons.at(standby_gid).state == MDSMap::STATE_STANDBY);
   }
 
-  MDSMap &mds_map = filesystem->mds_map;
+  MDSMap &mds_map = filesystem.mds_map;
 
   // Insert daemon state to Filesystem
   if (!is_standby_replay) {
     mds_map.mds_info[standby_gid] = standby_daemons.at(standby_gid);
   } else {
-    assert(mds_map.mds_info.count(standby_gid));
-    assert(mds_map.mds_info.at(standby_gid).state == MDSMap::STATE_STANDBY_REPLAY);
-    assert(mds_map.mds_info.at(standby_gid).rank == assigned_rank);
+    ceph_assert(mds_map.mds_info.count(standby_gid));
+    ceph_assert(mds_map.mds_info.at(standby_gid).state == MDSMap::STATE_STANDBY_REPLAY);
+    ceph_assert(mds_map.mds_info.at(standby_gid).rank == assigned_rank);
   }
   MDSMap::mds_info_t &info = mds_map.mds_info[standby_gid];
 
@@ -846,7 +836,7 @@ void FSMap::promote(
   }
   info.rank = assigned_rank;
   info.inc = epoch;
-  mds_roles[standby_gid] = filesystem->fscid;
+  mds_roles[standby_gid] = filesystem.fscid;
 
   // Update the rank state in Filesystem
   mds_map.in.insert(assigned_rank);
@@ -867,10 +857,10 @@ void FSMap::assign_standby_replay(
     const fs_cluster_id_t leader_ns,
     const mds_rank_t leader_rank)
 {
-  assert(mds_roles.at(standby_gid) == FS_CLUSTER_ID_NONE);
-  assert(gid_exists(standby_gid));
-  assert(!gid_has_rank(standby_gid));
-  assert(standby_daemons.count(standby_gid));
+  ceph_assert(mds_roles.at(standby_gid) == FS_CLUSTER_ID_NONE);
+  ceph_assert(gid_exists(standby_gid));
+  ceph_assert(!gid_has_rank(standby_gid));
+  ceph_assert(standby_daemons.count(standby_gid));
 
   // Insert to the filesystem
   auto fs = filesystems.at(leader_ns);
@@ -906,7 +896,7 @@ void FSMap::erase(mds_gid_t who, epoch_t blacklist_epoch)
         // STANDBY will pick it up.
         fs->mds_map.failed.insert(info.rank);
       }
-      assert(fs->mds_map.up.at(info.rank) == info.global_id);
+      ceph_assert(fs->mds_map.up.at(info.rank) == info.global_id);
       fs->mds_map.up.erase(info.rank);
     }
     fs->mds_map.mds_info.erase(who);
@@ -919,7 +909,7 @@ void FSMap::erase(mds_gid_t who, epoch_t blacklist_epoch)
 
 void FSMap::damaged(mds_gid_t who, epoch_t blacklist_epoch)
 {
-  assert(mds_roles.at(who) != FS_CLUSTER_ID_NONE);
+  ceph_assert(mds_roles.at(who) != FS_CLUSTER_ID_NONE);
   auto fs = filesystems.at(mds_roles.at(who));
   mds_rank_t rank = fs->mds_map.mds_info[who].rank;
 
@@ -927,7 +917,7 @@ void FSMap::damaged(mds_gid_t who, epoch_t blacklist_epoch)
   fs->mds_map.failed.erase(rank);
   fs->mds_map.damaged.insert(rank);
 
-  assert(fs->mds_map.epoch == epoch);
+  ceph_assert(fs->mds_map.epoch == epoch);
 }
 
 /**
@@ -949,8 +939,8 @@ bool FSMap::undamaged(const fs_cluster_id_t fscid, const mds_rank_t rank)
 
 void FSMap::insert(const MDSMap::mds_info_t &new_info)
 {
-  assert(new_info.state == MDSMap::STATE_STANDBY);
-  assert(new_info.rank == MDS_RANK_NONE);
+  ceph_assert(new_info.state == MDSMap::STATE_STANDBY);
+  ceph_assert(new_info.rank == MDS_RANK_NONE);
   mds_roles[new_info.global_id] = FS_CLUSTER_ID_NONE;
   standby_daemons[new_info.global_id] = new_info;
   standby_epochs[new_info.global_id] = epoch;
@@ -958,7 +948,7 @@ void FSMap::insert(const MDSMap::mds_info_t &new_info)
 
 std::list<mds_gid_t> FSMap::stop(mds_gid_t who)
 {
-  assert(mds_roles.at(who) != FS_CLUSTER_ID_NONE);
+  ceph_assert(mds_roles.at(who) != FS_CLUSTER_ID_NONE);
   auto fs = filesystems.at(mds_roles.at(who));
   const auto &info = fs->mds_map.mds_info.at(who);
   fs->mds_map.up.erase(info.rank);
@@ -996,13 +986,13 @@ std::list<mds_gid_t> FSMap::stop(mds_gid_t who)
  * if legacy_client_ns is set.
  */
 int FSMap::parse_role(
-    boost::string_view role_str,
+    std::string_view role_str,
     mds_role_t *role,
     std::ostream &ss) const
 {
   size_t colon_pos = role_str.find(":");
   size_t rank_pos;
-  std::shared_ptr<const Filesystem> fs;
+  Filesystem::const_ref fs;
   if (colon_pos == std::string::npos) {
     if (legacy_client_fscid == FS_CLUSTER_ID_NONE) {
       ss << "No filesystem selected";