]> git.proxmox.com Git - ceph.git/blame - ceph/src/os/bluestore/bluestore_tool.cc
import 15.2.2 octopus source
[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, "
264 "free-score")
7c673cae
FG
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;
c07f9fc5 282 exit(EXIT_FAILURE);
7c673cae 283 }
11fdf7f2
TL
284 // normalize path (remove ending '/' if any)
285 if (path.size() > 1 && *(path.end() - 1) == '/') {
286 path.resize(path.size() - 1);
287 }
7c673cae
FG
288 if (vm.count("help")) {
289 usage(po_all);
c07f9fc5 290 exit(EXIT_SUCCESS);
7c673cae
FG
291 }
292 if (action.empty()) {
293 cerr << "must specify an action; --help for help" << std::endl;
c07f9fc5 294 exit(EXIT_FAILURE);
7c673cae
FG
295 }
296
eafe8130 297 if (action == "fsck" || action == "repair" || action == "quick-fix") {
7c673cae
FG
298 if (path.empty()) {
299 cerr << "must specify bluestore path" << std::endl;
c07f9fc5 300 exit(EXIT_FAILURE);
7c673cae
FG
301 }
302 }
3efd9988
FG
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 }
c07f9fc5 328 if (action == "show-label") {
7c673cae
FG
329 if (devs.empty() && path.empty()) {
330 cerr << "must specify bluestore path *or* raw device(s)" << std::endl;
c07f9fc5 331 exit(EXIT_FAILURE);
7c673cae 332 }
11fdf7f2
TL
333 if (devs.empty())
334 inferring_bluefs_devices(devs, path);
7c673cae 335 }
11fdf7f2 336 if (action == "bluefs-export" || action == "bluefs-log-dump") {
c07f9fc5
FG
337 if (path.empty()) {
338 cerr << "must specify bluestore path" << std::endl;
339 exit(EXIT_FAILURE);
340 }
11fdf7f2 341 if ((action == "bluefs-export") && out_dir.empty()) {
c07f9fc5
FG
342 cerr << "must specify out-dir to export bluefs" << std::endl;
343 exit(EXIT_FAILURE);
344 }
11fdf7f2 345 inferring_bluefs_devices(devs, path);
c07f9fc5 346 }
3efd9988
FG
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 }
11fdf7f2
TL
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);
3efd9988
FG
377 }
378 }
eafe8130
TL
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 }
7c673cae 397 vector<const char*> args;
3efd9988
FG
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
7c673cae
FG
411 for (auto& i : ceph_option_strings) {
412 args.push_back(i.c_str());
413 }
7c673cae 414 auto cct = global_init(NULL, args, CEPH_ENTITY_TYPE_CLIENT,
f64942e4
AA
415 CODE_ENVIRONMENT_UTILITY,
416 CINIT_FLAG_NO_DEFAULT_CONFIG_FILE);
417
7c673cae
FG
418 common_init_finish(cct.get());
419
7c673cae 420 if (action == "fsck" ||
eafe8130
TL
421 action == "repair" ||
422 action == "quick-fix") {
c07f9fc5 423 validate_path(cct.get(), path, false);
7c673cae 424 BlueStore bluestore(cct.get(), path);
3efd9988
FG
425 int r;
426 if (action == "fsck") {
427 r = bluestore.fsck(fsck_deep);
eafe8130 428 } else if (action == "repair") {
3efd9988 429 r = bluestore.repair(fsck_deep);
eafe8130
TL
430 } else {
431 r = bluestore.quick_fix();
3efd9988 432 }
7c673cae 433 if (r < 0) {
9f95a23c 434 cerr << action << " failed: " << cpp_strerror(r) << std::endl;
c07f9fc5 435 exit(EXIT_FAILURE);
11fdf7f2 436 } else if (r > 0) {
9f95a23c 437 cerr << action << " status: remaining " << r << " error(s) and warning(s)" << std::endl;
11fdf7f2
TL
438 exit(EXIT_FAILURE);
439 } else {
440 cout << action << " success" << std::endl;
7c673cae 441 }
3efd9988
FG
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",
3efd9988
FG
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 }
11fdf7f2
TL
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);
3efd9988 484 }
11fdf7f2
TL
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);
3efd9988 492 }
7c673cae
FG
493 }
494 else if (action == "show-label") {
495 JSONFormatter jf(true);
3efd9988 496 jf.open_object_section("devices");
7c673cae
FG
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;
c07f9fc5 503 exit(EXIT_FAILURE);
7c673cae
FG
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 }
3efd9988
FG
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);
7c673cae 519 }
f64942e4
AA
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 }
3efd9988
FG
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);
7c673cae 541 }
3efd9988
FG
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);
7c673cae 546 if (r < 0) {
3efd9988
FG
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;
c07f9fc5 560 exit(EXIT_FAILURE);
7c673cae 561 }
3efd9988
FG
562 }
563 else if (action == "bluefs-bdev-sizes") {
1911f103
TL
564 BlueStore bluestore(cct.get(), path);
565 bluestore.dump_bluefs_sizes(cout);
3efd9988
FG
566 }
567 else if (action == "bluefs-bdev-expand") {
11fdf7f2
TL
568 BlueStore bluestore(cct.get(), path);
569 auto r = bluestore.expand_devices(cout);
570 if (r <0) {
571 cerr << "failed to expand bluestore devices: "
572 << cpp_strerror(r) << std::endl;
573 exit(EXIT_FAILURE);
3efd9988 574 }
3efd9988
FG
575 }
576 else if (action == "bluefs-export") {
577 BlueFS *fs = open_bluefs(cct.get(), path, devs);
7c673cae
FG
578
579 vector<string> dirs;
3efd9988 580 int r = fs->readdir("", &dirs);
7c673cae
FG
581 if (r < 0) {
582 cerr << "readdir in root failed: " << cpp_strerror(r) << std::endl;
c07f9fc5 583 exit(EXIT_FAILURE);
7c673cae 584 }
11fdf7f2
TL
585
586 if (::access(out_dir.c_str(), F_OK)) {
587 r = ::mkdir(out_dir.c_str(), 0755);
588 if (r < 0) {
589 r = -errno;
590 cerr << "mkdir " << out_dir << " failed: " << cpp_strerror(r) << std::endl;
591 exit(EXIT_FAILURE);
592 }
593 }
594
7c673cae
FG
595 for (auto& dir : dirs) {
596 if (dir[0] == '.')
597 continue;
598 cout << dir << "/" << std::endl;
599 vector<string> ls;
3efd9988 600 r = fs->readdir(dir, &ls);
7c673cae
FG
601 if (r < 0) {
602 cerr << "readdir " << dir << " failed: " << cpp_strerror(r) << std::endl;
c07f9fc5 603 exit(EXIT_FAILURE);
7c673cae
FG
604 }
605 string full = out_dir + "/" + dir;
11fdf7f2
TL
606 if (::access(full.c_str(), F_OK)) {
607 r = ::mkdir(full.c_str(), 0755);
608 if (r < 0) {
609 r = -errno;
610 cerr << "mkdir " << full << " failed: " << cpp_strerror(r) << std::endl;
611 exit(EXIT_FAILURE);
612 }
7c673cae
FG
613 }
614 for (auto& file : ls) {
615 if (file[0] == '.')
616 continue;
617 cout << dir << "/" << file << std::endl;
618 uint64_t size;
619 utime_t mtime;
3efd9988 620 r = fs->stat(dir, file, &size, &mtime);
7c673cae
FG
621 if (r < 0) {
622 cerr << "stat " << file << " failed: " << cpp_strerror(r) << std::endl;
c07f9fc5 623 exit(EXIT_FAILURE);
7c673cae
FG
624 }
625 string path = out_dir + "/" + dir + "/" + file;
91327a77 626 int fd = ::open(path.c_str(), O_CREAT|O_WRONLY|O_TRUNC|O_CLOEXEC, 0644);
7c673cae
FG
627 if (fd < 0) {
628 r = -errno;
629 cerr << "open " << path << " failed: " << cpp_strerror(r) << std::endl;
c07f9fc5 630 exit(EXIT_FAILURE);
7c673cae 631 }
7c673cae
FG
632 if (size > 0) {
633 BlueFS::FileReader *h;
3efd9988 634 r = fs->open_for_read(dir, file, &h, false);
7c673cae
FG
635 if (r < 0) {
636 cerr << "open_for_read " << dir << "/" << file << " failed: "
637 << cpp_strerror(r) << std::endl;
c07f9fc5 638 exit(EXIT_FAILURE);
7c673cae
FG
639 }
640 int pos = 0;
641 int left = size;
642 while (left) {
643 bufferlist bl;
3efd9988 644 r = fs->read(h, &h->buf, pos, left, &bl, NULL);
7c673cae
FG
645 if (r <= 0) {
646 cerr << "read " << dir << "/" << file << " from " << pos
647 << " failed: " << cpp_strerror(r) << std::endl;
c07f9fc5 648 exit(EXIT_FAILURE);
7c673cae
FG
649 }
650 int rc = bl.write_fd(fd);
651 if (rc < 0) {
652 cerr << "write to " << path << " failed: "
653 << cpp_strerror(r) << std::endl;
c07f9fc5 654 exit(EXIT_FAILURE);
7c673cae
FG
655 }
656 pos += r;
657 left -= r;
658 }
659 delete h;
660 }
661 ::close(fd);
662 }
663 }
3efd9988
FG
664 fs->umount();
665 delete fs;
11fdf7f2
TL
666 } else if (action == "bluefs-log-dump") {
667 log_dump(cct.get(), path, devs);
668 } else if (action == "bluefs-bdev-new-db" || action == "bluefs-bdev-new-wal") {
669 map<string, int> cur_devs_map;
670 bool need_db = action == "bluefs-bdev-new-db";
671
672 bool has_wal = false;
673 bool has_db = false;
674 char target_path[PATH_MAX] = "";
675
676 parse_devices(cct.get(), devs, &cur_devs_map, &has_db, &has_wal);
677
678 if (has_db && has_wal) {
679 cerr << "can't allocate new device, both WAL and DB exist"
680 << std::endl;
681 exit(EXIT_FAILURE);
682 } else if (need_db && has_db) {
683 cerr << "can't allocate new DB device, already exists"
684 << std::endl;
685 exit(EXIT_FAILURE);
686 } else if (!need_db && has_wal) {
687 cerr << "can't allocate new WAL device, already exists"
688 << std::endl;
689 exit(EXIT_FAILURE);
690 } else if(!dev_target.empty() &&
691 realpath(dev_target.c_str(), target_path) == nullptr) {
692 cerr << "failed to retrieve absolute path for " << dev_target
693 << ": " << cpp_strerror(errno)
694 << std::endl;
695 exit(EXIT_FAILURE);
696 }
697
698 // Create either DB or WAL volume
699 int r = EXIT_FAILURE;
700 if (need_db && cct->_conf->bluestore_block_db_size == 0) {
701 cerr << "DB size isn't specified, "
702 "please set Ceph bluestore-block-db-size config parameter "
703 << std::endl;
704 } else if (!need_db && cct->_conf->bluestore_block_wal_size == 0) {
705 cerr << "WAL size isn't specified, "
706 "please set Ceph bluestore-block-wal-size config parameter "
707 << std::endl;
708 } else {
709 BlueStore bluestore(cct.get(), path);
710 r = bluestore.add_new_bluefs_device(
711 need_db ? BlueFS::BDEV_NEWDB : BlueFS::BDEV_NEWWAL,
712 target_path);
713 if (r == 0) {
714 cout << (need_db ? "DB" : "WAL") << " device added " << target_path
715 << std::endl;
716 } else {
717 cerr << "failed to add " << (need_db ? "DB" : "WAL") << " device:"
718 << cpp_strerror(r)
719 << std::endl;
720 }
721 return r;
722 }
723 } else if (action == "bluefs-bdev-migrate") {
724 map<string, int> cur_devs_map;
725 set<int> src_dev_ids;
726 map<string, int> src_devs;
727
728 parse_devices(cct.get(), devs, &cur_devs_map, nullptr, nullptr);
729 for (auto& s : devs_source) {
730 auto i = cur_devs_map.find(s);
731 if (i != cur_devs_map.end()) {
494da23a
TL
732 if (s == dev_target) {
733 cerr << "Device " << dev_target
734 << " is present in both source and target lists, omitted."
735 << std::endl;
736 } else {
737 src_devs.emplace(*i);
738 src_dev_ids.emplace(i->second);
739 }
11fdf7f2
TL
740 } else {
741 cerr << "can't migrate " << s << ", not a valid bluefs volume "
742 << std::endl;
743 exit(EXIT_FAILURE);
744 }
745 }
746
747 auto i = cur_devs_map.find(dev_target);
748
749 if (i != cur_devs_map.end()) {
750 // Migrate to an existing BlueFS volume
751
752 auto dev_target_id = i->second;
753 if (dev_target_id == BlueFS::BDEV_WAL) {
754 // currently we're unable to migrate to WAL device since there is no space
755 // reserved for superblock
756 cerr << "Migrate to WAL device isn't supported." << std::endl;
757 exit(EXIT_FAILURE);
758 }
759
11fdf7f2
TL
760 BlueStore bluestore(cct.get(), path);
761 int r = bluestore.migrate_to_existing_bluefs_device(
762 src_dev_ids,
763 dev_target_id);
764 if (r == 0) {
765 for(auto src : src_devs) {
766 if (src.second != BlueFS::BDEV_SLOW) {
767 cout << " device removed:" << src.second << " " << src.first
768 << std::endl;
769 }
770 }
771 } else {
494da23a 772 bool need_db = dev_target_id == BlueFS::BDEV_DB;
11fdf7f2 773 cerr << "failed to migrate to existing BlueFS device: "
494da23a 774 << (need_db ? BlueFS::BDEV_DB : BlueFS::BDEV_WAL)
11fdf7f2
TL
775 << " " << dev_target
776 << cpp_strerror(r)
777 << std::endl;
778 }
494da23a 779 return r;
11fdf7f2
TL
780 } else {
781 // Migrate to a new BlueFS volume
782 // via creating either DB or WAL volume
783 char target_path[PATH_MAX] = "";
784 int dev_target_id;
785 if (src_dev_ids.count(BlueFS::BDEV_DB)) {
786 // if we have DB device in the source list - we create DB device
787 // (and may be remove WAL).
788 dev_target_id = BlueFS::BDEV_NEWDB;
789 } else if (src_dev_ids.count(BlueFS::BDEV_WAL)) {
790 dev_target_id = BlueFS::BDEV_NEWWAL;
791 } else {
792 cerr << "Unable to migrate Slow volume to new location, "
793 "please allocate new DB or WAL with "
794 "--bluefs-bdev-new-db(wal) command"
795 << std::endl;
796 exit(EXIT_FAILURE);
797 }
798 if(!dev_target.empty() &&
799 realpath(dev_target.c_str(), target_path) == nullptr) {
800 cerr << "failed to retrieve absolute path for " << dev_target
801 << ": " << cpp_strerror(errno)
802 << std::endl;
803 exit(EXIT_FAILURE);
804 }
805
806 BlueStore bluestore(cct.get(), path);
807
808 bool need_db = dev_target_id == BlueFS::BDEV_NEWDB;
809 int r = bluestore.migrate_to_new_bluefs_device(
810 src_dev_ids,
811 dev_target_id,
812 target_path);
813 if (r == 0) {
814 for(auto src : src_devs) {
815 if (src.second != BlueFS::BDEV_SLOW) {
816 cout << " device removed:" << src.second << " " << src.first
817 << std::endl;
818 }
819 }
820 cout << " device added: "
821 << (need_db ? BlueFS::BDEV_DB : BlueFS::BDEV_DB)
822 << " " << target_path
823 << std::endl;
824 } else {
825 cerr << "failed to migrate to new BlueFS device: "
826 << (need_db ? BlueFS::BDEV_DB : BlueFS::BDEV_DB)
827 << " " << target_path
828 << cpp_strerror(r)
829 << std::endl;
830 }
831 return r;
832 }
eafe8130
TL
833 } else if (action == "free-dump" || action == "free-score") {
834 AdminSocket *admin_socket = g_ceph_context->get_admin_socket();
835 ceph_assert(admin_socket);
836 std::string action_name = action == "free-dump" ? "dump" : "score";
837 validate_path(cct.get(), path, false);
838 BlueStore bluestore(cct.get(), path);
839 int r = bluestore.cold_open();
840 if (r < 0) {
841 cerr << "error from cold_open: " << cpp_strerror(r) << std::endl;
842 exit(EXIT_FAILURE);
843 }
844
845 for (auto alloc_name : allocs_name) {
9f95a23c
TL
846 ceph::bufferlist in, out;
847 ostringstream err;
eafe8130 848 bool b = admin_socket->execute_command(
9f95a23c
TL
849 {"{\"prefix\": \"bluestore allocator " + action_name + " " + alloc_name + "\"}"},
850 in, err, &out);
eafe8130
TL
851 if (!b) {
852 cerr << "failure querying '" << alloc_name << "'" << std::endl;
853 exit(EXIT_FAILURE);
854 }
855 cout << alloc_name << ":" << std::endl;
856 cout << std::string(out.c_str(),out.length()) << std::endl;
857 }
858
859 bluestore.cold_close();
7c673cae
FG
860 } else {
861 cerr << "unrecognized action " << action << std::endl;
862 return 1;
863 }
864
865 return 0;
866}