]> git.proxmox.com Git - ceph.git/blame - ceph/src/os/bluestore/bluestore_tool.cc
Import ceph 15.2.8
[ceph.git] / ceph / src / os / bluestore / bluestore_tool.cc
CommitLineData
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#include <boost/program_options/variables_map.hpp>
5#include <boost/program_options/parsers.hpp>
6
7#include <stdio.h>
8#include <string.h>
9#include <iostream>
10#include <time.h>
11#include <fcntl.h>
12#include <unistd.h>
13#include "global/global_init.h"
14#include "common/ceph_argparse.h"
15#include "include/stringify.h"
16#include "common/errno.h"
3efd9988 17#include "common/safe_io.h"
7c673cae
FG
18
19#include "os/bluestore/BlueFS.h"
20#include "os/bluestore/BlueStore.h"
eafe8130 21#include "common/admin_socket.h"
7c673cae
FG
22
23namespace po = boost::program_options;
24
25void usage(po::options_description &desc)
26{
27 cout << desc << std::endl;
28}
29
c07f9fc5
FG
30void validate_path(CephContext *cct, const string& path, bool bluefs)
31{
32 BlueStore bluestore(cct, path);
33 string type;
34 int r = bluestore.read_meta("type", &type);
35 if (r < 0) {
36 cerr << "failed to load os-type: " << cpp_strerror(r) << std::endl;
37 exit(EXIT_FAILURE);
38 }
39 if (type != "bluestore") {
40 cerr << "expected bluestore, but type is " << type << std::endl;
41 exit(EXIT_FAILURE);
42 }
43 if (!bluefs) {
44 return;
45 }
46
47 string kv_backend;
48 r = bluestore.read_meta("kv_backend", &kv_backend);
49 if (r < 0) {
50 cerr << "failed to load kv_backend: " << cpp_strerror(r) << std::endl;
51 exit(EXIT_FAILURE);
52 }
53 if (kv_backend != "rocksdb") {
54 cerr << "expect kv_backend to be rocksdb, but is " << kv_backend
55 << std::endl;
56 exit(EXIT_FAILURE);
57 }
58 string bluefs_enabled;
59 r = bluestore.read_meta("bluefs", &bluefs_enabled);
60 if (r < 0) {
61 cerr << "failed to load do_bluefs: " << cpp_strerror(r) << std::endl;
62 exit(EXIT_FAILURE);
63 }
64 if (bluefs_enabled != "1") {
65 cerr << "bluefs not enabled for rocksdb" << std::endl;
66 exit(EXIT_FAILURE);
67 }
68}
69
f64942e4
AA
70const char* find_device_path(
71 int id,
72 CephContext *cct,
73 const vector<string>& devs)
74{
75 for (auto& i : devs) {
76 bluestore_bdev_label_t label;
77 int r = BlueStore::_read_bdev_label(cct, i, &label);
78 if (r < 0) {
79 cerr << "unable to read label for " << i << ": "
80 << cpp_strerror(r) << std::endl;
81 exit(EXIT_FAILURE);
82 }
83 if ((id == BlueFS::BDEV_SLOW && label.description == "main") ||
84 (id == BlueFS::BDEV_DB && label.description == "bluefs db") ||
85 (id == BlueFS::BDEV_WAL && label.description == "bluefs wal")) {
86 return i.c_str();
87 }
88 }
89 return nullptr;
90}
91
11fdf7f2 92void parse_devices(
3efd9988 93 CephContext *cct,
11fdf7f2
TL
94 const vector<string>& devs,
95 map<string, int>* got,
96 bool* has_db,
97 bool* has_wal)
3efd9988 98{
3efd9988 99 string main;
11fdf7f2
TL
100 bool was_db = false;
101 if (has_wal) {
102 *has_wal = false;
103 }
104 if (has_db) {
105 *has_db = false;
106 }
107 for (auto& d : devs) {
3efd9988 108 bluestore_bdev_label_t label;
11fdf7f2 109 int r = BlueStore::_read_bdev_label(cct, d, &label);
3efd9988 110 if (r < 0) {
11fdf7f2 111 cerr << "unable to read label for " << d << ": "
3efd9988
FG
112 << cpp_strerror(r) << std::endl;
113 exit(EXIT_FAILURE);
114 }
115 int id = -1;
116 if (label.description == "main")
11fdf7f2
TL
117 main = d;
118 else if (label.description == "bluefs db") {
3efd9988 119 id = BlueFS::BDEV_DB;
11fdf7f2
TL
120 was_db = true;
121 if (has_db) {
122 *has_db = true;
123 }
124 }
125 else if (label.description == "bluefs wal") {
3efd9988 126 id = BlueFS::BDEV_WAL;
11fdf7f2
TL
127 if (has_wal) {
128 *has_wal = true;
3efd9988
FG
129 }
130 }
11fdf7f2
TL
131 if (id >= 0) {
132 got->emplace(d, id);
133 }
3efd9988
FG
134 }
135 if (main.length()) {
11fdf7f2
TL
136 int id = was_db ? BlueFS::BDEV_SLOW : BlueFS::BDEV_DB;
137 got->emplace(main, id);
138 }
139}
140
141void add_devices(
142 BlueFS *fs,
143 CephContext *cct,
144 const vector<string>& devs)
145{
146 map<string, int> got;
147 parse_devices(cct, devs, &got, nullptr, nullptr);
148 for(auto e : got) {
149 char target_path[PATH_MAX] = "";
150 if(!e.first.empty()) {
151 if (realpath(e.first.c_str(), target_path) == nullptr) {
152 cerr << "failed to retrieve absolute path for " << e.first
153 << ": " << cpp_strerror(errno)
154 << std::endl;
155 }
156 }
157
158 cout << " slot " << e.second << " " << e.first;
159 if (target_path[0]) {
160 cout << " -> " << target_path;
161 }
162 cout << std::endl;
163 int r = fs->add_block_device(e.second, e.first, false);
3efd9988 164 if (r < 0) {
11fdf7f2 165 cerr << "unable to open " << e.first << ": " << cpp_strerror(r) << std::endl;
3efd9988
FG
166 exit(EXIT_FAILURE);
167 }
168 }
11fdf7f2
TL
169}
170
171BlueFS *open_bluefs(
172 CephContext *cct,
173 const string& path,
174 const vector<string>& devs)
175{
176 validate_path(cct, path, true);
177 BlueFS *fs = new BlueFS(cct);
178
179 add_devices(fs, cct, devs);
3efd9988
FG
180
181 int r = fs->mount();
182 if (r < 0) {
183 cerr << "unable to mount bluefs: " << cpp_strerror(r)
184 << std::endl;
185 exit(EXIT_FAILURE);
186 }
187 return fs;
188}
189
11fdf7f2
TL
190void log_dump(
191 CephContext *cct,
192 const string& path,
193 const vector<string>& devs)
194{
195 BlueFS* fs = open_bluefs(cct, path, devs);
196 int r = fs->log_dump();
197 if (r < 0) {
198 cerr << "log_dump failed" << ": "
199 << cpp_strerror(r) << std::endl;
200 exit(EXIT_FAILURE);
201 }
202
203 delete fs;
204}
205
206void inferring_bluefs_devices(vector<string>& devs, std::string& path)
207{
208 cout << "inferring bluefs devices from bluestore path" << std::endl;
209 for (auto fn : {"block", "block.wal", "block.db"}) {
210 string p = path + "/" + fn;
211 struct stat st;
212 if (::stat(p.c_str(), &st) == 0) {
213 devs.push_back(p);
214 }
215 }
216}
217
7c673cae
FG
218int main(int argc, char **argv)
219{
220 string out_dir;
221 vector<string> devs;
11fdf7f2
TL
222 vector<string> devs_source;
223 string dev_target;
7c673cae
FG
224 string path;
225 string action;
3efd9988
FG
226 string log_file;
227 string key, value;
eafe8130 228 vector<string> allocs_name;
3efd9988 229 int log_level = 30;
31f18b77 230 bool fsck_deep = false;
7c673cae
FG
231 po::options_description po_options("Options");
232 po_options.add_options()
233 ("help,h", "produce help message")
234 ("path", po::value<string>(&path), "bluestore path")
235 ("out-dir", po::value<string>(&out_dir), "output directory")
3efd9988
FG
236 ("log-file,l", po::value<string>(&log_file), "log file")
237 ("log-level", po::value<int>(&log_level), "log level (30=most, 20=lots, 10=some, 1=little)")
7c673cae 238 ("dev", po::value<vector<string>>(&devs), "device(s)")
11fdf7f2
TL
239 ("devs-source", po::value<vector<string>>(&devs_source), "bluefs-dev-migrate source device(s)")
240 ("dev-target", po::value<string>(&dev_target), "target/resulting device")
7c673cae 241 ("deep", po::value<bool>(&fsck_deep), "deep fsck (read all data)")
3efd9988
FG
242 ("key,k", po::value<string>(&key), "label metadata key name")
243 ("value,v", po::value<string>(&value), "label metadata value")
eafe8130 244 ("allocator", po::value<vector<string>>(&allocs_name), "allocator to inspect: 'block'/'bluefs-wal'/'bluefs-db'/'bluefs-slow'")
7c673cae
FG
245 ;
246 po::options_description po_positional("Positional options");
247 po_positional.add_options()
eafe8130
TL
248 ("command", po::value<string>(&action),
249 "fsck, "
250 "repair, "
251 "quick-fix, "
252 "bluefs-export, "
253 "bluefs-bdev-sizes, "
254 "bluefs-bdev-expand, "
255 "bluefs-bdev-new-db, "
256 "bluefs-bdev-new-wal, "
257 "bluefs-bdev-migrate, "
258 "show-label, "
259 "set-label-key, "
260 "rm-label-key, "
261 "prime-osd-dir, "
262 "bluefs-log-dump, "
263 "free-dump, "
f6b5b4d7
TL
264 "free-score, "
265 "bluefs-stats")
7c673cae
FG
266 ;
267 po::options_description po_all("All options");
268 po_all.add(po_options).add(po_positional);
269 po::positional_options_description pd;
270 pd.add("command", 1);
271
272 vector<string> ceph_option_strings;
273 po::variables_map vm;
274 try {
275 po::parsed_options parsed =
276 po::command_line_parser(argc, argv).options(po_all).allow_unregistered().positional(pd).run();
277 po::store( parsed, vm);
278 po::notify(vm);
279 ceph_option_strings = po::collect_unrecognized(parsed.options,
280 po::include_positional);
281 } catch(po::error &e) {
282 std::cerr << e.what() << std::endl;
c07f9fc5 283 exit(EXIT_FAILURE);
7c673cae 284 }
11fdf7f2
TL
285 // normalize path (remove ending '/' if any)
286 if (path.size() > 1 && *(path.end() - 1) == '/') {
287 path.resize(path.size() - 1);
288 }
7c673cae
FG
289 if (vm.count("help")) {
290 usage(po_all);
c07f9fc5 291 exit(EXIT_SUCCESS);
7c673cae
FG
292 }
293 if (action.empty()) {
294 cerr << "must specify an action; --help for help" << std::endl;
c07f9fc5 295 exit(EXIT_FAILURE);
7c673cae
FG
296 }
297
eafe8130 298 if (action == "fsck" || action == "repair" || action == "quick-fix") {
7c673cae
FG
299 if (path.empty()) {
300 cerr << "must specify bluestore path" << std::endl;
c07f9fc5 301 exit(EXIT_FAILURE);
7c673cae
FG
302 }
303 }
3efd9988
FG
304 if (action == "prime-osd-dir") {
305 if (devs.size() != 1) {
306 cerr << "must specify the main bluestore device" << std::endl;
307 exit(EXIT_FAILURE);
308 }
309 if (path.empty()) {
310 cerr << "must specify osd dir to prime" << std::endl;
311 exit(EXIT_FAILURE);
312 }
313 }
314 if (action == "set-label-key" ||
315 action == "rm-label-key") {
316 if (devs.size() != 1) {
317 cerr << "must specify the main bluestore device" << std::endl;
318 exit(EXIT_FAILURE);
319 }
320 if (key.size() == 0) {
321 cerr << "must specify a key name with -k" << std::endl;
322 exit(EXIT_FAILURE);
323 }
324 if (action == "set-label-key" && value.size() == 0) {
325 cerr << "must specify a value with -v" << std::endl;
326 exit(EXIT_FAILURE);
327 }
328 }
c07f9fc5 329 if (action == "show-label") {
7c673cae
FG
330 if (devs.empty() && path.empty()) {
331 cerr << "must specify bluestore path *or* raw device(s)" << std::endl;
c07f9fc5 332 exit(EXIT_FAILURE);
7c673cae 333 }
11fdf7f2
TL
334 if (devs.empty())
335 inferring_bluefs_devices(devs, path);
7c673cae 336 }
11fdf7f2 337 if (action == "bluefs-export" || action == "bluefs-log-dump") {
c07f9fc5
FG
338 if (path.empty()) {
339 cerr << "must specify bluestore path" << std::endl;
340 exit(EXIT_FAILURE);
341 }
11fdf7f2 342 if ((action == "bluefs-export") && out_dir.empty()) {
c07f9fc5
FG
343 cerr << "must specify out-dir to export bluefs" << std::endl;
344 exit(EXIT_FAILURE);
345 }
11fdf7f2 346 inferring_bluefs_devices(devs, path);
c07f9fc5 347 }
3efd9988
FG
348 if (action == "bluefs-bdev-sizes" || action == "bluefs-bdev-expand") {
349 if (path.empty()) {
350 cerr << "must specify bluestore path" << std::endl;
351 exit(EXIT_FAILURE);
352 }
11fdf7f2
TL
353 inferring_bluefs_devices(devs, path);
354 }
355 if (action == "bluefs-bdev-new-db" || action == "bluefs-bdev-new-wal") {
356 if (path.empty()) {
357 cerr << "must specify bluestore path" << std::endl;
358 exit(EXIT_FAILURE);
359 }
360 if (dev_target.empty()) {
361 cout << "NOTICE: --dev-target option omitted, will allocate as a file" << std::endl;
362 }
363 inferring_bluefs_devices(devs, path);
364 }
365 if (action == "bluefs-bdev-migrate") {
366 if (path.empty()) {
367 cerr << "must specify bluestore path" << std::endl;
368 exit(EXIT_FAILURE);
369 }
370 inferring_bluefs_devices(devs, path);
371 if (devs_source.size() == 0) {
372 cerr << "must specify source devices with --devs-source" << std::endl;
373 exit(EXIT_FAILURE);
374 }
375 if (dev_target.empty()) {
376 cerr << "must specify target device with --dev-target" << std::endl;
377 exit(EXIT_FAILURE);
3efd9988
FG
378 }
379 }
eafe8130
TL
380 if (action == "free-score" || action == "free-dump") {
381 if (path.empty()) {
382 cerr << "must specify bluestore path" << std::endl;
383 exit(EXIT_FAILURE);
384 }
385 for (auto name : allocs_name) {
386 if (!name.empty() &&
387 name != "block" &&
388 name != "bluefs-db" &&
389 name != "bluefs-wal" &&
390 name != "bluefs-slow") {
391 cerr << "unknown allocator '" << name << "'" << std::endl;
392 exit(EXIT_FAILURE);
393 }
394 }
395 if (allocs_name.empty())
396 allocs_name = vector<string>{"block", "bluefs-db", "bluefs-wal", "bluefs-slow"};
397 }
7c673cae 398 vector<const char*> args;
3efd9988
FG
399 if (log_file.size()) {
400 args.push_back("--log-file");
401 args.push_back(log_file.c_str());
402 static char ll[10];
403 snprintf(ll, sizeof(ll), "%d", log_level);
404 args.push_back("--debug-bluestore");
405 args.push_back(ll);
406 args.push_back("--debug-bluefs");
407 args.push_back(ll);
408 }
409 args.push_back("--no-log-to-stderr");
410 args.push_back("--err-to-stderr");
411
7c673cae
FG
412 for (auto& i : ceph_option_strings) {
413 args.push_back(i.c_str());
414 }
7c673cae 415 auto cct = global_init(NULL, args, CEPH_ENTITY_TYPE_CLIENT,
f64942e4
AA
416 CODE_ENVIRONMENT_UTILITY,
417 CINIT_FLAG_NO_DEFAULT_CONFIG_FILE);
418
7c673cae
FG
419 common_init_finish(cct.get());
420
7c673cae 421 if (action == "fsck" ||
eafe8130
TL
422 action == "repair" ||
423 action == "quick-fix") {
c07f9fc5 424 validate_path(cct.get(), path, false);
7c673cae 425 BlueStore bluestore(cct.get(), path);
3efd9988
FG
426 int r;
427 if (action == "fsck") {
428 r = bluestore.fsck(fsck_deep);
eafe8130 429 } else if (action == "repair") {
3efd9988 430 r = bluestore.repair(fsck_deep);
eafe8130
TL
431 } else {
432 r = bluestore.quick_fix();
3efd9988 433 }
7c673cae 434 if (r < 0) {
9f95a23c 435 cerr << action << " failed: " << cpp_strerror(r) << std::endl;
c07f9fc5 436 exit(EXIT_FAILURE);
11fdf7f2 437 } else if (r > 0) {
9f95a23c 438 cerr << action << " status: remaining " << r << " error(s) and warning(s)" << std::endl;
11fdf7f2
TL
439 exit(EXIT_FAILURE);
440 } else {
441 cout << action << " success" << std::endl;
7c673cae 442 }
3efd9988
FG
443 }
444 else if (action == "prime-osd-dir") {
445 bluestore_bdev_label_t label;
446 int r = BlueStore::_read_bdev_label(cct.get(), devs.front(), &label);
447 if (r < 0) {
448 cerr << "failed to read label for " << devs.front() << ": "
449 << cpp_strerror(r) << std::endl;
450 exit(EXIT_FAILURE);
451 }
452
453 // kludge some things into the map that we want to populate into
454 // target dir
455 label.meta["path_block"] = devs.front();
456 label.meta["type"] = "bluestore";
457 label.meta["fsid"] = stringify(label.osd_uuid);
458
459 for (auto kk : {
460 "whoami",
461 "osd_key",
3efd9988
FG
462 "ceph_fsid",
463 "fsid",
464 "type",
465 "ready" }) {
466 string k = kk;
467 auto i = label.meta.find(k);
468 if (i == label.meta.end()) {
469 continue;
470 }
471 string p = path + "/" + k;
472 string v = i->second;
473 if (k == "osd_key") {
474 p = path + "/keyring";
475 v = "[osd.";
476 v += label.meta["whoami"];
477 v += "]\nkey = " + i->second;
478 }
11fdf7f2
TL
479 v += "\n";
480 int fd = ::open(p.c_str(), O_CREAT|O_TRUNC|O_WRONLY|O_CLOEXEC, 0600);
481 if (fd < 0) {
482 cerr << "error writing " << p << ": " << cpp_strerror(errno)
483 << std::endl;
484 exit(EXIT_FAILURE);
3efd9988 485 }
11fdf7f2
TL
486 int r = safe_write(fd, v.c_str(), v.size());
487 if (r < 0) {
488 cerr << "error writing to " << p << ": " << cpp_strerror(errno)
489 << std::endl;
490 exit(EXIT_FAILURE);
491 }
492 ::close(fd);
3efd9988 493 }
7c673cae
FG
494 }
495 else if (action == "show-label") {
496 JSONFormatter jf(true);
3efd9988 497 jf.open_object_section("devices");
7c673cae
FG
498 for (auto& i : devs) {
499 bluestore_bdev_label_t label;
500 int r = BlueStore::_read_bdev_label(cct.get(), i, &label);
501 if (r < 0) {
502 cerr << "unable to read label for " << i << ": "
503 << cpp_strerror(r) << std::endl;
c07f9fc5 504 exit(EXIT_FAILURE);
7c673cae
FG
505 }
506 jf.open_object_section(i.c_str());
507 label.dump(&jf);
508 jf.close_section();
509 }
510 jf.close_section();
511 jf.flush(cout);
512 }
3efd9988
FG
513 else if (action == "set-label-key") {
514 bluestore_bdev_label_t label;
515 int r = BlueStore::_read_bdev_label(cct.get(), devs.front(), &label);
516 if (r < 0) {
517 cerr << "unable to read label for " << devs.front() << ": "
518 << cpp_strerror(r) << std::endl;
519 exit(EXIT_FAILURE);
7c673cae 520 }
f64942e4
AA
521 if (key == "size") {
522 label.size = strtoull(value.c_str(), nullptr, 10);
523 } else if (key =="osd_uuid") {
524 label.osd_uuid.parse(value.c_str());
525 } else if (key =="btime") {
526 uint64_t epoch;
527 uint64_t nsec;
528 int r = utime_t::parse_date(value.c_str(), &epoch, &nsec);
529 if (r == 0) {
530 label.btime = utime_t(epoch, nsec);
531 }
532 } else if (key =="description") {
533 label.description = value;
534 } else {
535 label.meta[key] = value;
536 }
3efd9988
FG
537 r = BlueStore::_write_bdev_label(cct.get(), devs.front(), label);
538 if (r < 0) {
539 cerr << "unable to write label for " << devs.front() << ": "
540 << cpp_strerror(r) << std::endl;
541 exit(EXIT_FAILURE);
7c673cae 542 }
3efd9988
FG
543 }
544 else if (action == "rm-label-key") {
545 bluestore_bdev_label_t label;
546 int r = BlueStore::_read_bdev_label(cct.get(), devs.front(), &label);
7c673cae 547 if (r < 0) {
3efd9988
FG
548 cerr << "unable to read label for " << devs.front() << ": "
549 << cpp_strerror(r) << std::endl;
550 exit(EXIT_FAILURE);
551 }
552 if (!label.meta.count(key)) {
553 cerr << "key '" << key << "' not present" << std::endl;
554 exit(EXIT_FAILURE);
555 }
556 label.meta.erase(key);
557 r = BlueStore::_write_bdev_label(cct.get(), devs.front(), label);
558 if (r < 0) {
559 cerr << "unable to write label for " << devs.front() << ": "
560 << cpp_strerror(r) << std::endl;
c07f9fc5 561 exit(EXIT_FAILURE);
7c673cae 562 }
3efd9988
FG
563 }
564 else if (action == "bluefs-bdev-sizes") {
1911f103
TL
565 BlueStore bluestore(cct.get(), path);
566 bluestore.dump_bluefs_sizes(cout);
3efd9988
FG
567 }
568 else if (action == "bluefs-bdev-expand") {
11fdf7f2
TL
569 BlueStore bluestore(cct.get(), path);
570 auto r = bluestore.expand_devices(cout);
571 if (r <0) {
572 cerr << "failed to expand bluestore devices: "
573 << cpp_strerror(r) << std::endl;
574 exit(EXIT_FAILURE);
3efd9988 575 }
3efd9988
FG
576 }
577 else if (action == "bluefs-export") {
578 BlueFS *fs = open_bluefs(cct.get(), path, devs);
7c673cae
FG
579
580 vector<string> dirs;
3efd9988 581 int r = fs->readdir("", &dirs);
7c673cae
FG
582 if (r < 0) {
583 cerr << "readdir in root failed: " << cpp_strerror(r) << std::endl;
c07f9fc5 584 exit(EXIT_FAILURE);
7c673cae 585 }
11fdf7f2
TL
586
587 if (::access(out_dir.c_str(), F_OK)) {
588 r = ::mkdir(out_dir.c_str(), 0755);
589 if (r < 0) {
590 r = -errno;
591 cerr << "mkdir " << out_dir << " failed: " << cpp_strerror(r) << std::endl;
592 exit(EXIT_FAILURE);
593 }
594 }
595
7c673cae
FG
596 for (auto& dir : dirs) {
597 if (dir[0] == '.')
598 continue;
599 cout << dir << "/" << std::endl;
600 vector<string> ls;
3efd9988 601 r = fs->readdir(dir, &ls);
7c673cae
FG
602 if (r < 0) {
603 cerr << "readdir " << dir << " failed: " << cpp_strerror(r) << std::endl;
c07f9fc5 604 exit(EXIT_FAILURE);
7c673cae
FG
605 }
606 string full = out_dir + "/" + dir;
11fdf7f2
TL
607 if (::access(full.c_str(), F_OK)) {
608 r = ::mkdir(full.c_str(), 0755);
609 if (r < 0) {
610 r = -errno;
611 cerr << "mkdir " << full << " failed: " << cpp_strerror(r) << std::endl;
612 exit(EXIT_FAILURE);
613 }
7c673cae
FG
614 }
615 for (auto& file : ls) {
616 if (file[0] == '.')
617 continue;
618 cout << dir << "/" << file << std::endl;
619 uint64_t size;
620 utime_t mtime;
3efd9988 621 r = fs->stat(dir, file, &size, &mtime);
7c673cae
FG
622 if (r < 0) {
623 cerr << "stat " << file << " failed: " << cpp_strerror(r) << std::endl;
c07f9fc5 624 exit(EXIT_FAILURE);
7c673cae
FG
625 }
626 string path = out_dir + "/" + dir + "/" + file;
91327a77 627 int fd = ::open(path.c_str(), O_CREAT|O_WRONLY|O_TRUNC|O_CLOEXEC, 0644);
7c673cae
FG
628 if (fd < 0) {
629 r = -errno;
630 cerr << "open " << path << " failed: " << cpp_strerror(r) << std::endl;
c07f9fc5 631 exit(EXIT_FAILURE);
7c673cae 632 }
7c673cae
FG
633 if (size > 0) {
634 BlueFS::FileReader *h;
3efd9988 635 r = fs->open_for_read(dir, file, &h, false);
7c673cae
FG
636 if (r < 0) {
637 cerr << "open_for_read " << dir << "/" << file << " failed: "
638 << cpp_strerror(r) << std::endl;
c07f9fc5 639 exit(EXIT_FAILURE);
7c673cae
FG
640 }
641 int pos = 0;
642 int left = size;
643 while (left) {
644 bufferlist bl;
3efd9988 645 r = fs->read(h, &h->buf, pos, left, &bl, NULL);
7c673cae
FG
646 if (r <= 0) {
647 cerr << "read " << dir << "/" << file << " from " << pos
648 << " failed: " << cpp_strerror(r) << std::endl;
c07f9fc5 649 exit(EXIT_FAILURE);
7c673cae
FG
650 }
651 int rc = bl.write_fd(fd);
652 if (rc < 0) {
653 cerr << "write to " << path << " failed: "
654 << cpp_strerror(r) << std::endl;
c07f9fc5 655 exit(EXIT_FAILURE);
7c673cae
FG
656 }
657 pos += r;
658 left -= r;
659 }
660 delete h;
661 }
662 ::close(fd);
663 }
664 }
3efd9988
FG
665 fs->umount();
666 delete fs;
11fdf7f2
TL
667 } else if (action == "bluefs-log-dump") {
668 log_dump(cct.get(), path, devs);
669 } else if (action == "bluefs-bdev-new-db" || action == "bluefs-bdev-new-wal") {
670 map<string, int> cur_devs_map;
671 bool need_db = action == "bluefs-bdev-new-db";
672
673 bool has_wal = false;
674 bool has_db = false;
675 char target_path[PATH_MAX] = "";
676
677 parse_devices(cct.get(), devs, &cur_devs_map, &has_db, &has_wal);
678
679 if (has_db && has_wal) {
680 cerr << "can't allocate new device, both WAL and DB exist"
681 << std::endl;
682 exit(EXIT_FAILURE);
683 } else if (need_db && has_db) {
684 cerr << "can't allocate new DB device, already exists"
685 << std::endl;
686 exit(EXIT_FAILURE);
687 } else if (!need_db && has_wal) {
688 cerr << "can't allocate new WAL device, already exists"
689 << std::endl;
690 exit(EXIT_FAILURE);
691 } else if(!dev_target.empty() &&
692 realpath(dev_target.c_str(), target_path) == nullptr) {
693 cerr << "failed to retrieve absolute path for " << dev_target
694 << ": " << cpp_strerror(errno)
695 << std::endl;
696 exit(EXIT_FAILURE);
697 }
698
699 // Create either DB or WAL volume
700 int r = EXIT_FAILURE;
701 if (need_db && cct->_conf->bluestore_block_db_size == 0) {
702 cerr << "DB size isn't specified, "
703 "please set Ceph bluestore-block-db-size config parameter "
704 << std::endl;
705 } else if (!need_db && cct->_conf->bluestore_block_wal_size == 0) {
706 cerr << "WAL size isn't specified, "
707 "please set Ceph bluestore-block-wal-size config parameter "
708 << std::endl;
709 } else {
710 BlueStore bluestore(cct.get(), path);
711 r = bluestore.add_new_bluefs_device(
712 need_db ? BlueFS::BDEV_NEWDB : BlueFS::BDEV_NEWWAL,
713 target_path);
714 if (r == 0) {
715 cout << (need_db ? "DB" : "WAL") << " device added " << target_path
716 << std::endl;
717 } else {
718 cerr << "failed to add " << (need_db ? "DB" : "WAL") << " device:"
719 << cpp_strerror(r)
720 << std::endl;
721 }
722 return r;
723 }
724 } else if (action == "bluefs-bdev-migrate") {
725 map<string, int> cur_devs_map;
726 set<int> src_dev_ids;
727 map<string, int> src_devs;
728
729 parse_devices(cct.get(), devs, &cur_devs_map, nullptr, nullptr);
730 for (auto& s : devs_source) {
731 auto i = cur_devs_map.find(s);
732 if (i != cur_devs_map.end()) {
494da23a
TL
733 if (s == dev_target) {
734 cerr << "Device " << dev_target
735 << " is present in both source and target lists, omitted."
736 << std::endl;
737 } else {
738 src_devs.emplace(*i);
739 src_dev_ids.emplace(i->second);
740 }
11fdf7f2
TL
741 } else {
742 cerr << "can't migrate " << s << ", not a valid bluefs volume "
743 << std::endl;
744 exit(EXIT_FAILURE);
745 }
746 }
747
748 auto i = cur_devs_map.find(dev_target);
749
750 if (i != cur_devs_map.end()) {
751 // Migrate to an existing BlueFS volume
752
753 auto dev_target_id = i->second;
754 if (dev_target_id == BlueFS::BDEV_WAL) {
755 // currently we're unable to migrate to WAL device since there is no space
756 // reserved for superblock
757 cerr << "Migrate to WAL device isn't supported." << std::endl;
758 exit(EXIT_FAILURE);
759 }
760
11fdf7f2
TL
761 BlueStore bluestore(cct.get(), path);
762 int r = bluestore.migrate_to_existing_bluefs_device(
763 src_dev_ids,
764 dev_target_id);
765 if (r == 0) {
766 for(auto src : src_devs) {
767 if (src.second != BlueFS::BDEV_SLOW) {
768 cout << " device removed:" << src.second << " " << src.first
769 << std::endl;
770 }
771 }
772 } else {
494da23a 773 bool need_db = dev_target_id == BlueFS::BDEV_DB;
11fdf7f2 774 cerr << "failed to migrate to existing BlueFS device: "
494da23a 775 << (need_db ? BlueFS::BDEV_DB : BlueFS::BDEV_WAL)
11fdf7f2
TL
776 << " " << dev_target
777 << cpp_strerror(r)
778 << std::endl;
779 }
494da23a 780 return r;
11fdf7f2
TL
781 } else {
782 // Migrate to a new BlueFS volume
783 // via creating either DB or WAL volume
784 char target_path[PATH_MAX] = "";
785 int dev_target_id;
786 if (src_dev_ids.count(BlueFS::BDEV_DB)) {
787 // if we have DB device in the source list - we create DB device
788 // (and may be remove WAL).
789 dev_target_id = BlueFS::BDEV_NEWDB;
790 } else if (src_dev_ids.count(BlueFS::BDEV_WAL)) {
791 dev_target_id = BlueFS::BDEV_NEWWAL;
792 } else {
793 cerr << "Unable to migrate Slow volume to new location, "
794 "please allocate new DB or WAL with "
795 "--bluefs-bdev-new-db(wal) command"
796 << std::endl;
797 exit(EXIT_FAILURE);
798 }
799 if(!dev_target.empty() &&
800 realpath(dev_target.c_str(), target_path) == nullptr) {
801 cerr << "failed to retrieve absolute path for " << dev_target
802 << ": " << cpp_strerror(errno)
803 << std::endl;
804 exit(EXIT_FAILURE);
805 }
806
807 BlueStore bluestore(cct.get(), path);
808
809 bool need_db = dev_target_id == BlueFS::BDEV_NEWDB;
810 int r = bluestore.migrate_to_new_bluefs_device(
811 src_dev_ids,
812 dev_target_id,
813 target_path);
814 if (r == 0) {
815 for(auto src : src_devs) {
816 if (src.second != BlueFS::BDEV_SLOW) {
817 cout << " device removed:" << src.second << " " << src.first
818 << std::endl;
819 }
820 }
821 cout << " device added: "
822 << (need_db ? BlueFS::BDEV_DB : BlueFS::BDEV_DB)
823 << " " << target_path
824 << std::endl;
825 } else {
826 cerr << "failed to migrate to new BlueFS device: "
827 << (need_db ? BlueFS::BDEV_DB : BlueFS::BDEV_DB)
828 << " " << target_path
829 << cpp_strerror(r)
830 << std::endl;
831 }
832 return r;
833 }
eafe8130
TL
834 } else if (action == "free-dump" || action == "free-score") {
835 AdminSocket *admin_socket = g_ceph_context->get_admin_socket();
836 ceph_assert(admin_socket);
837 std::string action_name = action == "free-dump" ? "dump" : "score";
838 validate_path(cct.get(), path, false);
839 BlueStore bluestore(cct.get(), path);
840 int r = bluestore.cold_open();
841 if (r < 0) {
842 cerr << "error from cold_open: " << cpp_strerror(r) << std::endl;
843 exit(EXIT_FAILURE);
844 }
845
846 for (auto alloc_name : allocs_name) {
9f95a23c
TL
847 ceph::bufferlist in, out;
848 ostringstream err;
f6b5b4d7 849 int r = admin_socket->execute_command(
9f95a23c
TL
850 {"{\"prefix\": \"bluestore allocator " + action_name + " " + alloc_name + "\"}"},
851 in, err, &out);
f6b5b4d7 852 if (r != 0) {
eafe8130
TL
853 cerr << "failure querying '" << alloc_name << "'" << std::endl;
854 exit(EXIT_FAILURE);
855 }
856 cout << alloc_name << ":" << std::endl;
857 cout << std::string(out.c_str(),out.length()) << std::endl;
858 }
859
860 bluestore.cold_close();
f6b5b4d7
TL
861 } else if (action == "bluefs-stats") {
862 AdminSocket* admin_socket = g_ceph_context->get_admin_socket();
863 ceph_assert(admin_socket);
864 validate_path(cct.get(), path, false);
865 BlueStore bluestore(cct.get(), path);
866 int r = bluestore.cold_open();
867 if (r < 0) {
868 cerr << "error from cold_open: " << cpp_strerror(r) << std::endl;
869 exit(EXIT_FAILURE);
870 }
871
872 ceph::bufferlist in, out;
873 ostringstream err;
874 r = admin_socket->execute_command(
875 { "{\"prefix\": \"bluefs stats\"}" },
876 in, err, &out);
877 if (r != 0) {
878 cerr << "failure querying bluefs stats: " << cpp_strerror(r) << std::endl;
879 exit(EXIT_FAILURE);
880 }
881 cout << std::string(out.c_str(), out.length()) << std::endl;
882 bluestore.cold_close();
7c673cae
FG
883 } else {
884 cerr << "unrecognized action " << action << std::endl;
885 return 1;
886 }
887
888 return 0;
889}