]> git.proxmox.com Git - ceph.git/blob - ceph/src/os/bluestore/bluestore_tool.cc
add subtree-ish sources for 12.0.3
[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
18 #include "os/bluestore/BlueFS.h"
19 #include "os/bluestore/BlueStore.h"
20
21 namespace po = boost::program_options;
22
23 void usage(po::options_description &desc)
24 {
25 cout << desc << std::endl;
26 }
27
28 int main(int argc, char **argv)
29 {
30 string out_dir;
31 vector<string> devs;
32 string path;
33 string action;
34 bool fsck_deep;
35 po::options_description po_options("Options");
36 po_options.add_options()
37 ("help,h", "produce help message")
38 ("path", po::value<string>(&path), "bluestore path")
39 ("out-dir", po::value<string>(&out_dir), "output directory")
40 ("dev", po::value<vector<string>>(&devs), "device(s)")
41 ("deep", po::value<bool>(&fsck_deep), "deep fsck (read all data)")
42 ;
43 po::options_description po_positional("Positional options");
44 po_positional.add_options()
45 ("command", po::value<string>(&action), "fsck, bluefs-export, show-label")
46 ;
47 po::options_description po_all("All options");
48 po_all.add(po_options).add(po_positional);
49 po::positional_options_description pd;
50 pd.add("command", 1);
51
52 vector<string> ceph_option_strings;
53 po::variables_map vm;
54 try {
55 po::parsed_options parsed =
56 po::command_line_parser(argc, argv).options(po_all).allow_unregistered().positional(pd).run();
57 po::store( parsed, vm);
58 po::notify(vm);
59 ceph_option_strings = po::collect_unrecognized(parsed.options,
60 po::include_positional);
61 } catch(po::error &e) {
62 std::cerr << e.what() << std::endl;
63 return 1;
64 }
65
66 if (vm.count("help")) {
67 usage(po_all);
68 return 1;
69 }
70 if (action.empty()) {
71 cerr << "must specify an action; --help for help" << std::endl;
72 return 1;
73 }
74
75 if (action == "fsck") {
76 if (path.empty()) {
77 cerr << "must specify bluestore path" << std::endl;
78 exit(1);
79 }
80 }
81 if (action == "bluefs-export" ||
82 action == "show-label") {
83 if (devs.empty() && path.empty()) {
84 cerr << "must specify bluestore path *or* raw device(s)" << std::endl;
85 exit(1);
86 }
87 cout << "infering bluefs devices from bluestore path" << std::endl;
88 for (auto fn : {"block", "block.wal", "block.db"}) {
89 string p = path + "/" + fn;
90 struct stat st;
91 if (::stat(p.c_str(), &st) == 0) {
92 devs.push_back(p);
93 }
94 }
95 }
96
97 vector<const char*> args;
98 for (auto& i : ceph_option_strings) {
99 args.push_back(i.c_str());
100 }
101 env_to_vec(args);
102
103 auto cct = global_init(NULL, args, CEPH_ENTITY_TYPE_CLIENT,
104 CODE_ENVIRONMENT_UTILITY, 0);
105 common_init_finish(cct.get());
106
107 cout << "action " << action << std::endl;
108
109 if (action == "fsck" ||
110 action == "fsck-deep") {
111 BlueStore bluestore(cct.get(), path);
112 int r = bluestore.fsck(fsck_deep);
113 if (r < 0) {
114 cerr << "error from fsck: " << cpp_strerror(r) << std::endl;
115 return 1;
116 }
117 }
118 else if (action == "show-label") {
119 JSONFormatter jf(true);
120 jf.open_array_section("devices");
121 for (auto& i : devs) {
122 bluestore_bdev_label_t label;
123 int r = BlueStore::_read_bdev_label(cct.get(), i, &label);
124 if (r < 0) {
125 cerr << "unable to read label for " << i << ": "
126 << cpp_strerror(r) << std::endl;
127 exit(1);
128 }
129 jf.open_object_section(i.c_str());
130 label.dump(&jf);
131 jf.close_section();
132 }
133 jf.close_section();
134 jf.flush(cout);
135 }
136 else if (action == "bluefs-export") {
137 if (out_dir.empty()) {
138 cerr << "must specify out-dir to export bluefs" << std::endl;
139 exit(1);
140 }
141 BlueFS fs(&(*cct));
142 string main;
143 set<int> got;
144 for (auto& i : devs) {
145 bluestore_bdev_label_t label;
146 int r = BlueStore::_read_bdev_label(cct.get(), i, &label);
147 if (r < 0) {
148 cerr << "unable to read label for " << i << ": "
149 << cpp_strerror(r) << std::endl;
150 exit(1);
151 }
152 int id = -1;
153 if (label.description == "main")
154 main = i;
155 else if (label.description == "bluefs db")
156 id = BlueFS::BDEV_DB;
157 else if (label.description == "bluefs wal")
158 id = BlueFS::BDEV_WAL;
159 if (id >= 0) {
160 got.insert(id);
161 cout << " slot " << id << " " << i << std::endl;
162 int r = fs.add_block_device(id, i);
163 if (r < 0) {
164 cerr << "unable to open " << i << ": " << cpp_strerror(r) << std::endl;
165 exit(1);
166 }
167 }
168 }
169 if (main.length()) {
170 int id = BlueFS::BDEV_DB;
171 if (got.count(BlueFS::BDEV_DB))
172 id = BlueFS::BDEV_SLOW;
173 cout << " slot " << id << " " << main << std::endl;
174 int r = fs.add_block_device(id, main);
175 if (r < 0) {
176 cerr << "unable to open " << main << ": " << cpp_strerror(r)
177 << std::endl;
178 exit(1);
179 }
180 }
181
182 int r = fs.mount();
183 if (r < 0) {
184 cerr << "unable to mount bluefs: " << cpp_strerror(r)
185 << std::endl;
186 exit(1);
187 }
188
189 vector<string> dirs;
190 r = fs.readdir("", &dirs);
191 if (r < 0) {
192 cerr << "readdir in root failed: " << cpp_strerror(r) << std::endl;
193 exit(1);
194 }
195 for (auto& dir : dirs) {
196 if (dir[0] == '.')
197 continue;
198 cout << dir << "/" << std::endl;
199 vector<string> ls;
200 r = fs.readdir(dir, &ls);
201 if (r < 0) {
202 cerr << "readdir " << dir << " failed: " << cpp_strerror(r) << std::endl;
203 exit(1);
204 }
205 string full = out_dir + "/" + dir;
206 r = ::mkdir(full.c_str(), 0755);
207 if (r < 0) {
208 cerr << "mkdir " << full << " failed: " << cpp_strerror(r) << std::endl;
209 exit(1);
210 }
211 for (auto& file : ls) {
212 if (file[0] == '.')
213 continue;
214 cout << dir << "/" << file << std::endl;
215 uint64_t size;
216 utime_t mtime;
217 r = fs.stat(dir, file, &size, &mtime);
218 if (r < 0) {
219 cerr << "stat " << file << " failed: " << cpp_strerror(r) << std::endl;
220 exit(1);
221 }
222 string path = out_dir + "/" + dir + "/" + file;
223 int fd = ::open(path.c_str(), O_CREAT|O_WRONLY|O_TRUNC, 0644);
224 if (fd < 0) {
225 r = -errno;
226 cerr << "open " << path << " failed: " << cpp_strerror(r) << std::endl;
227 exit(1);
228 }
229 assert(fd >= 0);
230 if (size > 0) {
231 BlueFS::FileReader *h;
232 r = fs.open_for_read(dir, file, &h, false);
233 if (r < 0) {
234 cerr << "open_for_read " << dir << "/" << file << " failed: "
235 << cpp_strerror(r) << std::endl;
236 exit(1);
237 }
238 int pos = 0;
239 int left = size;
240 while (left) {
241 bufferlist bl;
242 r = fs.read(h, &h->buf, pos, left, &bl, NULL);
243 if (r <= 0) {
244 cerr << "read " << dir << "/" << file << " from " << pos
245 << " failed: " << cpp_strerror(r) << std::endl;
246 exit(1);
247 }
248 int rc = bl.write_fd(fd);
249 if (rc < 0) {
250 cerr << "write to " << path << " failed: "
251 << cpp_strerror(r) << std::endl;
252 exit(1);
253 }
254 pos += r;
255 left -= r;
256 }
257 delete h;
258 }
259 ::close(fd);
260 }
261 }
262 fs.umount();
263 } else {
264 cerr << "unrecognized action " << action << std::endl;
265 return 1;
266 }
267
268 return 0;
269 }