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