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