]> git.proxmox.com Git - ceph.git/blob - ceph/src/mds/MDSDaemon.cc
update sources to v12.2.1
[ceph.git] / ceph / src / mds / MDSDaemon.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3 /*
4 * Ceph - scalable distributed file system
5 *
6 * Copyright (C) 2004-2006 Sage Weil <sage@newdream.net>
7 *
8 * This is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License version 2.1, as published by the Free Software
11 * Foundation. See file COPYING.
12 *
13 */
14
15 #include <unistd.h>
16
17 #include "include/compat.h"
18 #include "include/types.h"
19 #include "include/str_list.h"
20
21 #include "common/Clock.h"
22 #include "common/HeartbeatMap.h"
23 #include "common/Timer.h"
24 #include "common/backport14.h"
25 #include "common/ceph_argparse.h"
26 #include "common/config.h"
27 #include "common/entity_name.h"
28 #include "common/errno.h"
29 #include "common/perf_counters.h"
30 #include "common/signal.h"
31 #include "common/version.h"
32
33 #include "global/signal_handler.h"
34
35 #include "msg/Messenger.h"
36 #include "mon/MonClient.h"
37
38 #include "osdc/Objecter.h"
39
40 #include "MDSMap.h"
41
42 #include "MDSDaemon.h"
43 #include "Server.h"
44 #include "Locker.h"
45
46 #include "SnapServer.h"
47 #include "SnapClient.h"
48
49 #include "events/ESession.h"
50 #include "events/ESubtreeMap.h"
51
52 #include "messages/MMDSMap.h"
53
54 #include "messages/MGenericMessage.h"
55
56 #include "messages/MMonCommand.h"
57 #include "messages/MCommand.h"
58 #include "messages/MCommandReply.h"
59
60 #include "auth/AuthAuthorizeHandler.h"
61 #include "auth/RotatingKeyRing.h"
62 #include "auth/KeyRing.h"
63
64 #include "perfglue/cpu_profiler.h"
65 #include "perfglue/heap_profiler.h"
66
67 #define dout_context g_ceph_context
68 #define dout_subsys ceph_subsys_mds
69 #undef dout_prefix
70 #define dout_prefix *_dout << "mds." << name << ' '
71
72
73 class MDSDaemon::C_MDS_Tick : public Context {
74 protected:
75 MDSDaemon *mds_daemon;
76 public:
77 explicit C_MDS_Tick(MDSDaemon *m) : mds_daemon(m) {}
78 void finish(int r) override {
79 assert(mds_daemon->mds_lock.is_locked_by_me());
80 mds_daemon->tick();
81 }
82 };
83
84 // cons/des
85 MDSDaemon::MDSDaemon(const std::string &n, Messenger *m, MonClient *mc) :
86 Dispatcher(m->cct),
87 mds_lock("MDSDaemon::mds_lock"),
88 stopping(false),
89 timer(m->cct, mds_lock),
90 beacon(m->cct, mc, n),
91 authorize_handler_cluster_registry(new AuthAuthorizeHandlerRegistry(m->cct,
92 m->cct->_conf->auth_supported.empty() ?
93 m->cct->_conf->auth_cluster_required :
94 m->cct->_conf->auth_supported)),
95 authorize_handler_service_registry(new AuthAuthorizeHandlerRegistry(m->cct,
96 m->cct->_conf->auth_supported.empty() ?
97 m->cct->_conf->auth_service_required :
98 m->cct->_conf->auth_supported)),
99 name(n),
100 messenger(m),
101 monc(mc),
102 mgrc(m->cct, m),
103 log_client(m->cct, messenger, &mc->monmap, LogClient::NO_FLAGS),
104 mds_rank(NULL),
105 tick_event(0),
106 asok_hook(NULL)
107 {
108 orig_argc = 0;
109 orig_argv = NULL;
110
111 clog = log_client.create_channel();
112
113 monc->set_messenger(messenger);
114
115 mdsmap = new MDSMap;
116 }
117
118 MDSDaemon::~MDSDaemon() {
119 Mutex::Locker lock(mds_lock);
120
121 delete mds_rank;
122 mds_rank = NULL;
123 delete mdsmap;
124 mdsmap = NULL;
125
126 delete authorize_handler_service_registry;
127 delete authorize_handler_cluster_registry;
128 }
129
130 class MDSSocketHook : public AdminSocketHook {
131 MDSDaemon *mds;
132 public:
133 explicit MDSSocketHook(MDSDaemon *m) : mds(m) {}
134 bool call(std::string command, cmdmap_t& cmdmap, std::string format,
135 bufferlist& out) override {
136 stringstream ss;
137 bool r = mds->asok_command(command, cmdmap, format, ss);
138 out.append(ss);
139 return r;
140 }
141 };
142
143 bool MDSDaemon::asok_command(string command, cmdmap_t& cmdmap, string format,
144 ostream& ss)
145 {
146 dout(1) << "asok_command: " << command << " (starting...)" << dendl;
147
148 Formatter *f = Formatter::create(format, "json-pretty", "json-pretty");
149 bool handled = false;
150 if (command == "status") {
151 dump_status(f);
152 handled = true;
153 } else {
154 if (mds_rank == NULL) {
155 dout(1) << "Can't run that command on an inactive MDS!" << dendl;
156 f->dump_string("error", "mds_not_active");
157 } else {
158 handled = mds_rank->handle_asok_command(command, cmdmap, f, ss);
159 }
160 }
161 f->flush(ss);
162 delete f;
163
164 dout(1) << "asok_command: " << command << " (complete)" << dendl;
165
166 return handled;
167 }
168
169 void MDSDaemon::dump_status(Formatter *f)
170 {
171 f->open_object_section("status");
172 f->dump_stream("cluster_fsid") << monc->get_fsid();
173 if (mds_rank) {
174 f->dump_int("whoami", mds_rank->get_nodeid());
175 } else {
176 f->dump_int("whoami", MDS_RANK_NONE);
177 }
178
179 f->dump_int("id", monc->get_global_id());
180 f->dump_string("want_state", ceph_mds_state_name(beacon.get_want_state()));
181 f->dump_string("state", ceph_mds_state_name(mdsmap->get_state_gid(mds_gid_t(
182 monc->get_global_id()))));
183 if (mds_rank) {
184 Mutex::Locker l(mds_lock);
185 mds_rank->dump_status(f);
186 }
187
188 f->dump_unsigned("mdsmap_epoch", mdsmap->get_epoch());
189 if (mds_rank) {
190 f->dump_unsigned("osdmap_epoch", mds_rank->get_osd_epoch());
191 f->dump_unsigned("osdmap_epoch_barrier", mds_rank->get_osd_epoch_barrier());
192 } else {
193 f->dump_unsigned("osdmap_epoch", 0);
194 f->dump_unsigned("osdmap_epoch_barrier", 0);
195 }
196 f->close_section(); // status
197 }
198
199 void MDSDaemon::set_up_admin_socket()
200 {
201 int r;
202 AdminSocket *admin_socket = g_ceph_context->get_admin_socket();
203 assert(asok_hook == nullptr);
204 asok_hook = new MDSSocketHook(this);
205 r = admin_socket->register_command("status", "status", asok_hook,
206 "high-level status of MDS");
207 assert(r == 0);
208 r = admin_socket->register_command("dump_ops_in_flight",
209 "dump_ops_in_flight", asok_hook,
210 "show the ops currently in flight");
211 assert(r == 0);
212 r = admin_socket->register_command("ops",
213 "ops", asok_hook,
214 "show the ops currently in flight");
215 assert(r == 0);
216 r = admin_socket->register_command("dump_blocked_ops", "dump_blocked_ops",
217 asok_hook,
218 "show the blocked ops currently in flight");
219 assert(r == 0);
220 r = admin_socket->register_command("dump_historic_ops", "dump_historic_ops",
221 asok_hook,
222 "show slowest recent ops");
223 assert(r == 0);
224 r = admin_socket->register_command("dump_historic_ops_by_duration", "dump_historic_ops_by_duration",
225 asok_hook,
226 "show slowest recent ops, sorted by op duration");
227 assert(r == 0);
228 r = admin_socket->register_command("scrub_path",
229 "scrub_path name=path,type=CephString "
230 "name=scrubops,type=CephChoices,"
231 "strings=force|recursive|repair,n=N,req=false",
232 asok_hook,
233 "scrub an inode and output results");
234 assert(r == 0);
235 r = admin_socket->register_command("tag path",
236 "tag path name=path,type=CephString"
237 " name=tag,type=CephString",
238 asok_hook,
239 "Apply scrub tag recursively");
240 assert(r == 0);
241 r = admin_socket->register_command("flush_path",
242 "flush_path name=path,type=CephString",
243 asok_hook,
244 "flush an inode (and its dirfrags)");
245 assert(r == 0);
246 r = admin_socket->register_command("export dir",
247 "export dir "
248 "name=path,type=CephString "
249 "name=rank,type=CephInt",
250 asok_hook,
251 "migrate a subtree to named MDS");
252 assert(r == 0);
253 r = admin_socket->register_command("dump cache",
254 "dump cache name=path,type=CephString,req=false",
255 asok_hook,
256 "dump metadata cache (optionally to a file)");
257 assert(r == 0);
258 r = admin_socket->register_command("cache status",
259 "cache status",
260 asok_hook,
261 "show cache status");
262 assert(r == 0);
263 r = admin_socket->register_command("dump tree",
264 "dump tree "
265 "name=root,type=CephString,req=true "
266 "name=depth,type=CephInt,req=false ",
267 asok_hook,
268 "dump metadata cache for subtree");
269 assert(r == 0);
270 r = admin_socket->register_command("session evict",
271 "session evict name=client_id,type=CephString",
272 asok_hook,
273 "Evict a CephFS client");
274 assert(r == 0);
275 r = admin_socket->register_command("osdmap barrier",
276 "osdmap barrier name=target_epoch,type=CephInt",
277 asok_hook,
278 "Wait until the MDS has this OSD map epoch");
279 assert(r == 0);
280 r = admin_socket->register_command("session ls",
281 "session ls",
282 asok_hook,
283 "Enumerate connected CephFS clients");
284 assert(r == 0);
285 r = admin_socket->register_command("flush journal",
286 "flush journal",
287 asok_hook,
288 "Flush the journal to the backing store");
289 assert(r == 0);
290 r = admin_socket->register_command("force_readonly",
291 "force_readonly",
292 asok_hook,
293 "Force MDS to read-only mode");
294 assert(r == 0);
295 r = admin_socket->register_command("get subtrees",
296 "get subtrees",
297 asok_hook,
298 "Return the subtree map");
299 assert(r == 0);
300 r = admin_socket->register_command("dirfrag split",
301 "dirfrag split "
302 "name=path,type=CephString,req=true "
303 "name=frag,type=CephString,req=true "
304 "name=bits,type=CephInt,req=true ",
305 asok_hook,
306 "Fragment directory by path");
307 assert(r == 0);
308 r = admin_socket->register_command("dirfrag merge",
309 "dirfrag merge "
310 "name=path,type=CephString,req=true "
311 "name=frag,type=CephString,req=true",
312 asok_hook,
313 "De-fragment directory by path");
314 assert(r == 0);
315 r = admin_socket->register_command("dirfrag ls",
316 "dirfrag ls "
317 "name=path,type=CephString,req=true",
318 asok_hook,
319 "List fragments in directory");
320 assert(r == 0);
321 }
322
323 void MDSDaemon::clean_up_admin_socket()
324 {
325 AdminSocket *admin_socket = g_ceph_context->get_admin_socket();
326 admin_socket->unregister_command("status");
327 admin_socket->unregister_command("dump_ops_in_flight");
328 admin_socket->unregister_command("ops");
329 admin_socket->unregister_command("dump_blocked_ops");
330 admin_socket->unregister_command("dump_historic_ops");
331 admin_socket->unregister_command("dump_historic_ops_by_duration");
332 admin_socket->unregister_command("scrub_path");
333 admin_socket->unregister_command("tag path");
334 admin_socket->unregister_command("flush_path");
335 admin_socket->unregister_command("export dir");
336 admin_socket->unregister_command("dump cache");
337 admin_socket->unregister_command("cache status");
338 admin_socket->unregister_command("dump tree");
339 admin_socket->unregister_command("session evict");
340 admin_socket->unregister_command("osdmap barrier");
341 admin_socket->unregister_command("session ls");
342 admin_socket->unregister_command("flush journal");
343 admin_socket->unregister_command("force_readonly");
344 admin_socket->unregister_command("get subtrees");
345 admin_socket->unregister_command("dirfrag split");
346 admin_socket->unregister_command("dirfrag merge");
347 admin_socket->unregister_command("dirfrag ls");
348 delete asok_hook;
349 asok_hook = NULL;
350 }
351
352 const char** MDSDaemon::get_tracked_conf_keys() const
353 {
354 static const char* KEYS[] = {
355 "mds_op_complaint_time", "mds_op_log_threshold",
356 "mds_op_history_size", "mds_op_history_duration",
357 "mds_enable_op_tracker",
358 "mds_log_pause",
359 // clog & admin clog
360 "clog_to_monitors",
361 "clog_to_syslog",
362 "clog_to_syslog_facility",
363 "clog_to_syslog_level",
364 // PurgeQueue
365 "mds_max_purge_ops",
366 "mds_max_purge_ops_per_pg",
367 "mds_max_purge_files",
368 "clog_to_graylog",
369 "clog_to_graylog_host",
370 "clog_to_graylog_port",
371 "host",
372 "fsid",
373 NULL
374 };
375 return KEYS;
376 }
377
378 void MDSDaemon::handle_conf_change(const struct md_config_t *conf,
379 const std::set <std::string> &changed)
380 {
381 // We may be called within mds_lock (via `tell`) or outwith the
382 // lock (via admin socket `config set`), so handle either case.
383 const bool initially_locked = mds_lock.is_locked_by_me();
384 if (!initially_locked) {
385 mds_lock.Lock();
386 }
387
388 if (changed.count("mds_op_complaint_time") ||
389 changed.count("mds_op_log_threshold")) {
390 if (mds_rank) {
391 mds_rank->op_tracker.set_complaint_and_threshold(conf->mds_op_complaint_time,
392 conf->mds_op_log_threshold);
393 }
394 }
395 if (changed.count("mds_op_history_size") ||
396 changed.count("mds_op_history_duration")) {
397 if (mds_rank) {
398 mds_rank->op_tracker.set_history_size_and_duration(conf->mds_op_history_size,
399 conf->mds_op_history_duration);
400 }
401 }
402 if (changed.count("mds_enable_op_tracker")) {
403 if (mds_rank) {
404 mds_rank->op_tracker.set_tracking(conf->mds_enable_op_tracker);
405 }
406 }
407 if (changed.count("clog_to_monitors") ||
408 changed.count("clog_to_syslog") ||
409 changed.count("clog_to_syslog_level") ||
410 changed.count("clog_to_syslog_facility") ||
411 changed.count("clog_to_graylog") ||
412 changed.count("clog_to_graylog_host") ||
413 changed.count("clog_to_graylog_port") ||
414 changed.count("host") ||
415 changed.count("fsid")) {
416 if (mds_rank) {
417 mds_rank->update_log_config();
418 }
419 }
420
421 if (!g_conf->mds_log_pause && changed.count("mds_log_pause")) {
422 if (mds_rank) {
423 mds_rank->mdlog->kick_submitter();
424 }
425 }
426
427 if (mds_rank) {
428 mds_rank->handle_conf_change(conf, changed);
429 }
430
431 if (!initially_locked) {
432 mds_lock.Unlock();
433 }
434 }
435
436
437 int MDSDaemon::init()
438 {
439 dout(10) << sizeof(MDSCacheObject) << "\tMDSCacheObject" << dendl;
440 dout(10) << sizeof(CInode) << "\tCInode" << dendl;
441 dout(10) << sizeof(elist<void*>::item) << "\t elist<>::item *7=" << 7*sizeof(elist<void*>::item) << dendl;
442 dout(10) << sizeof(inode_t) << "\t inode_t " << dendl;
443 dout(10) << sizeof(nest_info_t) << "\t nest_info_t " << dendl;
444 dout(10) << sizeof(frag_info_t) << "\t frag_info_t " << dendl;
445 dout(10) << sizeof(SimpleLock) << "\t SimpleLock *5=" << 5*sizeof(SimpleLock) << dendl;
446 dout(10) << sizeof(ScatterLock) << "\t ScatterLock *3=" << 3*sizeof(ScatterLock) << dendl;
447 dout(10) << sizeof(CDentry) << "\tCDentry" << dendl;
448 dout(10) << sizeof(elist<void*>::item) << "\t elist<>::item" << dendl;
449 dout(10) << sizeof(SimpleLock) << "\t SimpleLock" << dendl;
450 dout(10) << sizeof(CDir) << "\tCDir " << dendl;
451 dout(10) << sizeof(elist<void*>::item) << "\t elist<>::item *2=" << 2*sizeof(elist<void*>::item) << dendl;
452 dout(10) << sizeof(fnode_t) << "\t fnode_t " << dendl;
453 dout(10) << sizeof(nest_info_t) << "\t nest_info_t *2" << dendl;
454 dout(10) << sizeof(frag_info_t) << "\t frag_info_t *2" << dendl;
455 dout(10) << sizeof(Capability) << "\tCapability " << dendl;
456 dout(10) << sizeof(xlist<void*>::item) << "\t xlist<>::item *2=" << 2*sizeof(xlist<void*>::item) << dendl;
457
458 messenger->add_dispatcher_tail(&beacon);
459 messenger->add_dispatcher_tail(this);
460
461 // get monmap
462 monc->set_messenger(messenger);
463
464 monc->set_want_keys(CEPH_ENTITY_TYPE_MON | CEPH_ENTITY_TYPE_OSD |
465 CEPH_ENTITY_TYPE_MDS | CEPH_ENTITY_TYPE_MGR);
466 int r = 0;
467 r = monc->init();
468 if (r < 0) {
469 derr << "ERROR: failed to get monmap: " << cpp_strerror(-r) << dendl;
470 mds_lock.Lock();
471 suicide();
472 mds_lock.Unlock();
473 return r;
474 }
475
476 // tell monc about log_client so it will know about mon session resets
477 monc->set_log_client(&log_client);
478
479 r = monc->authenticate();
480 if (r < 0) {
481 derr << "ERROR: failed to authenticate: " << cpp_strerror(-r) << dendl;
482 mds_lock.Lock();
483 suicide();
484 mds_lock.Unlock();
485 return r;
486 }
487
488 int rotating_auth_attempts = 0;
489 while (monc->wait_auth_rotating(30.0) < 0) {
490 if (++rotating_auth_attempts <= g_conf->max_rotating_auth_attempts) {
491 derr << "unable to obtain rotating service keys; retrying" << dendl;
492 continue;
493 }
494 derr << "ERROR: failed to refresh rotating keys, "
495 << "maximum retry time reached." << dendl;
496 mds_lock.Lock();
497 suicide();
498 mds_lock.Unlock();
499 return -ETIMEDOUT;
500 }
501
502 mgrc.init();
503 messenger->add_dispatcher_head(&mgrc);
504
505 mds_lock.Lock();
506 if (beacon.get_want_state() == CEPH_MDS_STATE_DNE) {
507 dout(4) << __func__ << ": terminated already, dropping out" << dendl;
508 mds_lock.Unlock();
509 return 0;
510 }
511
512 monc->sub_want("mdsmap", 0, 0);
513 monc->sub_want("mgrmap", 0, 0);
514 monc->renew_subs();
515
516 mds_lock.Unlock();
517
518 // Set up admin socket before taking mds_lock, so that ordering
519 // is consistent (later we take mds_lock within asok callbacks)
520 set_up_admin_socket();
521 g_conf->add_observer(this);
522 mds_lock.Lock();
523 if (beacon.get_want_state() == MDSMap::STATE_DNE) {
524 suicide(); // we could do something more graceful here
525 dout(4) << __func__ << ": terminated already, dropping out" << dendl;
526 mds_lock.Unlock();
527 return 0;
528 }
529
530 timer.init();
531
532 beacon.init(mdsmap);
533 messenger->set_myname(entity_name_t::MDS(MDS_RANK_NONE));
534
535 // schedule tick
536 reset_tick();
537 mds_lock.Unlock();
538
539 return 0;
540 }
541
542 void MDSDaemon::reset_tick()
543 {
544 // cancel old
545 if (tick_event) timer.cancel_event(tick_event);
546
547 // schedule
548 tick_event = new C_MDS_Tick(this);
549 timer.add_event_after(g_conf->mds_tick_interval, tick_event);
550 }
551
552 void MDSDaemon::tick()
553 {
554 // reschedule
555 reset_tick();
556
557 // Call through to subsystems' tick functions
558 if (mds_rank) {
559 mds_rank->tick();
560 }
561 }
562
563 void MDSDaemon::send_command_reply(MCommand *m, MDSRank *mds_rank,
564 int r, bufferlist outbl,
565 const std::string& outs)
566 {
567 Session *session = static_cast<Session *>(m->get_connection()->get_priv());
568 assert(session != NULL);
569 // If someone is using a closed session for sending commands (e.g.
570 // the ceph CLI) then we should feel free to clean up this connection
571 // as soon as we've sent them a response.
572 const bool live_session = mds_rank &&
573 mds_rank->sessionmap.get_session(session->info.inst.name) != nullptr
574 && session->get_state_seq() > 0;
575
576 if (!live_session) {
577 // This session only existed to issue commands, so terminate it
578 // as soon as we can.
579 assert(session->is_closed());
580 session->connection->mark_disposable();
581 session->put();
582 }
583
584 MCommandReply *reply = new MCommandReply(r, outs);
585 reply->set_tid(m->get_tid());
586 reply->set_data(outbl);
587 m->get_connection()->send_message(reply);
588 }
589
590 /* This function DOES put the passed message before returning*/
591 void MDSDaemon::handle_command(MCommand *m)
592 {
593 Session *session = static_cast<Session *>(m->get_connection()->get_priv());
594 assert(session != NULL);
595
596 int r = 0;
597 cmdmap_t cmdmap;
598 std::stringstream ss;
599 std::string outs;
600 bufferlist outbl;
601 Context *run_after = NULL;
602 bool need_reply = true;
603
604 if (!session->auth_caps.allow_all()) {
605 dout(1) << __func__
606 << ": received command from client without `tell` capability: "
607 << m->get_connection()->peer_addr << dendl;
608
609 ss << "permission denied";
610 r = -EPERM;
611 } else if (m->cmd.empty()) {
612 r = -EINVAL;
613 ss << "no command given";
614 outs = ss.str();
615 } else if (!cmdmap_from_json(m->cmd, &cmdmap, ss)) {
616 r = -EINVAL;
617 outs = ss.str();
618 } else {
619 r = _handle_command(cmdmap, m, &outbl, &outs, &run_after, &need_reply);
620 }
621
622 if (need_reply) {
623 send_command_reply(m, mds_rank, r, outbl, outs);
624 }
625
626 if (run_after) {
627 run_after->complete(0);
628 }
629
630 m->put();
631 }
632
633
634 struct MDSCommand {
635 string cmdstring;
636 string helpstring;
637 string module;
638 string perm;
639 string availability;
640 } mds_commands[] = {
641
642 #define COMMAND(parsesig, helptext, module, perm, availability) \
643 {parsesig, helptext, module, perm, availability},
644
645 COMMAND("injectargs " \
646 "name=injected_args,type=CephString,n=N",
647 "inject configuration arguments into running MDS",
648 "mds", "*", "cli,rest")
649 COMMAND("config set " \
650 "name=key,type=CephString name=value,type=CephString",
651 "Set a configuration option at runtime (not persistent)",
652 "mds", "*", "cli,rest")
653 COMMAND("exit",
654 "Terminate this MDS",
655 "mds", "*", "cli,rest")
656 COMMAND("respawn",
657 "Restart this MDS",
658 "mds", "*", "cli,rest")
659 COMMAND("session kill " \
660 "name=session_id,type=CephInt",
661 "End a client session",
662 "mds", "*", "cli,rest")
663 COMMAND("cpu_profiler " \
664 "name=arg,type=CephChoices,strings=status|flush",
665 "run cpu profiling on daemon", "mds", "rw", "cli,rest")
666 COMMAND("session ls " \
667 "name=filters,type=CephString,n=N,req=false",
668 "List client sessions", "mds", "r", "cli,rest")
669 COMMAND("client ls " \
670 "name=filters,type=CephString,n=N,req=false",
671 "List client sessions", "mds", "r", "cli,rest")
672 COMMAND("session evict " \
673 "name=filters,type=CephString,n=N,req=false",
674 "Evict client session(s)", "mds", "rw", "cli,rest")
675 COMMAND("client evict " \
676 "name=filters,type=CephString,n=N,req=false",
677 "Evict client session(s)", "mds", "rw", "cli,rest")
678 COMMAND("damage ls",
679 "List detected metadata damage", "mds", "r", "cli,rest")
680 COMMAND("damage rm name=damage_id,type=CephInt",
681 "Remove a damage table entry", "mds", "rw", "cli,rest")
682 COMMAND("version", "report version of MDS", "mds", "r", "cli,rest")
683 COMMAND("heap " \
684 "name=heapcmd,type=CephChoices,strings=dump|start_profiler|stop_profiler|release|stats", \
685 "show heap usage info (available only if compiled with tcmalloc)", \
686 "mds", "*", "cli,rest")
687 };
688
689
690 int MDSDaemon::_handle_command(
691 const cmdmap_t &cmdmap,
692 MCommand *m,
693 bufferlist *outbl,
694 std::string *outs,
695 Context **run_later,
696 bool *need_reply)
697 {
698 assert(outbl != NULL);
699 assert(outs != NULL);
700
701 class SuicideLater : public Context
702 {
703 MDSDaemon *mds;
704
705 public:
706 explicit SuicideLater(MDSDaemon *mds_) : mds(mds_) {}
707 void finish(int r) override {
708 // Wait a little to improve chances of caller getting
709 // our response before seeing us disappear from mdsmap
710 sleep(1);
711
712 mds->suicide();
713 }
714 };
715
716
717 class RespawnLater : public Context
718 {
719 MDSDaemon *mds;
720
721 public:
722
723 explicit RespawnLater(MDSDaemon *mds_) : mds(mds_) {}
724 void finish(int r) override {
725 // Wait a little to improve chances of caller getting
726 // our response before seeing us disappear from mdsmap
727 sleep(1);
728
729 mds->respawn();
730 }
731 };
732
733 std::stringstream ds;
734 std::stringstream ss;
735 std::string prefix;
736 std::string format;
737 std::unique_ptr<Formatter> f(Formatter::create(format));
738 cmd_getval(cct, cmdmap, "prefix", prefix);
739
740 int r = 0;
741
742 if (prefix == "get_command_descriptions") {
743 int cmdnum = 0;
744 std::unique_ptr<JSONFormatter> f(ceph::make_unique<JSONFormatter>());
745 f->open_object_section("command_descriptions");
746 for (MDSCommand *cp = mds_commands;
747 cp < &mds_commands[ARRAY_SIZE(mds_commands)]; cp++) {
748
749 ostringstream secname;
750 secname << "cmd" << setfill('0') << std::setw(3) << cmdnum;
751 dump_cmddesc_to_json(f.get(), secname.str(), cp->cmdstring, cp->helpstring,
752 cp->module, cp->perm, cp->availability, 0);
753 cmdnum++;
754 }
755 f->close_section(); // command_descriptions
756
757 f->flush(ds);
758 goto out;
759 }
760
761 cmd_getval(cct, cmdmap, "format", format);
762 if (prefix == "version") {
763 if (f) {
764 f->open_object_section("version");
765 f->dump_string("version", pretty_version_to_str());
766 f->close_section();
767 f->flush(ds);
768 } else {
769 ds << pretty_version_to_str();
770 }
771 } else if (prefix == "injectargs") {
772 vector<string> argsvec;
773 cmd_getval(cct, cmdmap, "injected_args", argsvec);
774
775 if (argsvec.empty()) {
776 r = -EINVAL;
777 ss << "ignoring empty injectargs";
778 goto out;
779 }
780 string args = argsvec.front();
781 for (vector<string>::iterator a = ++argsvec.begin(); a != argsvec.end(); ++a)
782 args += " " + *a;
783 r = cct->_conf->injectargs(args, &ss);
784 } else if (prefix == "config set") {
785 std::string key;
786 cmd_getval(cct, cmdmap, "key", key);
787 std::string val;
788 cmd_getval(cct, cmdmap, "value", val);
789 r = cct->_conf->set_val(key, val, true, &ss);
790 if (r == 0) {
791 cct->_conf->apply_changes(nullptr);
792 }
793 } else if (prefix == "exit") {
794 // We will send response before executing
795 ss << "Exiting...";
796 *run_later = new SuicideLater(this);
797 } else if (prefix == "respawn") {
798 // We will send response before executing
799 ss << "Respawning...";
800 *run_later = new RespawnLater(this);
801 } else if (prefix == "session kill") {
802 if (mds_rank == NULL) {
803 r = -EINVAL;
804 ss << "MDS not active";
805 goto out;
806 }
807 // FIXME harmonize `session kill` with admin socket session evict
808 int64_t session_id = 0;
809 bool got = cmd_getval(cct, cmdmap, "session_id", session_id);
810 assert(got);
811 bool killed = mds_rank->evict_client(session_id, false,
812 g_conf->mds_session_blacklist_on_evict,
813 ss);
814 if (!killed)
815 r = -ENOENT;
816 } else if (prefix == "heap") {
817 if (!ceph_using_tcmalloc()) {
818 r = -EOPNOTSUPP;
819 ss << "could not issue heap profiler command -- not using tcmalloc!";
820 } else {
821 string heapcmd;
822 cmd_getval(cct, cmdmap, "heapcmd", heapcmd);
823 vector<string> heapcmd_vec;
824 get_str_vec(heapcmd, heapcmd_vec);
825 ceph_heap_profiler_handle_command(heapcmd_vec, ds);
826 }
827 } else if (prefix == "cpu_profiler") {
828 string arg;
829 cmd_getval(cct, cmdmap, "arg", arg);
830 vector<string> argvec;
831 get_str_vec(arg, argvec);
832 cpu_profiler_handle_command(argvec, ds);
833 } else {
834 // Give MDSRank a shot at the command
835 if (mds_rank) {
836 bool handled = mds_rank->handle_command(cmdmap, m, &r, &ds, &ss,
837 need_reply);
838 if (handled) {
839 goto out;
840 }
841 }
842
843 // Neither MDSDaemon nor MDSRank know this command
844 std::ostringstream ss;
845 ss << "unrecognized command! " << prefix;
846 r = -EINVAL;
847 }
848
849 out:
850 *outs = ss.str();
851 outbl->append(ds);
852 return r;
853 }
854
855 /* This function deletes the passed message before returning. */
856
857 void MDSDaemon::handle_mds_map(MMDSMap *m)
858 {
859 version_t epoch = m->get_epoch();
860 dout(5) << "handle_mds_map epoch " << epoch << " from " << m->get_source() << dendl;
861
862 // is it new?
863 if (epoch <= mdsmap->get_epoch()) {
864 dout(5) << " old map epoch " << epoch << " <= " << mdsmap->get_epoch()
865 << ", discarding" << dendl;
866 m->put();
867 return;
868 }
869
870 entity_addr_t addr;
871
872 // keep old map, for a moment
873 MDSMap *oldmap = mdsmap;
874
875 // decode and process
876 mdsmap = new MDSMap;
877 mdsmap->decode(m->get_encoded());
878 const MDSMap::DaemonState new_state = mdsmap->get_state_gid(mds_gid_t(monc->get_global_id()));
879 const int incarnation = mdsmap->get_inc_gid(mds_gid_t(monc->get_global_id()));
880
881 monc->sub_got("mdsmap", mdsmap->get_epoch());
882
883 // Calculate my effective rank (either my owned rank or my
884 // standby_for_rank if in standby replay)
885 mds_rank_t whoami = mdsmap->get_rank_gid(mds_gid_t(monc->get_global_id()));
886
887 // verify compatset
888 CompatSet mdsmap_compat(get_mdsmap_compat_set_all());
889 dout(10) << " my compat " << mdsmap_compat << dendl;
890 dout(10) << " mdsmap compat " << mdsmap->compat << dendl;
891 if (!mdsmap_compat.writeable(mdsmap->compat)) {
892 dout(0) << "handle_mds_map mdsmap compatset " << mdsmap->compat
893 << " not writeable with daemon features " << mdsmap_compat
894 << ", killing myself" << dendl;
895 suicide();
896 goto out;
897 }
898
899 // mark down any failed peers
900 for (map<mds_gid_t,MDSMap::mds_info_t>::const_iterator p = oldmap->get_mds_info().begin();
901 p != oldmap->get_mds_info().end();
902 ++p) {
903 if (mdsmap->get_mds_info().count(p->first) == 0) {
904 dout(10) << " peer mds gid " << p->first << " removed from map" << dendl;
905 messenger->mark_down(p->second.addr);
906 }
907 }
908
909 if (whoami == MDS_RANK_NONE &&
910 new_state == MDSMap::STATE_STANDBY_REPLAY) {
911 whoami = mdsmap->get_mds_info_gid(mds_gid_t(monc->get_global_id())).standby_for_rank;
912 }
913
914 // see who i am
915 addr = messenger->get_myaddr();
916 dout(10) << "map says I am " << addr << " mds." << whoami << "." << incarnation
917 << " state " << ceph_mds_state_name(new_state) << dendl;
918
919 if (whoami == MDS_RANK_NONE) {
920 if (mds_rank != NULL) {
921 const auto myid = monc->get_global_id();
922 // We have entered a rank-holding state, we shouldn't be back
923 // here!
924 if (g_conf->mds_enforce_unique_name) {
925 if (mds_gid_t existing = mdsmap->find_mds_gid_by_name(name)) {
926 const MDSMap::mds_info_t& i = mdsmap->get_info_gid(existing);
927 if (i.global_id > myid) {
928 dout(1) << "map replaced me with another mds." << whoami
929 << " with gid (" << i.global_id << ") larger than myself ("
930 << myid << "); quitting!" << dendl;
931 // Call suicide() rather than respawn() because if someone else
932 // has taken our ID, we don't want to keep restarting and
933 // fighting them for the ID.
934 suicide();
935 m->put();
936 return;
937 }
938 }
939 }
940
941 dout(1) << "map removed me (mds." << whoami << " gid:"
942 << myid << ") from cluster due to lost contact; respawning" << dendl;
943 respawn();
944 }
945 // MDSRank not active: process the map here to see if we have
946 // been assigned a rank.
947 dout(10) << __func__ << ": handling map in rankless mode" << dendl;
948 _handle_mds_map(oldmap);
949 } else {
950
951 // Did we already hold a different rank? MDSMonitor shouldn't try
952 // to change that out from under me!
953 if (mds_rank && whoami != mds_rank->get_nodeid()) {
954 derr << "Invalid rank transition " << mds_rank->get_nodeid() << "->"
955 << whoami << dendl;
956 respawn();
957 }
958
959 // Did I previously not hold a rank? Initialize!
960 if (mds_rank == NULL) {
961 mds_rank = new MDSRankDispatcher(whoami, mds_lock, clog,
962 timer, beacon, mdsmap, messenger, monc,
963 new FunctionContext([this](int r){respawn();}),
964 new FunctionContext([this](int r){suicide();}));
965 dout(10) << __func__ << ": initializing MDS rank "
966 << mds_rank->get_nodeid() << dendl;
967 mds_rank->init();
968 }
969
970 // MDSRank is active: let him process the map, we have no say.
971 dout(10) << __func__ << ": handling map as rank "
972 << mds_rank->get_nodeid() << dendl;
973 mds_rank->handle_mds_map(m, oldmap);
974 }
975
976 out:
977 beacon.notify_mdsmap(mdsmap);
978 m->put();
979 delete oldmap;
980 }
981
982 void MDSDaemon::_handle_mds_map(MDSMap *oldmap)
983 {
984 MDSMap::DaemonState new_state = mdsmap->get_state_gid(mds_gid_t(monc->get_global_id()));
985
986 // Normal rankless case, we're marked as standby
987 if (new_state == MDSMap::STATE_STANDBY) {
988 beacon.set_want_state(mdsmap, new_state);
989 dout(1) << "handle_mds_map standby" << dendl;
990
991 return;
992 }
993
994 // Case where we thought we were standby, but MDSMap disagrees
995 if (beacon.get_want_state() == MDSMap::STATE_STANDBY) {
996 dout(10) << "dropped out of mdsmap, try to re-add myself" << dendl;
997 new_state = MDSMap::STATE_BOOT;
998 beacon.set_want_state(mdsmap, new_state);
999 return;
1000 }
1001
1002 // Case where we have sent a boot beacon that isn't reflected yet
1003 if (beacon.get_want_state() == MDSMap::STATE_BOOT) {
1004 dout(10) << "not in map yet" << dendl;
1005 }
1006 }
1007
1008 void MDSDaemon::handle_signal(int signum)
1009 {
1010 assert(signum == SIGINT || signum == SIGTERM);
1011 derr << "*** got signal " << sig_str(signum) << " ***" << dendl;
1012 {
1013 Mutex::Locker l(mds_lock);
1014 if (stopping) {
1015 return;
1016 }
1017 suicide();
1018 }
1019 }
1020
1021 void MDSDaemon::suicide()
1022 {
1023 assert(mds_lock.is_locked());
1024
1025 // make sure we don't suicide twice
1026 assert(stopping == false);
1027 stopping = true;
1028
1029 dout(1) << "suicide. wanted state "
1030 << ceph_mds_state_name(beacon.get_want_state()) << dendl;
1031
1032 if (tick_event) {
1033 timer.cancel_event(tick_event);
1034 tick_event = 0;
1035 }
1036
1037 //because add_observer is called after set_up_admin_socket
1038 //so we can use asok_hook to avoid assert in the remove_observer
1039 if (asok_hook != NULL)
1040 g_conf->remove_observer(this);
1041
1042 clean_up_admin_socket();
1043
1044 // Inform MDS we are going away, then shut down beacon
1045 beacon.set_want_state(mdsmap, MDSMap::STATE_DNE);
1046 if (!mdsmap->is_dne_gid(mds_gid_t(monc->get_global_id()))) {
1047 // Notify the MDSMonitor that we're dying, so that it doesn't have to
1048 // wait for us to go laggy. Only do this if we're actually in the
1049 // MDSMap, because otherwise the MDSMonitor will drop our message.
1050 beacon.send_and_wait(1);
1051 }
1052 beacon.shutdown();
1053
1054 mgrc.shutdown();
1055
1056 if (mds_rank) {
1057 mds_rank->shutdown();
1058 } else {
1059 timer.shutdown();
1060
1061 monc->shutdown();
1062 messenger->shutdown();
1063 }
1064 }
1065
1066 void MDSDaemon::respawn()
1067 {
1068 dout(1) << "respawn" << dendl;
1069
1070 char *new_argv[orig_argc+1];
1071 dout(1) << " e: '" << orig_argv[0] << "'" << dendl;
1072 for (int i=0; i<orig_argc; i++) {
1073 new_argv[i] = (char *)orig_argv[i];
1074 dout(1) << " " << i << ": '" << orig_argv[i] << "'" << dendl;
1075 }
1076 new_argv[orig_argc] = NULL;
1077
1078 /* Determine the path to our executable, test if Linux /proc/self/exe exists.
1079 * This allows us to exec the same executable even if it has since been
1080 * unlinked.
1081 */
1082 char exe_path[PATH_MAX] = "";
1083 if (readlink(PROCPREFIX "/proc/self/exe", exe_path, PATH_MAX-1) == -1) {
1084 /* Print CWD for the user's interest */
1085 char buf[PATH_MAX];
1086 char *cwd = getcwd(buf, sizeof(buf));
1087 assert(cwd);
1088 dout(1) << " cwd " << cwd << dendl;
1089
1090 /* Fall back to a best-effort: just running in our CWD */
1091 strncpy(exe_path, orig_argv[0], PATH_MAX-1);
1092 } else {
1093 dout(1) << "respawning with exe " << exe_path << dendl;
1094 strcpy(exe_path, PROCPREFIX "/proc/self/exe");
1095 }
1096
1097 dout(1) << " exe_path " << exe_path << dendl;
1098
1099 unblock_all_signals(NULL);
1100 execv(exe_path, new_argv);
1101
1102 dout(0) << "respawn execv " << orig_argv[0]
1103 << " failed with " << cpp_strerror(errno) << dendl;
1104
1105 // We have to assert out here, because suicide() returns, and callers
1106 // to respawn expect it never to return.
1107 ceph_abort();
1108 }
1109
1110
1111
1112 bool MDSDaemon::ms_dispatch(Message *m)
1113 {
1114 Mutex::Locker l(mds_lock);
1115 if (stopping) {
1116 return false;
1117 }
1118
1119 // Drop out early if shutting down
1120 if (beacon.get_want_state() == CEPH_MDS_STATE_DNE) {
1121 dout(10) << " stopping, discarding " << *m << dendl;
1122 m->put();
1123 return true;
1124 }
1125
1126 // First see if it's a daemon message
1127 const bool handled_core = handle_core_message(m);
1128 if (handled_core) {
1129 return true;
1130 }
1131
1132 // Not core, try it as a rank message
1133 if (mds_rank) {
1134 return mds_rank->ms_dispatch(m);
1135 } else {
1136 return false;
1137 }
1138 }
1139
1140 bool MDSDaemon::ms_get_authorizer(int dest_type, AuthAuthorizer **authorizer, bool force_new)
1141 {
1142 dout(10) << "MDSDaemon::ms_get_authorizer type="
1143 << ceph_entity_type_name(dest_type) << dendl;
1144
1145 /* monitor authorization is being handled on different layer */
1146 if (dest_type == CEPH_ENTITY_TYPE_MON)
1147 return true;
1148
1149 if (force_new) {
1150 if (monc->wait_auth_rotating(10) < 0)
1151 return false;
1152 }
1153
1154 *authorizer = monc->build_authorizer(dest_type);
1155 return *authorizer != NULL;
1156 }
1157
1158
1159 /*
1160 * high priority messages we always process
1161 */
1162 bool MDSDaemon::handle_core_message(Message *m)
1163 {
1164 switch (m->get_type()) {
1165 case CEPH_MSG_MON_MAP:
1166 ALLOW_MESSAGES_FROM(CEPH_ENTITY_TYPE_MON);
1167 m->put();
1168 break;
1169
1170 // MDS
1171 case CEPH_MSG_MDS_MAP:
1172 ALLOW_MESSAGES_FROM(CEPH_ENTITY_TYPE_MON | CEPH_ENTITY_TYPE_MDS);
1173 handle_mds_map(static_cast<MMDSMap*>(m));
1174 break;
1175
1176 // OSD
1177 case MSG_COMMAND:
1178 handle_command(static_cast<MCommand*>(m));
1179 break;
1180 case CEPH_MSG_OSD_MAP:
1181 ALLOW_MESSAGES_FROM(CEPH_ENTITY_TYPE_MON | CEPH_ENTITY_TYPE_OSD);
1182
1183 if (mds_rank) {
1184 mds_rank->handle_osd_map();
1185 }
1186 m->put();
1187 break;
1188
1189 case MSG_MON_COMMAND:
1190 ALLOW_MESSAGES_FROM(CEPH_ENTITY_TYPE_MON);
1191 clog->warn() << "dropping `mds tell` command from legacy monitor";
1192 m->put();
1193 break;
1194
1195 default:
1196 return false;
1197 }
1198 return true;
1199 }
1200
1201 void MDSDaemon::ms_handle_connect(Connection *con)
1202 {
1203 }
1204
1205 bool MDSDaemon::ms_handle_reset(Connection *con)
1206 {
1207 if (con->get_peer_type() != CEPH_ENTITY_TYPE_CLIENT)
1208 return false;
1209
1210 Mutex::Locker l(mds_lock);
1211 if (stopping) {
1212 return false;
1213 }
1214 dout(5) << "ms_handle_reset on " << con->get_peer_addr() << dendl;
1215 if (beacon.get_want_state() == CEPH_MDS_STATE_DNE)
1216 return false;
1217
1218 Session *session = static_cast<Session *>(con->get_priv());
1219 if (session) {
1220 if (session->is_closed()) {
1221 dout(3) << "ms_handle_reset closing connection for session " << session->info.inst << dendl;
1222 con->mark_down();
1223 con->set_priv(NULL);
1224 }
1225 session->put();
1226 } else {
1227 con->mark_down();
1228 }
1229 return false;
1230 }
1231
1232
1233 void MDSDaemon::ms_handle_remote_reset(Connection *con)
1234 {
1235 if (con->get_peer_type() != CEPH_ENTITY_TYPE_CLIENT)
1236 return;
1237
1238 Mutex::Locker l(mds_lock);
1239 if (stopping) {
1240 return;
1241 }
1242
1243 dout(5) << "ms_handle_remote_reset on " << con->get_peer_addr() << dendl;
1244 if (beacon.get_want_state() == CEPH_MDS_STATE_DNE)
1245 return;
1246
1247 Session *session = static_cast<Session *>(con->get_priv());
1248 if (session) {
1249 if (session->is_closed()) {
1250 dout(3) << "ms_handle_remote_reset closing connection for session " << session->info.inst << dendl;
1251 con->mark_down();
1252 con->set_priv(NULL);
1253 }
1254 session->put();
1255 }
1256 }
1257
1258 bool MDSDaemon::ms_handle_refused(Connection *con)
1259 {
1260 // do nothing for now
1261 return false;
1262 }
1263
1264 bool MDSDaemon::ms_verify_authorizer(Connection *con, int peer_type,
1265 int protocol, bufferlist& authorizer_data, bufferlist& authorizer_reply,
1266 bool& is_valid, CryptoKey& session_key)
1267 {
1268 Mutex::Locker l(mds_lock);
1269 if (stopping) {
1270 return false;
1271 }
1272 if (beacon.get_want_state() == CEPH_MDS_STATE_DNE)
1273 return false;
1274
1275 AuthAuthorizeHandler *authorize_handler = 0;
1276 switch (peer_type) {
1277 case CEPH_ENTITY_TYPE_MDS:
1278 authorize_handler = authorize_handler_cluster_registry->get_handler(protocol);
1279 break;
1280 default:
1281 authorize_handler = authorize_handler_service_registry->get_handler(protocol);
1282 }
1283 if (!authorize_handler) {
1284 dout(0) << "No AuthAuthorizeHandler found for protocol " << protocol << dendl;
1285 is_valid = false;
1286 return true;
1287 }
1288
1289 AuthCapsInfo caps_info;
1290 EntityName name;
1291 uint64_t global_id;
1292
1293 RotatingKeyRing *keys = monc->rotating_secrets.get();
1294 if (keys) {
1295 is_valid = authorize_handler->verify_authorizer(
1296 cct, keys,
1297 authorizer_data, authorizer_reply, name, global_id, caps_info,
1298 session_key);
1299 } else {
1300 dout(10) << __func__ << " no rotating_keys (yet), denied" << dendl;
1301 is_valid = false;
1302 }
1303
1304 if (is_valid) {
1305 entity_name_t n(con->get_peer_type(), global_id);
1306
1307 // We allow connections and assign Session instances to connections
1308 // even if we have not been assigned a rank, because clients with
1309 // "allow *" are allowed to connect and do 'tell' operations before
1310 // we have a rank.
1311 Session *s = NULL;
1312 if (mds_rank) {
1313 // If we do hold a rank, see if this is an existing client establishing
1314 // a new connection, rather than a new client
1315 s = mds_rank->sessionmap.get_session(n);
1316 }
1317
1318 // Wire up a Session* to this connection
1319 // It doesn't go into a SessionMap instance until it sends an explicit
1320 // request to open a session (initial state of Session is `closed`)
1321 if (!s) {
1322 s = new Session;
1323 s->info.auth_name = name;
1324 s->info.inst.addr = con->get_peer_addr();
1325 s->info.inst.name = n;
1326 dout(10) << " new session " << s << " for " << s->info.inst << " con " << con << dendl;
1327 con->set_priv(s);
1328 s->connection = con;
1329 } else {
1330 dout(10) << " existing session " << s << " for " << s->info.inst << " existing con " << s->connection
1331 << ", new/authorizing con " << con << dendl;
1332 con->set_priv(s->get());
1333
1334
1335
1336 // Wait until we fully accept the connection before setting
1337 // s->connection. In particular, if there are multiple incoming
1338 // connection attempts, they will all get their authorizer
1339 // validated, but some of them may "lose the race" and get
1340 // dropped. We only want to consider the winner(s). See
1341 // ms_handle_accept(). This is important for Sessions we replay
1342 // from the journal on recovery that don't have established
1343 // messenger state; we want the con from only the winning
1344 // connect attempt(s). (Normal reconnects that don't follow MDS
1345 // recovery are reconnected to the existing con by the
1346 // messenger.)
1347 }
1348
1349 if (caps_info.allow_all) {
1350 // Flag for auth providers that don't provide cap strings
1351 s->auth_caps.set_allow_all();
1352 } else {
1353 bufferlist::iterator p = caps_info.caps.begin();
1354 string auth_cap_str;
1355 try {
1356 ::decode(auth_cap_str, p);
1357
1358 dout(10) << __func__ << ": parsing auth_cap_str='" << auth_cap_str << "'" << dendl;
1359 std::ostringstream errstr;
1360 if (!s->auth_caps.parse(g_ceph_context, auth_cap_str, &errstr)) {
1361 dout(1) << __func__ << ": auth cap parse error: " << errstr.str()
1362 << " parsing '" << auth_cap_str << "'" << dendl;
1363 clog->warn() << name << " mds cap '" << auth_cap_str
1364 << "' does not parse: " << errstr.str();
1365 is_valid = false;
1366 }
1367 } catch (buffer::error& e) {
1368 // Assume legacy auth, defaults to:
1369 // * permit all filesystem ops
1370 // * permit no `tell` ops
1371 dout(1) << __func__ << ": cannot decode auth caps bl of length " << caps_info.caps.length() << dendl;
1372 is_valid = false;
1373 }
1374 }
1375 }
1376
1377 return true; // we made a decision (see is_valid)
1378 }
1379
1380
1381 void MDSDaemon::ms_handle_accept(Connection *con)
1382 {
1383 Mutex::Locker l(mds_lock);
1384 if (stopping) {
1385 return;
1386 }
1387
1388 Session *s = static_cast<Session *>(con->get_priv());
1389 dout(10) << "ms_handle_accept " << con->get_peer_addr() << " con " << con << " session " << s << dendl;
1390 if (s) {
1391 if (s->connection != con) {
1392 dout(10) << " session connection " << s->connection << " -> " << con << dendl;
1393 s->connection = con;
1394
1395 // send out any queued messages
1396 while (!s->preopen_out_queue.empty()) {
1397 con->send_message(s->preopen_out_queue.front());
1398 s->preopen_out_queue.pop_front();
1399 }
1400 }
1401 s->put();
1402 }
1403 }
1404
1405 bool MDSDaemon::is_clean_shutdown()
1406 {
1407 if (mds_rank) {
1408 return mds_rank->is_stopped();
1409 } else {
1410 return true;
1411 }
1412 }