#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"
#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),
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;
f->dump_unsigned("osdmap_epoch", 0);
f->dump_unsigned("osdmap_epoch_barrier", 0);
}
+
+ f->dump_float("uptime", get_uptime().count());
+
f->close_section(); // status
}
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 "
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,
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");
"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",
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;
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();
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());
} 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);
"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")
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)", \
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);
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);
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") {
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:
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
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)) {
// 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.
}
}
- 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
// 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;
}
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) {
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;
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) {
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);
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;
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;
}
}