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/Utils.h"
5 #include "include/assert.h"
6 #include "include/Context.h"
7 #include "include/encoding.h"
8 #include "common/common_init.h"
9 #include "include/stringify.h"
10 #include "include/rbd/features.h"
11 #include "common/config.h"
12 #include "common/errno.h"
13 #include "common/safe_io.h"
14 #include "global/global_context.h"
16 #include <boost/regex.hpp>
17 #include <boost/algorithm/string.hpp>
18 #include <boost/lexical_cast.hpp>
23 namespace at
= argument_types
;
24 namespace po
= boost::program_options
;
26 int ProgressContext::update_progress(uint64_t offset
, uint64_t total
) {
28 int pc
= total
? (offset
* 100ull / total
) : 0;
30 cerr
<< "\r" << operation
<< ": "
31 << pc
<< "% complete...";
39 void ProgressContext::finish() {
41 cerr
<< "\r" << operation
<< ": 100% complete...done." << std::endl
;
45 void ProgressContext::fail() {
47 cerr
<< "\r" << operation
<< ": " << last_pc
<< "% complete...failed."
52 void aio_context_callback(librbd::completion_t completion
, void *arg
)
54 librbd::RBD::AioCompletion
*aio_completion
=
55 reinterpret_cast<librbd::RBD::AioCompletion
*>(completion
);
56 Context
*context
= reinterpret_cast<Context
*>(arg
);
57 context
->complete(aio_completion
->get_return_value());
58 aio_completion
->release();
61 int read_string(int fd
, unsigned max
, std::string
*out
) {
64 int r
= safe_read_exact(fd
, buf
, 4);
70 bufferlist::iterator p
= bl
.begin();
77 r
= safe_read_exact(fd
, sbuf
, len
);
80 out
->assign(sbuf
, len
);
84 int extract_spec(const std::string
&spec
, std::string
*pool_name
,
85 std::string
*image_name
, std::string
*snap_name
,
86 SpecValidation spec_validation
) {
87 if (!g_ceph_context
->_conf
->rbd_validate_names
) {
88 spec_validation
= SPEC_VALIDATION_NONE
;
92 switch (spec_validation
) {
93 case SPEC_VALIDATION_FULL
:
94 // disallow "/" and "@" in image and snap name
95 pattern
= "^(?:([^/@]+)/)?([^/@]+)(?:@([^/@]+))?$";
97 case SPEC_VALIDATION_SNAP
:
98 // disallow "/" and "@" in snap name
99 pattern
= "^(?:([^/]+)/)?([^@]+)(?:@([^/@]+))?$";
101 case SPEC_VALIDATION_NONE
:
102 // relaxed pattern assumes pool is before first "/" and snap
103 // name is after first "@"
104 pattern
= "^(?:([^/]+)/)?([^@]+)(?:@(.+))?$";
112 if (!boost::regex_match(spec
, match
, pattern
)) {
113 std::cerr
<< "rbd: invalid spec '" << spec
<< "'" << std::endl
;
117 if (pool_name
!= nullptr && match
[1].matched
) {
118 *pool_name
= match
[1];
120 if (image_name
!= nullptr) {
121 *image_name
= match
[2];
123 if (snap_name
!= nullptr && match
[3].matched
) {
124 *snap_name
= match
[3];
129 int extract_group_spec(const std::string
&spec
,
130 std::string
*pool_name
,
131 std::string
*group_name
) {
132 boost::regex pattern
;
133 pattern
= "^(?:([^/]+)/)?(.+)?$";
136 if (!boost::regex_match(spec
, match
, pattern
)) {
137 std::cerr
<< "rbd: invalid spec '" << spec
<< "'" << std::endl
;
141 if (pool_name
!= nullptr && match
[1].matched
) {
142 *pool_name
= match
[1];
144 if (group_name
!= nullptr) {
145 *group_name
= match
[2];
151 int extract_image_id_spec(const std::string
&spec
, std::string
*pool_name
,
152 std::string
*image_id
) {
153 boost::regex pattern
;
154 pattern
= "^(?:([^/]+)/)?(.+)?$";
157 if (!boost::regex_match(spec
, match
, pattern
)) {
158 std::cerr
<< "rbd: invalid spec '" << spec
<< "'" << std::endl
;
162 if (pool_name
!= nullptr && match
[1].matched
) {
163 *pool_name
= match
[1];
165 if (image_id
!= nullptr) {
166 *image_id
= match
[2];
173 std::string
get_positional_argument(const po::variables_map
&vm
, size_t index
) {
174 if (vm
.count(at::POSITIONAL_ARGUMENTS
) == 0) {
178 const std::vector
<std::string
> &args
=
179 boost::any_cast
<std::vector
<std::string
> >(
180 vm
[at::POSITIONAL_ARGUMENTS
].value());
181 if (index
< args
.size()) {
187 std::string
get_pool_name(const po::variables_map
&vm
,
189 std::string pool_name
;
190 if (vm
.count(at::POOL_NAME
)) {
191 pool_name
= vm
[at::POOL_NAME
].as
<std::string
>();
193 pool_name
= get_positional_argument(vm
, *arg_index
);
194 if (!pool_name
.empty()) {
199 if (pool_name
.empty()) {
200 pool_name
= at::DEFAULT_POOL_NAME
;
205 int get_special_pool_group_names(const po::variables_map
&vm
,
207 std::string
*group_pool_name
,
208 std::string
*group_name
) {
209 if (nullptr == group_pool_name
) return -EINVAL
;
210 if (nullptr == group_name
) return -EINVAL
;
211 std::string pool_key
= at::POOL_NAME
;
213 std::string group_pool_key
= "group-" + at::POOL_NAME
;
214 std::string group_key
= at::GROUP_NAME
;
216 if (vm
.count(group_pool_key
)) {
217 *group_pool_name
= vm
[group_pool_key
].as
<std::string
>();
220 if (vm
.count(group_key
)) {
221 *group_name
= vm
[group_key
].as
<std::string
>();
225 if (group_name
->empty()) {
226 std::string spec
= utils::get_positional_argument(vm
, (*arg_index
)++);
228 r
= utils::extract_group_spec(spec
, group_pool_name
, group_name
);
235 if (group_pool_name
->empty() && vm
.count(pool_key
)) {
236 *group_pool_name
= vm
[pool_key
].as
<std::string
>();
239 if (group_pool_name
->empty()) {
240 *group_pool_name
= at::DEFAULT_POOL_NAME
;
243 if (group_name
->empty()) {
244 std::cerr
<< "rbd: consistency group name was not specified" << std::endl
;
251 int get_special_pool_image_names(const po::variables_map
&vm
,
253 std::string
*image_pool_name
,
254 std::string
*image_name
) {
255 if (nullptr == image_pool_name
) return -EINVAL
;
256 if (nullptr == image_name
) return -EINVAL
;
258 std::string pool_key
= at::POOL_NAME
;
260 std::string image_pool_key
= "image-" + at::POOL_NAME
;
261 std::string image_key
= at::IMAGE_NAME
;
263 if (vm
.count(image_pool_key
)) {
264 *image_pool_name
= vm
[image_pool_key
].as
<std::string
>();
267 if (vm
.count(image_key
)) {
268 *image_name
= vm
[image_key
].as
<std::string
>();
272 if (image_name
->empty()) {
273 std::string spec
= utils::get_positional_argument(vm
, (*arg_index
)++);
275 r
= utils::extract_spec(spec
, image_pool_name
,
277 utils::SPEC_VALIDATION_NONE
);
284 if (image_pool_name
->empty() && vm
.count(pool_key
)) {
285 *image_pool_name
= vm
[pool_key
].as
<std::string
>();
288 if (image_pool_name
->empty()) {
289 *image_pool_name
= at::DEFAULT_POOL_NAME
;
292 if (image_name
->empty()) {
293 std::cerr
<< "rbd: image name was not specified" << std::endl
;
300 int get_pool_image_id(const po::variables_map
&vm
,
301 size_t *spec_arg_index
,
302 std::string
*pool_name
,
303 std::string
*image_id
) {
305 if (vm
.count(at::POOL_NAME
) && pool_name
!= nullptr) {
306 *pool_name
= vm
[at::POOL_NAME
].as
<std::string
>();
308 if (vm
.count(at::IMAGE_ID
) && image_id
!= nullptr) {
309 *image_id
= vm
[at::IMAGE_ID
].as
<std::string
>();
313 if (image_id
!= nullptr && spec_arg_index
!= nullptr && image_id
->empty()) {
314 std::string spec
= get_positional_argument(vm
, (*spec_arg_index
)++);
316 r
= extract_image_id_spec(spec
, pool_name
, image_id
);
323 if (pool_name
->empty()) {
324 *pool_name
= at::DEFAULT_POOL_NAME
;
327 if (image_id
!= nullptr && image_id
->empty()) {
328 std::cerr
<< "rbd: image id was not specified" << std::endl
;
335 int get_pool_group_names(const po::variables_map
&vm
,
336 at::ArgumentModifier mod
,
337 size_t *spec_arg_index
,
338 std::string
*pool_name
,
339 std::string
*group_name
) {
340 std::string pool_key
= (mod
== at::ARGUMENT_MODIFIER_DEST
?
341 at::DEST_POOL_NAME
: at::POOL_NAME
);
342 std::string group_key
= (mod
== at::ARGUMENT_MODIFIER_DEST
?
343 at::DEST_GROUP_NAME
: at::GROUP_NAME
);
345 if (vm
.count(pool_key
) && pool_name
!= nullptr) {
346 *pool_name
= vm
[pool_key
].as
<std::string
>();
348 if (vm
.count(group_key
) && group_name
!= nullptr) {
349 *group_name
= vm
[group_key
].as
<std::string
>();
353 if (group_name
!= nullptr && spec_arg_index
!= nullptr &&
354 group_name
->empty()) {
355 std::string spec
= get_positional_argument(vm
, (*spec_arg_index
)++);
357 r
= extract_group_spec(spec
, pool_name
, group_name
);
364 if (pool_name
->empty()) {
365 *pool_name
= at::DEFAULT_POOL_NAME
;
368 if (group_name
!= nullptr && group_name
->empty()) {
369 std::string prefix
= at::get_description_prefix(mod
);
371 << (mod
== at::ARGUMENT_MODIFIER_DEST
? prefix
: std::string())
372 << "group name was not specified" << std::endl
;
379 int get_pool_image_snapshot_names(const po::variables_map
&vm
,
380 at::ArgumentModifier mod
,
381 size_t *spec_arg_index
,
382 std::string
*pool_name
,
383 std::string
*image_name
,
384 std::string
*snap_name
,
385 SnapshotPresence snapshot_presence
,
386 SpecValidation spec_validation
,
387 bool image_required
) {
388 std::string pool_key
= (mod
== at::ARGUMENT_MODIFIER_DEST
?
389 at::DEST_POOL_NAME
: at::POOL_NAME
);
390 std::string image_key
= (mod
== at::ARGUMENT_MODIFIER_DEST
?
391 at::DEST_IMAGE_NAME
: at::IMAGE_NAME
);
392 std::string snap_key
= (mod
== at::ARGUMENT_MODIFIER_DEST
?
393 at::DEST_SNAPSHOT_NAME
: at::SNAPSHOT_NAME
);
395 if (vm
.count(pool_key
) && pool_name
!= nullptr) {
396 *pool_name
= vm
[pool_key
].as
<std::string
>();
398 if (vm
.count(image_key
) && image_name
!= nullptr) {
399 *image_name
= vm
[image_key
].as
<std::string
>();
401 if (vm
.count(snap_key
) && snap_name
!= nullptr) {
402 *snap_name
= vm
[snap_key
].as
<std::string
>();
406 if (image_name
!= nullptr && !image_name
->empty()) {
407 // despite the separate pool and snapshot name options,
408 // we can also specify them via the image option
409 std::string
image_name_copy(*image_name
);
410 r
= extract_spec(image_name_copy
, pool_name
, image_name
, snap_name
,
417 if (image_name
!= nullptr && spec_arg_index
!= nullptr &&
418 image_name
->empty()) {
419 std::string spec
= get_positional_argument(vm
, (*spec_arg_index
)++);
421 r
= extract_spec(spec
, pool_name
, image_name
, snap_name
, spec_validation
);
428 if (pool_name
!= nullptr && pool_name
->empty()) {
429 *pool_name
= at::DEFAULT_POOL_NAME
;
432 if (image_name
!= nullptr && image_required
&& image_name
->empty()) {
433 std::string prefix
= at::get_description_prefix(mod
);
435 << (mod
== at::ARGUMENT_MODIFIER_DEST
? prefix
: std::string())
436 << "image name was not specified" << std::endl
;
440 //Validate pool name while creating/renaming/copying/cloning/importing/etc image
441 if (spec_validation
== SPEC_VALIDATION_FULL
) {
442 boost::regex
pattern("^[^@/]*?$");
443 if (!boost::regex_match (*pool_name
, pattern
)) {
444 std::cerr
<< "rbd: invalid spec '" << *pool_name
<< "'" << std::endl
;
449 if (snap_name
!= nullptr) {
450 r
= validate_snapshot_name(mod
, *snap_name
, snapshot_presence
,
459 int get_pool_snapshot_names(const po::variables_map
&vm
,
460 at::ArgumentModifier mod
,
461 size_t *spec_arg_index
,
462 std::string
*pool_name
,
463 std::string
*snap_name
,
464 SnapshotPresence snapshot_presence
,
465 SpecValidation spec_validation
) {
466 std::string pool_key
= (mod
== at::ARGUMENT_MODIFIER_DEST
?
467 at::DEST_POOL_NAME
: at::POOL_NAME
);
468 std::string snap_key
= (mod
== at::ARGUMENT_MODIFIER_DEST
?
469 at::DEST_SNAPSHOT_NAME
: at::SNAPSHOT_NAME
);
471 if (vm
.count(pool_key
) && pool_name
!= nullptr) {
472 *pool_name
= vm
[pool_key
].as
<std::string
>();
474 if (vm
.count(snap_key
) && snap_name
!= nullptr) {
475 *snap_name
= vm
[snap_key
].as
<std::string
>();
478 if (pool_name
!= nullptr && pool_name
->empty()) {
479 *pool_name
= at::DEFAULT_POOL_NAME
;
482 if (snap_name
!= nullptr) {
483 int r
= validate_snapshot_name(mod
, *snap_name
, snapshot_presence
,
492 int get_pool_journal_names(const po::variables_map
&vm
,
493 at::ArgumentModifier mod
,
494 size_t *spec_arg_index
,
495 std::string
*pool_name
,
496 std::string
*journal_name
) {
497 std::string pool_key
= (mod
== at::ARGUMENT_MODIFIER_DEST
?
498 at::DEST_POOL_NAME
: at::POOL_NAME
);
499 std::string image_key
= (mod
== at::ARGUMENT_MODIFIER_DEST
?
500 at::DEST_IMAGE_NAME
: at::IMAGE_NAME
);
501 std::string journal_key
= (mod
== at::ARGUMENT_MODIFIER_DEST
?
502 at::DEST_JOURNAL_NAME
: at::JOURNAL_NAME
);
504 if (vm
.count(pool_key
) && pool_name
!= nullptr) {
505 *pool_name
= vm
[pool_key
].as
<std::string
>();
507 if (vm
.count(journal_key
) && journal_name
!= nullptr) {
508 *journal_name
= vm
[journal_key
].as
<std::string
>();
511 std::string image_name
;
512 if (vm
.count(image_key
)) {
513 image_name
= vm
[image_key
].as
<std::string
>();
517 if (journal_name
!= nullptr && !journal_name
->empty()) {
518 // despite the separate pool option,
519 // we can also specify them via the journal option
520 std::string
journal_name_copy(*journal_name
);
521 r
= extract_spec(journal_name_copy
, pool_name
, journal_name
, nullptr,
522 SPEC_VALIDATION_FULL
);
528 if (!image_name
.empty()) {
529 // despite the separate pool option,
530 // we can also specify them via the image option
531 std::string
image_name_copy(image_name
);
532 r
= extract_spec(image_name_copy
, pool_name
, &image_name
, nullptr,
533 SPEC_VALIDATION_NONE
);
539 if (journal_name
!= nullptr && spec_arg_index
!= nullptr &&
540 journal_name
->empty()) {
541 std::string spec
= get_positional_argument(vm
, (*spec_arg_index
)++);
543 r
= extract_spec(spec
, pool_name
, journal_name
, nullptr,
544 SPEC_VALIDATION_FULL
);
551 if (pool_name
!= nullptr && pool_name
->empty()) {
552 *pool_name
= at::DEFAULT_POOL_NAME
;
555 if (pool_name
!= nullptr && journal_name
!= nullptr &&
556 journal_name
->empty() && !image_name
.empty()) {
557 // Try to get journal name from image info.
558 librados::Rados rados
;
559 librados::IoCtx io_ctx
;
561 int r
= init_and_open_image(*pool_name
, image_name
, "", "", true, &rados
,
564 std::cerr
<< "rbd: failed to open image " << image_name
565 << " to get journal name: " << cpp_strerror(r
) << std::endl
;
570 r
= image
.features(&features
);
574 if ((features
& RBD_FEATURE_JOURNALING
) == 0) {
575 std::cerr
<< "rbd: journaling is not enabled for image " << image_name
579 *journal_name
= image_id(image
);
582 if (journal_name
!= nullptr && journal_name
->empty()) {
583 std::string prefix
= at::get_description_prefix(mod
);
585 << (mod
== at::ARGUMENT_MODIFIER_DEST
? prefix
: std::string())
586 << "journal was not specified" << std::endl
;
593 int validate_snapshot_name(at::ArgumentModifier mod
,
594 const std::string
&snap_name
,
595 SnapshotPresence snapshot_presence
,
596 SpecValidation spec_validation
) {
597 std::string prefix
= at::get_description_prefix(mod
);
598 switch (snapshot_presence
) {
599 case SNAPSHOT_PRESENCE_PERMITTED
:
601 case SNAPSHOT_PRESENCE_NONE
:
602 if (!snap_name
.empty()) {
604 << (mod
== at::ARGUMENT_MODIFIER_DEST
? prefix
: std::string())
605 << "snapname specified for a command that doesn't use it"
610 case SNAPSHOT_PRESENCE_REQUIRED
:
611 if (snap_name
.empty()) {
613 << (mod
== at::ARGUMENT_MODIFIER_DEST
? prefix
: std::string())
614 << "snap name was not specified" << std::endl
;
620 if (spec_validation
== SPEC_VALIDATION_SNAP
) {
621 // disallow "/" and "@" in snap name
622 boost::regex
pattern("^[^@/]*?$");
623 if (!boost::regex_match (snap_name
, pattern
)) {
624 std::cerr
<< "rbd: invalid spec '" << snap_name
<< "'" << std::endl
;
631 int get_image_options(const boost::program_options::variables_map
&vm
,
632 bool get_format
, librbd::ImageOptions
*opts
) {
633 uint64_t order
= 0, stripe_unit
= 0, stripe_count
= 0, object_size
= 0;
634 uint64_t features
= 0, features_clear
= 0, features_set
= 0;
635 std::string data_pool
;
636 bool order_specified
= true;
637 bool features_specified
= false;
638 bool features_clear_specified
= false;
639 bool features_set_specified
= false;
640 bool stripe_specified
= false;
642 if (vm
.count(at::IMAGE_ORDER
)) {
643 order
= vm
[at::IMAGE_ORDER
].as
<uint64_t>();
644 std::cerr
<< "rbd: --order is deprecated, use --object-size"
646 } else if (vm
.count(at::IMAGE_OBJECT_SIZE
)) {
647 object_size
= vm
[at::IMAGE_OBJECT_SIZE
].as
<uint64_t>();
648 order
= std::round(std::log2(object_size
));
650 order_specified
= false;
653 if (vm
.count(at::IMAGE_FEATURES
)) {
654 features
= vm
[at::IMAGE_FEATURES
].as
<uint64_t>();
655 features_specified
= true;
657 features
= get_rbd_default_features(g_ceph_context
);
660 if (vm
.count(at::IMAGE_STRIPE_UNIT
)) {
661 stripe_unit
= vm
[at::IMAGE_STRIPE_UNIT
].as
<uint64_t>();
662 stripe_specified
= true;
665 if (vm
.count(at::IMAGE_STRIPE_COUNT
)) {
666 stripe_count
= vm
[at::IMAGE_STRIPE_COUNT
].as
<uint64_t>();
667 stripe_specified
= true;
670 if (vm
.count(at::IMAGE_SHARED
) && vm
[at::IMAGE_SHARED
].as
<bool>()) {
671 if (features_specified
) {
672 features
&= ~RBD_FEATURES_SINGLE_CLIENT
;
674 features_clear
|= RBD_FEATURES_SINGLE_CLIENT
;
675 features_clear_specified
= true;
679 if (vm
.count(at::IMAGE_DATA_POOL
)) {
680 data_pool
= vm
[at::IMAGE_DATA_POOL
].as
<std::string
>();
685 bool format_specified
= false;
686 if (vm
.count(at::IMAGE_NEW_FORMAT
)) {
688 format_specified
= true;
689 } else if (vm
.count(at::IMAGE_FORMAT
)) {
690 format
= vm
[at::IMAGE_FORMAT
].as
<uint32_t>();
691 format_specified
= true;
694 std::cerr
<< "rbd: image format 1 is deprecated" << std::endl
;
697 if (features_specified
&& features
!= 0) {
698 if (format_specified
&& format
== 1) {
699 std::cerr
<< "rbd: features not allowed with format 1; "
700 << "use --image-format 2" << std::endl
;
704 format_specified
= true;
708 if ((stripe_unit
|| stripe_count
) &&
709 (stripe_unit
!= (1ull << order
) && stripe_count
!= 1)) {
710 if (format_specified
&& format
== 1) {
711 std::cerr
<< "rbd: non-default striping not allowed with format 1; "
712 << "use --image-format 2" << std::endl
;
716 format_specified
= true;
720 if (!data_pool
.empty()) {
721 if (format_specified
&& format
== 1) {
722 std::cerr
<< "rbd: data pool not allowed with format 1; "
723 << "use --image-format 2" << std::endl
;
727 format_specified
= true;
731 if (format_specified
) {
732 int r
= g_conf
->set_val("rbd_default_format", stringify(format
));
734 opts
->set(RBD_IMAGE_OPTION_FORMAT
, format
);
739 opts
->set(RBD_IMAGE_OPTION_ORDER
, order
);
740 if (features_specified
)
741 opts
->set(RBD_IMAGE_OPTION_FEATURES
, features
);
742 if (features_clear_specified
) {
743 opts
->set(RBD_IMAGE_OPTION_FEATURES_CLEAR
, features_clear
);
745 if (features_set_specified
)
746 opts
->set(RBD_IMAGE_OPTION_FEATURES_SET
, features_set
);
747 if (stripe_specified
) {
748 opts
->set(RBD_IMAGE_OPTION_STRIPE_UNIT
, stripe_unit
);
749 opts
->set(RBD_IMAGE_OPTION_STRIPE_COUNT
, stripe_count
);
751 if (!data_pool
.empty()) {
752 opts
->set(RBD_IMAGE_OPTION_DATA_POOL
, data_pool
);
754 int r
= get_journal_options(vm
, opts
);
762 int get_journal_options(const boost::program_options::variables_map
&vm
,
763 librbd::ImageOptions
*opts
) {
765 if (vm
.count(at::JOURNAL_OBJECT_SIZE
)) {
766 uint64_t size
= vm
[at::JOURNAL_OBJECT_SIZE
].as
<uint64_t>();
768 while ((1ULL << order
) < size
) {
771 opts
->set(RBD_IMAGE_OPTION_JOURNAL_ORDER
, order
);
773 int r
= g_conf
->set_val("rbd_journal_order", stringify(order
));
776 if (vm
.count(at::JOURNAL_SPLAY_WIDTH
)) {
777 opts
->set(RBD_IMAGE_OPTION_JOURNAL_SPLAY_WIDTH
,
778 vm
[at::JOURNAL_SPLAY_WIDTH
].as
<uint64_t>());
780 int r
= g_conf
->set_val("rbd_journal_splay_width",
782 vm
[at::JOURNAL_SPLAY_WIDTH
].as
<uint64_t>()));
785 if (vm
.count(at::JOURNAL_POOL
)) {
786 opts
->set(RBD_IMAGE_OPTION_JOURNAL_POOL
,
787 vm
[at::JOURNAL_POOL
].as
<std::string
>());
789 int r
= g_conf
->set_val("rbd_journal_pool",
790 vm
[at::JOURNAL_POOL
].as
<std::string
>());
797 int get_image_size(const boost::program_options::variables_map
&vm
,
799 if (vm
.count(at::IMAGE_SIZE
) == 0) {
800 std::cerr
<< "rbd: must specify --size <M/G/T>" << std::endl
;
804 *size
= vm
[at::IMAGE_SIZE
].as
<uint64_t>();
808 int get_path(const boost::program_options::variables_map
&vm
,
809 const std::string
&positional_path
, std::string
*path
) {
810 if (!positional_path
.empty()) {
811 *path
= positional_path
;
812 } else if (vm
.count(at::PATH
)) {
813 *path
= vm
[at::PATH
].as
<std::string
>();
817 std::cerr
<< "rbd: path was not specified" << std::endl
;
823 int get_formatter(const po::variables_map
&vm
,
824 at::Format::Formatter
*formatter
) {
825 if (vm
.count(at::FORMAT
)) {
826 bool pretty
= vm
[at::PRETTY_FORMAT
].as
<bool>();
827 *formatter
= vm
[at::FORMAT
].as
<at::Format
>().create_formatter(pretty
);
828 if (*formatter
== nullptr && pretty
) {
829 std::cerr
<< "rbd: --pretty-format only works when --format "
830 << "is json or xml" << std::endl
;
837 void init_context() {
838 g_conf
->set_val_or_die("rbd_cache_writethrough_until_flush", "false");
839 g_conf
->apply_changes(NULL
);
840 common_init_finish(g_ceph_context
);
843 int init(const std::string
&pool_name
, librados::Rados
*rados
,
844 librados::IoCtx
*io_ctx
) {
847 int r
= rados
->init_with_context(g_ceph_context
);
849 std::cerr
<< "rbd: couldn't initialize rados!" << std::endl
;
853 r
= rados
->connect();
855 std::cerr
<< "rbd: couldn't connect to the cluster!" << std::endl
;
859 r
= init_io_ctx(*rados
, pool_name
, io_ctx
);
866 int init_io_ctx(librados::Rados
&rados
, const std::string
&pool_name
,
867 librados::IoCtx
*io_ctx
) {
868 int r
= rados
.ioctx_create(pool_name
.c_str(), *io_ctx
);
870 std::cerr
<< "rbd: error opening pool " << pool_name
<< ": "
871 << cpp_strerror(r
) << std::endl
;
877 int open_image(librados::IoCtx
&io_ctx
, const std::string
&image_name
,
878 bool read_only
, librbd::Image
*image
) {
882 r
= rbd
.open_read_only(io_ctx
, *image
, image_name
.c_str(), NULL
);
884 r
= rbd
.open(io_ctx
, *image
, image_name
.c_str());
888 std::cerr
<< "rbd: error opening image " << image_name
<< ": "
889 << cpp_strerror(r
) << std::endl
;
895 int open_image_by_id(librados::IoCtx
&io_ctx
, const std::string
&image_id
,
896 bool read_only
, librbd::Image
*image
) {
900 r
= rbd
.open_by_id_read_only(io_ctx
, *image
, image_id
.c_str(), NULL
);
902 r
= rbd
.open_by_id(io_ctx
, *image
, image_id
.c_str());
906 std::cerr
<< "rbd: error opening image with id " << image_id
<< ": "
907 << cpp_strerror(r
) << std::endl
;
913 int init_and_open_image(const std::string
&pool_name
,
914 const std::string
&image_name
,
915 const std::string
&image_id
,
916 const std::string
&snap_name
, bool read_only
,
917 librados::Rados
*rados
, librados::IoCtx
*io_ctx
,
918 librbd::Image
*image
) {
919 int r
= init(pool_name
, rados
, io_ctx
);
924 if (image_id
.empty()) {
925 r
= open_image(*io_ctx
, image_name
, read_only
, image
);
927 r
= open_image_by_id(*io_ctx
, image_id
, read_only
, image
);
933 if (!snap_name
.empty()) {
934 r
= snap_set(*image
, snap_name
);
942 int snap_set(librbd::Image
&image
, const std::string
&snap_name
) {
943 int r
= image
.snap_set(snap_name
.c_str());
945 std::cerr
<< "error setting snapshot context: " << cpp_strerror(r
)
952 void calc_sparse_extent(const bufferptr
&bp
,
954 size_t buffer_offset
,
955 uint64_t buffer_length
,
956 size_t *write_length
,
958 if (sparse_size
== 0) {
959 // sparse writes are disabled -- write the full extent
960 assert(buffer_offset
== 0);
961 *write_length
= buffer_length
;
967 size_t original_offset
= buffer_offset
;
968 while (buffer_offset
< buffer_length
) {
969 size_t extent_size
= std::min
<size_t>(
970 sparse_size
, buffer_length
- buffer_offset
);
972 bufferptr
extent(bp
, buffer_offset
, extent_size
);
974 bool extent_is_zero
= extent
.is_zero();
975 if (original_offset
== buffer_offset
) {
976 *zeroed
= extent_is_zero
;
977 } else if (*zeroed
!= extent_is_zero
) {
978 assert(*write_length
> 0);
982 buffer_offset
+= extent_size
;
983 *write_length
+= extent_size
;
987 std::string
image_id(librbd::Image
& image
) {
989 int r
= image
.get_id(&id
);
991 return std::string();
996 std::string
mirror_image_state(librbd::mirror_image_state_t state
) {
998 case RBD_MIRROR_IMAGE_DISABLING
:
1000 case RBD_MIRROR_IMAGE_ENABLED
:
1002 case RBD_MIRROR_IMAGE_DISABLED
:
1009 std::string
mirror_image_status_state(librbd::mirror_image_status_state_t state
) {
1011 case MIRROR_IMAGE_STATUS_STATE_UNKNOWN
:
1013 case MIRROR_IMAGE_STATUS_STATE_ERROR
:
1015 case MIRROR_IMAGE_STATUS_STATE_SYNCING
:
1017 case MIRROR_IMAGE_STATUS_STATE_STARTING_REPLAY
:
1018 return "starting_replay";
1019 case MIRROR_IMAGE_STATUS_STATE_REPLAYING
:
1021 case MIRROR_IMAGE_STATUS_STATE_STOPPING_REPLAY
:
1022 return "stopping_replay";
1023 case MIRROR_IMAGE_STATUS_STATE_STOPPED
:
1026 return "unknown (" + stringify(static_cast<uint32_t>(state
)) + ")";
1030 std::string
mirror_image_status_state(librbd::mirror_image_status_t status
) {
1031 return (status
.up
? "up+" : "down+") +
1032 mirror_image_status_state(status
.state
);
1035 std::string
timestr(time_t t
) {
1038 localtime_r(&t
, &tm
);
1041 strftime(buf
, sizeof(buf
), "%F %T", &tm
);
1046 uint64_t get_rbd_default_features(CephContext
* cct
) {
1047 auto features
= cct
->_conf
->get_val
<std::string
>("rbd_default_features");
1048 return boost::lexical_cast
<uint64_t>(features
);
1051 bool check_if_image_spec_present(const po::variables_map
&vm
,
1052 at::ArgumentModifier mod
,
1053 size_t spec_arg_index
) {
1054 std::string image_key
= (mod
== at::ARGUMENT_MODIFIER_DEST
?
1055 at::DEST_IMAGE_NAME
: at::IMAGE_NAME
);
1057 if (vm
.count(image_key
)) {
1061 std::string spec
= get_positional_argument(vm
, spec_arg_index
);
1062 if (!spec
.empty()) {
1069 } // namespace utils