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  	  }
147  	  ~MempoolObs() override {
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  	
(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]
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) {
(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]
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