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