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