1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 #include <boost/program_options/variables_map.hpp>
5 #include <boost/program_options/parsers.hpp>
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"
19 #include "os/bluestore/BlueFS.h"
20 #include "os/bluestore/BlueStore.h"
22 namespace po
= boost::program_options
;
24 void usage(po::options_description
&desc
)
26 cout
<< desc
<< std::endl
;
29 void validate_path(CephContext
*cct
, const string
& path
, bool bluefs
)
31 BlueStore
bluestore(cct
, path
);
33 int r
= bluestore
.read_meta("type", &type
);
35 cerr
<< "failed to load os-type: " << cpp_strerror(r
) << std::endl
;
38 if (type
!= "bluestore") {
39 cerr
<< "expected bluestore, but type is " << type
<< std::endl
;
47 r
= bluestore
.read_meta("kv_backend", &kv_backend
);
49 cerr
<< "failed to load kv_backend: " << cpp_strerror(r
) << std::endl
;
52 if (kv_backend
!= "rocksdb") {
53 cerr
<< "expect kv_backend to be rocksdb, but is " << kv_backend
57 string bluefs_enabled
;
58 r
= bluestore
.read_meta("bluefs", &bluefs_enabled
);
60 cerr
<< "failed to load do_bluefs: " << cpp_strerror(r
) << std::endl
;
63 if (bluefs_enabled
!= "1") {
64 cerr
<< "bluefs not enabled for rocksdb" << std::endl
;
72 const vector
<string
>& devs
)
74 validate_path(cct
, path
, true);
75 BlueFS
*fs
= new BlueFS(cct
);
79 for (auto& i
: devs
) {
80 bluestore_bdev_label_t label
;
81 int r
= BlueStore::_read_bdev_label(cct
, i
, &label
);
83 cerr
<< "unable to read label for " << i
<< ": "
84 << cpp_strerror(r
) << std::endl
;
88 if (label
.description
== "main")
90 else if (label
.description
== "bluefs db")
92 else if (label
.description
== "bluefs wal")
93 id
= BlueFS::BDEV_WAL
;
96 cout
<< " slot " << id
<< " " << i
<< std::endl
;
97 int r
= fs
->add_block_device(id
, i
);
99 cerr
<< "unable to open " << i
<< ": " << cpp_strerror(r
) << std::endl
;
105 int id
= BlueFS::BDEV_DB
;
106 if (got
.count(BlueFS::BDEV_DB
))
107 id
= BlueFS::BDEV_SLOW
;
108 cout
<< " slot " << id
<< " " << main
<< std::endl
;
109 int r
= fs
->add_block_device(id
, main
);
111 cerr
<< "unable to open " << main
<< ": " << cpp_strerror(r
)
119 cerr
<< "unable to mount bluefs: " << cpp_strerror(r
)
126 int main(int argc
, char **argv
)
135 bool fsck_deep
= false;
136 po::options_description
po_options("Options");
137 po_options
.add_options()
138 ("help,h", "produce help message")
139 ("path", po::value
<string
>(&path
), "bluestore path")
140 ("out-dir", po::value
<string
>(&out_dir
), "output directory")
141 ("log-file,l", po::value
<string
>(&log_file
), "log file")
142 ("log-level", po::value
<int>(&log_level
), "log level (30=most, 20=lots, 10=some, 1=little)")
143 ("dev", po::value
<vector
<string
>>(&devs
), "device(s)")
144 ("deep", po::value
<bool>(&fsck_deep
), "deep fsck (read all data)")
145 ("key,k", po::value
<string
>(&key
), "label metadata key name")
146 ("value,v", po::value
<string
>(&value
), "label metadata value")
148 po::options_description
po_positional("Positional options");
149 po_positional
.add_options()
150 ("command", po::value
<string
>(&action
), "fsck, repair, bluefs-export, bluefs-bdev-sizes, bluefs-bdev-expand, show-label, set-label-key, rm-label-key, prime-osd-dir")
152 po::options_description
po_all("All options");
153 po_all
.add(po_options
).add(po_positional
);
154 po::positional_options_description pd
;
155 pd
.add("command", 1);
157 vector
<string
> ceph_option_strings
;
158 po::variables_map vm
;
160 po::parsed_options parsed
=
161 po::command_line_parser(argc
, argv
).options(po_all
).allow_unregistered().positional(pd
).run();
162 po::store( parsed
, vm
);
164 ceph_option_strings
= po::collect_unrecognized(parsed
.options
,
165 po::include_positional
);
166 } catch(po::error
&e
) {
167 std::cerr
<< e
.what() << std::endl
;
171 if (vm
.count("help")) {
175 if (action
.empty()) {
176 cerr
<< "must specify an action; --help for help" << std::endl
;
180 if (action
== "fsck" || action
== "repair") {
182 cerr
<< "must specify bluestore path" << std::endl
;
186 if (action
== "prime-osd-dir") {
187 if (devs
.size() != 1) {
188 cerr
<< "must specify the main bluestore device" << std::endl
;
192 cerr
<< "must specify osd dir to prime" << std::endl
;
196 if (action
== "set-label-key" ||
197 action
== "rm-label-key") {
198 if (devs
.size() != 1) {
199 cerr
<< "must specify the main bluestore device" << std::endl
;
202 if (key
.size() == 0) {
203 cerr
<< "must specify a key name with -k" << std::endl
;
206 if (action
== "set-label-key" && value
.size() == 0) {
207 cerr
<< "must specify a value with -v" << std::endl
;
211 if (action
== "show-label") {
212 if (devs
.empty() && path
.empty()) {
213 cerr
<< "must specify bluestore path *or* raw device(s)" << std::endl
;
217 cout
<< "infering bluefs devices from bluestore path" << std::endl
;
218 for (auto fn
: {"block", "block.wal", "block.db"}) {
219 string p
= path
+ "/" + fn
;
221 if (::stat(p
.c_str(), &st
) == 0) {
227 if (action
== "bluefs-export") {
229 cerr
<< "must specify bluestore path" << std::endl
;
232 if (out_dir
.empty()) {
233 cerr
<< "must specify out-dir to export bluefs" << std::endl
;
236 cout
<< "infering bluefs devices from bluestore path" << std::endl
;
237 for (auto fn
: {"block", "block.wal", "block.db"}) {
238 string p
= path
+ "/" + fn
;
240 if (::stat(p
.c_str(), &st
) == 0) {
245 if (action
== "bluefs-bdev-sizes" || action
== "bluefs-bdev-expand") {
247 cerr
<< "must specify bluestore path" << std::endl
;
250 cout
<< "infering bluefs devices from bluestore path" << std::endl
;
251 for (auto fn
: {"block", "block.wal", "block.db"}) {
252 string p
= path
+ "/" + fn
;
254 if (::stat(p
.c_str(), &st
) == 0) {
260 vector
<const char*> args
;
261 if (log_file
.size()) {
262 args
.push_back("--log-file");
263 args
.push_back(log_file
.c_str());
265 snprintf(ll
, sizeof(ll
), "%d", log_level
);
266 args
.push_back("--debug-bluestore");
268 args
.push_back("--debug-bluefs");
271 args
.push_back("--no-log-to-stderr");
272 args
.push_back("--err-to-stderr");
274 for (auto& i
: ceph_option_strings
) {
275 args
.push_back(i
.c_str());
279 auto cct
= global_init(NULL
, args
, CEPH_ENTITY_TYPE_CLIENT
,
280 CODE_ENVIRONMENT_UTILITY
, 0);
281 common_init_finish(cct
.get());
283 if (action
== "fsck" ||
284 action
== "repair") {
285 validate_path(cct
.get(), path
, false);
286 BlueStore
bluestore(cct
.get(), path
);
288 if (action
== "fsck") {
289 r
= bluestore
.fsck(fsck_deep
);
291 r
= bluestore
.repair(fsck_deep
);
294 cerr
<< "error from fsck: " << cpp_strerror(r
) << std::endl
;
297 cout
<< action
<< " success" << std::endl
;
299 else if (action
== "prime-osd-dir") {
300 bluestore_bdev_label_t label
;
301 int r
= BlueStore::_read_bdev_label(cct
.get(), devs
.front(), &label
);
303 cerr
<< "failed to read label for " << devs
.front() << ": "
304 << cpp_strerror(r
) << std::endl
;
308 // kludge some things into the map that we want to populate into
310 label
.meta
["path_block"] = devs
.front();
311 label
.meta
["type"] = "bluestore";
312 label
.meta
["fsid"] = stringify(label
.osd_uuid
);
317 "path_block", "path_block.db", "path_block.wal",
323 auto i
= label
.meta
.find(k
);
324 if (i
== label
.meta
.end()) {
327 string p
= path
+ "/" + k
;
328 string v
= i
->second
;
329 if (k
== "osd_key") {
330 p
= path
+ "/keyring";
332 v
+= label
.meta
["whoami"];
333 v
+= "]\nkey = " + i
->second
;
335 if (k
.find("path_") == 0) {
336 p
= path
+ "/" + k
.substr(5);
337 int r
= ::symlink(v
.c_str(), p
.c_str());
338 if (r
< 0 && errno
== EEXIST
) {
340 r
= ::stat(p
.c_str(), &st
);
341 if (r
== 0 && S_ISLNK(st
.st_mode
)) {
342 char target
[PATH_MAX
];
343 r
= ::readlink(p
.c_str(), target
, sizeof(target
));
346 r
= 0; // already matches our target
349 r
= ::symlink(v
.c_str(), p
.c_str());
352 cerr
<< "error reading existing link at " << p
<< ": " << cpp_strerror(errno
)
358 cerr
<< "error symlinking " << p
<< ": " << cpp_strerror(errno
)
364 int fd
= ::open(p
.c_str(), O_CREAT
|O_TRUNC
|O_WRONLY
|O_CLOEXEC
, 0600);
366 cerr
<< "error writing " << p
<< ": " << cpp_strerror(errno
)
370 int r
= safe_write(fd
, v
.c_str(), v
.size());
372 cerr
<< "error writing to " << p
<< ": " << cpp_strerror(errno
)
380 else if (action
== "show-label") {
381 JSONFormatter
jf(true);
382 jf
.open_object_section("devices");
383 for (auto& i
: devs
) {
384 bluestore_bdev_label_t label
;
385 int r
= BlueStore::_read_bdev_label(cct
.get(), i
, &label
);
387 cerr
<< "unable to read label for " << i
<< ": "
388 << cpp_strerror(r
) << std::endl
;
391 jf
.open_object_section(i
.c_str());
398 else if (action
== "set-label-key") {
399 bluestore_bdev_label_t label
;
400 int r
= BlueStore::_read_bdev_label(cct
.get(), devs
.front(), &label
);
402 cerr
<< "unable to read label for " << devs
.front() << ": "
403 << cpp_strerror(r
) << std::endl
;
406 label
.meta
[key
] = value
;
407 r
= BlueStore::_write_bdev_label(cct
.get(), devs
.front(), label
);
409 cerr
<< "unable to write label for " << devs
.front() << ": "
410 << cpp_strerror(r
) << std::endl
;
414 else if (action
== "rm-label-key") {
415 bluestore_bdev_label_t label
;
416 int r
= BlueStore::_read_bdev_label(cct
.get(), devs
.front(), &label
);
418 cerr
<< "unable to read label for " << devs
.front() << ": "
419 << cpp_strerror(r
) << std::endl
;
422 if (!label
.meta
.count(key
)) {
423 cerr
<< "key '" << key
<< "' not present" << std::endl
;
426 label
.meta
.erase(key
);
427 r
= BlueStore::_write_bdev_label(cct
.get(), devs
.front(), label
);
429 cerr
<< "unable to write label for " << devs
.front() << ": "
430 << cpp_strerror(r
) << std::endl
;
434 else if (action
== "bluefs-bdev-sizes") {
435 BlueFS
*fs
= open_bluefs(cct
.get(), path
, devs
);
436 fs
->dump_block_extents(cout
);
439 else if (action
== "bluefs-bdev-expand") {
440 BlueFS
*fs
= open_bluefs(cct
.get(), path
, devs
);
441 cout
<< "start:" << std::endl
;
442 fs
->dump_block_extents(cout
);
443 for (int devid
: { BlueFS::BDEV_WAL
, BlueFS::BDEV_DB
}) {
444 interval_set
<uint64_t> before
;
445 fs
->get_block_extents(devid
, &before
);
446 uint64_t end
= before
.range_end();
447 uint64_t size
= fs
->get_block_device_size(devid
);
449 cout
<< "expanding dev " << devid
<< " from 0x" << std::hex
450 << end
<< " to 0x" << size
<< std::dec
<< std::endl
;
451 fs
->add_block_extent(devid
, end
, size
-end
);
456 else if (action
== "bluefs-export") {
457 BlueFS
*fs
= open_bluefs(cct
.get(), path
, devs
);
460 int r
= fs
->readdir("", &dirs
);
462 cerr
<< "readdir in root failed: " << cpp_strerror(r
) << std::endl
;
465 for (auto& dir
: dirs
) {
468 cout
<< dir
<< "/" << std::endl
;
470 r
= fs
->readdir(dir
, &ls
);
472 cerr
<< "readdir " << dir
<< " failed: " << cpp_strerror(r
) << std::endl
;
475 string full
= out_dir
+ "/" + dir
;
476 r
= ::mkdir(full
.c_str(), 0755);
479 cerr
<< "mkdir " << full
<< " failed: " << cpp_strerror(r
) << std::endl
;
482 for (auto& file
: ls
) {
485 cout
<< dir
<< "/" << file
<< std::endl
;
488 r
= fs
->stat(dir
, file
, &size
, &mtime
);
490 cerr
<< "stat " << file
<< " failed: " << cpp_strerror(r
) << std::endl
;
493 string path
= out_dir
+ "/" + dir
+ "/" + file
;
494 int fd
= ::open(path
.c_str(), O_CREAT
|O_WRONLY
|O_TRUNC
|O_CLOEXEC
, 0644);
497 cerr
<< "open " << path
<< " failed: " << cpp_strerror(r
) << std::endl
;
502 BlueFS::FileReader
*h
;
503 r
= fs
->open_for_read(dir
, file
, &h
, false);
505 cerr
<< "open_for_read " << dir
<< "/" << file
<< " failed: "
506 << cpp_strerror(r
) << std::endl
;
513 r
= fs
->read(h
, &h
->buf
, pos
, left
, &bl
, NULL
);
515 cerr
<< "read " << dir
<< "/" << file
<< " from " << pos
516 << " failed: " << cpp_strerror(r
) << std::endl
;
519 int rc
= bl
.write_fd(fd
);
521 cerr
<< "write to " << path
<< " failed: "
522 << cpp_strerror(r
) << std::endl
;
536 cerr
<< "unrecognized action " << action
<< std::endl
;