]>
Commit | Line | Data |
---|---|---|
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 "tools/rbd/ArgumentTypes.h" | |
5 | #include "tools/rbd/Shell.h" | |
6 | #include "tools/rbd/Utils.h" | |
d2e6a577 | 7 | #include "include/Context.h" |
7c673cae FG |
8 | #include "include/stringify.h" |
9 | #include "include/types.h" | |
10 | #include "common/errno.h" | |
11 | #include "common/Formatter.h" | |
12 | #include "common/TextTable.h" | |
13 | #include <iostream> | |
f67539c2 | 14 | #include <boost/bind/bind.hpp> |
7c673cae | 15 | #include <boost/program_options.hpp> |
d2e6a577 | 16 | #include "global/global_context.h" |
7c673cae FG |
17 | |
18 | namespace rbd { | |
d2e6a577 | 19 | |
7c673cae FG |
20 | namespace action { |
21 | namespace list { | |
22 | ||
23 | namespace at = argument_types; | |
24 | namespace po = boost::program_options; | |
f67539c2 | 25 | using namespace boost::placeholders; |
7c673cae | 26 | |
d2e6a577 FG |
27 | enum WorkerState { |
28 | STATE_IDLE = 0, | |
29 | STATE_OPENED, | |
30 | STATE_DONE | |
31 | } ; | |
32 | ||
33 | struct WorkerEntry { | |
34 | librbd::Image img; | |
35 | librbd::RBD::AioCompletion* completion; | |
36 | WorkerState state; | |
20effc67 TL |
37 | std::string name; |
38 | std::string id; | |
d2e6a577 FG |
39 | |
40 | WorkerEntry() { | |
41 | state = STATE_IDLE; | |
42 | completion = nullptr; | |
43 | } | |
44 | }; | |
45 | ||
46 | ||
47 | int list_process_image(librados::Rados* rados, WorkerEntry* w, bool lflag, Formatter *f, TextTable &tbl) | |
48 | { | |
49 | int r = 0; | |
50 | librbd::image_info_t info; | |
11fdf7f2 | 51 | std::string parent; |
d2e6a577 FG |
52 | |
53 | // handle second-nth trips through loop | |
11fdf7f2 TL |
54 | librbd::linked_image_spec_t parent_image_spec; |
55 | librbd::snap_spec_t parent_snap_spec; | |
56 | r = w->img.get_parent(&parent_image_spec, &parent_snap_spec); | |
57 | if (r < 0 && r != -ENOENT) { | |
d2e6a577 | 58 | return r; |
11fdf7f2 TL |
59 | } |
60 | ||
d2e6a577 FG |
61 | bool has_parent = false; |
62 | if (r != -ENOENT) { | |
11fdf7f2 TL |
63 | parent = parent_image_spec.pool_name + "/"; |
64 | if (!parent_image_spec.pool_namespace.empty()) { | |
65 | parent += parent_image_spec.pool_namespace + "/"; | |
66 | } | |
67 | parent += parent_image_spec.image_name + "@" + parent_snap_spec.name; | |
d2e6a577 FG |
68 | has_parent = true; |
69 | } | |
70 | ||
71 | if (w->img.stat(info, sizeof(info)) < 0) { | |
72 | return -EINVAL; | |
73 | } | |
74 | ||
75 | uint8_t old_format; | |
76 | w->img.old_format(&old_format); | |
77 | ||
78 | std::list<librbd::locker_t> lockers; | |
79 | bool exclusive; | |
80 | r = w->img.list_lockers(&lockers, &exclusive, NULL); | |
81 | if (r < 0) | |
82 | return r; | |
83 | std::string lockstr; | |
84 | if (!lockers.empty()) { | |
85 | lockstr = (exclusive) ? "excl" : "shr"; | |
86 | } | |
87 | ||
88 | if (f) { | |
89 | f->open_object_section("image"); | |
90 | f->dump_string("image", w->name); | |
9f95a23c | 91 | f->dump_string("id", w->id); |
d2e6a577 FG |
92 | f->dump_unsigned("size", info.size); |
93 | if (has_parent) { | |
94 | f->open_object_section("parent"); | |
11fdf7f2 TL |
95 | f->dump_string("pool", parent_image_spec.pool_name); |
96 | f->dump_string("pool_namespace", parent_image_spec.pool_namespace); | |
97 | f->dump_string("image", parent_image_spec.image_name); | |
98 | f->dump_string("snapshot", parent_snap_spec.name); | |
d2e6a577 FG |
99 | f->close_section(); |
100 | } | |
101 | f->dump_int("format", old_format ? 1 : 2); | |
102 | if (!lockers.empty()) | |
103 | f->dump_string("lock_type", exclusive ? "exclusive" : "shared"); | |
104 | f->close_section(); | |
105 | } else { | |
106 | tbl << w->name | |
1adf2230 | 107 | << stringify(byte_u_t(info.size)) |
d2e6a577 FG |
108 | << parent |
109 | << ((old_format) ? '1' : '2') | |
110 | << "" // protect doesn't apply to images | |
111 | << lockstr | |
112 | << TextTable::endrow; | |
113 | } | |
114 | ||
115 | std::vector<librbd::snap_info_t> snaplist; | |
116 | if (w->img.snap_list(snaplist) >= 0 && !snaplist.empty()) { | |
11fdf7f2 TL |
117 | snaplist.erase(remove_if(snaplist.begin(), |
118 | snaplist.end(), | |
119 | boost::bind(utils::is_not_user_snap_namespace, &w->img, _1)), | |
120 | snaplist.end()); | |
d2e6a577 FG |
121 | for (std::vector<librbd::snap_info_t>::iterator s = snaplist.begin(); |
122 | s != snaplist.end(); ++s) { | |
123 | bool is_protected; | |
124 | bool has_parent = false; | |
125 | parent.clear(); | |
126 | w->img.snap_set(s->name.c_str()); | |
127 | r = w->img.snap_is_protected(s->name.c_str(), &is_protected); | |
128 | if (r < 0) | |
129 | return r; | |
11fdf7f2 TL |
130 | if (w->img.get_parent(&parent_image_spec, &parent_snap_spec) >= 0) { |
131 | parent = parent_image_spec.pool_name + "/"; | |
132 | if (!parent_image_spec.pool_namespace.empty()) { | |
133 | parent += parent_image_spec.pool_namespace + "/"; | |
134 | } | |
135 | parent += parent_image_spec.image_name + "@" + parent_snap_spec.name; | |
d2e6a577 FG |
136 | has_parent = true; |
137 | } | |
138 | if (f) { | |
139 | f->open_object_section("snapshot"); | |
140 | f->dump_string("image", w->name); | |
9f95a23c | 141 | f->dump_string("id", w->id); |
d2e6a577 | 142 | f->dump_string("snapshot", s->name); |
9f95a23c | 143 | f->dump_unsigned("snapshot_id", s->id); |
d2e6a577 FG |
144 | f->dump_unsigned("size", s->size); |
145 | if (has_parent) { | |
146 | f->open_object_section("parent"); | |
11fdf7f2 TL |
147 | f->dump_string("pool", parent_image_spec.pool_name); |
148 | f->dump_string("pool_namespace", parent_image_spec.pool_namespace); | |
149 | f->dump_string("image", parent_image_spec.image_name); | |
150 | f->dump_string("snapshot", parent_snap_spec.name); | |
d2e6a577 FG |
151 | f->close_section(); |
152 | } | |
153 | f->dump_int("format", old_format ? 1 : 2); | |
154 | f->dump_string("protected", is_protected ? "true" : "false"); | |
155 | f->close_section(); | |
156 | } else { | |
157 | tbl << w->name + "@" + s->name | |
1adf2230 | 158 | << stringify(byte_u_t(s->size)) |
d2e6a577 FG |
159 | << parent |
160 | << ((old_format) ? '1' : '2') | |
161 | << (is_protected ? "yes" : "") | |
162 | << "" // locks don't apply to snaps | |
163 | << TextTable::endrow; | |
164 | } | |
165 | } | |
166 | } | |
167 | ||
11fdf7f2 | 168 | return 0; |
d2e6a577 FG |
169 | } |
170 | ||
11fdf7f2 | 171 | int do_list(const std::string &pool_name, const std::string& namespace_name, |
f67539c2 | 172 | bool lflag, Formatter *f) { |
d2e6a577 | 173 | std::vector<WorkerEntry*> workers; |
11fdf7f2 | 174 | std::vector<librbd::image_spec_t> images; |
d2e6a577 FG |
175 | librados::Rados rados; |
176 | librbd::RBD rbd; | |
177 | librados::IoCtx ioctx; | |
178 | ||
f67539c2 TL |
179 | int r = utils::init(pool_name, namespace_name, &rados, &ioctx); |
180 | if (r < 0) { | |
181 | return r; | |
182 | } | |
183 | ||
184 | int threads = g_conf().get_val<uint64_t>("rbd_concurrent_management_ops"); | |
d2e6a577 FG |
185 | if (threads < 1) { |
186 | threads = 1; | |
187 | } | |
188 | if (threads > 32) { | |
189 | threads = 32; | |
190 | } | |
191 | ||
11fdf7f2 TL |
192 | utils::disable_cache(); |
193 | ||
194 | r = rbd.list2(ioctx, &images); | |
7c673cae FG |
195 | if (r < 0) |
196 | return r; | |
197 | ||
198 | if (!lflag) { | |
199 | if (f) | |
200 | f->open_array_section("images"); | |
11fdf7f2 | 201 | for (auto& image : images) { |
7c673cae | 202 | if (f) |
11fdf7f2 | 203 | f->dump_string("name", image.name); |
7c673cae | 204 | else |
11fdf7f2 | 205 | std::cout << image.name << std::endl; |
7c673cae FG |
206 | } |
207 | if (f) { | |
208 | f->close_section(); | |
209 | f->flush(std::cout); | |
210 | } | |
211 | return 0; | |
212 | } | |
213 | ||
214 | TextTable tbl; | |
215 | ||
216 | if (f) { | |
217 | f->open_array_section("images"); | |
218 | } else { | |
219 | tbl.define_column("NAME", TextTable::LEFT, TextTable::LEFT); | |
11fdf7f2 | 220 | tbl.define_column("SIZE", TextTable::LEFT, TextTable::RIGHT); |
7c673cae | 221 | tbl.define_column("PARENT", TextTable::LEFT, TextTable::LEFT); |
11fdf7f2 | 222 | tbl.define_column("FMT", TextTable::LEFT, TextTable::RIGHT); |
7c673cae FG |
223 | tbl.define_column("PROT", TextTable::LEFT, TextTable::LEFT); |
224 | tbl.define_column("LOCK", TextTable::LEFT, TextTable::LEFT); | |
225 | } | |
226 | ||
11fdf7f2 TL |
227 | for (size_t left = 0; left < std::min<size_t>(threads, images.size()); |
228 | left++) { | |
d2e6a577 FG |
229 | workers.push_back(new WorkerEntry()); |
230 | } | |
7c673cae | 231 | |
11fdf7f2 | 232 | auto i = images.begin(); |
d2e6a577 FG |
233 | while (true) { |
234 | size_t workers_idle = 0; | |
235 | for (auto comp : workers) { | |
236 | switch (comp->state) { | |
237 | case STATE_DONE: | |
238 | comp->completion->wait_for_complete(); | |
239 | comp->state = STATE_IDLE; | |
240 | comp->completion->release(); | |
241 | comp->completion = nullptr; | |
242 | // we want it to fall through in this case | |
243 | case STATE_IDLE: | |
11fdf7f2 | 244 | if (i == images.end()) { |
d2e6a577 FG |
245 | workers_idle++; |
246 | continue; | |
247 | } | |
11fdf7f2 | 248 | comp->name = i->name; |
9f95a23c | 249 | comp->id = i->id; |
d2e6a577 | 250 | comp->completion = new librbd::RBD::AioCompletion(nullptr, nullptr); |
11fdf7f2 TL |
251 | r = rbd.aio_open_read_only(ioctx, comp->img, i->name.c_str(), nullptr, |
252 | comp->completion); | |
d2e6a577 FG |
253 | i++; |
254 | comp->state = STATE_OPENED; | |
255 | break; | |
256 | case STATE_OPENED: | |
257 | comp->completion->wait_for_complete(); | |
258 | // image might disappear between rbd.list() and rbd.open(); ignore | |
259 | // that, warn about other possible errors (EPERM, say, for opening | |
260 | // an old-format image, because you need execute permission for the | |
261 | // class method) | |
262 | r = comp->completion->get_return_value(); | |
263 | comp->completion->release(); | |
264 | if (r < 0) { | |
11fdf7f2 TL |
265 | std::cerr << "rbd: error opening " << comp->name << ": " |
266 | << cpp_strerror(r) << std::endl; | |
267 | ||
d2e6a577 FG |
268 | // in any event, continue to next image |
269 | comp->state = STATE_IDLE; | |
270 | continue; | |
271 | } | |
272 | r = list_process_image(&rados, comp, lflag, f, tbl); | |
273 | if (r < 0) { | |
11fdf7f2 TL |
274 | std::cerr << "rbd: error processing image " << comp->name << ": " |
275 | << cpp_strerror(r) << std::endl; | |
d2e6a577 FG |
276 | } |
277 | comp->completion = new librbd::RBD::AioCompletion(nullptr, nullptr); | |
278 | r = comp->img.aio_close(comp->completion); | |
279 | comp->state = STATE_DONE; | |
280 | break; | |
7c673cae | 281 | } |
7c673cae | 282 | } |
d2e6a577 FG |
283 | if (workers_idle == workers.size()) { |
284 | break; | |
7c673cae FG |
285 | } |
286 | } | |
287 | ||
7c673cae FG |
288 | if (f) { |
289 | f->close_section(); | |
290 | f->flush(std::cout); | |
11fdf7f2 | 291 | } else if (!images.empty()) { |
7c673cae FG |
292 | std::cout << tbl; |
293 | } | |
294 | ||
d2e6a577 FG |
295 | rados.shutdown(); |
296 | ||
297 | for (auto comp : workers) { | |
298 | delete comp; | |
299 | } | |
300 | ||
7c673cae FG |
301 | return r < 0 ? r : 0; |
302 | } | |
303 | ||
304 | void get_arguments(po::options_description *positional, | |
305 | po::options_description *options) { | |
306 | options->add_options() | |
307 | ("long,l", po::bool_switch(), "long listing format"); | |
11fdf7f2 | 308 | at::add_pool_options(positional, options, true); |
7c673cae FG |
309 | at::add_format_options(options); |
310 | } | |
311 | ||
11fdf7f2 TL |
312 | int execute(const po::variables_map &vm, |
313 | const std::vector<std::string> &ceph_global_init_args) { | |
314 | std::string pool_name; | |
315 | std::string namespace_name; | |
7c673cae | 316 | size_t arg_index = 0; |
2a845540 | 317 | int r = utils::get_pool_and_namespace_names(vm, false, &pool_name, |
11fdf7f2 TL |
318 | &namespace_name, &arg_index); |
319 | if (r < 0) { | |
320 | return r; | |
321 | } | |
7c673cae FG |
322 | |
323 | at::Format::Formatter formatter; | |
11fdf7f2 | 324 | r = utils::get_formatter(vm, &formatter); |
7c673cae FG |
325 | if (r < 0) { |
326 | return r; | |
327 | } | |
328 | ||
11fdf7f2 | 329 | r = do_list(pool_name, namespace_name, vm["long"].as<bool>(), |
181888fb | 330 | formatter.get()); |
7c673cae | 331 | if (r < 0) { |
11fdf7f2 TL |
332 | std::cerr << "rbd: listing images failed: " << cpp_strerror(r) |
333 | << std::endl; | |
7c673cae FG |
334 | return r; |
335 | } | |
336 | ||
337 | return 0; | |
338 | } | |
339 | ||
340 | Shell::SwitchArguments switched_arguments({"long", "l"}); | |
341 | Shell::Action action( | |
342 | {"list"}, {"ls"}, "List rbd images.", "", &get_arguments, &execute); | |
343 | ||
344 | } // namespace list | |
345 | } // namespace action | |
346 | } // namespace rbd |