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