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,
63 if (r < 0 && r != -ENOENT) {
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_);
801 if (r < 0 && r != -ENOENT) {
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 if (info.state == cls::rbd::MIRROR_IMAGE_STATE_DISABLED) {
817 auto &image_name = id_to_name[image_id];
818 if (image_name.empty()) {
819 lderr(cct) << "failed to find image name for image " << image_id << ", "
820 << "using image id as name" << dendl;
821 image_name = image_id;
823 auto s_it = statuses_.find(image_id);
824 auto &s = s_it != statuses_.end() ? s_it->second : unknown_status;
825 (*images)[image_id] = mirror_image_status_t{
828 info.global_image_id,
829 static_cast<mirror_image_state_t>(info.state),
830 false}, // XXX: To set "primary" right would require an additional call.
831 static_cast<mirror_image_status_state_t>(s.state),
840 template <typename I>
841 int Mirror<I>::image_status_summary(librados::IoCtx& io_ctx,
842 MirrorImageStatusStates *states) {
843 CephContext *cct = reinterpret_cast<CephContext *>(io_ctx.cct());
845 std::map<cls::rbd::MirrorImageStatusState, int> states_;
846 int r = cls_client::mirror_image_status_get_summary(&io_ctx, &states_);
847 if (r < 0 && r != -ENOENT) {
848 lderr(cct) << "failed to get mirror status summary: "
849 << cpp_strerror(r) << dendl;
852 for (auto &s : states_) {
853 (*states)[static_cast<mirror_image_status_state_t>(s.first)] = s.second;
859 } // namespace librbd
861 template class librbd::api::Mirror<librbd::ImageCtx>;