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
->get_val
<bool>("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];
172 std::string
get_positional_argument(const po::variables_map
&vm
, size_t index
) {
173 if (vm
.count(at::POSITIONAL_ARGUMENTS
) == 0) {
177 const std::vector
<std::string
> &args
=
178 boost::any_cast
<std::vector
<std::string
> >(
179 vm
[at::POSITIONAL_ARGUMENTS
].value());
180 if (index
< args
.size()) {
186 std::string
get_default_pool_name() {
187 return g_ceph_context
->_conf
->get_val
<std::string
>("rbd_default_pool");
190 std::string
get_pool_name(const po::variables_map
&vm
, size_t *arg_index
) {
191 std::string pool_name
;
192 if (vm
.count(at::POOL_NAME
)) {
193 pool_name
= vm
[at::POOL_NAME
].as
<std::string
>();
195 pool_name
= get_positional_argument(vm
, *arg_index
);
196 if (!pool_name
.empty()) {
201 if (pool_name
.empty()) {
202 pool_name
= get_default_pool_name();
207 int get_special_pool_group_names(const po::variables_map
&vm
,
209 std::string
*group_pool_name
,
210 std::string
*group_name
) {
211 if (nullptr == group_pool_name
) return -EINVAL
;
212 if (nullptr == group_name
) return -EINVAL
;
213 std::string pool_key
= at::POOL_NAME
;
215 std::string group_pool_key
= "group-" + at::POOL_NAME
;
216 std::string group_key
= at::GROUP_NAME
;
218 if (vm
.count(group_pool_key
)) {
219 *group_pool_name
= vm
[group_pool_key
].as
<std::string
>();
222 if (vm
.count(group_key
)) {
223 *group_name
= vm
[group_key
].as
<std::string
>();
227 if (group_name
->empty()) {
228 std::string spec
= utils::get_positional_argument(vm
, (*arg_index
)++);
230 r
= utils::extract_group_spec(spec
, group_pool_name
, group_name
);
237 if (group_pool_name
->empty() && vm
.count(pool_key
)) {
238 *group_pool_name
= vm
[pool_key
].as
<std::string
>();
241 if (group_pool_name
->empty()) {
242 *group_pool_name
= get_default_pool_name();
245 if (group_name
->empty()) {
246 std::cerr
<< "rbd: consistency group name was not specified" << std::endl
;
253 int get_special_pool_image_names(const po::variables_map
&vm
,
255 std::string
*image_pool_name
,
256 std::string
*image_name
) {
257 if (nullptr == image_pool_name
) return -EINVAL
;
258 if (nullptr == image_name
) return -EINVAL
;
260 std::string pool_key
= at::POOL_NAME
;
262 std::string image_pool_key
= "image-" + at::POOL_NAME
;
263 std::string image_key
= at::IMAGE_NAME
;
265 if (vm
.count(image_pool_key
)) {
266 *image_pool_name
= vm
[image_pool_key
].as
<std::string
>();
269 if (vm
.count(image_key
)) {
270 *image_name
= vm
[image_key
].as
<std::string
>();
274 if (image_name
->empty()) {
275 std::string spec
= utils::get_positional_argument(vm
, (*arg_index
)++);
277 r
= utils::extract_spec(spec
, image_pool_name
,
279 utils::SPEC_VALIDATION_NONE
);
286 if (image_pool_name
->empty() && vm
.count(pool_key
)) {
287 *image_pool_name
= vm
[pool_key
].as
<std::string
>();
290 if (image_pool_name
->empty()) {
291 *image_pool_name
= get_default_pool_name();
294 if (image_name
->empty()) {
295 std::cerr
<< "rbd: image name was not specified" << std::endl
;
302 int get_pool_image_id(const po::variables_map
&vm
,
303 size_t *spec_arg_index
,
304 std::string
*pool_name
,
305 std::string
*image_id
) {
307 if (vm
.count(at::POOL_NAME
) && pool_name
!= nullptr) {
308 *pool_name
= vm
[at::POOL_NAME
].as
<std::string
>();
310 if (vm
.count(at::IMAGE_ID
) && image_id
!= nullptr) {
311 *image_id
= vm
[at::IMAGE_ID
].as
<std::string
>();
315 if (image_id
!= nullptr && spec_arg_index
!= nullptr && image_id
->empty()) {
316 std::string spec
= get_positional_argument(vm
, (*spec_arg_index
)++);
318 r
= extract_image_id_spec(spec
, pool_name
, image_id
);
325 if (pool_name
!= nullptr && pool_name
->empty()) {
326 *pool_name
= get_default_pool_name();
329 if (image_id
!= nullptr && image_id
->empty()) {
330 std::cerr
<< "rbd: image id was not specified" << std::endl
;
337 int get_pool_group_names(const po::variables_map
&vm
,
338 at::ArgumentModifier mod
,
339 size_t *spec_arg_index
,
340 std::string
*pool_name
,
341 std::string
*group_name
) {
342 std::string pool_key
= (mod
== at::ARGUMENT_MODIFIER_DEST
?
343 at::DEST_POOL_NAME
: at::POOL_NAME
);
344 std::string group_key
= (mod
== at::ARGUMENT_MODIFIER_DEST
?
345 at::DEST_GROUP_NAME
: at::GROUP_NAME
);
347 if (vm
.count(pool_key
) && pool_name
!= nullptr) {
348 *pool_name
= vm
[pool_key
].as
<std::string
>();
350 if (vm
.count(group_key
) && group_name
!= nullptr) {
351 *group_name
= vm
[group_key
].as
<std::string
>();
355 if (group_name
!= nullptr && spec_arg_index
!= nullptr &&
356 group_name
->empty()) {
357 std::string spec
= get_positional_argument(vm
, (*spec_arg_index
)++);
359 r
= extract_group_spec(spec
, pool_name
, group_name
);
366 if (pool_name
!= nullptr && pool_name
->empty()) {
367 *pool_name
= get_default_pool_name();
370 if (group_name
!= nullptr && group_name
->empty()) {
371 std::string prefix
= at::get_description_prefix(mod
);
373 << (mod
== at::ARGUMENT_MODIFIER_DEST
? prefix
: std::string())
374 << "group name was not specified" << std::endl
;
381 int get_pool_image_snapshot_names(const po::variables_map
&vm
,
382 at::ArgumentModifier mod
,
383 size_t *spec_arg_index
,
384 std::string
*pool_name
,
385 std::string
*image_name
,
386 std::string
*snap_name
,
387 SnapshotPresence snapshot_presence
,
388 SpecValidation spec_validation
,
389 bool image_required
) {
390 std::string pool_key
= (mod
== at::ARGUMENT_MODIFIER_DEST
?
391 at::DEST_POOL_NAME
: at::POOL_NAME
);
392 std::string image_key
= (mod
== at::ARGUMENT_MODIFIER_DEST
?
393 at::DEST_IMAGE_NAME
: at::IMAGE_NAME
);
394 std::string snap_key
= (mod
== at::ARGUMENT_MODIFIER_DEST
?
395 at::DEST_SNAPSHOT_NAME
: at::SNAPSHOT_NAME
);
397 if (vm
.count(pool_key
) && pool_name
!= nullptr) {
398 *pool_name
= vm
[pool_key
].as
<std::string
>();
400 if (vm
.count(image_key
) && image_name
!= nullptr) {
401 *image_name
= vm
[image_key
].as
<std::string
>();
403 if (vm
.count(snap_key
) && snap_name
!= nullptr) {
404 *snap_name
= vm
[snap_key
].as
<std::string
>();
408 if (image_name
!= nullptr && !image_name
->empty()) {
409 // despite the separate pool and snapshot name options,
410 // we can also specify them via the image option
411 std::string
image_name_copy(*image_name
);
412 r
= extract_spec(image_name_copy
, pool_name
, image_name
, snap_name
,
419 if (image_name
!= nullptr && spec_arg_index
!= nullptr &&
420 image_name
->empty()) {
421 std::string spec
= get_positional_argument(vm
, (*spec_arg_index
)++);
423 r
= extract_spec(spec
, pool_name
, image_name
, snap_name
, spec_validation
);
430 if (pool_name
!= nullptr && pool_name
->empty()) {
431 *pool_name
= get_default_pool_name();
434 if (image_name
!= nullptr && image_required
&& image_name
->empty()) {
435 std::string prefix
= at::get_description_prefix(mod
);
437 << (mod
== at::ARGUMENT_MODIFIER_DEST
? prefix
: std::string())
438 << "image name was not specified" << std::endl
;
442 //Validate pool name while creating/renaming/copying/cloning/importing/etc
443 if (spec_validation
== SPEC_VALIDATION_FULL
) {
444 boost::regex
pattern("^[^@/]+?$");
445 if (!boost::regex_match (*pool_name
, pattern
)) {
446 std::cerr
<< "rbd: invalid pool name '" << *pool_name
<< "'" << std::endl
;
451 if (snap_name
!= nullptr) {
452 r
= validate_snapshot_name(mod
, *snap_name
, snapshot_presence
,
461 int get_pool_snapshot_names(const po::variables_map
&vm
,
462 at::ArgumentModifier mod
,
463 size_t *spec_arg_index
,
464 std::string
*pool_name
,
465 std::string
*snap_name
,
466 SnapshotPresence snapshot_presence
,
467 SpecValidation spec_validation
) {
468 std::string pool_key
= (mod
== at::ARGUMENT_MODIFIER_DEST
?
469 at::DEST_POOL_NAME
: at::POOL_NAME
);
470 std::string snap_key
= (mod
== at::ARGUMENT_MODIFIER_DEST
?
471 at::DEST_SNAPSHOT_NAME
: at::SNAPSHOT_NAME
);
473 if (vm
.count(pool_key
) && pool_name
!= nullptr) {
474 *pool_name
= vm
[pool_key
].as
<std::string
>();
476 if (vm
.count(snap_key
) && snap_name
!= nullptr) {
477 *snap_name
= vm
[snap_key
].as
<std::string
>();
480 if (pool_name
!= nullptr && pool_name
->empty()) {
481 *pool_name
= get_default_pool_name();
484 if (snap_name
!= nullptr) {
485 int r
= validate_snapshot_name(mod
, *snap_name
, snapshot_presence
,
494 int get_pool_journal_names(const po::variables_map
&vm
,
495 at::ArgumentModifier mod
,
496 size_t *spec_arg_index
,
497 std::string
*pool_name
,
498 std::string
*journal_name
) {
499 std::string pool_key
= (mod
== at::ARGUMENT_MODIFIER_DEST
?
500 at::DEST_POOL_NAME
: at::POOL_NAME
);
501 std::string image_key
= (mod
== at::ARGUMENT_MODIFIER_DEST
?
502 at::DEST_IMAGE_NAME
: at::IMAGE_NAME
);
503 std::string journal_key
= (mod
== at::ARGUMENT_MODIFIER_DEST
?
504 at::DEST_JOURNAL_NAME
: at::JOURNAL_NAME
);
506 if (vm
.count(pool_key
) && pool_name
!= nullptr) {
507 *pool_name
= vm
[pool_key
].as
<std::string
>();
509 if (vm
.count(journal_key
) && journal_name
!= nullptr) {
510 *journal_name
= vm
[journal_key
].as
<std::string
>();
513 std::string image_name
;
514 if (vm
.count(image_key
)) {
515 image_name
= vm
[image_key
].as
<std::string
>();
519 if (journal_name
!= nullptr && !journal_name
->empty()) {
520 // despite the separate pool option,
521 // we can also specify them via the journal option
522 std::string
journal_name_copy(*journal_name
);
523 r
= extract_spec(journal_name_copy
, pool_name
, journal_name
, nullptr,
524 SPEC_VALIDATION_FULL
);
530 if (!image_name
.empty()) {
531 // despite the separate pool option,
532 // we can also specify them via the image option
533 std::string
image_name_copy(image_name
);
534 r
= extract_spec(image_name_copy
, pool_name
, &image_name
, nullptr,
535 SPEC_VALIDATION_NONE
);
541 if (journal_name
!= nullptr && spec_arg_index
!= nullptr &&
542 journal_name
->empty()) {
543 std::string spec
= get_positional_argument(vm
, (*spec_arg_index
)++);
545 r
= extract_spec(spec
, pool_name
, journal_name
, nullptr,
546 SPEC_VALIDATION_FULL
);
553 if (pool_name
!= nullptr && pool_name
->empty()) {
554 *pool_name
= get_default_pool_name();
557 if (pool_name
!= nullptr && journal_name
!= nullptr &&
558 journal_name
->empty() && !image_name
.empty()) {
559 // Try to get journal name from image info.
560 librados::Rados rados
;
561 librados::IoCtx io_ctx
;
563 int r
= init_and_open_image(*pool_name
, image_name
, "", "", true, &rados
,
566 std::cerr
<< "rbd: failed to open image " << image_name
567 << " to get journal name: " << cpp_strerror(r
) << std::endl
;
572 r
= image
.features(&features
);
576 if ((features
& RBD_FEATURE_JOURNALING
) == 0) {
577 std::cerr
<< "rbd: journaling is not enabled for image " << image_name
581 *journal_name
= image_id(image
);
584 if (journal_name
!= nullptr && journal_name
->empty()) {
585 std::string prefix
= at::get_description_prefix(mod
);
587 << (mod
== at::ARGUMENT_MODIFIER_DEST
? prefix
: std::string())
588 << "journal was not specified" << std::endl
;
595 int validate_snapshot_name(at::ArgumentModifier mod
,
596 const std::string
&snap_name
,
597 SnapshotPresence snapshot_presence
,
598 SpecValidation spec_validation
) {
599 std::string prefix
= at::get_description_prefix(mod
);
600 switch (snapshot_presence
) {
601 case SNAPSHOT_PRESENCE_PERMITTED
:
603 case SNAPSHOT_PRESENCE_NONE
:
604 if (!snap_name
.empty()) {
606 << (mod
== at::ARGUMENT_MODIFIER_DEST
? prefix
: std::string())
607 << "snapname specified for a command that doesn't use it"
612 case SNAPSHOT_PRESENCE_REQUIRED
:
613 if (snap_name
.empty()) {
615 << (mod
== at::ARGUMENT_MODIFIER_DEST
? prefix
: std::string())
616 << "snap name was not specified" << std::endl
;
622 if (spec_validation
== SPEC_VALIDATION_SNAP
) {
623 // disallow "/" and "@" in snap name
624 boost::regex
pattern("^[^@/]*?$");
625 if (!boost::regex_match (snap_name
, pattern
)) {
626 std::cerr
<< "rbd: invalid snap name '" << snap_name
<< "'" << std::endl
;
633 int get_image_options(const boost::program_options::variables_map
&vm
,
634 bool get_format
, librbd::ImageOptions
*opts
) {
635 uint64_t order
= 0, stripe_unit
= 0, stripe_count
= 0, object_size
= 0;
636 uint64_t features
= 0, features_clear
= 0, features_set
= 0;
637 std::string data_pool
;
638 bool order_specified
= true;
639 bool features_specified
= false;
640 bool features_clear_specified
= false;
641 bool features_set_specified
= false;
642 bool stripe_specified
= false;
644 if (vm
.count(at::IMAGE_ORDER
)) {
645 order
= vm
[at::IMAGE_ORDER
].as
<uint64_t>();
646 std::cerr
<< "rbd: --order is deprecated, use --object-size"
648 } else if (vm
.count(at::IMAGE_OBJECT_SIZE
)) {
649 object_size
= vm
[at::IMAGE_OBJECT_SIZE
].as
<uint64_t>();
650 order
= std::round(std::log2(object_size
));
652 order_specified
= false;
655 if (vm
.count(at::IMAGE_FEATURES
)) {
656 features
= vm
[at::IMAGE_FEATURES
].as
<uint64_t>();
657 features_specified
= true;
659 features
= get_rbd_default_features(g_ceph_context
);
662 if (vm
.count(at::IMAGE_STRIPE_UNIT
)) {
663 stripe_unit
= vm
[at::IMAGE_STRIPE_UNIT
].as
<uint64_t>();
664 stripe_specified
= true;
667 if (vm
.count(at::IMAGE_STRIPE_COUNT
)) {
668 stripe_count
= vm
[at::IMAGE_STRIPE_COUNT
].as
<uint64_t>();
669 stripe_specified
= true;
672 if (vm
.count(at::IMAGE_SHARED
) && vm
[at::IMAGE_SHARED
].as
<bool>()) {
673 if (features_specified
) {
674 features
&= ~RBD_FEATURES_SINGLE_CLIENT
;
676 features_clear
|= RBD_FEATURES_SINGLE_CLIENT
;
677 features_clear_specified
= true;
681 if (vm
.count(at::IMAGE_DATA_POOL
)) {
682 data_pool
= vm
[at::IMAGE_DATA_POOL
].as
<std::string
>();
687 bool format_specified
= false;
688 if (vm
.count(at::IMAGE_NEW_FORMAT
)) {
690 format_specified
= true;
691 } else if (vm
.count(at::IMAGE_FORMAT
)) {
692 format
= vm
[at::IMAGE_FORMAT
].as
<uint32_t>();
693 format_specified
= true;
696 std::cerr
<< "rbd: image format 1 is deprecated" << std::endl
;
699 if (features_specified
&& features
!= 0) {
700 if (format_specified
&& format
== 1) {
701 std::cerr
<< "rbd: features not allowed with format 1; "
702 << "use --image-format 2" << std::endl
;
706 format_specified
= true;
710 if ((stripe_unit
|| stripe_count
) &&
711 (stripe_unit
!= (1ull << order
) && stripe_count
!= 1)) {
712 if (format_specified
&& format
== 1) {
713 std::cerr
<< "rbd: non-default striping not allowed with format 1; "
714 << "use --image-format 2" << std::endl
;
718 format_specified
= true;
722 if (!data_pool
.empty()) {
723 if (format_specified
&& format
== 1) {
724 std::cerr
<< "rbd: data pool not allowed with format 1; "
725 << "use --image-format 2" << std::endl
;
729 format_specified
= true;
733 if (format_specified
) {
734 int r
= g_conf
->set_val("rbd_default_format", stringify(format
));
736 opts
->set(RBD_IMAGE_OPTION_FORMAT
, format
);
741 opts
->set(RBD_IMAGE_OPTION_ORDER
, order
);
742 if (features_specified
)
743 opts
->set(RBD_IMAGE_OPTION_FEATURES
, features
);
744 if (features_clear_specified
) {
745 opts
->set(RBD_IMAGE_OPTION_FEATURES_CLEAR
, features_clear
);
747 if (features_set_specified
)
748 opts
->set(RBD_IMAGE_OPTION_FEATURES_SET
, features_set
);
749 if (stripe_specified
) {
750 opts
->set(RBD_IMAGE_OPTION_STRIPE_UNIT
, stripe_unit
);
751 opts
->set(RBD_IMAGE_OPTION_STRIPE_COUNT
, stripe_count
);
753 if (!data_pool
.empty()) {
754 opts
->set(RBD_IMAGE_OPTION_DATA_POOL
, data_pool
);
756 int r
= get_journal_options(vm
, opts
);
764 int get_journal_options(const boost::program_options::variables_map
&vm
,
765 librbd::ImageOptions
*opts
) {
767 if (vm
.count(at::JOURNAL_OBJECT_SIZE
)) {
768 uint64_t size
= vm
[at::JOURNAL_OBJECT_SIZE
].as
<uint64_t>();
770 while ((1ULL << order
) < size
) {
773 opts
->set(RBD_IMAGE_OPTION_JOURNAL_ORDER
, order
);
775 int r
= g_conf
->set_val("rbd_journal_order", stringify(order
));
778 if (vm
.count(at::JOURNAL_SPLAY_WIDTH
)) {
779 opts
->set(RBD_IMAGE_OPTION_JOURNAL_SPLAY_WIDTH
,
780 vm
[at::JOURNAL_SPLAY_WIDTH
].as
<uint64_t>());
782 int r
= g_conf
->set_val("rbd_journal_splay_width",
784 vm
[at::JOURNAL_SPLAY_WIDTH
].as
<uint64_t>()));
787 if (vm
.count(at::JOURNAL_POOL
)) {
788 opts
->set(RBD_IMAGE_OPTION_JOURNAL_POOL
,
789 vm
[at::JOURNAL_POOL
].as
<std::string
>());
791 int r
= g_conf
->set_val("rbd_journal_pool",
792 vm
[at::JOURNAL_POOL
].as
<std::string
>());
799 int get_image_size(const boost::program_options::variables_map
&vm
,
801 if (vm
.count(at::IMAGE_SIZE
) == 0) {
802 std::cerr
<< "rbd: must specify --size <M/G/T>" << std::endl
;
806 *size
= vm
[at::IMAGE_SIZE
].as
<uint64_t>();
810 int get_path(const boost::program_options::variables_map
&vm
,
811 const std::string
&positional_path
, std::string
*path
) {
812 if (!positional_path
.empty()) {
813 *path
= positional_path
;
814 } else if (vm
.count(at::PATH
)) {
815 *path
= vm
[at::PATH
].as
<std::string
>();
819 std::cerr
<< "rbd: path was not specified" << std::endl
;
825 int get_formatter(const po::variables_map
&vm
,
826 at::Format::Formatter
*formatter
) {
827 if (vm
.count(at::FORMAT
)) {
828 bool pretty
= vm
[at::PRETTY_FORMAT
].as
<bool>();
829 *formatter
= vm
[at::FORMAT
].as
<at::Format
>().create_formatter(pretty
);
830 if (*formatter
== nullptr && pretty
) {
831 std::cerr
<< "rbd: --pretty-format only works when --format "
832 << "is json or xml" << std::endl
;
834 } else if (*formatter
!= nullptr && !pretty
) {
835 formatter
->get()->enable_line_break();
837 } else if (vm
[at::PRETTY_FORMAT
].as
<bool>()) {
838 std::cerr
<< "rbd: --pretty-format only works when --format "
839 << "is json or xml" << std::endl
;
845 void init_context() {
846 g_conf
->set_val_or_die("rbd_cache_writethrough_until_flush", "false");
847 g_conf
->apply_changes(NULL
);
848 common_init_finish(g_ceph_context
);
851 int init(const std::string
&pool_name
, librados::Rados
*rados
,
852 librados::IoCtx
*io_ctx
) {
855 int r
= rados
->init_with_context(g_ceph_context
);
857 std::cerr
<< "rbd: couldn't initialize rados!" << std::endl
;
861 r
= rados
->connect();
863 std::cerr
<< "rbd: couldn't connect to the cluster!" << std::endl
;
867 r
= init_io_ctx(*rados
, pool_name
, io_ctx
);
874 int init_io_ctx(librados::Rados
&rados
, const std::string
&pool_name
,
875 librados::IoCtx
*io_ctx
) {
876 int r
= rados
.ioctx_create(pool_name
.c_str(), *io_ctx
);
878 if (r
== -ENOENT
&& pool_name
== get_default_pool_name()) {
879 std::cerr
<< "rbd: error opening default pool "
880 << "'" << pool_name
<< "'" << std::endl
881 << "Ensure that the default pool has been created or specify "
882 << "an alternate pool name." << std::endl
;
884 std::cerr
<< "rbd: error opening pool '" << pool_name
<< "': "
885 << cpp_strerror(r
) << std::endl
;
892 int open_image(librados::IoCtx
&io_ctx
, const std::string
&image_name
,
893 bool read_only
, librbd::Image
*image
) {
897 r
= rbd
.open_read_only(io_ctx
, *image
, image_name
.c_str(), NULL
);
899 r
= rbd
.open(io_ctx
, *image
, image_name
.c_str());
903 std::cerr
<< "rbd: error opening image " << image_name
<< ": "
904 << cpp_strerror(r
) << std::endl
;
910 int open_image_by_id(librados::IoCtx
&io_ctx
, const std::string
&image_id
,
911 bool read_only
, librbd::Image
*image
) {
915 r
= rbd
.open_by_id_read_only(io_ctx
, *image
, image_id
.c_str(), NULL
);
917 r
= rbd
.open_by_id(io_ctx
, *image
, image_id
.c_str());
921 std::cerr
<< "rbd: error opening image with id " << image_id
<< ": "
922 << cpp_strerror(r
) << std::endl
;
928 int init_and_open_image(const std::string
&pool_name
,
929 const std::string
&image_name
,
930 const std::string
&image_id
,
931 const std::string
&snap_name
, bool read_only
,
932 librados::Rados
*rados
, librados::IoCtx
*io_ctx
,
933 librbd::Image
*image
) {
934 int r
= init(pool_name
, rados
, io_ctx
);
939 if (image_id
.empty()) {
940 r
= open_image(*io_ctx
, image_name
, read_only
, image
);
942 r
= open_image_by_id(*io_ctx
, image_id
, read_only
, image
);
948 if (!snap_name
.empty()) {
949 r
= snap_set(*image
, snap_name
);
957 int snap_set(librbd::Image
&image
, const std::string
&snap_name
) {
958 int r
= image
.snap_set(snap_name
.c_str());
960 std::cerr
<< "error setting snapshot context: " << cpp_strerror(r
)
967 void calc_sparse_extent(const bufferptr
&bp
,
969 size_t buffer_offset
,
970 uint64_t buffer_length
,
971 size_t *write_length
,
973 if (sparse_size
== 0) {
974 // sparse writes are disabled -- write the full extent
975 assert(buffer_offset
== 0);
976 *write_length
= buffer_length
;
982 size_t original_offset
= buffer_offset
;
983 while (buffer_offset
< buffer_length
) {
984 size_t extent_size
= std::min
<size_t>(
985 sparse_size
, buffer_length
- buffer_offset
);
987 bufferptr
extent(bp
, buffer_offset
, extent_size
);
989 bool extent_is_zero
= extent
.is_zero();
990 if (original_offset
== buffer_offset
) {
991 *zeroed
= extent_is_zero
;
992 } else if (*zeroed
!= extent_is_zero
) {
993 assert(*write_length
> 0);
997 buffer_offset
+= extent_size
;
998 *write_length
+= extent_size
;
1002 std::string
image_id(librbd::Image
& image
) {
1004 int r
= image
.get_id(&id
);
1006 return std::string();
1011 std::string
mirror_image_state(librbd::mirror_image_state_t state
) {
1013 case RBD_MIRROR_IMAGE_DISABLING
:
1015 case RBD_MIRROR_IMAGE_ENABLED
:
1017 case RBD_MIRROR_IMAGE_DISABLED
:
1024 std::string
mirror_image_status_state(librbd::mirror_image_status_state_t state
) {
1026 case MIRROR_IMAGE_STATUS_STATE_UNKNOWN
:
1028 case MIRROR_IMAGE_STATUS_STATE_ERROR
:
1030 case MIRROR_IMAGE_STATUS_STATE_SYNCING
:
1032 case MIRROR_IMAGE_STATUS_STATE_STARTING_REPLAY
:
1033 return "starting_replay";
1034 case MIRROR_IMAGE_STATUS_STATE_REPLAYING
:
1036 case MIRROR_IMAGE_STATUS_STATE_STOPPING_REPLAY
:
1037 return "stopping_replay";
1038 case MIRROR_IMAGE_STATUS_STATE_STOPPED
:
1041 return "unknown (" + stringify(static_cast<uint32_t>(state
)) + ")";
1045 std::string
mirror_image_status_state(librbd::mirror_image_status_t status
) {
1046 return (status
.up
? "up+" : "down+") +
1047 mirror_image_status_state(status
.state
);
1050 std::string
timestr(time_t t
) {
1053 localtime_r(&t
, &tm
);
1056 strftime(buf
, sizeof(buf
), "%F %T", &tm
);
1061 uint64_t get_rbd_default_features(CephContext
* cct
) {
1062 auto features
= cct
->_conf
->get_val
<std::string
>("rbd_default_features");
1063 return boost::lexical_cast
<uint64_t>(features
);
1066 bool check_if_image_spec_present(const po::variables_map
&vm
,
1067 at::ArgumentModifier mod
,
1068 size_t spec_arg_index
) {
1069 std::string image_key
= (mod
== at::ARGUMENT_MODIFIER_DEST
?
1070 at::DEST_IMAGE_NAME
: at::IMAGE_NAME
);
1072 if (vm
.count(image_key
)) {
1076 std::string spec
= get_positional_argument(vm
, spec_arg_index
);
1077 if (!spec
.empty()) {
1084 } // namespace utils