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