]> git.proxmox.com Git - ceph.git/blobdiff - ceph/src/mds/MDSDaemon.cc
update sources to 12.2.8
[ceph.git] / ceph / src / mds / MDSDaemon.cc
index 4c3d558ed46b9f899034c706f29e68efc61439bd..0b651a7d523bc3ddec1fcd51930da14968305a8f 100644 (file)
 #include <unistd.h>
 
 #include "include/compat.h"
-#include "global/signal_handler.h"
-
 #include "include/types.h"
 #include "include/str_list.h"
-#include "common/entity_name.h"
+
 #include "common/Clock.h"
-#include "common/signal.h"
+#include "common/HeartbeatMap.h"
+#include "common/Timer.h"
+#include "common/backport14.h"
 #include "common/ceph_argparse.h"
+#include "common/config.h"
+#include "common/entity_name.h"
 #include "common/errno.h"
+#include "common/perf_counters.h"
+#include "common/signal.h"
+#include "common/version.h"
+
+#include "global/signal_handler.h"
 
 #include "msg/Messenger.h"
 #include "mon/MonClient.h"
 #include "SnapServer.h"
 #include "SnapClient.h"
 
-#include "common/HeartbeatMap.h"
-
-#include "common/perf_counters.h"
-
-#include "common/Timer.h"
-
 #include "events/ESession.h"
 #include "events/ESubtreeMap.h"
 
@@ -60,8 +61,6 @@
 #include "auth/RotatingKeyRing.h"
 #include "auth/KeyRing.h"
 
-#include "common/config.h"
-
 #include "perfglue/cpu_profiler.h"
 #include "perfglue/heap_profiler.h"
 
 #undef dout_prefix
 #define dout_prefix *_dout << "mds." << name << ' '
 
-
-class MDSDaemon::C_MDS_Tick : public Context {
-  protected:
-    MDSDaemon *mds_daemon;
-public:
-  explicit C_MDS_Tick(MDSDaemon *m) : mds_daemon(m) {}
-  void finish(int r) override {
-    assert(mds_daemon->mds_lock.is_locked_by_me());
-
-    mds_daemon->tick_event = 0;
-    mds_daemon->tick();
-  }
-};
-
 // cons/des
-MDSDaemon::MDSDaemon(const std::string &n, Messenger *m, MonClient *mc) :
+MDSDaemon::MDSDaemon(boost::string_view n, Messenger *m, MonClient *mc) :
   Dispatcher(m->cct),
   mds_lock("MDSDaemon::mds_lock"),
   stopping(false),
@@ -105,8 +90,8 @@ MDSDaemon::MDSDaemon(const std::string &n, Messenger *m, MonClient *mc) :
   mgrc(m->cct, m),
   log_client(m->cct, messenger, &mc->monmap, LogClient::NO_FLAGS),
   mds_rank(NULL),
-  tick_event(0),
-  asok_hook(NULL)
+  asok_hook(NULL),
+  starttime(mono_clock::now())
 {
   orig_argc = 0;
   orig_argv = NULL;
@@ -196,6 +181,9 @@ void MDSDaemon::dump_status(Formatter *f)
     f->dump_unsigned("osdmap_epoch", 0);
     f->dump_unsigned("osdmap_epoch_barrier", 0);
   }
+
+  f->dump_float("uptime", get_uptime().count());
+
   f->close_section(); // status
 }
 
@@ -258,6 +246,11 @@ void MDSDaemon::set_up_admin_socket()
                                      asok_hook,
                                      "dump metadata cache (optionally to a file)");
   assert(r == 0);
+  r = admin_socket->register_command("cache status",
+                                     "cache status",
+                                     asok_hook,
+                                     "show cache status");
+  assert(r == 0);
   r = admin_socket->register_command("dump tree",
                                     "dump tree "
                                     "name=root,type=CephString,req=true "
@@ -265,6 +258,11 @@ void MDSDaemon::set_up_admin_socket()
                                     asok_hook,
                                     "dump metadata cache for subtree");
   assert(r == 0);
+  r = admin_socket->register_command("dump loads",
+                                     "dump loads",
+                                     asok_hook,
+                                     "dump metadata loads");
+  assert(r == 0);
   r = admin_socket->register_command("session evict",
                                     "session evict name=client_id,type=CephString",
                                     asok_hook,
@@ -332,7 +330,9 @@ void MDSDaemon::clean_up_admin_socket()
   admin_socket->unregister_command("flush_path");
   admin_socket->unregister_command("export dir");
   admin_socket->unregister_command("dump cache");
+  admin_socket->unregister_command("cache status");
   admin_socket->unregister_command("dump tree");
+  admin_socket->unregister_command("dump loads");
   admin_socket->unregister_command("session evict");
   admin_socket->unregister_command("osdmap barrier");
   admin_socket->unregister_command("session ls");
@@ -362,6 +362,8 @@ const char** MDSDaemon::get_tracked_conf_keys() const
     "mds_max_purge_ops",
     "mds_max_purge_ops_per_pg",
     "mds_max_purge_files",
+    "mds_inject_migrator_session_race",
+    "mds_inject_migrator_message_loss",
     "clog_to_graylog",
     "clog_to_graylog_host",
     "clog_to_graylog_port",
@@ -436,7 +438,8 @@ int MDSDaemon::init()
   dout(10) << sizeof(MDSCacheObject) << "\tMDSCacheObject" << dendl;
   dout(10) << sizeof(CInode) << "\tCInode" << dendl;
   dout(10) << sizeof(elist<void*>::item) << "\t elist<>::item   *7=" << 7*sizeof(elist<void*>::item) << dendl;
-  dout(10) << sizeof(inode_t) << "\t inode_t " << dendl;
+  dout(10) << sizeof(CInode::mempool_inode) << "\t inode  " << dendl;
+  dout(10) << sizeof(CInode::mempool_old_inode) << "\t old_inode " << dendl;
   dout(10) << sizeof(nest_info_t) << "\t  nest_info_t " << dendl;
   dout(10) << sizeof(frag_info_t) << "\t  frag_info_t " << dendl;
   dout(10) << sizeof(SimpleLock) << "\t SimpleLock   *5=" << 5*sizeof(SimpleLock) << dendl;
@@ -542,14 +545,16 @@ void MDSDaemon::reset_tick()
   if (tick_event) timer.cancel_event(tick_event);
 
   // schedule
-  tick_event = new C_MDS_Tick(this);
-  timer.add_event_after(g_conf->mds_tick_interval, tick_event);
+  tick_event = timer.add_event_after(
+    g_conf->mds_tick_interval,
+    new FunctionContext([this](int) {
+       assert(mds_lock.is_locked_by_me());
+       tick();
+      }));
 }
 
 void MDSDaemon::tick()
 {
-  tick_event = 0;
-
   // reschedule
   reset_tick();
 
@@ -561,24 +566,25 @@ void MDSDaemon::tick()
 
 void MDSDaemon::send_command_reply(MCommand *m, MDSRank *mds_rank,
                                   int r, bufferlist outbl,
-                                  const std::string& outs)
+                                  boost::string_view outs)
 {
   Session *session = static_cast<Session *>(m->get_connection()->get_priv());
   assert(session != NULL);
   // If someone is using a closed session for sending commands (e.g.
   // the ceph CLI) then we should feel free to clean up this connection
   // as soon as we've sent them a response.
-  const bool live_session = mds_rank &&
-    mds_rank->sessionmap.get_session(session->info.inst.name) != nullptr
-    && session->get_state_seq() > 0;
+  const bool live_session =
+    session->get_state_seq() > 0 &&
+    mds_rank &&
+    mds_rank->sessionmap.get_session(session->info.inst.name);
 
   if (!live_session) {
     // This session only existed to issue commands, so terminate it
     // as soon as we can.
     assert(session->is_closed());
     session->connection->mark_disposable();
-    session->put();
   }
+  session->put();
 
   MCommandReply *reply = new MCommandReply(r, outs);
   reply->set_tid(m->get_tid());
@@ -617,6 +623,7 @@ void MDSDaemon::handle_command(MCommand *m)
   } else {
     r = _handle_command(cmdmap, m, &outbl, &outs, &run_after, &need_reply);
   }
+  session->put();
 
   if (need_reply) {
     send_command_reply(m, mds_rank, r, outbl, outs);
@@ -645,6 +652,10 @@ COMMAND("injectargs " \
        "name=injected_args,type=CephString,n=N",
        "inject configuration arguments into running MDS",
        "mds", "*", "cli,rest")
+COMMAND("config set " \
+       "name=key,type=CephString name=value,type=CephString",
+       "Set a configuration option at runtime (not persistent)",
+       "mds", "*", "cli,rest")
 COMMAND("exit",
        "Terminate this MDS",
        "mds", "*", "cli,rest")
@@ -661,13 +672,20 @@ COMMAND("cpu_profiler " \
 COMMAND("session ls " \
        "name=filters,type=CephString,n=N,req=false",
        "List client sessions", "mds", "r", "cli,rest")
+COMMAND("client ls " \
+       "name=filters,type=CephString,n=N,req=false",
+       "List client sessions", "mds", "r", "cli,rest")
 COMMAND("session evict " \
        "name=filters,type=CephString,n=N,req=false",
        "Evict client session(s)", "mds", "rw", "cli,rest")
+COMMAND("client evict " \
+       "name=filters,type=CephString,n=N,req=false",
+       "Evict client session(s)", "mds", "rw", "cli,rest")
 COMMAND("damage ls",
        "List detected metadata damage", "mds", "r", "cli,rest")
 COMMAND("damage rm name=damage_id,type=CephInt",
        "Remove a damage table entry", "mds", "rw", "cli,rest")
+COMMAND("version", "report version of MDS", "mds", "r", "cli,rest")
 COMMAND("heap " \
        "name=heapcmd,type=CephChoices,strings=dump|start_profiler|stop_profiler|release|stats", \
        "show heap usage info (available only if compiled with tcmalloc)", \
@@ -721,27 +739,41 @@ int MDSDaemon::_handle_command(
   std::stringstream ds;
   std::stringstream ss;
   std::string prefix;
+  std::string format;
+  std::unique_ptr<Formatter> f(Formatter::create(format));
   cmd_getval(cct, cmdmap, "prefix", prefix);
 
   int r = 0;
 
   if (prefix == "get_command_descriptions") {
     int cmdnum = 0;
-    JSONFormatter *f = new JSONFormatter();
+    std::unique_ptr<JSONFormatter> f(ceph::make_unique<JSONFormatter>());
     f->open_object_section("command_descriptions");
     for (MDSCommand *cp = mds_commands;
         cp < &mds_commands[ARRAY_SIZE(mds_commands)]; cp++) {
 
       ostringstream secname;
       secname << "cmd" << setfill('0') << std::setw(3) << cmdnum;
-      dump_cmddesc_to_json(f, secname.str(), cp->cmdstring, cp->helpstring,
+      dump_cmddesc_to_json(f.get(), secname.str(), cp->cmdstring, cp->helpstring,
                           cp->module, cp->perm, cp->availability, 0);
       cmdnum++;
     }
     f->close_section();        // command_descriptions
 
     f->flush(ds);
-    delete f;
+    goto out; 
+  }
+
+  cmd_getval(cct, cmdmap, "format", format);
+  if (prefix == "version") {
+    if (f) {
+      f->open_object_section("version");
+      f->dump_string("version", pretty_version_to_str());
+      f->close_section();
+      f->flush(ds);
+    } else {
+      ds << pretty_version_to_str();
+    }
   } else if (prefix == "injectargs") {
     vector<string> argsvec;
     cmd_getval(cct, cmdmap, "injected_args", argsvec);
@@ -755,12 +787,20 @@ int MDSDaemon::_handle_command(
     for (vector<string>::iterator a = ++argsvec.begin(); a != argsvec.end(); ++a)
       args += " " + *a;
     r = cct->_conf->injectargs(args, &ss);
+  } else if (prefix == "config set") {
+    std::string key;
+    cmd_getval(cct, cmdmap, "key", key);
+    std::string val;
+    cmd_getval(cct, cmdmap, "value", val);
+    r = cct->_conf->set_val(key, val, true, &ss);
+    if (r == 0) {
+      cct->_conf->apply_changes(nullptr);
+    }
   } else if (prefix == "exit") {
     // We will send response before executing
     ss << "Exiting...";
     *run_later = new SuicideLater(this);
-  }
-  else if (prefix == "respawn") {
+  } else if (prefix == "respawn") {
     // We will send response before executing
     ss << "Respawning...";
     *run_later = new RespawnLater(this);
@@ -774,7 +814,9 @@ int MDSDaemon::_handle_command(
     int64_t session_id = 0;
     bool got = cmd_getval(cct, cmdmap, "session_id", session_id);
     assert(got);
-    bool killed = mds_rank->kill_session(session_id, false, ss);
+    bool killed = mds_rank->evict_client(session_id, false,
+                                         g_conf->mds_session_blacklist_on_evict,
+                                         ss);
     if (!killed)
       r = -ENOENT;
   } else if (prefix == "heap") {
@@ -796,18 +838,19 @@ int MDSDaemon::_handle_command(
     cpu_profiler_handle_command(argvec, ds);
   } else {
     // Give MDSRank a shot at the command
-    if (mds_rank) {
+    if (!mds_rank) {
+      ss << "MDS not active";
+      r = -EINVAL;
+    }
+    else {
       bool handled = mds_rank->handle_command(cmdmap, m, &r, &ds, &ss,
                                              need_reply);
-      if (handled) {
-        goto out;
+      if (!handled) {
+        // MDSDaemon doesn't know this command
+        ss << "unrecognized command! " << prefix;
+        r = -EINVAL;
       }
     }
-
-    // Neither MDSDaemon nor MDSRank know this command
-    std::ostringstream ss;
-    ss << "unrecognized command! " << prefix;
-    r = -EINVAL;
   }
 
 out:
@@ -821,16 +864,17 @@ out:
 void MDSDaemon::handle_mds_map(MMDSMap *m)
 {
   version_t epoch = m->get_epoch();
-  dout(5) << "handle_mds_map epoch " << epoch << " from " << m->get_source() << dendl;
 
   // is it new?
   if (epoch <= mdsmap->get_epoch()) {
-    dout(5) << " old map epoch " << epoch << " <= " << mdsmap->get_epoch()
-           << ", discarding" << dendl;
+    dout(5) << "handle_mds_map old map epoch " << epoch << " <= "
+            << mdsmap->get_epoch() << ", discarding" << dendl;
     m->put();
     return;
   }
 
+  dout(1) << "Updating MDS map to version " << epoch << " from " << m->get_source() << dendl;
+
   entity_addr_t addr;
 
   // keep old map, for a moment
@@ -849,7 +893,7 @@ void MDSDaemon::handle_mds_map(MMDSMap *m)
   mds_rank_t whoami = mdsmap->get_rank_gid(mds_gid_t(monc->get_global_id()));
 
   // verify compatset
-  CompatSet mdsmap_compat(get_mdsmap_compat_set_all());
+  CompatSet mdsmap_compat(MDSMap::get_compat_set_all());
   dout(10) << "     my compat " << mdsmap_compat << dendl;
   dout(10) << " mdsmap compat " << mdsmap->compat << dendl;
   if (!mdsmap_compat.writeable(mdsmap->compat)) {
@@ -877,20 +921,21 @@ void MDSDaemon::handle_mds_map(MMDSMap *m)
 
   // see who i am
   addr = messenger->get_myaddr();
-  dout(10) << "map says i am " << addr << " mds." << whoami << "." << incarnation
+  dout(10) << "map says I am " << addr << " mds." << whoami << "." << incarnation
           << " state " << ceph_mds_state_name(new_state) << dendl;
 
   if (whoami == MDS_RANK_NONE) {
     if (mds_rank != NULL) {
+      const auto myid = monc->get_global_id();
       // We have entered a rank-holding state, we shouldn't be back
       // here!
       if (g_conf->mds_enforce_unique_name) {
         if (mds_gid_t existing = mdsmap->find_mds_gid_by_name(name)) {
           const 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;
+          if (i.global_id > myid) {
+            dout(1) << "Map replaced me with another mds." << whoami
+                    << " with gid (" << i.global_id << ") larger than myself ("
+                    << myid << "); quitting!" << 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.
@@ -901,8 +946,8 @@ void MDSDaemon::handle_mds_map(MMDSMap *m)
         }
       }
 
-      dout(1) << "handle_mds_map i (" << addr
-          << ") dne in the mdsmap, respawning myself" << dendl;
+      dout(1) << "Map removed me (mds." << whoami << " gid:"
+              << myid << ") from cluster due to lost contact; respawning" << dendl;
       respawn();
     }
     // MDSRank not active: process the map here to see if we have
@@ -949,7 +994,7 @@ void MDSDaemon::_handle_mds_map(MDSMap *oldmap)
   // Normal rankless case, we're marked as standby
   if (new_state == MDSMap::STATE_STANDBY) {
     beacon.set_want_state(mdsmap, new_state);
-    dout(1) << "handle_mds_map standby" << dendl;
+    dout(1) << "Map has assigned me to become a standby" << dendl;
 
     return;
   }
@@ -989,7 +1034,7 @@ void MDSDaemon::suicide()
   assert(stopping == false);
   stopping = true;
 
-  dout(1) << "suicide.  wanted state "
+  dout(1) << "suicide! Wanted state "
           << ceph_mds_state_name(beacon.get_want_state()) << dendl;
 
   if (tick_event) {
@@ -1028,7 +1073,11 @@ void MDSDaemon::suicide()
 
 void MDSDaemon::respawn()
 {
-  dout(1) << "respawn" << dendl;
+  dout(1) << "respawn!" << dendl;
+
+  /* Dump recent in case the MDS was stuck doing something which caused it to
+   * be removed from the MDSMap leading to respawn. */
+  g_ceph_context->_log->dump_recent();
 
   char *new_argv[orig_argc+1];
   dout(1) << " e: '" << orig_argv[0] << "'" << dendl;
@@ -1226,7 +1275,8 @@ bool MDSDaemon::ms_handle_refused(Connection *con)
 
 bool MDSDaemon::ms_verify_authorizer(Connection *con, int peer_type,
                               int protocol, bufferlist& authorizer_data, bufferlist& authorizer_reply,
-                              bool& is_valid, CryptoKey& session_key)
+                                    bool& is_valid, CryptoKey& session_key,
+                                    std::unique_ptr<AuthAuthorizerChallenge> *challenge)
 {
   Mutex::Locker l(mds_lock);
   if (stopping) {
@@ -1253,9 +1303,16 @@ bool MDSDaemon::ms_verify_authorizer(Connection *con, int peer_type,
   EntityName name;
   uint64_t global_id;
 
-  is_valid = authorize_handler->verify_authorizer(
-    cct, monc->rotating_secrets.get(),
-    authorizer_data, authorizer_reply, name, global_id, caps_info, session_key);
+  RotatingKeyRing *keys = monc->rotating_secrets.get();
+  if (keys) {
+    is_valid = authorize_handler->verify_authorizer(
+      cct, keys,
+      authorizer_data, authorizer_reply, name, global_id, caps_info,
+      session_key, nullptr, challenge);
+  } else {
+    dout(10) << __func__ << " no rotating_keys (yet), denied" << dendl;
+    is_valid = false;
+  }
 
   if (is_valid) {
     entity_name_t n(con->get_peer_type(), global_id);
@@ -1282,6 +1339,9 @@ bool MDSDaemon::ms_verify_authorizer(Connection *con, int peer_type,
       dout(10) << " new session " << s << " for " << s->info.inst << " con " << con << dendl;
       con->set_priv(s);
       s->connection = con;
+      if (mds_rank) {
+        mds_rank->kick_waiters_for_any_client_connection();
+      }
     } else {
       dout(10) << " existing session " << s << " for " << s->info.inst << " existing con " << s->connection
               << ", new/authorizing con " << con << dendl;
@@ -1305,26 +1365,28 @@ bool MDSDaemon::ms_verify_authorizer(Connection *con, int peer_type,
     if (caps_info.allow_all) {
       // Flag for auth providers that don't provide cap strings
       s->auth_caps.set_allow_all();
-    }
-
-    bufferlist::iterator p = caps_info.caps.begin();
-    string auth_cap_str;
-    try {
-      ::decode(auth_cap_str, p);
-
-      dout(10) << __func__ << ": parsing auth_cap_str='" << auth_cap_str << "'" << dendl;
-      std::ostringstream errstr;
-      if (!s->auth_caps.parse(g_ceph_context, auth_cap_str, &errstr)) {
-        dout(1) << __func__ << ": auth cap parse error: " << errstr.str()
-               << " parsing '" << auth_cap_str << "'" << dendl;
-       clog->warn() << name << " mds cap '" << auth_cap_str
-                    << "' does not parse: " << errstr.str();
+    } else {
+      bufferlist::iterator p = caps_info.caps.begin();
+      string auth_cap_str;
+      try {
+        ::decode(auth_cap_str, p);
+
+        dout(10) << __func__ << ": parsing auth_cap_str='" << auth_cap_str << "'" << dendl;
+        std::ostringstream errstr;
+        if (!s->auth_caps.parse(g_ceph_context, auth_cap_str, &errstr)) {
+          dout(1) << __func__ << ": auth cap parse error: " << errstr.str()
+                 << " parsing '" << auth_cap_str << "'" << dendl;
+         clog->warn() << name << " mds cap '" << auth_cap_str
+                      << "' does not parse: " << errstr.str();
+          is_valid = false;
+        }
+      } catch (buffer::error& e) {
+        // Assume legacy auth, defaults to:
+        //  * permit all filesystem ops
+        //  * permit no `tell` ops
+        dout(1) << __func__ << ": cannot decode auth caps bl of length " << caps_info.caps.length() << dendl;
+        is_valid = false;
       }
-    } catch (buffer::error& e) {
-      // Assume legacy auth, defaults to:
-      //  * permit all filesystem ops
-      //  * permit no `tell` ops
-      dout(1) << __func__ << ": cannot decode auth caps bl of length " << caps_info.caps.length() << dendl;
     }
   }