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