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