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