1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 #include "librbd/api/Mirror.h"
5 #include "include/rados/librados.hpp"
6 #include "common/dout.h"
7 #include "common/errno.h"
8 #include "cls/rbd/cls_rbd_client.h"
9 #include "librbd/ExclusiveLock.h"
10 #include "librbd/ImageCtx.h"
11 #include "librbd/ImageState.h"
12 #include "librbd/Journal.h"
13 #include "librbd/Utils.h"
14 #include "librbd/api/Image.h"
15 #include "librbd/mirror/DemoteRequest.h"
16 #include "librbd/mirror/DisableRequest.h"
17 #include "librbd/mirror/EnableRequest.h"
18 #include "librbd/mirror/GetInfoRequest.h"
19 #include "librbd/mirror/GetStatusRequest.h"
20 #include "librbd/mirror/PromoteRequest.h"
21 #include "librbd/mirror/Types.h"
22 #include "librbd/MirroringWatcher.h"
23 #include <boost/scope_exit.hpp>
25 #define dout_subsys ceph_subsys_rbd
27 #define dout_prefix *_dout << "librbd::api::Mirror: " << __func__ << ": "
35 int validate_mirroring_enabled(I
*ictx
) {
36 CephContext
*cct
= ictx
->cct
;
37 cls::rbd::MirrorImage mirror_image_internal
;
38 int r
= cls_client::mirror_image_get(&ictx
->md_ctx
, ictx
->id
,
39 &mirror_image_internal
);
40 if (r
< 0 && r
!= -ENOENT
) {
41 lderr(cct
) << "failed to retrieve mirroring state: " << cpp_strerror(r
)
44 } else if (mirror_image_internal
.state
!=
45 cls::rbd::MIRROR_IMAGE_STATE_ENABLED
) {
46 lderr(cct
) << "mirroring is not currently enabled" << dendl
;
52 int list_mirror_images(librados::IoCtx
& io_ctx
,
53 std::set
<std::string
>& mirror_image_ids
) {
54 CephContext
*cct
= reinterpret_cast<CephContext
*>(io_ctx
.cct());
56 std::string last_read
= "";
60 std::map
<std::string
, std::string
> mirror_images
;
61 r
= cls_client::mirror_image_list(&io_ctx
, last_read
, max_read
,
64 lderr(cct
) << "error listing mirrored image directory: "
65 << cpp_strerror(r
) << dendl
;
68 for (auto it
= mirror_images
.begin(); it
!= mirror_images
.end(); ++it
) {
69 mirror_image_ids
.insert(it
->first
);
71 if (!mirror_images
.empty()) {
72 last_read
= mirror_images
.rbegin()->first
;
74 r
= mirror_images
.size();
75 } while (r
== max_read
);
80 struct C_ImageGetInfo
: public Context
{
81 mirror_image_info_t
*mirror_image_info
;
84 cls::rbd::MirrorImage mirror_image
;
85 mirror::PromotionState promotion_state
;
87 C_ImageGetInfo(mirror_image_info_t
*mirror_image_info
, Context
*on_finish
)
88 : mirror_image_info(mirror_image_info
), on_finish(on_finish
) {
91 void finish(int r
) override
{
93 on_finish
->complete(r
);
97 mirror_image_info
->global_id
= mirror_image
.global_image_id
;
98 mirror_image_info
->state
= static_cast<rbd_mirror_image_state_t
>(
100 mirror_image_info
->primary
= (
101 promotion_state
== mirror::PROMOTION_STATE_PRIMARY
);
102 on_finish
->complete(0);
106 struct C_ImageGetStatus
: public C_ImageGetInfo
{
107 std::string image_name
;
108 mirror_image_status_t
*mirror_image_status
;
110 cls::rbd::MirrorImageStatus mirror_image_status_internal
;
112 C_ImageGetStatus(const std::string
&image_name
,
113 mirror_image_status_t
*mirror_image_status
,
115 : C_ImageGetInfo(&mirror_image_status
->info
, on_finish
),
116 image_name(image_name
), mirror_image_status(mirror_image_status
) {
119 void finish(int r
) override
{
121 on_finish
->complete(r
);
125 mirror_image_status
->name
= image_name
;
126 mirror_image_status
->state
= static_cast<mirror_image_status_state_t
>(
127 mirror_image_status_internal
.state
);
128 mirror_image_status
->description
= mirror_image_status_internal
.description
;
129 mirror_image_status
->last_update
=
130 mirror_image_status_internal
.last_update
.sec();
131 mirror_image_status
->up
= mirror_image_status_internal
.up
;
132 C_ImageGetInfo::finish(0);
136 } // anonymous namespace
138 template <typename I
>
139 int Mirror
<I
>::image_enable(I
*ictx
, bool relax_same_pool_parent_check
) {
140 CephContext
*cct
= ictx
->cct
;
141 ldout(cct
, 20) << "ictx=" << ictx
<< dendl
;
143 int r
= ictx
->state
->refresh_if_required();
148 cls::rbd::MirrorMode mirror_mode
;
149 r
= cls_client::mirror_mode_get(&ictx
->md_ctx
, &mirror_mode
);
151 lderr(cct
) << "cannot enable mirroring: failed to retrieve mirror mode: "
152 << cpp_strerror(r
) << dendl
;
156 if (mirror_mode
!= cls::rbd::MIRROR_MODE_IMAGE
) {
157 lderr(cct
) << "cannot enable mirroring in the current pool mirroring mode"
162 // is mirroring not enabled for the parent?
164 RWLock::RLocker
l(ictx
->parent_lock
);
165 ImageCtx
*parent
= ictx
->parent
;
167 if (relax_same_pool_parent_check
&&
168 parent
->md_ctx
.get_id() == ictx
->md_ctx
.get_id()) {
169 if (!parent
->test_features(RBD_FEATURE_JOURNALING
)) {
170 lderr(cct
) << "journaling is not enabled for the parent" << dendl
;
174 cls::rbd::MirrorImage mirror_image_internal
;
175 r
= cls_client::mirror_image_get(&(parent
->md_ctx
), parent
->id
,
176 &mirror_image_internal
);
178 lderr(cct
) << "mirroring is not enabled for the parent" << dendl
;
185 if ((ictx
->features
& RBD_FEATURE_JOURNALING
) == 0) {
186 lderr(cct
) << "cannot enable mirroring: journaling is not enabled" << dendl
;
191 auto req
= mirror::EnableRequest
<ImageCtx
>::create(ictx
, &ctx
);
196 lderr(cct
) << "cannot enable mirroring: " << cpp_strerror(r
) << dendl
;
203 template <typename I
>
204 int Mirror
<I
>::image_disable(I
*ictx
, bool force
) {
205 CephContext
*cct
= ictx
->cct
;
206 ldout(cct
, 20) << "ictx=" << ictx
<< dendl
;
208 int r
= ictx
->state
->refresh_if_required();
213 cls::rbd::MirrorMode mirror_mode
;
214 r
= cls_client::mirror_mode_get(&ictx
->md_ctx
, &mirror_mode
);
216 lderr(cct
) << "cannot disable mirroring: failed to retrieve pool "
217 "mirroring mode: " << cpp_strerror(r
) << dendl
;
221 if (mirror_mode
!= cls::rbd::MIRROR_MODE_IMAGE
) {
222 lderr(cct
) << "cannot disable mirroring in the current pool mirroring "
227 // is mirroring enabled for the child?
228 cls::rbd::MirrorImage mirror_image_internal
;
229 r
= cls_client::mirror_image_get(&ictx
->md_ctx
, ictx
->id
,
230 &mirror_image_internal
);
232 // mirroring is not enabled for this image
233 ldout(cct
, 20) << "ignoring disable command: mirroring is not enabled for "
234 << "this image" << dendl
;
236 } else if (r
== -EOPNOTSUPP
) {
237 ldout(cct
, 5) << "mirroring not supported by OSD" << dendl
;
240 lderr(cct
) << "failed to retrieve mirror image metadata: "
241 << cpp_strerror(r
) << dendl
;
245 mirror_image_internal
.state
= cls::rbd::MIRROR_IMAGE_STATE_DISABLING
;
246 r
= cls_client::mirror_image_set(&ictx
->md_ctx
, ictx
->id
,
247 mirror_image_internal
);
249 lderr(cct
) << "cannot disable mirroring: " << cpp_strerror(r
) << dendl
;
252 bool rollback
= false;
253 BOOST_SCOPE_EXIT_ALL(ictx
, &mirror_image_internal
, &rollback
) {
255 CephContext
*cct
= ictx
->cct
;
256 mirror_image_internal
.state
= cls::rbd::MIRROR_IMAGE_STATE_ENABLED
;
257 int r
= cls_client::mirror_image_set(&ictx
->md_ctx
, ictx
->id
,
258 mirror_image_internal
);
260 lderr(cct
) << "failed to re-enable image mirroring: "
261 << cpp_strerror(r
) << dendl
;
267 RWLock::RLocker
l(ictx
->snap_lock
);
268 map
<librados::snap_t
, SnapInfo
> snap_info
= ictx
->snap_info
;
269 for (auto &info
: snap_info
) {
270 ParentSpec
parent_spec(ictx
->md_ctx
.get_id(), ictx
->id
, info
.first
);
271 map
< pair
<int64_t, string
>, set
<string
> > image_info
;
273 r
= Image
<I
>::list_children(ictx
, parent_spec
, &image_info
);
278 if (image_info
.empty())
281 librados::Rados
rados(ictx
->md_ctx
);
282 for (auto &info
: image_info
) {
283 librados::IoCtx ioctx
;
284 r
= rados
.ioctx_create2(info
.first
.first
, ioctx
);
287 lderr(cct
) << "error accessing child image pool "
288 << info
.first
.second
<< dendl
;
291 for (auto &id_it
: info
.second
) {
292 cls::rbd::MirrorImage mirror_image_internal
;
293 r
= cls_client::mirror_image_get(&ioctx
, id_it
,
294 &mirror_image_internal
);
297 lderr(cct
) << "mirroring is enabled on one or more children "
307 auto req
= mirror::DisableRequest
<ImageCtx
>::create(ictx
, force
, true,
313 lderr(cct
) << "cannot disable mirroring: " << cpp_strerror(r
) << dendl
;
322 template <typename I
>
323 int Mirror
<I
>::image_promote(I
*ictx
, bool force
) {
324 CephContext
*cct
= ictx
->cct
;
327 Mirror
<I
>::image_promote(ictx
, force
, &ctx
);
330 lderr(cct
) << "failed to promote image" << dendl
;
337 template <typename I
>
338 void Mirror
<I
>::image_promote(I
*ictx
, bool force
, Context
*on_finish
) {
339 CephContext
*cct
= ictx
->cct
;
340 ldout(cct
, 20) << "ictx=" << ictx
<< ", "
341 << "force=" << force
<< dendl
;
343 auto req
= mirror::PromoteRequest
<>::create(*ictx
, force
, on_finish
);
347 template <typename I
>
348 int Mirror
<I
>::image_demote(I
*ictx
) {
349 CephContext
*cct
= ictx
->cct
;
352 Mirror
<I
>::image_demote(ictx
, &ctx
);
355 lderr(cct
) << "failed to demote image" << dendl
;
362 template <typename I
>
363 void Mirror
<I
>::image_demote(I
*ictx
, Context
*on_finish
) {
364 CephContext
*cct
= ictx
->cct
;
365 ldout(cct
, 20) << "ictx=" << ictx
<< dendl
;
367 auto req
= mirror::DemoteRequest
<>::create(*ictx
, on_finish
);
371 template <typename I
>
372 int Mirror
<I
>::image_resync(I
*ictx
) {
373 CephContext
*cct
= ictx
->cct
;
374 ldout(cct
, 20) << "ictx=" << ictx
<< dendl
;
376 int r
= ictx
->state
->refresh_if_required();
381 r
= validate_mirroring_enabled(ictx
);
386 C_SaferCond tag_owner_ctx
;
388 Journal
<I
>::is_tag_owner(ictx
, &is_tag_owner
, &tag_owner_ctx
);
389 r
= tag_owner_ctx
.wait();
391 lderr(cct
) << "failed to determine tag ownership: " << cpp_strerror(r
)
394 } else if (is_tag_owner
) {
395 lderr(cct
) << "image is primary, cannot resync to itself" << dendl
;
399 // flag the journal indicating that we want to rebuild the local image
400 r
= Journal
<I
>::request_resync(ictx
);
402 lderr(cct
) << "failed to request resync: " << cpp_strerror(r
) << dendl
;
409 template <typename I
>
410 void Mirror
<I
>::image_get_info(I
*ictx
, mirror_image_info_t
*mirror_image_info
,
411 size_t info_size
, Context
*on_finish
) {
412 CephContext
*cct
= ictx
->cct
;
413 ldout(cct
, 20) << "ictx=" << ictx
<< dendl
;
414 if (info_size
< sizeof(mirror_image_info_t
)) {
415 on_finish
->complete(-ERANGE
);
419 auto ctx
= new C_ImageGetInfo(mirror_image_info
, on_finish
);
420 auto req
= mirror::GetInfoRequest
<I
>::create(*ictx
, &ctx
->mirror_image
,
421 &ctx
->promotion_state
,
426 template <typename I
>
427 int Mirror
<I
>::image_get_info(I
*ictx
, mirror_image_info_t
*mirror_image_info
,
430 image_get_info(ictx
, mirror_image_info
, info_size
, &ctx
);
439 template <typename I
>
440 void Mirror
<I
>::image_get_status(I
*ictx
, mirror_image_status_t
*status
,
441 size_t status_size
, Context
*on_finish
) {
442 CephContext
*cct
= ictx
->cct
;
443 ldout(cct
, 20) << "ictx=" << ictx
<< dendl
;
444 if (status_size
< sizeof(mirror_image_status_t
)) {
445 on_finish
->complete(-ERANGE
);
449 auto ctx
= new C_ImageGetStatus(ictx
->name
, status
, on_finish
);
450 auto req
= mirror::GetStatusRequest
<I
>::create(
451 *ictx
, &ctx
->mirror_image_status_internal
, &ctx
->mirror_image
,
452 &ctx
->promotion_state
, ctx
);
456 template <typename I
>
457 int Mirror
<I
>::image_get_status(I
*ictx
, mirror_image_status_t
*status
,
458 size_t status_size
) {
460 image_get_status(ictx
, status
, status_size
, &ctx
);
469 template <typename I
>
470 int Mirror
<I
>::mode_get(librados::IoCtx
& io_ctx
,
471 rbd_mirror_mode_t
*mirror_mode
) {
472 CephContext
*cct
= reinterpret_cast<CephContext
*>(io_ctx
.cct());
473 ldout(cct
, 20) << dendl
;
475 cls::rbd::MirrorMode mirror_mode_internal
;
476 int r
= cls_client::mirror_mode_get(&io_ctx
, &mirror_mode_internal
);
478 lderr(cct
) << "failed to retrieve mirror mode: " << cpp_strerror(r
)
483 switch (mirror_mode_internal
) {
484 case cls::rbd::MIRROR_MODE_DISABLED
:
485 case cls::rbd::MIRROR_MODE_IMAGE
:
486 case cls::rbd::MIRROR_MODE_POOL
:
487 *mirror_mode
= static_cast<rbd_mirror_mode_t
>(mirror_mode_internal
);
490 lderr(cct
) << "unknown mirror mode ("
491 << static_cast<uint32_t>(mirror_mode_internal
) << ")"
498 template <typename I
>
499 int Mirror
<I
>::mode_set(librados::IoCtx
& io_ctx
,
500 rbd_mirror_mode_t mirror_mode
) {
501 CephContext
*cct
= reinterpret_cast<CephContext
*>(io_ctx
.cct());
502 ldout(cct
, 20) << dendl
;
504 cls::rbd::MirrorMode next_mirror_mode
;
505 switch (mirror_mode
) {
506 case RBD_MIRROR_MODE_DISABLED
:
507 case RBD_MIRROR_MODE_IMAGE
:
508 case RBD_MIRROR_MODE_POOL
:
509 next_mirror_mode
= static_cast<cls::rbd::MirrorMode
>(mirror_mode
);
512 lderr(cct
) << "unknown mirror mode ("
513 << static_cast<uint32_t>(mirror_mode
) << ")" << dendl
;
518 if (next_mirror_mode
== cls::rbd::MIRROR_MODE_DISABLED
) {
519 // fail early if pool still has peers registered and attempting to disable
520 std::vector
<cls::rbd::MirrorPeer
> mirror_peers
;
521 r
= cls_client::mirror_peer_list(&io_ctx
, &mirror_peers
);
522 if (r
< 0 && r
!= -ENOENT
) {
523 lderr(cct
) << "failed to list peers: " << cpp_strerror(r
) << dendl
;
525 } else if (!mirror_peers
.empty()) {
526 lderr(cct
) << "mirror peers still registered" << dendl
;
531 cls::rbd::MirrorMode current_mirror_mode
;
532 r
= cls_client::mirror_mode_get(&io_ctx
, ¤t_mirror_mode
);
534 lderr(cct
) << "failed to retrieve mirror mode: " << cpp_strerror(r
)
539 if (current_mirror_mode
== next_mirror_mode
) {
541 } else if (current_mirror_mode
== cls::rbd::MIRROR_MODE_DISABLED
) {
543 uuid_gen
.generate_random();
544 r
= cls_client::mirror_uuid_set(&io_ctx
, uuid_gen
.to_string());
546 lderr(cct
) << "failed to allocate mirroring uuid: " << cpp_strerror(r
)
552 if (current_mirror_mode
!= cls::rbd::MIRROR_MODE_IMAGE
) {
553 r
= cls_client::mirror_mode_set(&io_ctx
, cls::rbd::MIRROR_MODE_IMAGE
);
555 lderr(cct
) << "failed to set mirror mode to image: "
556 << cpp_strerror(r
) << dendl
;
560 r
= MirroringWatcher
<>::notify_mode_updated(io_ctx
,
561 cls::rbd::MIRROR_MODE_IMAGE
);
563 lderr(cct
) << "failed to send update notification: " << cpp_strerror(r
)
568 if (next_mirror_mode
== cls::rbd::MIRROR_MODE_IMAGE
) {
572 if (next_mirror_mode
== cls::rbd::MIRROR_MODE_POOL
) {
573 map
<string
, string
> images
;
574 r
= Image
<I
>::list_images(io_ctx
, &images
);
576 lderr(cct
) << "failed listing images: " << cpp_strerror(r
) << dendl
;
580 for (const auto& img_pair
: images
) {
582 r
= cls_client::get_features(&io_ctx
,
583 util::header_name(img_pair
.second
),
584 CEPH_NOSNAP
, &features
);
586 lderr(cct
) << "error getting features for image " << img_pair
.first
587 << ": " << cpp_strerror(r
) << dendl
;
591 if ((features
& RBD_FEATURE_JOURNALING
) != 0) {
592 I
*img_ctx
= I::create("", img_pair
.second
, nullptr, io_ctx
, false);
593 r
= img_ctx
->state
->open(false);
595 lderr(cct
) << "error opening image "<< img_pair
.first
<< ": "
596 << cpp_strerror(r
) << dendl
;
600 r
= image_enable(img_ctx
, true);
601 int close_r
= img_ctx
->state
->close();
603 lderr(cct
) << "error enabling mirroring for image "
604 << img_pair
.first
<< ": " << cpp_strerror(r
) << dendl
;
606 } else if (close_r
< 0) {
607 lderr(cct
) << "failed to close image " << img_pair
.first
<< ": "
608 << cpp_strerror(close_r
) << dendl
;
613 } else if (next_mirror_mode
== cls::rbd::MIRROR_MODE_DISABLED
) {
614 std::set
<std::string
> image_ids
;
615 r
= list_mirror_images(io_ctx
, image_ids
);
617 lderr(cct
) << "failed listing images: " << cpp_strerror(r
) << dendl
;
621 for (const auto& img_id
: image_ids
) {
622 if (current_mirror_mode
== cls::rbd::MIRROR_MODE_IMAGE
) {
623 cls::rbd::MirrorImage mirror_image
;
624 r
= cls_client::mirror_image_get(&io_ctx
, img_id
, &mirror_image
);
625 if (r
< 0 && r
!= -ENOENT
) {
626 lderr(cct
) << "failed to retrieve mirroring state for image id "
627 << img_id
<< ": " << cpp_strerror(r
) << dendl
;
630 if (mirror_image
.state
== cls::rbd::MIRROR_IMAGE_STATE_ENABLED
) {
631 lderr(cct
) << "failed to disable mirror mode: there are still "
632 << "images with mirroring enabled" << dendl
;
636 I
*img_ctx
= I::create("", img_id
, nullptr, io_ctx
, false);
637 r
= img_ctx
->state
->open(false);
639 lderr(cct
) << "error opening image id "<< img_id
<< ": "
640 << cpp_strerror(r
) << dendl
;
644 r
= image_disable(img_ctx
, false);
645 int close_r
= img_ctx
->state
->close();
647 lderr(cct
) << "error disabling mirroring for image id " << img_id
648 << cpp_strerror(r
) << dendl
;
650 } else if (close_r
< 0) {
651 lderr(cct
) << "failed to close image id " << img_id
<< ": "
652 << cpp_strerror(close_r
) << dendl
;
659 r
= cls_client::mirror_mode_set(&io_ctx
, next_mirror_mode
);
661 lderr(cct
) << "failed to set mirror mode: " << cpp_strerror(r
) << dendl
;
665 r
= MirroringWatcher
<>::notify_mode_updated(io_ctx
, next_mirror_mode
);
667 lderr(cct
) << "failed to send update notification: " << cpp_strerror(r
)
673 template <typename I
>
674 int Mirror
<I
>::peer_add(librados::IoCtx
& io_ctx
, std::string
*uuid
,
675 const std::string
&cluster_name
,
676 const std::string
&client_name
) {
677 CephContext
*cct
= reinterpret_cast<CephContext
*>(io_ctx
.cct());
678 ldout(cct
, 20) << "name=" << cluster_name
<< ", "
679 << "client=" << client_name
<< dendl
;
681 if (cct
->_conf
->cluster
== cluster_name
) {
682 lderr(cct
) << "cannot add self as remote peer" << dendl
;
689 uuid_gen
.generate_random();
691 *uuid
= uuid_gen
.to_string();
692 r
= cls_client::mirror_peer_add(&io_ctx
, *uuid
, cluster_name
,
695 ldout(cct
, 5) << "duplicate UUID detected, retrying" << dendl
;
697 lderr(cct
) << "failed to add mirror peer '" << uuid
<< "': "
698 << cpp_strerror(r
) << dendl
;
701 } while (r
== -ESTALE
);
705 template <typename I
>
706 int Mirror
<I
>::peer_remove(librados::IoCtx
& io_ctx
, const std::string
&uuid
) {
707 CephContext
*cct
= reinterpret_cast<CephContext
*>(io_ctx
.cct());
708 ldout(cct
, 20) << "uuid=" << uuid
<< dendl
;
710 int r
= cls_client::mirror_peer_remove(&io_ctx
, uuid
);
711 if (r
< 0 && r
!= -ENOENT
) {
712 lderr(cct
) << "failed to remove peer '" << uuid
<< "': "
713 << cpp_strerror(r
) << dendl
;
719 template <typename I
>
720 int Mirror
<I
>::peer_list(librados::IoCtx
& io_ctx
,
721 std::vector
<mirror_peer_t
> *peers
) {
722 CephContext
*cct
= reinterpret_cast<CephContext
*>(io_ctx
.cct());
723 ldout(cct
, 20) << dendl
;
725 std::vector
<cls::rbd::MirrorPeer
> mirror_peers
;
726 int r
= cls_client::mirror_peer_list(&io_ctx
, &mirror_peers
);
727 if (r
< 0 && r
!= -ENOENT
) {
728 lderr(cct
) << "failed to list peers: " << cpp_strerror(r
) << dendl
;
733 peers
->reserve(mirror_peers
.size());
734 for (auto &mirror_peer
: mirror_peers
) {
736 peer
.uuid
= mirror_peer
.uuid
;
737 peer
.cluster_name
= mirror_peer
.cluster_name
;
738 peer
.client_name
= mirror_peer
.client_name
;
739 peers
->push_back(peer
);
744 template <typename I
>
745 int Mirror
<I
>::peer_set_client(librados::IoCtx
& io_ctx
, const std::string
&uuid
,
746 const std::string
&client_name
) {
747 CephContext
*cct
= reinterpret_cast<CephContext
*>(io_ctx
.cct());
748 ldout(cct
, 20) << "uuid=" << uuid
<< ", "
749 << "client=" << client_name
<< dendl
;
751 int r
= cls_client::mirror_peer_set_client(&io_ctx
, uuid
, client_name
);
753 lderr(cct
) << "failed to update client '" << uuid
<< "': "
754 << cpp_strerror(r
) << dendl
;
760 template <typename I
>
761 int Mirror
<I
>::peer_set_cluster(librados::IoCtx
& io_ctx
,
762 const std::string
&uuid
,
763 const std::string
&cluster_name
) {
764 CephContext
*cct
= reinterpret_cast<CephContext
*>(io_ctx
.cct());
765 ldout(cct
, 20) << "uuid=" << uuid
<< ", "
766 << "cluster=" << cluster_name
<< dendl
;
768 int r
= cls_client::mirror_peer_set_cluster(&io_ctx
, uuid
, cluster_name
);
770 lderr(cct
) << "failed to update cluster '" << uuid
<< "': "
771 << cpp_strerror(r
) << dendl
;
777 template <typename I
>
778 int Mirror
<I
>::image_status_list(librados::IoCtx
& io_ctx
,
779 const std::string
&start_id
, size_t max
,
780 IdToMirrorImageStatus
*images
) {
781 CephContext
*cct
= reinterpret_cast<CephContext
*>(io_ctx
.cct());
784 map
<string
, string
> id_to_name
;
786 map
<string
, string
> name_to_id
;
787 r
= Image
<I
>::list_images(io_ctx
, &name_to_id
);
791 for (auto it
: name_to_id
) {
792 id_to_name
[it
.second
] = it
.first
;
796 map
<std::string
, cls::rbd::MirrorImage
> images_
;
797 map
<std::string
, cls::rbd::MirrorImageStatus
> statuses_
;
799 r
= librbd::cls_client::mirror_image_status_list(&io_ctx
, start_id
, max
,
800 &images_
, &statuses_
);
802 lderr(cct
) << "failed to list mirror image statuses: "
803 << cpp_strerror(r
) << dendl
;
807 cls::rbd::MirrorImageStatus
unknown_status(
808 cls::rbd::MIRROR_IMAGE_STATUS_STATE_UNKNOWN
, "status not found");
810 for (auto it
= images_
.begin(); it
!= images_
.end(); ++it
) {
811 auto &image_id
= it
->first
;
812 auto &info
= it
->second
;
813 auto &image_name
= id_to_name
[image_id
];
814 if (image_name
.empty()) {
815 lderr(cct
) << "failed to find image name for image " << image_id
<< ", "
816 << "using image id as name" << dendl
;
817 image_name
= image_id
;
819 auto s_it
= statuses_
.find(image_id
);
820 auto &s
= s_it
!= statuses_
.end() ? s_it
->second
: unknown_status
;
821 (*images
)[image_id
] = mirror_image_status_t
{
824 info
.global_image_id
,
825 static_cast<mirror_image_state_t
>(info
.state
),
826 false}, // XXX: To set "primary" right would require an additional call.
827 static_cast<mirror_image_status_state_t
>(s
.state
),
836 template <typename I
>
837 int Mirror
<I
>::image_status_summary(librados::IoCtx
& io_ctx
,
838 MirrorImageStatusStates
*states
) {
839 CephContext
*cct
= reinterpret_cast<CephContext
*>(io_ctx
.cct());
841 std::map
<cls::rbd::MirrorImageStatusState
, int> states_
;
842 int r
= cls_client::mirror_image_status_get_summary(&io_ctx
, &states_
);
844 lderr(cct
) << "failed to get mirror status summary: "
845 << cpp_strerror(r
) << dendl
;
848 for (auto &s
: states_
) {
849 (*states
)[static_cast<mirror_image_status_state_t
>(s
.first
)] = s
.second
;
855 } // namespace librbd
857 template class librbd::api::Mirror
<librbd::ImageCtx
>;