diff options
Diffstat (limited to 'src/common/ceph_context.cc')
-rw-r--r-- | src/common/ceph_context.cc | 1059 |
1 files changed, 1059 insertions, 0 deletions
diff --git a/src/common/ceph_context.cc b/src/common/ceph_context.cc new file mode 100644 index 000000000..d26f24511 --- /dev/null +++ b/src/common/ceph_context.cc @@ -0,0 +1,1059 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab +/* + * Ceph - scalable distributed file system + * + * Copyright (C) 2011 New Dream Network + * Copyright (C) 2017 OVH + * + * This is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software + * Foundation. See file COPYING. + * + */ + +#include "common/ceph_context.h" + +#include <mutex> +#include <iostream> + +#include <pthread.h> + +#include <boost/algorithm/string.hpp> + +#include "include/common_fwd.h" +#include "include/mempool.h" +#include "include/stringify.h" +#include "common/admin_socket.h" +#include "common/code_environment.h" +#include "common/ceph_mutex.h" +#include "common/debug.h" +#include "common/config.h" +#include "common/ceph_crypto.h" +#include "common/hostname.h" +#include "common/HeartbeatMap.h" +#include "common/errno.h" +#include "common/Graylog.h" +#ifdef CEPH_DEBUG_MUTEX +#include "common/lockdep.h" +#endif + +#include "log/Log.h" + +#include "auth/Crypto.h" +#include "include/str_list.h" +#include "common/config.h" +#include "common/config_obs.h" +#include "common/PluginRegistry.h" +#include "common/valgrind.h" +#include "include/spinlock.h" +#if !(defined(WITH_SEASTAR) && !defined(WITH_ALIEN)) +#include "mon/MonMap.h" +#endif + +// for CINIT_FLAGS +#include "common/common_init.h" + +#include <iostream> +#include <pthread.h> + +using namespace std::literals; + +using ceph::bufferlist; +using ceph::HeartbeatMap; + + +#if defined(WITH_SEASTAR) && !defined(WITH_ALIEN) +namespace crimson::common { +CephContext::CephContext() + : _conf{crimson::common::local_conf()}, + _perf_counters_collection{crimson::common::local_perf_coll()}, + _crypto_random{std::make_unique<CryptoRandom>()} +{} + +// define the dtor in .cc as CryptoRandom is an incomplete type in the header +CephContext::~CephContext() +{} + +uint32_t CephContext::get_module_type() const +{ + return CEPH_ENTITY_TYPE_OSD; +} + +CryptoRandom* CephContext::random() const +{ + return _crypto_random.get(); +} + +CephContext* CephContext::get() +{ + ++nref; + return this; +} + +void CephContext::put() +{ + if (--nref == 0) { + delete this; + } +} + +PerfCountersCollectionImpl* CephContext::get_perfcounters_collection() +{ + return _perf_counters_collection.get_perf_collection(); +} + +} +#else // WITH_SEASTAR +namespace { + +#ifdef CEPH_DEBUG_MUTEX +class LockdepObs : public md_config_obs_t { +public: + explicit LockdepObs(CephContext *cct) + : m_cct(cct), m_registered(false), lock(ceph::make_mutex("lock_dep_obs")) { + } + ~LockdepObs() override { + if (m_registered) { + lockdep_unregister_ceph_context(m_cct); + } + } + + const char** get_tracked_conf_keys() const override { + static const char *KEYS[] = {"lockdep", NULL}; + return KEYS; + } + + void handle_conf_change(const ConfigProxy& conf, + const std::set <std::string> &changed) override { + std::unique_lock locker(lock); + if (conf->lockdep && !m_registered) { + lockdep_register_ceph_context(m_cct); + m_registered = true; + } else if (!conf->lockdep && m_registered) { + lockdep_unregister_ceph_context(m_cct); + m_registered = false; + } + } +private: + CephContext *m_cct; + bool m_registered; + ceph::mutex lock; +}; +#endif // CEPH_DEBUG_MUTEX + +class MempoolObs : public md_config_obs_t, + public AdminSocketHook { + CephContext *cct; + ceph::mutex lock; + +public: + explicit MempoolObs(CephContext *cct) + : cct(cct), lock(ceph::make_mutex("mem_pool_obs")) { + cct->_conf.add_observer(this); + int r = cct->get_admin_socket()->register_command( + "dump_mempools", + this, + "get mempool stats"); + ceph_assert(r == 0); + } + ~MempoolObs() override { + cct->_conf.remove_observer(this); + cct->get_admin_socket()->unregister_commands(this); + } + + // md_config_obs_t + const char** get_tracked_conf_keys() const override { + static const char *KEYS[] = { + "mempool_debug", + NULL + }; + return KEYS; + } + + void handle_conf_change(const ConfigProxy& conf, + const std::set <std::string> &changed) override { + std::unique_lock locker(lock); + if (changed.count("mempool_debug")) { + mempool::set_debug_mode(cct->_conf->mempool_debug); + } + } + + // AdminSocketHook + int call(std::string_view command, const cmdmap_t& cmdmap, + const bufferlist& inbl, + ceph::Formatter *f, + std::ostream& errss, + bufferlist& out) override { + if (command == "dump_mempools") { + f->open_object_section("mempools"); + mempool::dump(f); + f->close_section(); + return 0; + } + return -ENOSYS; + } +}; + +} // anonymous namespace + +namespace ceph::common { +class CephContextServiceThread : public Thread +{ +public: + explicit CephContextServiceThread(CephContext *cct) + : _reopen_logs(false), _exit_thread(false), _cct(cct) + { + } + + ~CephContextServiceThread() override {} + + void *entry() override + { + while (1) { + std::unique_lock l(_lock); + if (_exit_thread) { + break; + } + + if (_cct->_conf->heartbeat_interval) { + auto interval = ceph::make_timespan(_cct->_conf->heartbeat_interval); + _cond.wait_for(l, interval); + } else + _cond.wait(l); + + if (_exit_thread) { + break; + } + + if (_reopen_logs) { + _cct->_log->reopen_log_file(); + _reopen_logs = false; + } + _cct->_heartbeat_map->check_touch_file(); + + // refresh the perf coutners + _cct->_refresh_perf_values(); + } + return NULL; + } + + void reopen_logs() + { + std::lock_guard l(_lock); + _reopen_logs = true; + _cond.notify_all(); + } + + void exit_thread() + { + std::lock_guard l(_lock); + _exit_thread = true; + _cond.notify_all(); + } + +private: + ceph::mutex _lock = ceph::make_mutex("CephContextServiceThread::_lock"); + ceph::condition_variable _cond; + bool _reopen_logs; + bool _exit_thread; + CephContext *_cct; +}; +} + +/** + * observe logging config changes + * + * The logging subsystem sits below most of the ceph code, including + * the config subsystem, to keep it simple and self-contained. Feed + * logging-related config changes to the log. + */ +class LogObs : public md_config_obs_t { + ceph::logging::Log *log; + ceph::mutex lock; + +public: + explicit LogObs(ceph::logging::Log *l) + : log(l), lock(ceph::make_mutex("log_obs")) { + } + + const char** get_tracked_conf_keys() const override { + static const char *KEYS[] = { + "log_file", + "log_max_new", + "log_max_recent", + "log_to_file", + "log_to_syslog", + "err_to_syslog", + "log_stderr_prefix", + "log_to_stderr", + "err_to_stderr", + "log_to_graylog", + "err_to_graylog", + "log_graylog_host", + "log_graylog_port", + "log_to_journald", + "err_to_journald", + "log_coarse_timestamps", + "fsid", + "host", + NULL + }; + return KEYS; + } + + void handle_conf_change(const ConfigProxy& conf, + const std::set <std::string> &changed) override { + std::unique_lock locker(lock); + // stderr + if (changed.count("log_to_stderr") || changed.count("err_to_stderr")) { + int l = conf->log_to_stderr ? 99 : (conf->err_to_stderr ? -1 : -2); + log->set_stderr_level(l, l); + } + + // syslog + if (changed.count("log_to_syslog")) { + int l = conf->log_to_syslog ? 99 : (conf->err_to_syslog ? -1 : -2); + log->set_syslog_level(l, l); + } + + // file + if (changed.count("log_file") || + changed.count("log_to_file")) { + if (conf->log_to_file) { + log->set_log_file(conf->log_file); + } else { + log->set_log_file({}); + } + log->reopen_log_file(); + } + + if (changed.count("log_stderr_prefix")) { + log->set_log_stderr_prefix(conf.get_val<std::string>("log_stderr_prefix")); + } + + if (changed.count("log_max_new")) { + + log->set_max_new(conf->log_max_new); + } + + if (changed.count("log_max_recent")) { + log->set_max_recent(conf->log_max_recent); + } + + // graylog + if (changed.count("log_to_graylog") || changed.count("err_to_graylog")) { + int l = conf->log_to_graylog ? 99 : (conf->err_to_graylog ? -1 : -2); + log->set_graylog_level(l, l); + + if (conf->log_to_graylog || conf->err_to_graylog) { + log->start_graylog(conf->host, conf.get_val<uuid_d>("fsid")); + } else if (! (conf->log_to_graylog && conf->err_to_graylog)) { + log->stop_graylog(); + } + } + + if (log->graylog() && (changed.count("log_graylog_host") || changed.count("log_graylog_port"))) { + log->graylog()->set_destination(conf->log_graylog_host, conf->log_graylog_port); + } + + // journald + if (changed.count("log_to_journald") || changed.count("err_to_journald")) { + int l = conf.get_val<bool>("log_to_journald") ? 99 : (conf.get_val<bool>("err_to_journald") ? -1 : -2); + log->set_journald_level(l, l); + + if (l > -2) { + log->start_journald_logger(); + } else { + log->stop_journald_logger(); + } + } + + if (changed.find("log_coarse_timestamps") != changed.end()) { + log->set_coarse_timestamps(conf.get_val<bool>("log_coarse_timestamps")); + } + + // metadata + if (log->graylog() && changed.count("host")) { + log->graylog()->set_hostname(conf->host); + } + + if (log->graylog() && changed.count("fsid")) { + log->graylog()->set_fsid(conf.get_val<uuid_d>("fsid")); + } + } +}; + + +namespace ceph::common { +// cct config watcher +class CephContextObs : public md_config_obs_t { + CephContext *cct; + +public: + explicit CephContextObs(CephContext *cct) : cct(cct) {} + + const char** get_tracked_conf_keys() const override { + static const char *KEYS[] = { + "enable_experimental_unrecoverable_data_corrupting_features", + "crush_location", + "container_image", // just so we don't hear complaints about it! + NULL + }; + return KEYS; + } + + void handle_conf_change(const ConfigProxy& conf, + const std::set <std::string> &changed) override { + if (changed.count( + "enable_experimental_unrecoverable_data_corrupting_features")) { + std::lock_guard lg(cct->_feature_lock); + + cct->_experimental_features.clear(); + auto add_experimental_feature = [this] (auto feature) { + cct->_experimental_features.emplace(std::string{feature}); + }; + for_each_substr(conf->enable_experimental_unrecoverable_data_corrupting_features, + ";,= \t", add_experimental_feature); + + if (getenv("CEPH_DEV") == NULL) { + if (!cct->_experimental_features.empty()) { + if (cct->_experimental_features.count("*")) { + lderr(cct) << "WARNING: all dangerous and experimental features are enabled." << dendl; + } else { + lderr(cct) << "WARNING: the following dangerous and experimental features are enabled: " + << cct->_experimental_features << dendl; + } + } + } + + } + if (changed.count("crush_location")) { + cct->crush_location.update_from_conf(); + } + } +}; +// perfcounter hooks + +class CephContextHook : public AdminSocketHook { + CephContext *m_cct; + +public: + explicit CephContextHook(CephContext *cct) : m_cct(cct) {} + + int call(std::string_view command, const cmdmap_t& cmdmap, + const bufferlist& inbl, + Formatter *f, + std::ostream& errss, + bufferlist& out) override { + try { + return m_cct->do_command(command, cmdmap, f, errss, &out); + } catch (const bad_cmd_get& e) { + return -EINVAL; + } + } +}; + + +bool CephContext::check_experimental_feature_enabled(const std::string& feat) +{ + std::stringstream message; + bool enabled = check_experimental_feature_enabled(feat, &message); + lderr(this) << message.str() << dendl; + return enabled; +} + +bool CephContext::check_experimental_feature_enabled(const std::string& feat, + std::ostream *message) +{ + std::unique_lock<ceph::spinlock> lg(_feature_lock); + + bool enabled = (_experimental_features.count(feat) || + _experimental_features.count("*")); + + if (enabled) { + (*message) << "WARNING: experimental feature '" << feat << "' is enabled\n"; + (*message) << "Please be aware that this feature is experimental, untested,\n"; + (*message) << "unsupported, and may result in data corruption, data loss,\n"; + (*message) << "and/or irreparable damage to your cluster. Do not use\n"; + (*message) << "feature with important data.\n"; + } else { + (*message) << "*** experimental feature '" << feat << "' is not enabled ***\n"; + (*message) << "This feature is marked as experimental, which means it\n"; + (*message) << " - is untested\n"; + (*message) << " - is unsupported\n"; + (*message) << " - may corrupt your data\n"; + (*message) << " - may break your cluster is an unrecoverable fashion\n"; + (*message) << "To enable this feature, add this to your ceph.conf:\n"; + (*message) << " enable experimental unrecoverable data corrupting features = " << feat << "\n"; + } + return enabled; +} + +int CephContext::do_command(std::string_view command, const cmdmap_t& cmdmap, + Formatter *f, + std::ostream& ss, + bufferlist *out) +{ + try { + return _do_command(command, cmdmap, f, ss, out); + } catch (const bad_cmd_get& e) { + ss << e.what(); + return -EINVAL; + } +} + +#pragma GCC push_options +#pragma GCC optimize ("O0") +static void leak_some_memory() { + volatile char *foo = new char[1234]; + (void)foo; +} +#pragma GCC pop_options + +int CephContext::_do_command( + std::string_view command, const cmdmap_t& cmdmap, + Formatter *f, + std::ostream& ss, + bufferlist *out) +{ + int r = 0; + lgeneric_dout(this, 1) << "do_command '" << command << "' '" << cmdmap << "'" + << dendl; + ceph_assert_always(!(command == "assert" && _conf->debug_asok_assert_abort)); + if (command == "abort") { + if (_conf->debug_asok_assert_abort) { + ceph_abort(); + } else { + return -EPERM; + } + } + if (command == "leak_some_memory") { + leak_some_memory(); + } + else if (command == "perfcounters_dump" || command == "1" || + command == "perf dump") { + std::string logger; + std::string counter; + cmd_getval(cmdmap, "logger", logger); + cmd_getval(cmdmap, "counter", counter); + _perf_counters_collection->dump_formatted(f, false, false, logger, counter); + } + else if (command == "perfcounters_schema" || command == "2" || + command == "perf schema") { + _perf_counters_collection->dump_formatted(f, true, false); + } + else if (command == "counter dump") { + _perf_counters_collection->dump_formatted(f, false, true); + } + else if (command == "counter schema") { + _perf_counters_collection->dump_formatted(f, true, true); + } + else if (command == "perf histogram dump") { + std::string logger; + std::string counter; + cmd_getval(cmdmap, "logger", logger); + cmd_getval(cmdmap, "counter", counter); + _perf_counters_collection->dump_formatted_histograms(f, false, logger, + counter); + } + else if (command == "perf histogram schema") { + _perf_counters_collection->dump_formatted_histograms(f, true); + } + else if (command == "perf reset") { + std::string var; + std::string section(command); + f->open_object_section(section.c_str()); + if (!cmd_getval(cmdmap, "var", var)) { + f->dump_string("error", "syntax error: 'perf reset <var>'"); + } else { + if(!_perf_counters_collection->reset(var)) + f->dump_stream("error") << "Not find: " << var; + else + f->dump_string("success", std::string(command) + ' ' + var); + } + f->close_section(); + } + else { + std::string section(command); + boost::replace_all(section, " ", "_"); + f->open_object_section(section.c_str()); + if (command == "config show") { + _conf.show_config(f); + } + else if (command == "config unset") { + std::string var; + if (!(cmd_getval(cmdmap, "var", var))) { + r = -EINVAL; + } else { + r = _conf.rm_val(var.c_str()); + if (r < 0 && r != -ENOENT) { + ss << "error unsetting '" << var << "': " + << cpp_strerror(r); + } else { + _conf.apply_changes(&ss); + r = 0; + } + } + + } + else if (command == "config set") { + std::string var; + std::vector<std::string> val; + + if (!(cmd_getval(cmdmap, "var", var)) || + !(cmd_getval(cmdmap, "val", val))) { + r = -EINVAL; + } else { + // val may be multiple words + auto valstr = str_join(val, " "); + r = _conf.set_val(var.c_str(), valstr.c_str()); + if (r < 0) { + ss << "error setting '" << var << "' to '" << valstr << "': " + << cpp_strerror(r); + } else { + std::stringstream ss; + _conf.apply_changes(&ss); + f->dump_string("success", ss.str()); + } + } + } else if (command == "config get") { + std::string var; + if (!cmd_getval(cmdmap, "var", var)) { + r = -EINVAL; + } else { + char buf[4096]; + // FIPS zeroization audit 20191115: this memset is not security related. + memset(buf, 0, sizeof(buf)); + char *tmp = buf; + r = _conf.get_val(var.c_str(), &tmp, sizeof(buf)); + if (r < 0) { + ss << "error getting '" << var << "': " << cpp_strerror(r); + } else { + f->dump_string(var.c_str(), buf); + } + } + } else if (command == "config help") { + std::string var; + if (cmd_getval(cmdmap, "var", var)) { + // Output a single one + std::string key = ConfFile::normalize_key_name(var); + auto schema = _conf.get_schema(key); + if (!schema) { + ss << "Setting not found: '" << key << "'"; + r = -ENOENT; + } else { + f->dump_object("option", *schema); + } + } else { + // Output all + f->open_array_section("options"); + for (const auto &option : ceph_options) { + f->dump_object("option", option); + } + f->close_section(); + } + } else if (command == "config diff") { + f->open_object_section("diff"); + _conf.diff(f); + f->close_section(); // unknown + } else if (command == "config diff get") { + std::string setting; + f->open_object_section("diff"); + _conf.diff(f, setting); + f->close_section(); // unknown + } + else if (command == "injectargs") { + std::vector<std::string> argsvec; + cmd_getval(cmdmap, "injected_args", argsvec); + if (!argsvec.empty()) { + auto args = joinify<std::string>(argsvec.begin(), argsvec.end(), " "); + r = _conf.injectargs(args, &ss); + } + } + else if (command == "log flush") { + _log->flush(); + } + else if (command == "log dump") { + _log->dump_recent(); + } + else if (command == "log reopen") { + _log->reopen_log_file(); + } + else { + ceph_abort_msg("registered under wrong command?"); + } + f->close_section(); + } + lgeneric_dout(this, 1) << "do_command '" << command << "' '" << cmdmap + << "' result is " << out->length() << " bytes" << dendl; + return r; +} + +CephContext::CephContext(uint32_t module_type_, + enum code_environment_t code_env, + int init_flags_) + : CephContext(module_type_, create_options{code_env, init_flags_, nullptr}) +{} + +CephContext::CephContext(uint32_t module_type_, + const create_options& options) + : nref(1), + _conf{options.code_env == CODE_ENVIRONMENT_DAEMON}, + _log(NULL), + _module_type(module_type_), + _init_flags(options.init_flags), + _set_uid(0), + _set_gid(0), + _set_uid_string(), + _set_gid_string(), + _crypto_inited(0), + _service_thread(NULL), + _log_obs(NULL), + _admin_socket(NULL), + _perf_counters_collection(NULL), + _perf_counters_conf_obs(NULL), + _heartbeat_map(NULL), + _crypto_none(NULL), + _crypto_aes(NULL), + _plugin_registry(NULL), +#ifdef CEPH_DEBUG_MUTEX + _lockdep_obs(NULL), +#endif + crush_location(this) +{ + if (options.create_log) { + _log = options.create_log(&_conf->subsys); + } else { + _log = new ceph::logging::Log(&_conf->subsys); + } + + _log_obs = new LogObs(_log); + _conf.add_observer(_log_obs); + + _cct_obs = new CephContextObs(this); + _conf.add_observer(_cct_obs); +#ifdef CEPH_DEBUG_MUTEX + _lockdep_obs = new LockdepObs(this); + _conf.add_observer(_lockdep_obs); +#endif + _perf_counters_collection = new PerfCountersCollection(this); + + _admin_socket = new AdminSocket(this); + _heartbeat_map = new HeartbeatMap(this); + + _plugin_registry = new PluginRegistry(this); + + _admin_hook = new CephContextHook(this); + _admin_socket->register_command("assert", _admin_hook, ""); + _admin_socket->register_command("abort", _admin_hook, ""); + _admin_socket->register_command("leak_some_memory", _admin_hook, ""); + _admin_socket->register_command("perfcounters_dump", _admin_hook, ""); + _admin_socket->register_command("1", _admin_hook, ""); + _admin_socket->register_command("perf dump name=logger,type=CephString,req=false name=counter,type=CephString,req=false", _admin_hook, "dump non-labeled counters and their values"); + _admin_socket->register_command("perfcounters_schema", _admin_hook, ""); + _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"); + _admin_socket->register_command("2", _admin_hook, ""); + _admin_socket->register_command("perf schema", _admin_hook, "dump non-labeled counters schemas"); + _admin_socket->register_command("counter dump", _admin_hook, "dump all labeled and non-labeled counters and their values"); + _admin_socket->register_command("counter schema", _admin_hook, "dump all labeled and non-labeled counters schemas"); + _admin_socket->register_command("perf histogram schema", _admin_hook, "dump perf histogram schema"); + _admin_socket->register_command("perf reset name=var,type=CephString", _admin_hook, "perf reset <name>: perf reset all or one perfcounter name"); + _admin_socket->register_command("config show", _admin_hook, "dump current config settings"); + _admin_socket->register_command("config help name=var,type=CephString,req=false", _admin_hook, "get config setting schema and descriptions"); + _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"); + _admin_socket->register_command("config unset name=var,type=CephString", _admin_hook, "config unset <field>: unset a config variable"); + _admin_socket->register_command("config get name=var,type=CephString", _admin_hook, "config get <field>: get the config value"); + _admin_socket->register_command( + "config diff", _admin_hook, + "dump diff of current config and default config"); + _admin_socket->register_command( + "config diff get name=var,type=CephString", _admin_hook, + "dump diff get <field>: dump diff of current and default config setting <field>"); + _admin_socket->register_command("injectargs name=injected_args,type=CephString,n=N", _admin_hook, "inject configuration arguments into running daemon"), + _admin_socket->register_command("log flush", _admin_hook, "flush log entries to log file"); + _admin_socket->register_command("log dump", _admin_hook, "dump recent log entries to log file"); + _admin_socket->register_command("log reopen", _admin_hook, "reopen log file"); + + _crypto_none = CryptoHandler::create(CEPH_CRYPTO_NONE); + _crypto_aes = CryptoHandler::create(CEPH_CRYPTO_AES); + _crypto_random.reset(new CryptoRandom()); + + lookup_or_create_singleton_object<MempoolObs>("mempool_obs", false, this); +} + +CephContext::~CephContext() +{ + associated_objs.clear(); + join_service_thread(); + + if (_cct_perf) { + _perf_counters_collection->remove(_cct_perf); + delete _cct_perf; + _cct_perf = NULL; + } + + delete _plugin_registry; + + _admin_socket->unregister_commands(_admin_hook); + delete _admin_hook; + delete _admin_socket; + + delete _heartbeat_map; + + delete _perf_counters_collection; + _perf_counters_collection = NULL; + + delete _perf_counters_conf_obs; + _perf_counters_conf_obs = NULL; + + _conf.remove_observer(_log_obs); + delete _log_obs; + _log_obs = NULL; + + _conf.remove_observer(_cct_obs); + delete _cct_obs; + _cct_obs = NULL; +#ifdef CEPH_DEBUG_MUTEX + _conf.remove_observer(_lockdep_obs); + delete _lockdep_obs; + _lockdep_obs = NULL; +#endif + _log->stop(); + delete _log; + _log = NULL; + + delete _crypto_none; + delete _crypto_aes; + if (_crypto_inited > 0) { + ceph_assert(_crypto_inited == 1); // or else someone explicitly did + // init but not shutdown + shutdown_crypto(); + } +} + +void CephContext::put() { + if (--nref == 0) { + ANNOTATE_HAPPENS_AFTER(&nref); + ANNOTATE_HAPPENS_BEFORE_FORGET_ALL(&nref); + if (g_ceph_context == this) + g_ceph_context = nullptr; + delete this; + } else { + ANNOTATE_HAPPENS_BEFORE(&nref); + } +} + +void CephContext::init_crypto() +{ + if (_crypto_inited++ == 0) { + TOPNSPC::crypto::init(); + } +} + +void CephContext::shutdown_crypto() +{ + if (--_crypto_inited == 0) { + TOPNSPC::crypto::shutdown(g_code_env == CODE_ENVIRONMENT_LIBRARY); + } +} + +void CephContext::start_service_thread() +{ + { + std::lock_guard lg(_service_thread_lock); + if (_service_thread) { + return; + } + _service_thread = new CephContextServiceThread(this); + _service_thread->create("service"); + } + + if (!(get_init_flags() & CINIT_FLAG_NO_CCT_PERF_COUNTERS)) + _enable_perf_counter(); + + // make logs flush on_exit() + if (_conf->log_flush_on_exit) + _log->set_flush_on_exit(); + + // Trigger callbacks on any config observers that were waiting for + // it to become safe to start threads. + _conf.set_safe_to_start_threads(); + _conf.call_all_observers(); + + // start admin socket + if (_conf->admin_socket.length()) + _admin_socket->init(_conf->admin_socket); +} + +void CephContext::reopen_logs() +{ + std::lock_guard lg(_service_thread_lock); + if (_service_thread) + _service_thread->reopen_logs(); +} + +void CephContext::join_service_thread() +{ + std::unique_lock<ceph::spinlock> lg(_service_thread_lock); + + CephContextServiceThread *thread = _service_thread; + if (!thread) { + return; + } + _service_thread = NULL; + + lg.unlock(); + + thread->exit_thread(); + thread->join(); + delete thread; + + if (!(get_init_flags() & CINIT_FLAG_NO_CCT_PERF_COUNTERS)) + _disable_perf_counter(); +} + +uint32_t CephContext::get_module_type() const +{ + return _module_type; +} + +void CephContext::set_init_flags(int flags) +{ + _init_flags = flags; +} + +int CephContext::get_init_flags() const +{ + return _init_flags; +} + +PerfCountersCollection *CephContext::get_perfcounters_collection() +{ + return _perf_counters_collection; +} + +void CephContext::_enable_perf_counter() +{ + assert(!_cct_perf); + PerfCountersBuilder plb(this, "cct", l_cct_first, l_cct_last); + plb.add_u64(l_cct_total_workers, "total_workers", "Total workers"); + plb.add_u64(l_cct_unhealthy_workers, "unhealthy_workers", "Unhealthy workers"); + _cct_perf = plb.create_perf_counters(); + _perf_counters_collection->add(_cct_perf); + + assert(_mempool_perf_names.empty()); + assert(_mempool_perf_descriptions.empty()); + _mempool_perf_names.reserve(mempool::num_pools * 2); + _mempool_perf_descriptions.reserve(mempool::num_pools * 2); + for (unsigned i = 0; i < mempool::num_pools; ++i) { + std::string n = mempool::get_pool_name(mempool::pool_index_t(i)); + _mempool_perf_names.push_back(n + "_bytes"s); + _mempool_perf_descriptions.push_back( + "mempool "s + n + " total bytes"); + _mempool_perf_names.push_back(n + "_items"s); + _mempool_perf_descriptions.push_back( + "mempool "s + n + " total items"s); + } + + PerfCountersBuilder plb2(this, "mempool", l_mempool_first, + l_mempool_first + 1 + 2*mempool::num_pools); + unsigned l = l_mempool_first + 1; + for (unsigned i = 0; i < mempool::num_pools; ++i) { + plb2.add_u64(l++, _mempool_perf_names[i*2].c_str(), + _mempool_perf_descriptions[i*2].c_str()); + plb2.add_u64(l++, _mempool_perf_names[i*2+1].c_str(), + _mempool_perf_descriptions[i*2+1].c_str()); + } + _mempool_perf = plb2.create_perf_counters(); + _perf_counters_collection->add(_mempool_perf); +} + +void CephContext::_disable_perf_counter() +{ + if (!_cct_perf) { + return; + } + _perf_counters_collection->remove(_cct_perf); + delete _cct_perf; + _cct_perf = nullptr; + + _perf_counters_collection->remove(_mempool_perf); + delete _mempool_perf; + _mempool_perf = nullptr; + _mempool_perf_names.clear(); + _mempool_perf_descriptions.clear(); +} + +void CephContext::_refresh_perf_values() +{ + if (_cct_perf) { + _cct_perf->set(l_cct_total_workers, _heartbeat_map->get_total_workers()); + _cct_perf->set(l_cct_unhealthy_workers, _heartbeat_map->get_unhealthy_workers()); + } + unsigned l = l_mempool_first + 1; + for (unsigned i = 0; i < mempool::num_pools; ++i) { + mempool::pool_t& p = mempool::get_pool(mempool::pool_index_t(i)); + _mempool_perf->set(l++, p.allocated_bytes()); + _mempool_perf->set(l++, p.allocated_items()); + } +} + +AdminSocket *CephContext::get_admin_socket() +{ + return _admin_socket; +} + +CryptoHandler *CephContext::get_crypto_handler(int type) +{ + switch (type) { + case CEPH_CRYPTO_NONE: + return _crypto_none; + case CEPH_CRYPTO_AES: + return _crypto_aes; + default: + return NULL; + } +} + +void CephContext::notify_pre_fork() +{ + { + std::lock_guard lg(_fork_watchers_lock); + for (auto &&t : _fork_watchers) { + t->handle_pre_fork(); + } + } + { + // note: we don't hold a lock here, but we assume we are idle at + // fork time, which happens during process init and startup. + auto i = associated_objs.begin(); + while (i != associated_objs.end()) { + if (associated_objs_drop_on_fork.count(i->first.first)) { + i = associated_objs.erase(i); + } else { + ++i; + } + } + associated_objs_drop_on_fork.clear(); + } +} + +void CephContext::notify_post_fork() +{ + ceph::spin_unlock(&_fork_watchers_lock); + for (auto &&t : _fork_watchers) + t->handle_post_fork(); +} + +void CephContext::set_mon_addrs(const MonMap& mm) { + std::vector<entity_addrvec_t> mon_addrs; + for (auto& i : mm.mon_info) { + mon_addrs.push_back(i.second.public_addrs); + } + + set_mon_addrs(mon_addrs); +} +} +#endif // WITH_SEASTAR |