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, 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, 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;