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