]> git.proxmox.com Git - ceph.git/blob - ceph/src/common/ceph_context.cc
bump version to 18.2.2-pve1
[ceph.git] / ceph / src / common / ceph_context.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) 2011 New Dream Network
7 * Copyright (C) 2017 OVH
8 *
9 * This is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License version 2.1, as published by the Free Software
12 * Foundation. See file COPYING.
13 *
14 */
15
16 #include "common/ceph_context.h"
17
18 #include <mutex>
19 #include <iostream>
20
21 #include <pthread.h>
22
23 #include <boost/algorithm/string.hpp>
24
25 #include "include/common_fwd.h"
26 #include "include/mempool.h"
27 #include "include/stringify.h"
28 #include "common/admin_socket.h"
29 #include "common/code_environment.h"
30 #include "common/ceph_mutex.h"
31 #include "common/debug.h"
32 #include "common/config.h"
33 #include "common/ceph_crypto.h"
34 #include "common/hostname.h"
35 #include "common/HeartbeatMap.h"
36 #include "common/errno.h"
37 #include "common/Graylog.h"
38 #ifdef CEPH_DEBUG_MUTEX
39 #include "common/lockdep.h"
40 #endif
41
42 #include "log/Log.h"
43
44 #include "auth/Crypto.h"
45 #include "include/str_list.h"
46 #include "common/config.h"
47 #include "common/config_obs.h"
48 #include "common/PluginRegistry.h"
49 #include "common/valgrind.h"
50 #include "include/spinlock.h"
51 #if !(defined(WITH_SEASTAR) && !defined(WITH_ALIEN))
52 #include "mon/MonMap.h"
53 #endif
54
55 // for CINIT_FLAGS
56 #include "common/common_init.h"
57
58 #include <iostream>
59 #include <pthread.h>
60
61 using namespace std::literals;
62
63 using ceph::bufferlist;
64 using ceph::HeartbeatMap;
65
66
67 #if defined(WITH_SEASTAR) && !defined(WITH_ALIEN)
68 namespace crimson::common {
69 CephContext::CephContext()
70 : _conf{crimson::common::local_conf()},
71 _perf_counters_collection{crimson::common::local_perf_coll()},
72 _crypto_random{std::make_unique<CryptoRandom>()}
73 {}
74
75 // define the dtor in .cc as CryptoRandom is an incomplete type in the header
76 CephContext::~CephContext()
77 {}
78
79 uint32_t CephContext::get_module_type() const
80 {
81 return CEPH_ENTITY_TYPE_OSD;
82 }
83
84 CryptoRandom* CephContext::random() const
85 {
86 return _crypto_random.get();
87 }
88
89 CephContext* CephContext::get()
90 {
91 ++nref;
92 return this;
93 }
94
95 void CephContext::put()
96 {
97 if (--nref == 0) {
98 delete this;
99 }
100 }
101
102 PerfCountersCollectionImpl* CephContext::get_perfcounters_collection()
103 {
104 return _perf_counters_collection.get_perf_collection();
105 }
106
107 }
108 #else // WITH_SEASTAR
109 namespace {
110
111 #ifdef CEPH_DEBUG_MUTEX
112 class LockdepObs : public md_config_obs_t {
113 public:
114 explicit LockdepObs(CephContext *cct)
115 : m_cct(cct), m_registered(false), lock(ceph::make_mutex("lock_dep_obs")) {
116 }
117 ~LockdepObs() override {
118 if (m_registered) {
119 lockdep_unregister_ceph_context(m_cct);
120 }
121 }
122
123 const char** get_tracked_conf_keys() const override {
124 static const char *KEYS[] = {"lockdep", NULL};
125 return KEYS;
126 }
127
128 void handle_conf_change(const ConfigProxy& conf,
129 const std::set <std::string> &changed) override {
130 std::unique_lock locker(lock);
131 if (conf->lockdep && !m_registered) {
132 lockdep_register_ceph_context(m_cct);
133 m_registered = true;
134 } else if (!conf->lockdep && m_registered) {
135 lockdep_unregister_ceph_context(m_cct);
136 m_registered = false;
137 }
138 }
139 private:
140 CephContext *m_cct;
141 bool m_registered;
142 ceph::mutex lock;
143 };
144 #endif // CEPH_DEBUG_MUTEX
145
146 class MempoolObs : public md_config_obs_t,
147 public AdminSocketHook {
148 CephContext *cct;
149 ceph::mutex lock;
150
151 public:
152 explicit MempoolObs(CephContext *cct)
153 : cct(cct), lock(ceph::make_mutex("mem_pool_obs")) {
154 cct->_conf.add_observer(this);
155 int r = cct->get_admin_socket()->register_command(
156 "dump_mempools",
157 this,
158 "get mempool stats");
159 ceph_assert(r == 0);
160 }
161 ~MempoolObs() override {
162 cct->_conf.remove_observer(this);
163 cct->get_admin_socket()->unregister_commands(this);
164 }
165
166 // md_config_obs_t
167 const char** get_tracked_conf_keys() const override {
168 static const char *KEYS[] = {
169 "mempool_debug",
170 NULL
171 };
172 return KEYS;
173 }
174
175 void handle_conf_change(const ConfigProxy& conf,
176 const std::set <std::string> &changed) override {
177 std::unique_lock locker(lock);
178 if (changed.count("mempool_debug")) {
179 mempool::set_debug_mode(cct->_conf->mempool_debug);
180 }
181 }
182
183 // AdminSocketHook
184 int call(std::string_view command, const cmdmap_t& cmdmap,
185 const bufferlist& inbl,
186 ceph::Formatter *f,
187 std::ostream& errss,
188 bufferlist& out) override {
189 if (command == "dump_mempools") {
190 f->open_object_section("mempools");
191 mempool::dump(f);
192 f->close_section();
193 return 0;
194 }
195 return -ENOSYS;
196 }
197 };
198
199 } // anonymous namespace
200
201 namespace ceph::common {
202 class CephContextServiceThread : public Thread
203 {
204 public:
205 explicit CephContextServiceThread(CephContext *cct)
206 : _reopen_logs(false), _exit_thread(false), _cct(cct)
207 {
208 }
209
210 ~CephContextServiceThread() override {}
211
212 void *entry() override
213 {
214 while (1) {
215 std::unique_lock l(_lock);
216 if (_exit_thread) {
217 break;
218 }
219
220 if (_cct->_conf->heartbeat_interval) {
221 auto interval = ceph::make_timespan(_cct->_conf->heartbeat_interval);
222 _cond.wait_for(l, interval);
223 } else
224 _cond.wait(l);
225
226 if (_exit_thread) {
227 break;
228 }
229
230 if (_reopen_logs) {
231 _cct->_log->reopen_log_file();
232 _reopen_logs = false;
233 }
234 _cct->_heartbeat_map->check_touch_file();
235
236 // refresh the perf coutners
237 _cct->_refresh_perf_values();
238 }
239 return NULL;
240 }
241
242 void reopen_logs()
243 {
244 std::lock_guard l(_lock);
245 _reopen_logs = true;
246 _cond.notify_all();
247 }
248
249 void exit_thread()
250 {
251 std::lock_guard l(_lock);
252 _exit_thread = true;
253 _cond.notify_all();
254 }
255
256 private:
257 ceph::mutex _lock = ceph::make_mutex("CephContextServiceThread::_lock");
258 ceph::condition_variable _cond;
259 bool _reopen_logs;
260 bool _exit_thread;
261 CephContext *_cct;
262 };
263 }
264
265 /**
266 * observe logging config changes
267 *
268 * The logging subsystem sits below most of the ceph code, including
269 * the config subsystem, to keep it simple and self-contained. Feed
270 * logging-related config changes to the log.
271 */
272 class LogObs : public md_config_obs_t {
273 ceph::logging::Log *log;
274 ceph::mutex lock;
275
276 public:
277 explicit LogObs(ceph::logging::Log *l)
278 : log(l), lock(ceph::make_mutex("log_obs")) {
279 }
280
281 const char** get_tracked_conf_keys() const override {
282 static const char *KEYS[] = {
283 "log_file",
284 "log_max_new",
285 "log_max_recent",
286 "log_to_file",
287 "log_to_syslog",
288 "err_to_syslog",
289 "log_stderr_prefix",
290 "log_to_stderr",
291 "err_to_stderr",
292 "log_to_graylog",
293 "err_to_graylog",
294 "log_graylog_host",
295 "log_graylog_port",
296 "log_to_journald",
297 "err_to_journald",
298 "log_coarse_timestamps",
299 "fsid",
300 "host",
301 NULL
302 };
303 return KEYS;
304 }
305
306 void handle_conf_change(const ConfigProxy& conf,
307 const std::set <std::string> &changed) override {
308 std::unique_lock locker(lock);
309 // stderr
310 if (changed.count("log_to_stderr") || changed.count("err_to_stderr")) {
311 int l = conf->log_to_stderr ? 99 : (conf->err_to_stderr ? -1 : -2);
312 log->set_stderr_level(l, l);
313 }
314
315 // syslog
316 if (changed.count("log_to_syslog")) {
317 int l = conf->log_to_syslog ? 99 : (conf->err_to_syslog ? -1 : -2);
318 log->set_syslog_level(l, l);
319 }
320
321 // file
322 if (changed.count("log_file") ||
323 changed.count("log_to_file")) {
324 if (conf->log_to_file) {
325 log->set_log_file(conf->log_file);
326 } else {
327 log->set_log_file({});
328 }
329 log->reopen_log_file();
330 }
331
332 if (changed.count("log_stderr_prefix")) {
333 log->set_log_stderr_prefix(conf.get_val<std::string>("log_stderr_prefix"));
334 }
335
336 if (changed.count("log_max_new")) {
337
338 log->set_max_new(conf->log_max_new);
339 }
340
341 if (changed.count("log_max_recent")) {
342 log->set_max_recent(conf->log_max_recent);
343 }
344
345 // graylog
346 if (changed.count("log_to_graylog") || changed.count("err_to_graylog")) {
347 int l = conf->log_to_graylog ? 99 : (conf->err_to_graylog ? -1 : -2);
348 log->set_graylog_level(l, l);
349
350 if (conf->log_to_graylog || conf->err_to_graylog) {
351 log->start_graylog(conf->host, conf.get_val<uuid_d>("fsid"));
352 } else if (! (conf->log_to_graylog && conf->err_to_graylog)) {
353 log->stop_graylog();
354 }
355 }
356
357 if (log->graylog() && (changed.count("log_graylog_host") || changed.count("log_graylog_port"))) {
358 log->graylog()->set_destination(conf->log_graylog_host, conf->log_graylog_port);
359 }
360
361 // journald
362 if (changed.count("log_to_journald") || changed.count("err_to_journald")) {
363 int l = conf.get_val<bool>("log_to_journald") ? 99 : (conf.get_val<bool>("err_to_journald") ? -1 : -2);
364 log->set_journald_level(l, l);
365
366 if (l > -2) {
367 log->start_journald_logger();
368 } else {
369 log->stop_journald_logger();
370 }
371 }
372
373 if (changed.find("log_coarse_timestamps") != changed.end()) {
374 log->set_coarse_timestamps(conf.get_val<bool>("log_coarse_timestamps"));
375 }
376
377 // metadata
378 if (log->graylog() && changed.count("host")) {
379 log->graylog()->set_hostname(conf->host);
380 }
381
382 if (log->graylog() && changed.count("fsid")) {
383 log->graylog()->set_fsid(conf.get_val<uuid_d>("fsid"));
384 }
385 }
386 };
387
388
389 namespace ceph::common {
390 // cct config watcher
391 class CephContextObs : public md_config_obs_t {
392 CephContext *cct;
393
394 public:
395 explicit CephContextObs(CephContext *cct) : cct(cct) {}
396
397 const char** get_tracked_conf_keys() const override {
398 static const char *KEYS[] = {
399 "enable_experimental_unrecoverable_data_corrupting_features",
400 "crush_location",
401 "container_image", // just so we don't hear complaints about it!
402 NULL
403 };
404 return KEYS;
405 }
406
407 void handle_conf_change(const ConfigProxy& conf,
408 const std::set <std::string> &changed) override {
409 if (changed.count(
410 "enable_experimental_unrecoverable_data_corrupting_features")) {
411 std::lock_guard lg(cct->_feature_lock);
412
413 cct->_experimental_features.clear();
414 auto add_experimental_feature = [this] (auto feature) {
415 cct->_experimental_features.emplace(std::string{feature});
416 };
417 for_each_substr(conf->enable_experimental_unrecoverable_data_corrupting_features,
418 ";,= \t", add_experimental_feature);
419
420 if (getenv("CEPH_DEV") == NULL) {
421 if (!cct->_experimental_features.empty()) {
422 if (cct->_experimental_features.count("*")) {
423 lderr(cct) << "WARNING: all dangerous and experimental features are enabled." << dendl;
424 } else {
425 lderr(cct) << "WARNING: the following dangerous and experimental features are enabled: "
426 << cct->_experimental_features << dendl;
427 }
428 }
429 }
430
431 }
432 if (changed.count("crush_location")) {
433 cct->crush_location.update_from_conf();
434 }
435 }
436 };
437 // perfcounter hooks
438
439 class CephContextHook : public AdminSocketHook {
440 CephContext *m_cct;
441
442 public:
443 explicit CephContextHook(CephContext *cct) : m_cct(cct) {}
444
445 int call(std::string_view command, const cmdmap_t& cmdmap,
446 const bufferlist& inbl,
447 Formatter *f,
448 std::ostream& errss,
449 bufferlist& out) override {
450 try {
451 return m_cct->do_command(command, cmdmap, f, errss, &out);
452 } catch (const bad_cmd_get& e) {
453 return -EINVAL;
454 }
455 }
456 };
457
458
459 bool CephContext::check_experimental_feature_enabled(const std::string& feat)
460 {
461 std::stringstream message;
462 bool enabled = check_experimental_feature_enabled(feat, &message);
463 lderr(this) << message.str() << dendl;
464 return enabled;
465 }
466
467 bool CephContext::check_experimental_feature_enabled(const std::string& feat,
468 std::ostream *message)
469 {
470 std::unique_lock<ceph::spinlock> lg(_feature_lock);
471
472 bool enabled = (_experimental_features.count(feat) ||
473 _experimental_features.count("*"));
474
475 if (enabled) {
476 (*message) << "WARNING: experimental feature '" << feat << "' is enabled\n";
477 (*message) << "Please be aware that this feature is experimental, untested,\n";
478 (*message) << "unsupported, and may result in data corruption, data loss,\n";
479 (*message) << "and/or irreparable damage to your cluster. Do not use\n";
480 (*message) << "feature with important data.\n";
481 } else {
482 (*message) << "*** experimental feature '" << feat << "' is not enabled ***\n";
483 (*message) << "This feature is marked as experimental, which means it\n";
484 (*message) << " - is untested\n";
485 (*message) << " - is unsupported\n";
486 (*message) << " - may corrupt your data\n";
487 (*message) << " - may break your cluster is an unrecoverable fashion\n";
488 (*message) << "To enable this feature, add this to your ceph.conf:\n";
489 (*message) << " enable experimental unrecoverable data corrupting features = " << feat << "\n";
490 }
491 return enabled;
492 }
493
494 int CephContext::do_command(std::string_view command, const cmdmap_t& cmdmap,
495 Formatter *f,
496 std::ostream& ss,
497 bufferlist *out)
498 {
499 try {
500 return _do_command(command, cmdmap, f, ss, out);
501 } catch (const bad_cmd_get& e) {
502 ss << e.what();
503 return -EINVAL;
504 }
505 }
506
507 #pragma GCC push_options
508 #pragma GCC optimize ("O0")
509 static void leak_some_memory() {
510 volatile char *foo = new char[1234];
511 (void)foo;
512 }
513 #pragma GCC pop_options
514
515 int CephContext::_do_command(
516 std::string_view command, const cmdmap_t& cmdmap,
517 Formatter *f,
518 std::ostream& ss,
519 bufferlist *out)
520 {
521 int r = 0;
522 lgeneric_dout(this, 1) << "do_command '" << command << "' '" << cmdmap << "'"
523 << dendl;
524 ceph_assert_always(!(command == "assert" && _conf->debug_asok_assert_abort));
525 if (command == "abort") {
526 if (_conf->debug_asok_assert_abort) {
527 ceph_abort();
528 } else {
529 return -EPERM;
530 }
531 }
532 if (command == "leak_some_memory") {
533 leak_some_memory();
534 }
535 else if (command == "perfcounters_dump" || command == "1" ||
536 command == "perf dump") {
537 std::string logger;
538 std::string counter;
539 cmd_getval(cmdmap, "logger", logger);
540 cmd_getval(cmdmap, "counter", counter);
541 _perf_counters_collection->dump_formatted(f, false, false, logger, counter);
542 }
543 else if (command == "perfcounters_schema" || command == "2" ||
544 command == "perf schema") {
545 _perf_counters_collection->dump_formatted(f, true, false);
546 }
547 else if (command == "counter dump") {
548 _perf_counters_collection->dump_formatted(f, false, true);
549 }
550 else if (command == "counter schema") {
551 _perf_counters_collection->dump_formatted(f, true, true);
552 }
553 else if (command == "perf histogram dump") {
554 std::string logger;
555 std::string counter;
556 cmd_getval(cmdmap, "logger", logger);
557 cmd_getval(cmdmap, "counter", counter);
558 _perf_counters_collection->dump_formatted_histograms(f, false, logger,
559 counter);
560 }
561 else if (command == "perf histogram schema") {
562 _perf_counters_collection->dump_formatted_histograms(f, true);
563 }
564 else if (command == "perf reset") {
565 std::string var;
566 std::string section(command);
567 f->open_object_section(section.c_str());
568 if (!cmd_getval(cmdmap, "var", var)) {
569 f->dump_string("error", "syntax error: 'perf reset <var>'");
570 } else {
571 if(!_perf_counters_collection->reset(var))
572 f->dump_stream("error") << "Not find: " << var;
573 else
574 f->dump_string("success", std::string(command) + ' ' + var);
575 }
576 f->close_section();
577 }
578 else {
579 std::string section(command);
580 boost::replace_all(section, " ", "_");
581 f->open_object_section(section.c_str());
582 if (command == "config show") {
583 _conf.show_config(f);
584 }
585 else if (command == "config unset") {
586 std::string var;
587 if (!(cmd_getval(cmdmap, "var", var))) {
588 r = -EINVAL;
589 } else {
590 r = _conf.rm_val(var.c_str());
591 if (r < 0 && r != -ENOENT) {
592 ss << "error unsetting '" << var << "': "
593 << cpp_strerror(r);
594 } else {
595 _conf.apply_changes(&ss);
596 r = 0;
597 }
598 }
599
600 }
601 else if (command == "config set") {
602 std::string var;
603 std::vector<std::string> val;
604
605 if (!(cmd_getval(cmdmap, "var", var)) ||
606 !(cmd_getval(cmdmap, "val", val))) {
607 r = -EINVAL;
608 } else {
609 // val may be multiple words
610 auto valstr = str_join(val, " ");
611 r = _conf.set_val(var.c_str(), valstr.c_str());
612 if (r < 0) {
613 ss << "error setting '" << var << "' to '" << valstr << "': "
614 << cpp_strerror(r);
615 } else {
616 std::stringstream ss;
617 _conf.apply_changes(&ss);
618 f->dump_string("success", ss.str());
619 }
620 }
621 } else if (command == "config get") {
622 std::string var;
623 if (!cmd_getval(cmdmap, "var", var)) {
624 r = -EINVAL;
625 } else {
626 char buf[4096];
627 // FIPS zeroization audit 20191115: this memset is not security related.
628 memset(buf, 0, sizeof(buf));
629 char *tmp = buf;
630 r = _conf.get_val(var.c_str(), &tmp, sizeof(buf));
631 if (r < 0) {
632 ss << "error getting '" << var << "': " << cpp_strerror(r);
633 } else {
634 f->dump_string(var.c_str(), buf);
635 }
636 }
637 } else if (command == "config help") {
638 std::string var;
639 if (cmd_getval(cmdmap, "var", var)) {
640 // Output a single one
641 std::string key = ConfFile::normalize_key_name(var);
642 auto schema = _conf.get_schema(key);
643 if (!schema) {
644 ss << "Setting not found: '" << key << "'";
645 r = -ENOENT;
646 } else {
647 f->dump_object("option", *schema);
648 }
649 } else {
650 // Output all
651 f->open_array_section("options");
652 for (const auto &option : ceph_options) {
653 f->dump_object("option", option);
654 }
655 f->close_section();
656 }
657 } else if (command == "config diff") {
658 f->open_object_section("diff");
659 _conf.diff(f);
660 f->close_section(); // unknown
661 } else if (command == "config diff get") {
662 std::string setting;
663 f->open_object_section("diff");
664 _conf.diff(f, setting);
665 f->close_section(); // unknown
666 }
667 else if (command == "injectargs") {
668 std::vector<std::string> argsvec;
669 cmd_getval(cmdmap, "injected_args", argsvec);
670 if (!argsvec.empty()) {
671 auto args = joinify<std::string>(argsvec.begin(), argsvec.end(), " ");
672 r = _conf.injectargs(args, &ss);
673 }
674 }
675 else if (command == "log flush") {
676 _log->flush();
677 }
678 else if (command == "log dump") {
679 _log->dump_recent();
680 }
681 else if (command == "log reopen") {
682 _log->reopen_log_file();
683 }
684 else {
685 ceph_abort_msg("registered under wrong command?");
686 }
687 f->close_section();
688 }
689 lgeneric_dout(this, 1) << "do_command '" << command << "' '" << cmdmap
690 << "' result is " << out->length() << " bytes" << dendl;
691 return r;
692 }
693
694 CephContext::CephContext(uint32_t module_type_,
695 enum code_environment_t code_env,
696 int init_flags_)
697 : CephContext(module_type_, create_options{code_env, init_flags_, nullptr})
698 {}
699
700 CephContext::CephContext(uint32_t module_type_,
701 const create_options& options)
702 : nref(1),
703 _conf{options.code_env == CODE_ENVIRONMENT_DAEMON},
704 _log(NULL),
705 _module_type(module_type_),
706 _init_flags(options.init_flags),
707 _set_uid(0),
708 _set_gid(0),
709 _set_uid_string(),
710 _set_gid_string(),
711 _crypto_inited(0),
712 _service_thread(NULL),
713 _log_obs(NULL),
714 _admin_socket(NULL),
715 _perf_counters_collection(NULL),
716 _perf_counters_conf_obs(NULL),
717 _heartbeat_map(NULL),
718 _crypto_none(NULL),
719 _crypto_aes(NULL),
720 _plugin_registry(NULL),
721 #ifdef CEPH_DEBUG_MUTEX
722 _lockdep_obs(NULL),
723 #endif
724 crush_location(this)
725 {
726 if (options.create_log) {
727 _log = options.create_log(&_conf->subsys);
728 } else {
729 _log = new ceph::logging::Log(&_conf->subsys);
730 }
731
732 _log_obs = new LogObs(_log);
733 _conf.add_observer(_log_obs);
734
735 _cct_obs = new CephContextObs(this);
736 _conf.add_observer(_cct_obs);
737 #ifdef CEPH_DEBUG_MUTEX
738 _lockdep_obs = new LockdepObs(this);
739 _conf.add_observer(_lockdep_obs);
740 #endif
741 _perf_counters_collection = new PerfCountersCollection(this);
742
743 _admin_socket = new AdminSocket(this);
744 _heartbeat_map = new HeartbeatMap(this);
745
746 _plugin_registry = new PluginRegistry(this);
747
748 _admin_hook = new CephContextHook(this);
749 _admin_socket->register_command("assert", _admin_hook, "");
750 _admin_socket->register_command("abort", _admin_hook, "");
751 _admin_socket->register_command("leak_some_memory", _admin_hook, "");
752 _admin_socket->register_command("perfcounters_dump", _admin_hook, "");
753 _admin_socket->register_command("1", _admin_hook, "");
754 _admin_socket->register_command("perf dump name=logger,type=CephString,req=false name=counter,type=CephString,req=false", _admin_hook, "dump non-labeled counters and their values");
755 _admin_socket->register_command("perfcounters_schema", _admin_hook, "");
756 _admin_socket->register_command("perf histogram dump name=logger,type=CephString,req=false name=counter,type=CephString,req=false", _admin_hook, "dump perf histogram values");
757 _admin_socket->register_command("2", _admin_hook, "");
758 _admin_socket->register_command("perf schema", _admin_hook, "dump non-labeled counters schemas");
759 _admin_socket->register_command("counter dump", _admin_hook, "dump all labeled and non-labeled counters and their values");
760 _admin_socket->register_command("counter schema", _admin_hook, "dump all labeled and non-labeled counters schemas");
761 _admin_socket->register_command("perf histogram schema", _admin_hook, "dump perf histogram schema");
762 _admin_socket->register_command("perf reset name=var,type=CephString", _admin_hook, "perf reset <name>: perf reset all or one perfcounter name");
763 _admin_socket->register_command("config show", _admin_hook, "dump current config settings");
764 _admin_socket->register_command("config help name=var,type=CephString,req=false", _admin_hook, "get config setting schema and descriptions");
765 _admin_socket->register_command("config set name=var,type=CephString name=val,type=CephString,n=N", _admin_hook, "config set <field> <val> [<val> ...]: set a config variable");
766 _admin_socket->register_command("config unset name=var,type=CephString", _admin_hook, "config unset <field>: unset a config variable");
767 _admin_socket->register_command("config get name=var,type=CephString", _admin_hook, "config get <field>: get the config value");
768 _admin_socket->register_command(
769 "config diff", _admin_hook,
770 "dump diff of current config and default config");
771 _admin_socket->register_command(
772 "config diff get name=var,type=CephString", _admin_hook,
773 "dump diff get <field>: dump diff of current and default config setting <field>");
774 _admin_socket->register_command("injectargs name=injected_args,type=CephString,n=N", _admin_hook, "inject configuration arguments into running daemon"),
775 _admin_socket->register_command("log flush", _admin_hook, "flush log entries to log file");
776 _admin_socket->register_command("log dump", _admin_hook, "dump recent log entries to log file");
777 _admin_socket->register_command("log reopen", _admin_hook, "reopen log file");
778
779 _crypto_none = CryptoHandler::create(CEPH_CRYPTO_NONE);
780 _crypto_aes = CryptoHandler::create(CEPH_CRYPTO_AES);
781 _crypto_random.reset(new CryptoRandom());
782
783 lookup_or_create_singleton_object<MempoolObs>("mempool_obs", false, this);
784 }
785
786 CephContext::~CephContext()
787 {
788 associated_objs.clear();
789 join_service_thread();
790
791 if (_cct_perf) {
792 _perf_counters_collection->remove(_cct_perf);
793 delete _cct_perf;
794 _cct_perf = NULL;
795 }
796
797 delete _plugin_registry;
798
799 _admin_socket->unregister_commands(_admin_hook);
800 delete _admin_hook;
801 delete _admin_socket;
802
803 delete _heartbeat_map;
804
805 delete _perf_counters_collection;
806 _perf_counters_collection = NULL;
807
808 delete _perf_counters_conf_obs;
809 _perf_counters_conf_obs = NULL;
810
811 _conf.remove_observer(_log_obs);
812 delete _log_obs;
813 _log_obs = NULL;
814
815 _conf.remove_observer(_cct_obs);
816 delete _cct_obs;
817 _cct_obs = NULL;
818 #ifdef CEPH_DEBUG_MUTEX
819 _conf.remove_observer(_lockdep_obs);
820 delete _lockdep_obs;
821 _lockdep_obs = NULL;
822 #endif
823 _log->stop();
824 delete _log;
825 _log = NULL;
826
827 delete _crypto_none;
828 delete _crypto_aes;
829 if (_crypto_inited > 0) {
830 ceph_assert(_crypto_inited == 1); // or else someone explicitly did
831 // init but not shutdown
832 shutdown_crypto();
833 }
834 }
835
836 void CephContext::put() {
837 if (--nref == 0) {
838 ANNOTATE_HAPPENS_AFTER(&nref);
839 ANNOTATE_HAPPENS_BEFORE_FORGET_ALL(&nref);
840 if (g_ceph_context == this)
841 g_ceph_context = nullptr;
842 delete this;
843 } else {
844 ANNOTATE_HAPPENS_BEFORE(&nref);
845 }
846 }
847
848 void CephContext::init_crypto()
849 {
850 if (_crypto_inited++ == 0) {
851 TOPNSPC::crypto::init();
852 }
853 }
854
855 void CephContext::shutdown_crypto()
856 {
857 if (--_crypto_inited == 0) {
858 TOPNSPC::crypto::shutdown(g_code_env == CODE_ENVIRONMENT_LIBRARY);
859 }
860 }
861
862 void CephContext::start_service_thread()
863 {
864 {
865 std::lock_guard lg(_service_thread_lock);
866 if (_service_thread) {
867 return;
868 }
869 _service_thread = new CephContextServiceThread(this);
870 _service_thread->create("service");
871 }
872
873 if (!(get_init_flags() & CINIT_FLAG_NO_CCT_PERF_COUNTERS))
874 _enable_perf_counter();
875
876 // make logs flush on_exit()
877 if (_conf->log_flush_on_exit)
878 _log->set_flush_on_exit();
879
880 // Trigger callbacks on any config observers that were waiting for
881 // it to become safe to start threads.
882 _conf.set_safe_to_start_threads();
883 _conf.call_all_observers();
884
885 // start admin socket
886 if (_conf->admin_socket.length())
887 _admin_socket->init(_conf->admin_socket);
888 }
889
890 void CephContext::reopen_logs()
891 {
892 std::lock_guard lg(_service_thread_lock);
893 if (_service_thread)
894 _service_thread->reopen_logs();
895 }
896
897 void CephContext::join_service_thread()
898 {
899 std::unique_lock<ceph::spinlock> lg(_service_thread_lock);
900
901 CephContextServiceThread *thread = _service_thread;
902 if (!thread) {
903 return;
904 }
905 _service_thread = NULL;
906
907 lg.unlock();
908
909 thread->exit_thread();
910 thread->join();
911 delete thread;
912
913 if (!(get_init_flags() & CINIT_FLAG_NO_CCT_PERF_COUNTERS))
914 _disable_perf_counter();
915 }
916
917 uint32_t CephContext::get_module_type() const
918 {
919 return _module_type;
920 }
921
922 void CephContext::set_init_flags(int flags)
923 {
924 _init_flags = flags;
925 }
926
927 int CephContext::get_init_flags() const
928 {
929 return _init_flags;
930 }
931
932 PerfCountersCollection *CephContext::get_perfcounters_collection()
933 {
934 return _perf_counters_collection;
935 }
936
937 void CephContext::_enable_perf_counter()
938 {
939 assert(!_cct_perf);
940 PerfCountersBuilder plb(this, "cct", l_cct_first, l_cct_last);
941 plb.add_u64(l_cct_total_workers, "total_workers", "Total workers");
942 plb.add_u64(l_cct_unhealthy_workers, "unhealthy_workers", "Unhealthy workers");
943 _cct_perf = plb.create_perf_counters();
944 _perf_counters_collection->add(_cct_perf);
945
946 assert(_mempool_perf_names.empty());
947 assert(_mempool_perf_descriptions.empty());
948 _mempool_perf_names.reserve(mempool::num_pools * 2);
949 _mempool_perf_descriptions.reserve(mempool::num_pools * 2);
950 for (unsigned i = 0; i < mempool::num_pools; ++i) {
951 std::string n = mempool::get_pool_name(mempool::pool_index_t(i));
952 _mempool_perf_names.push_back(n + "_bytes"s);
953 _mempool_perf_descriptions.push_back(
954 "mempool "s + n + " total bytes");
955 _mempool_perf_names.push_back(n + "_items"s);
956 _mempool_perf_descriptions.push_back(
957 "mempool "s + n + " total items"s);
958 }
959
960 PerfCountersBuilder plb2(this, "mempool", l_mempool_first,
961 l_mempool_first + 1 + 2*mempool::num_pools);
962 unsigned l = l_mempool_first + 1;
963 for (unsigned i = 0; i < mempool::num_pools; ++i) {
964 plb2.add_u64(l++, _mempool_perf_names[i*2].c_str(),
965 _mempool_perf_descriptions[i*2].c_str());
966 plb2.add_u64(l++, _mempool_perf_names[i*2+1].c_str(),
967 _mempool_perf_descriptions[i*2+1].c_str());
968 }
969 _mempool_perf = plb2.create_perf_counters();
970 _perf_counters_collection->add(_mempool_perf);
971 }
972
973 void CephContext::_disable_perf_counter()
974 {
975 if (!_cct_perf) {
976 return;
977 }
978 _perf_counters_collection->remove(_cct_perf);
979 delete _cct_perf;
980 _cct_perf = nullptr;
981
982 _perf_counters_collection->remove(_mempool_perf);
983 delete _mempool_perf;
984 _mempool_perf = nullptr;
985 _mempool_perf_names.clear();
986 _mempool_perf_descriptions.clear();
987 }
988
989 void CephContext::_refresh_perf_values()
990 {
991 if (_cct_perf) {
992 _cct_perf->set(l_cct_total_workers, _heartbeat_map->get_total_workers());
993 _cct_perf->set(l_cct_unhealthy_workers, _heartbeat_map->get_unhealthy_workers());
994 }
995 unsigned l = l_mempool_first + 1;
996 for (unsigned i = 0; i < mempool::num_pools; ++i) {
997 mempool::pool_t& p = mempool::get_pool(mempool::pool_index_t(i));
998 _mempool_perf->set(l++, p.allocated_bytes());
999 _mempool_perf->set(l++, p.allocated_items());
1000 }
1001 }
1002
1003 AdminSocket *CephContext::get_admin_socket()
1004 {
1005 return _admin_socket;
1006 }
1007
1008 CryptoHandler *CephContext::get_crypto_handler(int type)
1009 {
1010 switch (type) {
1011 case CEPH_CRYPTO_NONE:
1012 return _crypto_none;
1013 case CEPH_CRYPTO_AES:
1014 return _crypto_aes;
1015 default:
1016 return NULL;
1017 }
1018 }
1019
1020 void CephContext::notify_pre_fork()
1021 {
1022 {
1023 std::lock_guard lg(_fork_watchers_lock);
1024 for (auto &&t : _fork_watchers) {
1025 t->handle_pre_fork();
1026 }
1027 }
1028 {
1029 // note: we don't hold a lock here, but we assume we are idle at
1030 // fork time, which happens during process init and startup.
1031 auto i = associated_objs.begin();
1032 while (i != associated_objs.end()) {
1033 if (associated_objs_drop_on_fork.count(i->first.first)) {
1034 i = associated_objs.erase(i);
1035 } else {
1036 ++i;
1037 }
1038 }
1039 associated_objs_drop_on_fork.clear();
1040 }
1041 }
1042
1043 void CephContext::notify_post_fork()
1044 {
1045 ceph::spin_unlock(&_fork_watchers_lock);
1046 for (auto &&t : _fork_watchers)
1047 t->handle_post_fork();
1048 }
1049
1050 void CephContext::set_mon_addrs(const MonMap& mm) {
1051 std::vector<entity_addrvec_t> mon_addrs;
1052 for (auto& i : mm.mon_info) {
1053 mon_addrs.push_back(i.second.public_addrs);
1054 }
1055
1056 set_mon_addrs(mon_addrs);
1057 }
1058 }
1059 #endif // WITH_SEASTAR