1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 #include "tools/rbd/ArgumentTypes.h"
5 #include "tools/rbd/Shell.h"
6 #include "tools/rbd/Utils.h"
7 #include "include/types.h"
8 #include "include/stringify.h"
9 #include "common/errno.h"
10 #include "common/Formatter.h"
12 #include <boost/program_options.hpp>
14 #include "common/Clock.h"
20 namespace at
= argument_types
;
21 namespace po
= boost::program_options
;
23 static void format_bitmask(Formatter
*f
, const std::string
&name
,
24 const std::map
<uint64_t, std::string
>& mapping
,
28 std::string
group_name(name
+ "s");
30 std::cout
<< "\t" << group_name
<< ": ";
32 f
->open_array_section(group_name
.c_str());
34 for (std::map
<uint64_t, std::string
>::const_iterator it
= mapping
.begin();
35 it
!= mapping
.end(); ++it
) {
36 if ((it
->first
& bitmask
) == 0) {
44 std::cout
<< it
->second
;
46 f
->dump_string(name
.c_str(), it
->second
);
50 std::cout
<< std::endl
;
56 static void format_features(Formatter
*f
, uint64_t features
)
58 format_bitmask(f
, "feature", at::ImageFeatures::FEATURE_MAPPING
, features
);
61 static void format_op_features(Formatter
*f
, uint64_t op_features
)
63 static std::map
<uint64_t, std::string
> mapping
= {
64 {RBD_OPERATION_FEATURE_CLONE_PARENT
, RBD_OPERATION_FEATURE_NAME_CLONE_PARENT
},
65 {RBD_OPERATION_FEATURE_CLONE_CHILD
, RBD_OPERATION_FEATURE_NAME_CLONE_CHILD
},
66 {RBD_OPERATION_FEATURE_GROUP
, RBD_OPERATION_FEATURE_NAME_GROUP
},
67 {RBD_OPERATION_FEATURE_SNAP_TRASH
, RBD_OPERATION_FEATURE_NAME_SNAP_TRASH
}};
68 format_bitmask(f
, "op_feature", mapping
, op_features
);
71 static void format_flags(Formatter
*f
, uint64_t flags
)
73 std::map
<uint64_t, std::string
> mapping
= {
74 {RBD_FLAG_OBJECT_MAP_INVALID
, "object map invalid"},
75 {RBD_FLAG_FAST_DIFF_INVALID
, "fast diff invalid"}};
76 format_bitmask(f
, "flag", mapping
, flags
);
79 void format_timestamp(struct timespec timestamp
, std::string
×tamp_str
) {
80 if(timestamp
.tv_sec
!= 0) {
81 time_t ts
= timestamp
.tv_sec
;
82 timestamp_str
= ctime(&ts
);
83 timestamp_str
= timestamp_str
.substr(0, timestamp_str
.length() - 1);
87 static int do_show_info(librados::IoCtx
&io_ctx
, librbd::Image
& image
,
88 const std::string
&snapname
, Formatter
*f
)
90 librbd::image_info_t info
;
92 uint64_t overlap
, features
, flags
, snap_limit
;
93 bool snap_protected
= false;
94 librbd::mirror_image_info_t mirror_image
;
95 librbd::mirror_image_mode_t mirror_mode
= RBD_MIRROR_IMAGE_MODE_JOURNAL
;
96 std::vector
<librbd::snap_info_t
> snaps
;
100 r
= image
.get_name(&imgname
);
104 r
= image
.snap_list(snaps
);
108 r
= image
.stat(info
, sizeof(info
));
112 r
= image
.old_format(&old_format
);
118 r
= image
.get_id(&imgid
);
123 std::string data_pool
;
125 int64_t data_pool_id
= image
.get_data_pool_id();
126 if (data_pool_id
!= io_ctx
.get_id()) {
127 librados::Rados
rados(io_ctx
);
128 librados::IoCtx data_io_ctx
;
129 r
= rados
.ioctx_create2(data_pool_id
, data_io_ctx
);
131 data_pool
= "<missing data pool " + stringify(data_pool_id
) + ">";
133 data_pool
= data_io_ctx
.get_pool_name();
138 r
= image
.overlap(&overlap
);
142 r
= image
.features(&features
);
146 uint64_t op_features
;
147 r
= image
.get_op_features(&op_features
);
152 r
= image
.get_flags(&flags
);
157 if (!snapname
.empty()) {
158 r
= image
.snap_is_protected(snapname
.c_str(), &snap_protected
);
163 mirror_image
.state
= RBD_MIRROR_IMAGE_DISABLED
;
164 r
= image
.mirror_image_get_info(&mirror_image
, sizeof(mirror_image
));
169 if (mirror_image
.state
!= RBD_MIRROR_IMAGE_DISABLED
) {
170 r
= image
.mirror_image_get_mode(&mirror_mode
);
176 r
= image
.snap_get_limit(&snap_limit
);
180 std::string prefix
= image
.get_block_name_prefix();
182 librbd::group_info_t group_info
;
183 r
= image
.get_group(&group_info
, sizeof(group_info
));
188 std::string group_string
= "";
189 if (RBD_GROUP_INVALID_POOL
!= group_info
.pool
) {
190 std::string group_pool
;
191 librados::Rados
rados(io_ctx
);
192 librados::IoCtx group_io_ctx
;
193 r
= rados
.ioctx_create2(group_info
.pool
, group_io_ctx
);
195 group_pool
= "<missing group pool " + stringify(group_info
.pool
) + ">";
197 group_pool
= group_io_ctx
.get_pool_name();
200 group_string
= group_pool
+ "/";
201 if (!io_ctx
.get_namespace().empty()) {
202 group_string
+= io_ctx
.get_namespace() + "/";
204 group_string
+= group_info
.name
;
207 struct timespec create_timestamp
;
208 image
.get_create_timestamp(&create_timestamp
);
210 std::string create_timestamp_str
= "";
211 format_timestamp(create_timestamp
, create_timestamp_str
);
213 struct timespec access_timestamp
;
214 image
.get_access_timestamp(&access_timestamp
);
216 std::string access_timestamp_str
= "";
217 format_timestamp(access_timestamp
, access_timestamp_str
);
219 struct timespec modify_timestamp
;
220 image
.get_modify_timestamp(&modify_timestamp
);
222 std::string modify_timestamp_str
= "";
223 format_timestamp(modify_timestamp
, modify_timestamp_str
);
226 f
->open_object_section("image");
227 f
->dump_string("name", imgname
);
228 f
->dump_string("id", imgid
);
229 f
->dump_unsigned("size", info
.size
);
230 f
->dump_unsigned("objects", info
.num_objs
);
231 f
->dump_int("order", info
.order
);
232 f
->dump_unsigned("object_size", info
.obj_size
);
233 f
->dump_int("snapshot_count", snaps
.size());
234 if (!data_pool
.empty()) {
235 f
->dump_string("data_pool", data_pool
);
237 f
->dump_string("block_name_prefix", prefix
);
238 f
->dump_int("format", (old_format
? 1 : 2));
240 std::cout
<< "rbd image '" << imgname
<< "':\n"
241 << "\tsize " << byte_u_t(info
.size
) << " in "
242 << info
.num_objs
<< " objects"
244 << "\torder " << info
.order
245 << " (" << byte_u_t(info
.obj_size
) << " objects)"
247 << "\tsnapshot_count: " << snaps
.size()
249 if (!imgid
.empty()) {
250 std::cout
<< "\tid: " << imgid
<< std::endl
;
252 if (!data_pool
.empty()) {
253 std::cout
<< "\tdata_pool: " << data_pool
<< std::endl
;
255 std::cout
<< "\tblock_name_prefix: " << prefix
257 << "\tformat: " << (old_format
? "1" : "2")
262 format_features(f
, features
);
263 format_op_features(f
, op_features
);
264 format_flags(f
, flags
);
267 if (!group_string
.empty()) {
269 f
->dump_string("group", group_string
);
271 std::cout
<< "\tgroup: " << group_string
276 if (!create_timestamp_str
.empty()) {
278 f
->dump_string("create_timestamp", create_timestamp_str
);
280 std::cout
<< "\tcreate_timestamp: " << create_timestamp_str
285 if (!access_timestamp_str
.empty()) {
287 f
->dump_string("access_timestamp", access_timestamp_str
);
289 std::cout
<< "\taccess_timestamp: " << access_timestamp_str
294 if (!modify_timestamp_str
.empty()) {
296 f
->dump_string("modify_timestamp", modify_timestamp_str
);
298 std::cout
<< "\tmodify_timestamp: " << modify_timestamp_str
303 // snapshot info, if present
304 if (!snapname
.empty()) {
306 f
->dump_string("protected", snap_protected
? "true" : "false");
308 std::cout
<< "\tprotected: " << (snap_protected
? "True" : "False")
313 if (snap_limit
< UINT64_MAX
) {
315 f
->dump_unsigned("snapshot_limit", snap_limit
);
317 std::cout
<< "\tsnapshot_limit: " << snap_limit
<< std::endl
;
321 // parent info, if present
322 librbd::linked_image_spec_t parent_image_spec
;
323 librbd::snap_spec_t parent_snap_spec
;
324 if ((image
.get_parent(&parent_image_spec
, &parent_snap_spec
) == 0) &&
325 (parent_image_spec
.image_name
.length() > 0)) {
327 f
->open_object_section("parent");
328 f
->dump_string("pool", parent_image_spec
.pool_name
);
329 f
->dump_string("pool_namespace", parent_image_spec
.pool_namespace
);
330 f
->dump_string("image", parent_image_spec
.image_name
);
331 f
->dump_string("id", parent_image_spec
.image_id
);
332 f
->dump_string("snapshot", parent_snap_spec
.name
);
333 f
->dump_bool("trash", parent_image_spec
.trash
);
334 f
->dump_unsigned("overlap", overlap
);
337 std::cout
<< "\tparent: " << parent_image_spec
.pool_name
<< "/";
338 if (!parent_image_spec
.pool_namespace
.empty()) {
339 std::cout
<< parent_image_spec
.pool_namespace
<< "/";
341 std::cout
<< parent_image_spec
.image_name
<< "@"
342 << parent_snap_spec
.name
;
343 if (parent_image_spec
.trash
) {
344 std::cout
<< " (trash " << parent_image_spec
.image_id
<< ")";
346 std::cout
<< std::endl
;
347 std::cout
<< "\toverlap: " << byte_u_t(overlap
) << std::endl
;
351 // striping info, if feature is set
352 if (features
& RBD_FEATURE_STRIPINGV2
) {
354 f
->dump_unsigned("stripe_unit", image
.get_stripe_unit());
355 f
->dump_unsigned("stripe_count", image
.get_stripe_count());
357 std::cout
<< "\tstripe unit: " << byte_u_t(image
.get_stripe_unit())
359 << "\tstripe count: " << image
.get_stripe_count() << std::endl
;
363 if (features
& RBD_FEATURE_JOURNALING
) {
365 f
->dump_string("journal", utils::image_id(image
));
367 std::cout
<< "\tjournal: " << utils::image_id(image
) << std::endl
;
371 if (features
& RBD_FEATURE_JOURNALING
||
372 mirror_image
.state
!= RBD_MIRROR_IMAGE_DISABLED
) {
374 f
->open_object_section("mirroring");
375 f
->dump_string("mode",
376 utils::mirror_image_mode(mirror_mode
));
377 f
->dump_string("state",
378 utils::mirror_image_state(mirror_image
.state
));
379 if (mirror_image
.state
!= RBD_MIRROR_IMAGE_DISABLED
) {
380 f
->dump_string("global_id", mirror_image
.global_id
);
381 f
->dump_bool("primary", mirror_image
.primary
);
385 std::cout
<< "\tmirroring state: "
386 << utils::mirror_image_state(mirror_image
.state
) << std::endl
;
387 if (mirror_image
.state
!= RBD_MIRROR_IMAGE_DISABLED
) {
388 std::cout
<< "\tmirroring mode: "
389 << utils::mirror_image_mode(mirror_mode
) << std::endl
390 << "\tmirroring global id: " << mirror_image
.global_id
392 << "\tmirroring primary: "
393 << (mirror_image
.primary
? "true" : "false") <<std::endl
;
406 void get_arguments(po::options_description
*positional
,
407 po::options_description
*options
) {
408 at::add_image_or_snap_spec_options(positional
, options
,
409 at::ARGUMENT_MODIFIER_NONE
);
410 at::add_image_id_option(options
);
411 at::add_format_options(options
);
414 int execute(const po::variables_map
&vm
,
415 const std::vector
<std::string
> &ceph_global_init_args
) {
416 size_t arg_index
= 0;
417 std::string pool_name
;
418 std::string namespace_name
;
419 std::string image_name
;
420 std::string snap_name
;
421 std::string image_id
;
423 if (vm
.count(at::IMAGE_ID
)) {
424 image_id
= vm
[at::IMAGE_ID
].as
<std::string
>();
427 int r
= utils::get_pool_image_snapshot_names(
428 vm
, at::ARGUMENT_MODIFIER_NONE
, &arg_index
, &pool_name
, &namespace_name
,
429 &image_name
, &snap_name
, image_id
.empty(),
430 utils::SNAPSHOT_PRESENCE_PERMITTED
, utils::SPEC_VALIDATION_NONE
);
435 if (!image_id
.empty() && !image_name
.empty()) {
436 std::cerr
<< "rbd: trying to access image using both name and id. "
441 at::Format::Formatter formatter
;
442 r
= utils::get_formatter(vm
, &formatter
);
447 librados::Rados rados
;
448 librados::IoCtx io_ctx
;
450 r
= utils::init_and_open_image(pool_name
, namespace_name
, image_name
,
451 image_id
, snap_name
, true, &rados
, &io_ctx
,
457 r
= do_show_info(io_ctx
, image
, snap_name
, formatter
.get());
459 std::cerr
<< "rbd: info: " << cpp_strerror(r
) << std::endl
;
465 Shell::Action
action(
466 {"info"}, {}, "Show information about image size, striping, etc.", "",
467 &get_arguments
, &execute
);
470 } // namespace action