Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / 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 <boost/algorithm/string.hpp>
17
18 #include "include/mempool.h"
19 #include "common/admin_socket.h"
20 #include "common/perf_counters.h"
21 #include "common/code_environment.h"
22 #include "common/ceph_crypto.h"
23 #include "common/HeartbeatMap.h"
24 #include "common/errno.h"
25 #include "common/Graylog.h"
26 #include "auth/Crypto.h"
27 #include "include/str_list.h"
28 #include "common/PluginRegistry.h"
29
30 using ceph::bufferlist;
31 using ceph::HeartbeatMap;
32
33 namespace {
34
35 class LockdepObs : public md_config_obs_t {
36 public:
37   explicit LockdepObs(CephContext *cct) : m_cct(cct), m_registered(false) {
38   }
39   ~LockdepObs() override {
40     if (m_registered) {
41       lockdep_unregister_ceph_context(m_cct);
42     }
43   }
44
45   const char** get_tracked_conf_keys() const override {
46     static const char *KEYS[] = {"lockdep", NULL};
47     return KEYS;
48   }
49
50   void handle_conf_change(const md_config_t *conf,
51                           const std::set <std::string> &changed) override {
52     if (conf->lockdep && !m_registered) {
53       lockdep_register_ceph_context(m_cct);
54       m_registered = true;
55     } else if (!conf->lockdep && m_registered) {
56       lockdep_unregister_ceph_context(m_cct);
57       m_registered = false;
58     }
59   }
60 private:
61   CephContext *m_cct;
62   bool m_registered;
63 };
64
65 class MempoolObs : public md_config_obs_t,
66                   public AdminSocketHook {
67   CephContext *cct;
68
69 public:
70   explicit MempoolObs(CephContext *cct) : cct(cct) {
71     cct->_conf->add_observer(this);
72     int r = cct->get_admin_socket()->register_command(
73       "dump_mempools",
74       "dump_mempools",
75       this,
76       "get mempool stats");
77     assert(r == 0);
78   }
79   ~MempoolObs() override {
80     cct->_conf->remove_observer(this);
81     cct->get_admin_socket()->unregister_command("dump_mempools");
82   }
83
84   // md_config_obs_t
85   const char** get_tracked_conf_keys() const override {
86     static const char *KEYS[] = {
87       "mempool_debug",
88       NULL
89     };
90     return KEYS;
91   }
92
93   void handle_conf_change(const md_config_t *conf,
94                           const std::set <std::string> &changed) override {
95     if (changed.count("mempool_debug")) {
96       mempool::set_debug_mode(cct->_conf->mempool_debug);
97     }
98   }
99
100   // AdminSocketHook
101   bool call(std::string command, cmdmap_t& cmdmap, std::string format,
102             bufferlist& out) override {
103     if (command == "dump_mempools") {
104       std::unique_ptr<Formatter> f(Formatter::create(format));
105       f->open_object_section("mempools");
106       mempool::dump(f.get());
107       f->close_section();
108       f->flush(out);
109       return true;
110     }
111     return false;
112   }
113 };
114
115 } // anonymous namespace
116
117 class CephContextServiceThread : public Thread
118 {
119 public:
120   explicit CephContextServiceThread(CephContext *cct)
121     : _lock("CephContextServiceThread::_lock"),
122       _reopen_logs(false), _exit_thread(false), _cct(cct)
123   {
124   }
125
126   ~CephContextServiceThread() override {}
127
128   void *entry() override
129   {
130     while (1) {
131       Mutex::Locker l(_lock);
132
133       if (_cct->_conf->heartbeat_interval) {
134         utime_t interval(_cct->_conf->heartbeat_interval, 0);
135         _cond.WaitInterval(_lock, interval);
136       } else
137         _cond.Wait(_lock);
138
139       if (_exit_thread) {
140         break;
141       }
142
143       if (_reopen_logs) {
144         _cct->_log->reopen_log_file();
145         _reopen_logs = false;
146       }
147       _cct->_heartbeat_map->check_touch_file();
148
149       // refresh the perf coutners
150       _cct->refresh_perf_values();
151     }
152     return NULL;
153   }
154
155   void reopen_logs()
156   {
157     Mutex::Locker l(_lock);
158     _reopen_logs = true;
159     _cond.Signal();
160   }
161
162   void exit_thread()
163   {
164     Mutex::Locker l(_lock);
165     _exit_thread = true;
166     _cond.Signal();
167   }
168
169 private:
170   Mutex _lock;
171   Cond _cond;
172   bool _reopen_logs;
173   bool _exit_thread;
174   CephContext *_cct;
175 };
176
177
178 /**
179  * observe logging config changes
180  *
181  * The logging subsystem sits below most of the ceph code, including
182  * the config subsystem, to keep it simple and self-contained.  Feed
183  * logging-related config changes to the log.
184  */
185 class LogObs : public md_config_obs_t {
186   ceph::logging::Log *log;
187
188 public:
189   explicit LogObs(ceph::logging::Log *l) : log(l) {}
190
191   const char** get_tracked_conf_keys() const override {
192     static const char *KEYS[] = {
193       "log_file",
194       "log_max_new",
195       "log_max_recent",
196       "log_to_syslog",
197       "err_to_syslog",
198       "log_to_stderr",
199       "err_to_stderr",
200       "log_to_graylog",
201       "err_to_graylog",
202       "log_graylog_host",
203       "log_graylog_port",
204       "fsid",
205       "host",
206       NULL
207     };
208     return KEYS;
209   }
210
211   void handle_conf_change(const md_config_t *conf,
212                           const std::set <std::string> &changed) override {
213     // stderr
214     if (changed.count("log_to_stderr") || changed.count("err_to_stderr")) {
215       int l = conf->log_to_stderr ? 99 : (conf->err_to_stderr ? -1 : -2);
216       log->set_stderr_level(l, l);
217     }
218
219     // syslog
220     if (changed.count("log_to_syslog")) {
221       int l = conf->log_to_syslog ? 99 : (conf->err_to_syslog ? -1 : -2);
222       log->set_syslog_level(l, l);
223     }
224
225     // file
226     if (changed.count("log_file")) {
227       log->set_log_file(conf->log_file);
228       log->reopen_log_file();
229     }
230
231     if (changed.count("log_max_new")) {
232
233       log->set_max_new(conf->log_max_new);
234     }
235
236     if (changed.count("log_max_recent")) {
237       log->set_max_recent(conf->log_max_recent);
238     }
239
240     // graylog
241     if (changed.count("log_to_graylog") || changed.count("err_to_graylog")) {
242       int l = conf->log_to_graylog ? 99 : (conf->err_to_graylog ? -1 : -2);
243       log->set_graylog_level(l, l);
244
245       if (conf->log_to_graylog || conf->err_to_graylog) {
246         log->start_graylog();
247       } else if (! (conf->log_to_graylog && conf->err_to_graylog)) {
248         log->stop_graylog();
249       }
250     }
251
252     if (log->graylog() && (changed.count("log_graylog_host") || changed.count("log_graylog_port"))) {
253       log->graylog()->set_destination(conf->log_graylog_host, conf->log_graylog_port);
254     }
255
256     // metadata
257     if (log->graylog() && changed.count("host")) {
258       log->graylog()->set_hostname(conf->host);
259     }
260
261     if (log->graylog() && changed.count("fsid")) {
262       log->graylog()->set_fsid(conf->get_val<uuid_d>("fsid"));
263     }
264   }
265 };
266
267
268 // cct config watcher
269 class CephContextObs : public md_config_obs_t {
270   CephContext *cct;
271
272 public:
273   explicit CephContextObs(CephContext *cct) : cct(cct) {}
274
275   const char** get_tracked_conf_keys() const override {
276     static const char *KEYS[] = {
277       "enable_experimental_unrecoverable_data_corrupting_features",
278       "crush_location",
279       NULL
280     };
281     return KEYS;
282   }
283
284   void handle_conf_change(const md_config_t *conf,
285                           const std::set <std::string> &changed) override {
286     if (changed.count(
287           "enable_experimental_unrecoverable_data_corrupting_features")) {
288       ceph_spin_lock(&cct->_feature_lock);
289       get_str_set(
290         conf->enable_experimental_unrecoverable_data_corrupting_features,
291         cct->_experimental_features);
292       ceph_spin_unlock(&cct->_feature_lock);
293       if (getenv("CEPH_DEV") == NULL) {
294         if (!cct->_experimental_features.empty()) {
295           if (cct->_experimental_features.count("*")) {
296             lderr(cct) << "WARNING: all dangerous and experimental features are enabled." << dendl;
297           } else {
298             lderr(cct) << "WARNING: the following dangerous and experimental features are enabled: "
299               << cct->_experimental_features << dendl;
300           }
301         }
302       }
303
304     }
305     if (changed.count("crush_location")) {
306       cct->crush_location.update_from_conf();
307     }
308   }
309 };
310
311 bool CephContext::check_experimental_feature_enabled(const std::string& feat)
312 {
313   stringstream message;
314   bool enabled = check_experimental_feature_enabled(feat, &message);
315   lderr(this) << message.str() << dendl;
316   return enabled;
317 }
318
319 bool CephContext::check_experimental_feature_enabled(const std::string& feat,
320                                                      std::ostream *message)
321 {
322   ceph_spin_lock(&_feature_lock);
323   bool enabled = (_experimental_features.count(feat) ||
324                   _experimental_features.count("*"));
325   ceph_spin_unlock(&_feature_lock);
326
327   if (enabled) {
328     (*message) << "WARNING: experimental feature '" << feat << "' is enabled\n";
329     (*message) << "Please be aware that this feature is experimental, untested,\n";
330     (*message) << "unsupported, and may result in data corruption, data loss,\n";
331     (*message) << "and/or irreparable damage to your cluster.  Do not use\n";
332     (*message) << "feature with important data.\n";
333   } else {
334     (*message) << "*** experimental feature '" << feat << "' is not enabled ***\n";
335     (*message) << "This feature is marked as experimental, which means it\n";
336     (*message) << " - is untested\n";
337     (*message) << " - is unsupported\n";
338     (*message) << " - may corrupt your data\n";
339     (*message) << " - may break your cluster is an unrecoverable fashion\n";
340     (*message) << "To enable this feature, add this to your ceph.conf:\n";
341     (*message) << "  enable experimental unrecoverable data corrupting features = " << feat << "\n";
342   }
343   return enabled;
344 }
345
346 // perfcounter hooks
347
348 class CephContextHook : public AdminSocketHook {
349   CephContext *m_cct;
350
351 public:
352   explicit CephContextHook(CephContext *cct) : m_cct(cct) {}
353
354   bool call(std::string command, cmdmap_t& cmdmap, std::string format,
355             bufferlist& out) override {
356     m_cct->do_command(command, cmdmap, format, &out);
357     return true;
358   }
359 };
360
361 void CephContext::do_command(std::string command, cmdmap_t& cmdmap,
362                              std::string format, bufferlist *out)
363 {
364   Formatter *f = Formatter::create(format, "json-pretty", "json-pretty");
365   stringstream ss;
366   for (cmdmap_t::iterator it = cmdmap.begin(); it != cmdmap.end(); ++it) {
367     if (it->first != "prefix") {
368       ss << it->first  << ":" << cmd_vartype_stringify(it->second) << " ";
369     }
370   }
371   lgeneric_dout(this, 1) << "do_command '" << command << "' '"
372                          << ss.str() << dendl;
373   if (command == "perfcounters_dump" || command == "1" ||
374       command == "perf dump") {
375     std::string logger;
376     std::string counter;
377     cmd_getval(this, cmdmap, "logger", logger);
378     cmd_getval(this, cmdmap, "counter", counter);
379     _perf_counters_collection->dump_formatted(f, false, logger, counter);
380   }
381   else if (command == "perfcounters_schema" || command == "2" ||
382     command == "perf schema") {
383     _perf_counters_collection->dump_formatted(f, true);
384   }
385   else if (command == "perf histogram dump") {
386     std::string logger;
387     std::string counter;
388     cmd_getval(this, cmdmap, "logger", logger);
389     cmd_getval(this, cmdmap, "counter", counter);
390     _perf_counters_collection->dump_formatted_histograms(f, false, logger,
391                                                          counter);
392   }
393   else if (command == "perf histogram schema") {
394     _perf_counters_collection->dump_formatted_histograms(f, true);
395   }
396   else if (command == "perf reset") {
397     std::string var;
398     string section = command;
399     f->open_object_section(section.c_str());
400     if (!cmd_getval(this, cmdmap, "var", var)) {
401       f->dump_string("error", "syntax error: 'perf reset <var>'");
402     } else {
403      if(!_perf_counters_collection->reset(var))
404         f->dump_stream("error") << "Not find: " << var;
405      else
406        f->dump_string("success", command + ' ' + var);
407     }
408     f->close_section();
409   }
410   else {
411     string section = command;
412     boost::replace_all(section, " ", "_");
413     f->open_object_section(section.c_str());
414     if (command == "config show") {
415       _conf->show_config(f);
416     }
417     else if (command == "config set") {
418       std::string var;
419       std::vector<std::string> val;
420
421       if (!(cmd_getval(this, cmdmap, "var", var)) ||
422           !(cmd_getval(this, cmdmap, "val", val))) {
423         f->dump_string("error", "syntax error: 'config set <var> <value>'");
424       } else {
425         // val may be multiple words
426         string valstr = str_join(val, " ");
427         int r = _conf->set_val(var.c_str(), valstr.c_str());
428         if (r < 0) {
429           f->dump_stream("error") << "error setting '" << var << "' to '" << valstr << "': " << cpp_strerror(r);
430         } else {
431           ostringstream ss;
432           _conf->apply_changes(&ss);
433           f->dump_string("success", ss.str());
434         }
435       }
436     } else if (command == "config get") {
437       std::string var;
438       if (!cmd_getval(this, cmdmap, "var", var)) {
439         f->dump_string("error", "syntax error: 'config get <var>'");
440       } else {
441         char buf[4096];
442         memset(buf, 0, sizeof(buf));
443         char *tmp = buf;
444         int r = _conf->get_val(var.c_str(), &tmp, sizeof(buf));
445         if (r < 0) {
446             f->dump_stream("error") << "error getting '" << var << "': " << cpp_strerror(r);
447         } else {
448             f->dump_string(var.c_str(), buf);
449         }
450       }
451     } else if (command == "config help") {
452       std::string var;
453       if (cmd_getval(this, cmdmap, "var", var)) {
454         // Output a single one
455         std::string key = ConfFile::normalize_key_name(var);
456         const auto &i = _conf->schema.find(key);
457         if (i == _conf->schema.end()) {
458           std::ostringstream msg;
459           msg << "Setting not found: '" << key << "'";
460           f->dump_string("error", msg.str());
461         } else {
462           i->second.dump(f);
463         }
464       } else {
465         // Output all
466         f->open_array_section("options");
467         for (const auto &option : ceph_options) {
468           option.dump(f);
469         }
470         f->close_section();
471       }
472     } else if (command == "config diff") {
473       md_config_t def_conf;
474       def_conf.set_val("cluster", _conf->cluster);
475       def_conf.name = _conf->name;
476       def_conf.set_val("host", _conf->host);
477       def_conf.apply_changes(NULL);
478
479       map<string,pair<string,string> > diff;
480       set<string> unknown;
481       def_conf.diff(_conf, &diff, &unknown);
482       f->open_object_section("diff");
483
484       f->open_object_section("current");
485       for (map<string,pair<string,string> >::iterator p = diff.begin();
486            p != diff.end(); ++p) {
487         f->dump_string(p->first.c_str(), p->second.second);
488       }
489       f->close_section(); // current
490       f->open_object_section("defaults");
491       for (map<string,pair<string,string> >::iterator p = diff.begin();
492            p != diff.end(); ++p) {
493         f->dump_string(p->first.c_str(), p->second.first);
494       }
495       f->close_section(); // defaults
496       f->close_section(); // diff
497
498       f->open_array_section("unknown");
499       for (set<string>::iterator p = unknown.begin();
500            p != unknown.end(); ++p) {
501         f->dump_string("option", *p);
502       }
503       f->close_section(); // unknown
504     } else if (command == "config diff get") {
505       std::string setting;
506       if (!cmd_getval(this, cmdmap, "var", setting)) {
507         f->dump_string("error", "syntax error: 'config diff get <var>'");
508       } else {
509         md_config_t def_conf;
510         def_conf.set_val("cluster", _conf->cluster);
511         def_conf.name = _conf->name;
512         def_conf.set_val("host", _conf->host);
513         def_conf.apply_changes(NULL);
514
515         map<string, pair<string, string>> diff;
516         set<string> unknown;
517         def_conf.diff(_conf, &diff, &unknown, setting);
518         f->open_object_section("diff");
519         f->open_object_section("current");
520
521         for (const auto& p : diff) {
522           f->dump_string(p.first.c_str(), p.second.second);
523         } 
524         f->close_section();   //-- current
525
526         f->open_object_section("defaults");
527         for (const auto& p : diff) {
528           f->dump_string(p.first.c_str(), p.second.first);
529         } 
530         f->close_section();   //-- defaults
531         f->close_section();   //-- diff
532       } 
533     } else if (command == "log flush") {
534       _log->flush();
535     }
536     else if (command == "log dump") {
537       _log->dump_recent();
538     }
539     else if (command == "log reopen") {
540       _log->reopen_log_file();
541     }
542     else {
543       assert(0 == "registered under wrong command?");    
544     }
545     f->close_section();
546   }
547   f->flush(*out);
548   delete f;
549   lgeneric_dout(this, 1) << "do_command '" << command << "' '" << ss.str()
550                          << "result is " << out->length() << " bytes" << dendl;
551 }
552
553 CephContext::CephContext(uint32_t module_type_,
554                          enum code_environment_t code_env,
555                          int init_flags_)
556   : nref(1),
557     _conf(new md_config_t(code_env == CODE_ENVIRONMENT_DAEMON)),
558     _log(NULL),
559     _module_type(module_type_),
560     _init_flags(init_flags_),
561     _set_uid(0),
562     _set_gid(0),
563     _set_uid_string(),
564     _set_gid_string(),
565     _crypto_inited(false),
566     _service_thread(NULL),
567     _log_obs(NULL),
568     _admin_socket(NULL),
569     _perf_counters_collection(NULL),
570     _perf_counters_conf_obs(NULL),
571     _heartbeat_map(NULL),
572     _crypto_none(NULL),
573     _crypto_aes(NULL),
574     _plugin_registry(NULL),
575     _lockdep_obs(NULL),
576     crush_location(this),
577     _cct_perf(NULL)
578 {
579   ceph_spin_init(&_service_thread_lock);
580   ceph_spin_init(&_associated_objs_lock);
581   ceph_spin_init(&_fork_watchers_lock);
582   ceph_spin_init(&_feature_lock);
583   ceph_spin_init(&_cct_perf_lock);
584
585   _log = new ceph::logging::Log(&_conf->subsys);
586   _log->start();
587
588   _log_obs = new LogObs(_log);
589   _conf->add_observer(_log_obs);
590
591   _cct_obs = new CephContextObs(this);
592   _conf->add_observer(_cct_obs);
593
594   _lockdep_obs = new LockdepObs(this);
595   _conf->add_observer(_lockdep_obs);
596
597   _perf_counters_collection = new PerfCountersCollection(this);
598  
599   _admin_socket = new AdminSocket(this);
600   _heartbeat_map = new HeartbeatMap(this);
601
602   _plugin_registry = new PluginRegistry(this);
603
604   _admin_hook = new CephContextHook(this);
605   _admin_socket->register_command("perfcounters_dump", "perfcounters_dump", _admin_hook, "");
606   _admin_socket->register_command("1", "1", _admin_hook, "");
607   _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");
608   _admin_socket->register_command("perfcounters_schema", "perfcounters_schema", _admin_hook, "");
609   _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");
610   _admin_socket->register_command("2", "2", _admin_hook, "");
611   _admin_socket->register_command("perf schema", "perf schema", _admin_hook, "dump perfcounters schema");
612   _admin_socket->register_command("perf histogram schema", "perf histogram schema", _admin_hook, "dump perf histogram schema");
613   _admin_socket->register_command("perf reset", "perf reset name=var,type=CephString", _admin_hook, "perf reset <name>: perf reset all or one perfcounter name");
614   _admin_socket->register_command("config show", "config show", _admin_hook, "dump current config settings");
615   _admin_socket->register_command("config help", "config help name=var,type=CephString,req=false", _admin_hook, "get config setting schema and descriptions");
616   _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");
617   _admin_socket->register_command("config get", "config get name=var,type=CephString", _admin_hook, "config get <field>: get the config value");
618   _admin_socket->register_command("config diff",
619       "config diff", _admin_hook,
620       "dump diff of current config and default config");
621   _admin_socket->register_command("config diff get",
622       "config diff get name=var,type=CephString", _admin_hook,
623       "dump diff get <field>: dump diff of current and default config setting <field>");
624   _admin_socket->register_command("log flush", "log flush", _admin_hook, "flush log entries to log file");
625   _admin_socket->register_command("log dump", "log dump", _admin_hook, "dump recent log entries to log file");
626   _admin_socket->register_command("log reopen", "log reopen", _admin_hook, "reopen log file");
627
628   _crypto_none = CryptoHandler::create(CEPH_CRYPTO_NONE);
629   _crypto_aes = CryptoHandler::create(CEPH_CRYPTO_AES);
630
631   MempoolObs *mempool_obs = 0;
632   lookup_or_create_singleton_object(mempool_obs, "mempool_obs");
633 }
634
635 CephContext::~CephContext()
636 {
637   join_service_thread();
638
639   for (map<string, SingletonWrapper*>::iterator it = _associated_objs.begin();
640        it != _associated_objs.end(); ++it)
641     delete it->second;
642
643   if (_cct_perf) {
644     _perf_counters_collection->remove(_cct_perf);
645     delete _cct_perf;
646     _cct_perf = NULL;
647   }
648
649   delete _plugin_registry;
650
651   _admin_socket->unregister_command("perfcounters_dump");
652   _admin_socket->unregister_command("1");
653   _admin_socket->unregister_command("perf dump");
654   _admin_socket->unregister_command("perfcounters_schema");
655   _admin_socket->unregister_command("perf histogram dump");
656   _admin_socket->unregister_command("2");
657   _admin_socket->unregister_command("perf schema");
658   _admin_socket->unregister_command("perf histogram schema");
659   _admin_socket->unregister_command("perf reset");
660   _admin_socket->unregister_command("config show");
661   _admin_socket->unregister_command("config set");
662   _admin_socket->unregister_command("config get");
663   _admin_socket->unregister_command("config help");
664   _admin_socket->unregister_command("config diff");
665   _admin_socket->unregister_command("config diff get");
666   _admin_socket->unregister_command("log flush");
667   _admin_socket->unregister_command("log dump");
668   _admin_socket->unregister_command("log reopen");
669   delete _admin_hook;
670   delete _admin_socket;
671
672   delete _heartbeat_map;
673
674   delete _perf_counters_collection;
675   _perf_counters_collection = NULL;
676
677   delete _perf_counters_conf_obs;
678   _perf_counters_conf_obs = NULL;
679
680   _conf->remove_observer(_log_obs);
681   delete _log_obs;
682   _log_obs = NULL;
683
684   _conf->remove_observer(_cct_obs);
685   delete _cct_obs;
686   _cct_obs = NULL;
687
688   _conf->remove_observer(_lockdep_obs);
689   delete _lockdep_obs;
690   _lockdep_obs = NULL;
691
692   _log->stop();
693   delete _log;
694   _log = NULL;
695
696   delete _conf;
697   ceph_spin_destroy(&_service_thread_lock);
698   ceph_spin_destroy(&_fork_watchers_lock);
699   ceph_spin_destroy(&_associated_objs_lock);
700   ceph_spin_destroy(&_feature_lock);
701   ceph_spin_destroy(&_cct_perf_lock);
702
703   delete _crypto_none;
704   delete _crypto_aes;
705   if (_crypto_inited)
706     ceph::crypto::shutdown(g_code_env == CODE_ENVIRONMENT_LIBRARY);
707 }
708
709 void CephContext::put() {
710   if (--nref == 0) {
711     ANNOTATE_HAPPENS_AFTER(&nref);
712     ANNOTATE_HAPPENS_BEFORE_FORGET_ALL(&nref);
713     delete this;
714   } else {
715     ANNOTATE_HAPPENS_BEFORE(&nref);
716   }
717 }
718
719 void CephContext::init_crypto()
720 {
721   if (!_crypto_inited) {
722     ceph::crypto::init(this);
723     _crypto_inited = true;
724   }
725 }
726
727 void CephContext::start_service_thread()
728 {
729   ceph_spin_lock(&_service_thread_lock);
730   if (_service_thread) {
731     ceph_spin_unlock(&_service_thread_lock);
732     return;
733   }
734   _service_thread = new CephContextServiceThread(this);
735   _service_thread->create("service");
736   ceph_spin_unlock(&_service_thread_lock);
737
738   // make logs flush on_exit()
739   if (_conf->log_flush_on_exit)
740     _log->set_flush_on_exit();
741
742   // Trigger callbacks on any config observers that were waiting for
743   // it to become safe to start threads.
744   _conf->set_val("internal_safe_to_start_threads", "true");
745   _conf->call_all_observers();
746
747   // start admin socket
748   if (_conf->admin_socket.length())
749     _admin_socket->init(_conf->admin_socket);
750 }
751
752 void CephContext::reopen_logs()
753 {
754   ceph_spin_lock(&_service_thread_lock);
755   if (_service_thread)
756     _service_thread->reopen_logs();
757   ceph_spin_unlock(&_service_thread_lock);
758 }
759
760 void CephContext::join_service_thread()
761 {
762   ceph_spin_lock(&_service_thread_lock);
763   CephContextServiceThread *thread = _service_thread;
764   if (!thread) {
765     ceph_spin_unlock(&_service_thread_lock);
766     return;
767   }
768   _service_thread = NULL;
769   ceph_spin_unlock(&_service_thread_lock);
770
771   thread->exit_thread();
772   thread->join();
773   delete thread;
774 }
775
776 uint32_t CephContext::get_module_type() const
777 {
778   return _module_type;
779 }
780
781 void CephContext::set_init_flags(int flags)
782 {
783   _init_flags = flags;
784 }
785
786 int CephContext::get_init_flags() const
787 {
788   return _init_flags;
789 }
790
791 PerfCountersCollection *CephContext::get_perfcounters_collection()
792 {
793   return _perf_counters_collection;
794 }
795
796 void CephContext::enable_perf_counter()
797 {
798   PerfCountersBuilder plb(this, "cct", l_cct_first, l_cct_last);
799   plb.add_u64(l_cct_total_workers, "total_workers", "Total workers");
800   plb.add_u64(l_cct_unhealthy_workers, "unhealthy_workers", "Unhealthy workers");
801   PerfCounters *perf_tmp = plb.create_perf_counters();
802
803   ceph_spin_lock(&_cct_perf_lock);
804   assert(_cct_perf == NULL);
805   _cct_perf = perf_tmp;
806   ceph_spin_unlock(&_cct_perf_lock);
807
808   _perf_counters_collection->add(_cct_perf);
809 }
810
811 void CephContext::disable_perf_counter()
812 {
813   _perf_counters_collection->remove(_cct_perf);
814
815   ceph_spin_lock(&_cct_perf_lock);
816   delete _cct_perf;
817   _cct_perf = NULL;
818   ceph_spin_unlock(&_cct_perf_lock);
819 }
820
821 void CephContext::refresh_perf_values()
822 {
823   ceph_spin_lock(&_cct_perf_lock);
824   if (_cct_perf) {
825     _cct_perf->set(l_cct_total_workers, _heartbeat_map->get_total_workers());
826     _cct_perf->set(l_cct_unhealthy_workers, _heartbeat_map->get_unhealthy_workers());
827   }
828   ceph_spin_unlock(&_cct_perf_lock);
829 }
830
831 AdminSocket *CephContext::get_admin_socket()
832 {
833   return _admin_socket;
834 }
835
836 CryptoHandler *CephContext::get_crypto_handler(int type)
837 {
838   switch (type) {
839   case CEPH_CRYPTO_NONE:
840     return _crypto_none;
841   case CEPH_CRYPTO_AES:
842     return _crypto_aes;
843   default:
844     return NULL;
845   }
846 }