]> git.proxmox.com Git - ceph.git/blob - ceph/src/os/bluestore/bluestore_tool.cc
import ceph 14.2.5
[ceph.git] / ceph / src / os / bluestore / bluestore_tool.cc
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"
17 #include "common/safe_io.h"
18
19 #include "os/bluestore/BlueFS.h"
20 #include "os/bluestore/BlueStore.h"
21 #include "common/admin_socket.h"
22
23 namespace po = boost::program_options;
24
25 void usage(po::options_description &desc)
26 {
27 cout << desc << std::endl;
28 }
29
30 void 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
70 const 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
92 void parse_devices(
93 CephContext *cct,
94 const vector<string>& devs,
95 map<string, int>* got,
96 bool* has_db,
97 bool* has_wal)
98 {
99 string main;
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) {
108 bluestore_bdev_label_t label;
109 int r = BlueStore::_read_bdev_label(cct, d, &label);
110 if (r < 0) {
111 cerr << "unable to read label for " << d << ": "
112 << cpp_strerror(r) << std::endl;
113 exit(EXIT_FAILURE);
114 }
115 int id = -1;
116 if (label.description == "main")
117 main = d;
118 else if (label.description == "bluefs db") {
119 id = BlueFS::BDEV_DB;
120 was_db = true;
121 if (has_db) {
122 *has_db = true;
123 }
124 }
125 else if (label.description == "bluefs wal") {
126 id = BlueFS::BDEV_WAL;
127 if (has_wal) {
128 *has_wal = true;
129 }
130 }
131 if (id >= 0) {
132 got->emplace(d, id);
133 }
134 }
135 if (main.length()) {
136 int id = was_db ? BlueFS::BDEV_SLOW : BlueFS::BDEV_DB;
137 got->emplace(main, id);
138 }
139 }
140
141 void 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);
164 if (r < 0) {
165 cerr << "unable to open " << e.first << ": " << cpp_strerror(r) << std::endl;
166 exit(EXIT_FAILURE);
167 }
168 }
169 }
170
171 BlueFS *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);
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
190 void 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
206 void 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
218 int main(int argc, char **argv)
219 {
220 string out_dir;
221 vector<string> devs;
222 vector<string> devs_source;
223 string dev_target;
224 string path;
225 string action;
226 string log_file;
227 string key, value;
228 vector<string> allocs_name;
229 int log_level = 30;
230 bool fsck_deep = false;
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")
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)")
238 ("dev", po::value<vector<string>>(&devs), "device(s)")
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")
241 ("deep", po::value<bool>(&fsck_deep), "deep fsck (read all data)")
242 ("key,k", po::value<string>(&key), "label metadata key name")
243 ("value,v", po::value<string>(&value), "label metadata value")
244 ("allocator", po::value<vector<string>>(&allocs_name), "allocator to inspect: 'block'/'bluefs-wal'/'bluefs-db'/'bluefs-slow'")
245 ;
246 po::options_description po_positional("Positional options");
247 po_positional.add_options()
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, "
264 "free-score")
265 ;
266 po::options_description po_all("All options");
267 po_all.add(po_options).add(po_positional);
268 po::positional_options_description pd;
269 pd.add("command", 1);
270
271 vector<string> ceph_option_strings;
272 po::variables_map vm;
273 try {
274 po::parsed_options parsed =
275 po::command_line_parser(argc, argv).options(po_all).allow_unregistered().positional(pd).run();
276 po::store( parsed, vm);
277 po::notify(vm);
278 ceph_option_strings = po::collect_unrecognized(parsed.options,
279 po::include_positional);
280 } catch(po::error &e) {
281 std::cerr << e.what() << std::endl;
282 exit(EXIT_FAILURE);
283 }
284 // normalize path (remove ending '/' if any)
285 if (path.size() > 1 && *(path.end() - 1) == '/') {
286 path.resize(path.size() - 1);
287 }
288 if (vm.count("help")) {
289 usage(po_all);
290 exit(EXIT_SUCCESS);
291 }
292 if (action.empty()) {
293 cerr << "must specify an action; --help for help" << std::endl;
294 exit(EXIT_FAILURE);
295 }
296
297 if (action == "fsck" || action == "repair" || action == "quick-fix") {
298 if (path.empty()) {
299 cerr << "must specify bluestore path" << std::endl;
300 exit(EXIT_FAILURE);
301 }
302 }
303 if (action == "prime-osd-dir") {
304 if (devs.size() != 1) {
305 cerr << "must specify the main bluestore device" << std::endl;
306 exit(EXIT_FAILURE);
307 }
308 if (path.empty()) {
309 cerr << "must specify osd dir to prime" << std::endl;
310 exit(EXIT_FAILURE);
311 }
312 }
313 if (action == "set-label-key" ||
314 action == "rm-label-key") {
315 if (devs.size() != 1) {
316 cerr << "must specify the main bluestore device" << std::endl;
317 exit(EXIT_FAILURE);
318 }
319 if (key.size() == 0) {
320 cerr << "must specify a key name with -k" << std::endl;
321 exit(EXIT_FAILURE);
322 }
323 if (action == "set-label-key" && value.size() == 0) {
324 cerr << "must specify a value with -v" << std::endl;
325 exit(EXIT_FAILURE);
326 }
327 }
328 if (action == "show-label") {
329 if (devs.empty() && path.empty()) {
330 cerr << "must specify bluestore path *or* raw device(s)" << std::endl;
331 exit(EXIT_FAILURE);
332 }
333 if (devs.empty())
334 inferring_bluefs_devices(devs, path);
335 }
336 if (action == "bluefs-export" || action == "bluefs-log-dump") {
337 if (path.empty()) {
338 cerr << "must specify bluestore path" << std::endl;
339 exit(EXIT_FAILURE);
340 }
341 if ((action == "bluefs-export") && out_dir.empty()) {
342 cerr << "must specify out-dir to export bluefs" << std::endl;
343 exit(EXIT_FAILURE);
344 }
345 inferring_bluefs_devices(devs, path);
346 }
347 if (action == "bluefs-bdev-sizes" || action == "bluefs-bdev-expand") {
348 if (path.empty()) {
349 cerr << "must specify bluestore path" << std::endl;
350 exit(EXIT_FAILURE);
351 }
352 inferring_bluefs_devices(devs, path);
353 }
354 if (action == "bluefs-bdev-new-db" || action == "bluefs-bdev-new-wal") {
355 if (path.empty()) {
356 cerr << "must specify bluestore path" << std::endl;
357 exit(EXIT_FAILURE);
358 }
359 if (dev_target.empty()) {
360 cout << "NOTICE: --dev-target option omitted, will allocate as a file" << std::endl;
361 }
362 inferring_bluefs_devices(devs, path);
363 }
364 if (action == "bluefs-bdev-migrate") {
365 if (path.empty()) {
366 cerr << "must specify bluestore path" << std::endl;
367 exit(EXIT_FAILURE);
368 }
369 inferring_bluefs_devices(devs, path);
370 if (devs_source.size() == 0) {
371 cerr << "must specify source devices with --devs-source" << std::endl;
372 exit(EXIT_FAILURE);
373 }
374 if (dev_target.empty()) {
375 cerr << "must specify target device with --dev-target" << std::endl;
376 exit(EXIT_FAILURE);
377 }
378 }
379 if (action == "free-score" || action == "free-dump") {
380 if (path.empty()) {
381 cerr << "must specify bluestore path" << std::endl;
382 exit(EXIT_FAILURE);
383 }
384 for (auto name : allocs_name) {
385 if (!name.empty() &&
386 name != "block" &&
387 name != "bluefs-db" &&
388 name != "bluefs-wal" &&
389 name != "bluefs-slow") {
390 cerr << "unknown allocator '" << name << "'" << std::endl;
391 exit(EXIT_FAILURE);
392 }
393 }
394 if (allocs_name.empty())
395 allocs_name = vector<string>{"block", "bluefs-db", "bluefs-wal", "bluefs-slow"};
396 }
397 vector<const char*> args;
398 if (log_file.size()) {
399 args.push_back("--log-file");
400 args.push_back(log_file.c_str());
401 static char ll[10];
402 snprintf(ll, sizeof(ll), "%d", log_level);
403 args.push_back("--debug-bluestore");
404 args.push_back(ll);
405 args.push_back("--debug-bluefs");
406 args.push_back(ll);
407 }
408 args.push_back("--no-log-to-stderr");
409 args.push_back("--err-to-stderr");
410
411 for (auto& i : ceph_option_strings) {
412 args.push_back(i.c_str());
413 }
414 auto cct = global_init(NULL, args, CEPH_ENTITY_TYPE_CLIENT,
415 CODE_ENVIRONMENT_UTILITY,
416 CINIT_FLAG_NO_DEFAULT_CONFIG_FILE);
417
418 common_init_finish(cct.get());
419
420 if (action == "fsck" ||
421 action == "repair" ||
422 action == "quick-fix") {
423 validate_path(cct.get(), path, false);
424 BlueStore bluestore(cct.get(), path);
425 int r;
426 if (action == "fsck") {
427 r = bluestore.fsck(fsck_deep);
428 } else if (action == "repair") {
429 r = bluestore.repair(fsck_deep);
430 } else {
431 r = bluestore.quick_fix();
432 }
433 if (r < 0) {
434 cerr << "error from fsck: " << cpp_strerror(r) << std::endl;
435 exit(EXIT_FAILURE);
436 } else if (r > 0) {
437 cerr << action << " found " << r << " error(s)" << std::endl;
438 exit(EXIT_FAILURE);
439 } else {
440 cout << action << " success" << std::endl;
441 }
442 }
443 else if (action == "prime-osd-dir") {
444 bluestore_bdev_label_t label;
445 int r = BlueStore::_read_bdev_label(cct.get(), devs.front(), &label);
446 if (r < 0) {
447 cerr << "failed to read label for " << devs.front() << ": "
448 << cpp_strerror(r) << std::endl;
449 exit(EXIT_FAILURE);
450 }
451
452 // kludge some things into the map that we want to populate into
453 // target dir
454 label.meta["path_block"] = devs.front();
455 label.meta["type"] = "bluestore";
456 label.meta["fsid"] = stringify(label.osd_uuid);
457
458 for (auto kk : {
459 "whoami",
460 "osd_key",
461 "ceph_fsid",
462 "fsid",
463 "type",
464 "ready" }) {
465 string k = kk;
466 auto i = label.meta.find(k);
467 if (i == label.meta.end()) {
468 continue;
469 }
470 string p = path + "/" + k;
471 string v = i->second;
472 if (k == "osd_key") {
473 p = path + "/keyring";
474 v = "[osd.";
475 v += label.meta["whoami"];
476 v += "]\nkey = " + i->second;
477 }
478 v += "\n";
479 int fd = ::open(p.c_str(), O_CREAT|O_TRUNC|O_WRONLY|O_CLOEXEC, 0600);
480 if (fd < 0) {
481 cerr << "error writing " << p << ": " << cpp_strerror(errno)
482 << std::endl;
483 exit(EXIT_FAILURE);
484 }
485 int r = safe_write(fd, v.c_str(), v.size());
486 if (r < 0) {
487 cerr << "error writing to " << p << ": " << cpp_strerror(errno)
488 << std::endl;
489 exit(EXIT_FAILURE);
490 }
491 ::close(fd);
492 }
493 }
494 else if (action == "show-label") {
495 JSONFormatter jf(true);
496 jf.open_object_section("devices");
497 for (auto& i : devs) {
498 bluestore_bdev_label_t label;
499 int r = BlueStore::_read_bdev_label(cct.get(), i, &label);
500 if (r < 0) {
501 cerr << "unable to read label for " << i << ": "
502 << cpp_strerror(r) << std::endl;
503 exit(EXIT_FAILURE);
504 }
505 jf.open_object_section(i.c_str());
506 label.dump(&jf);
507 jf.close_section();
508 }
509 jf.close_section();
510 jf.flush(cout);
511 }
512 else if (action == "set-label-key") {
513 bluestore_bdev_label_t label;
514 int r = BlueStore::_read_bdev_label(cct.get(), devs.front(), &label);
515 if (r < 0) {
516 cerr << "unable to read label for " << devs.front() << ": "
517 << cpp_strerror(r) << std::endl;
518 exit(EXIT_FAILURE);
519 }
520 if (key == "size") {
521 label.size = strtoull(value.c_str(), nullptr, 10);
522 } else if (key =="osd_uuid") {
523 label.osd_uuid.parse(value.c_str());
524 } else if (key =="btime") {
525 uint64_t epoch;
526 uint64_t nsec;
527 int r = utime_t::parse_date(value.c_str(), &epoch, &nsec);
528 if (r == 0) {
529 label.btime = utime_t(epoch, nsec);
530 }
531 } else if (key =="description") {
532 label.description = value;
533 } else {
534 label.meta[key] = value;
535 }
536 r = BlueStore::_write_bdev_label(cct.get(), devs.front(), label);
537 if (r < 0) {
538 cerr << "unable to write label for " << devs.front() << ": "
539 << cpp_strerror(r) << std::endl;
540 exit(EXIT_FAILURE);
541 }
542 }
543 else if (action == "rm-label-key") {
544 bluestore_bdev_label_t label;
545 int r = BlueStore::_read_bdev_label(cct.get(), devs.front(), &label);
546 if (r < 0) {
547 cerr << "unable to read label for " << devs.front() << ": "
548 << cpp_strerror(r) << std::endl;
549 exit(EXIT_FAILURE);
550 }
551 if (!label.meta.count(key)) {
552 cerr << "key '" << key << "' not present" << std::endl;
553 exit(EXIT_FAILURE);
554 }
555 label.meta.erase(key);
556 r = BlueStore::_write_bdev_label(cct.get(), devs.front(), label);
557 if (r < 0) {
558 cerr << "unable to write label for " << devs.front() << ": "
559 << cpp_strerror(r) << std::endl;
560 exit(EXIT_FAILURE);
561 }
562 }
563 else if (action == "bluefs-bdev-sizes") {
564 BlueFS *fs = open_bluefs(cct.get(), path, devs);
565 fs->dump_block_extents(cout);
566 delete fs;
567 }
568 else if (action == "bluefs-bdev-expand") {
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);
575 }
576 }
577 else if (action == "bluefs-export") {
578 BlueFS *fs = open_bluefs(cct.get(), path, devs);
579
580 vector<string> dirs;
581 int r = fs->readdir("", &dirs);
582 if (r < 0) {
583 cerr << "readdir in root failed: " << cpp_strerror(r) << std::endl;
584 exit(EXIT_FAILURE);
585 }
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
596 for (auto& dir : dirs) {
597 if (dir[0] == '.')
598 continue;
599 cout << dir << "/" << std::endl;
600 vector<string> ls;
601 r = fs->readdir(dir, &ls);
602 if (r < 0) {
603 cerr << "readdir " << dir << " failed: " << cpp_strerror(r) << std::endl;
604 exit(EXIT_FAILURE);
605 }
606 string full = out_dir + "/" + dir;
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 }
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;
621 r = fs->stat(dir, file, &size, &mtime);
622 if (r < 0) {
623 cerr << "stat " << file << " failed: " << cpp_strerror(r) << std::endl;
624 exit(EXIT_FAILURE);
625 }
626 string path = out_dir + "/" + dir + "/" + file;
627 int fd = ::open(path.c_str(), O_CREAT|O_WRONLY|O_TRUNC|O_CLOEXEC, 0644);
628 if (fd < 0) {
629 r = -errno;
630 cerr << "open " << path << " failed: " << cpp_strerror(r) << std::endl;
631 exit(EXIT_FAILURE);
632 }
633 if (size > 0) {
634 BlueFS::FileReader *h;
635 r = fs->open_for_read(dir, file, &h, false);
636 if (r < 0) {
637 cerr << "open_for_read " << dir << "/" << file << " failed: "
638 << cpp_strerror(r) << std::endl;
639 exit(EXIT_FAILURE);
640 }
641 int pos = 0;
642 int left = size;
643 while (left) {
644 bufferlist bl;
645 r = fs->read(h, &h->buf, pos, left, &bl, NULL);
646 if (r <= 0) {
647 cerr << "read " << dir << "/" << file << " from " << pos
648 << " failed: " << cpp_strerror(r) << std::endl;
649 exit(EXIT_FAILURE);
650 }
651 int rc = bl.write_fd(fd);
652 if (rc < 0) {
653 cerr << "write to " << path << " failed: "
654 << cpp_strerror(r) << std::endl;
655 exit(EXIT_FAILURE);
656 }
657 pos += r;
658 left -= r;
659 }
660 delete h;
661 }
662 ::close(fd);
663 }
664 }
665 fs->umount();
666 delete fs;
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()) {
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 }
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
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 {
773 bool need_db = dev_target_id == BlueFS::BDEV_DB;
774 cerr << "failed to migrate to existing BlueFS device: "
775 << (need_db ? BlueFS::BDEV_DB : BlueFS::BDEV_WAL)
776 << " " << dev_target
777 << cpp_strerror(r)
778 << std::endl;
779 }
780 return r;
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 }
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) {
847 ceph::bufferlist out;
848 bool b = admin_socket->execute_command(
849 "{\"prefix\": \"bluestore allocator " + action_name + " " + alloc_name + "\"}", out);
850 if (!b) {
851 cerr << "failure querying '" << alloc_name << "'" << std::endl;
852 exit(EXIT_FAILURE);
853 }
854 cout << alloc_name << ":" << std::endl;
855 cout << std::string(out.c_str(),out.length()) << std::endl;
856 }
857
858 bluestore.cold_close();
859 } else {
860 cerr << "unrecognized action " << action << std::endl;
861 return 1;
862 }
863
864 return 0;
865 }