]> git.proxmox.com Git - ceph.git/blame - ceph/src/tools/rbd/action/List.cc
bump version to 18.2.2-pve1
[ceph.git] / ceph / src / tools / rbd / action / List.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 "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
18namespace rbd {
d2e6a577 19
7c673cae
FG
20namespace action {
21namespace list {
22
23namespace at = argument_types;
24namespace po = boost::program_options;
f67539c2 25using namespace boost::placeholders;
7c673cae 26
d2e6a577
FG
27enum WorkerState {
28 STATE_IDLE = 0,
29 STATE_OPENED,
30 STATE_DONE
31} ;
32
33struct 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
47int 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 171int 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
304void 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
312int 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
340Shell::SwitchArguments switched_arguments({"long", "l"});
341Shell::Action action(
342 {"list"}, {"ls"}, "List rbd images.", "", &get_arguments, &execute);
343
344} // namespace list
345} // namespace action
346} // namespace rbd