]> git.proxmox.com Git - ceph.git/blob - ceph/src/librbd/api/Mirror.cc
ce92b854274418ebcfb04b0895fcd8508d7d2cda
[ceph.git] / ceph / src / librbd / api / Mirror.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3
4 #include "librbd/api/Mirror.h"
5 #include "include/rados/librados.hpp"
6 #include "include/stringify.h"
7 #include "common/ceph_json.h"
8 #include "common/dout.h"
9 #include "common/errno.h"
10 #include "cls/rbd/cls_rbd_client.h"
11 #include "librbd/ImageCtx.h"
12 #include "librbd/ImageState.h"
13 #include "librbd/Journal.h"
14 #include "librbd/MirroringWatcher.h"
15 #include "librbd/Operations.h"
16 #include "librbd/Utils.h"
17 #include "librbd/api/Image.h"
18 #include "librbd/api/Namespace.h"
19 #include "librbd/mirror/DemoteRequest.h"
20 #include "librbd/mirror/DisableRequest.h"
21 #include "librbd/mirror/EnableRequest.h"
22 #include "librbd/mirror/GetInfoRequest.h"
23 #include "librbd/mirror/GetStatusRequest.h"
24 #include "librbd/mirror/GetUuidRequest.h"
25 #include "librbd/mirror/PromoteRequest.h"
26 #include "librbd/mirror/Types.h"
27 #include "librbd/MirroringWatcher.h"
28 #include "librbd/mirror/snapshot/CreatePrimaryRequest.h"
29 #include "librbd/mirror/snapshot/ImageMeta.h"
30 #include "librbd/mirror/snapshot/UnlinkPeerRequest.h"
31 #include "librbd/mirror/snapshot/Utils.h"
32 #include <boost/algorithm/string/trim.hpp>
33 #include <boost/algorithm/string/replace.hpp>
34 #include <boost/scope_exit.hpp>
35 #include "json_spirit/json_spirit.h"
36
37 #include <algorithm>
38
39 #define dout_subsys ceph_subsys_rbd
40 #undef dout_prefix
41 #define dout_prefix *_dout << "librbd::api::Mirror: " << __func__ << ": "
42
43 namespace librbd {
44 namespace api {
45
46 namespace {
47
48 int get_config_key(librados::Rados& rados, const std::string& key,
49 std::string* value) {
50 std::string cmd =
51 "{"
52 "\"prefix\": \"config-key get\", "
53 "\"key\": \"" + key + "\""
54 "}";
55
56 bufferlist in_bl;
57 bufferlist out_bl;
58
59 int r = rados.mon_command(cmd, in_bl, &out_bl, nullptr);
60 if (r == -EINVAL) {
61 return -EOPNOTSUPP;
62 } else if (r < 0 && r != -ENOENT) {
63 return r;
64 }
65
66 *value = out_bl.to_str();
67 return 0;
68 }
69
70 int set_config_key(librados::Rados& rados, const std::string& key,
71 const std::string& value) {
72 std::string cmd;
73 if (value.empty()) {
74 cmd = "{"
75 "\"prefix\": \"config-key rm\", "
76 "\"key\": \"" + key + "\""
77 "}";
78 } else {
79 cmd = "{"
80 "\"prefix\": \"config-key set\", "
81 "\"key\": \"" + key + "\", "
82 "\"val\": \"" + value + "\""
83 "}";
84 }
85 bufferlist in_bl;
86 bufferlist out_bl;
87
88 int r = rados.mon_command(cmd, in_bl, &out_bl, nullptr);
89 if (r == -EINVAL) {
90 return -EOPNOTSUPP;
91 } else if (r < 0) {
92 return r;
93 }
94
95 return 0;
96 }
97
98 std::string get_peer_config_key_name(int64_t pool_id,
99 const std::string& peer_uuid) {
100 return RBD_MIRROR_PEER_CONFIG_KEY_PREFIX + stringify(pool_id) + "/" +
101 peer_uuid;
102 }
103
104 int remove_peer_config_key(librados::IoCtx& io_ctx,
105 const std::string& peer_uuid) {
106 int64_t pool_id = io_ctx.get_id();
107 auto key = get_peer_config_key_name(pool_id, peer_uuid);
108
109 librados::Rados rados(io_ctx);
110 int r = set_config_key(rados, key, "");
111 if (r < 0 && r != -ENOENT && r != -EPERM) {
112 return r;
113 }
114 return 0;
115 }
116
117 int create_bootstrap_user(CephContext* cct, librados::Rados& rados,
118 std::string* peer_client_id, std::string* cephx_key) {
119 ldout(cct, 20) << dendl;
120
121 // retrieve peer CephX user from config-key
122 int r = get_config_key(rados, RBD_MIRROR_PEER_CLIENT_ID_CONFIG_KEY,
123 peer_client_id);
124 if (r == -EACCES) {
125 ldout(cct, 5) << "insufficient permissions to get peer-client-id "
126 << "config-key" << dendl;
127 return r;
128 } else if (r < 0 && r != -ENOENT) {
129 lderr(cct) << "failed to retrieve peer client id key: "
130 << cpp_strerror(r) << dendl;
131 return r;
132 } else if (r == -ENOENT || peer_client_id->empty()) {
133 ldout(cct, 20) << "creating new peer-client-id config-key" << dendl;
134
135 *peer_client_id = "rbd-mirror-peer";
136 r = set_config_key(rados, RBD_MIRROR_PEER_CLIENT_ID_CONFIG_KEY,
137 *peer_client_id);
138 if (r == -EACCES) {
139 ldout(cct, 5) << "insufficient permissions to update peer-client-id "
140 << "config-key" << dendl;
141 return r;
142 } else if (r < 0) {
143 lderr(cct) << "failed to update peer client id key: "
144 << cpp_strerror(r) << dendl;
145 return r;
146 }
147 }
148 ldout(cct, 20) << "peer_client_id=" << *peer_client_id << dendl;
149
150 // create peer client user
151 std::string cmd =
152 R"({)" \
153 R"( "prefix": "auth get-or-create",)" \
154 R"( "entity": "client.)" + *peer_client_id + R"(",)" \
155 R"( "caps": [)" \
156 R"( "mon", "profile rbd-mirror-peer",)" \
157 R"( "osd", "profile rbd"],)" \
158 R"( "format": "json")" \
159 R"(})";
160
161 bufferlist in_bl;
162 bufferlist out_bl;
163
164 r = rados.mon_command(cmd, in_bl, &out_bl, nullptr);
165 if (r == -EINVAL) {
166 ldout(cct, 5) << "caps mismatch for existing user" << dendl;
167 return -EEXIST;
168 } else if (r == -EACCES) {
169 ldout(cct, 5) << "insufficient permissions to create user" << dendl;
170 return r;
171 } else if (r < 0) {
172 lderr(cct) << "failed to create or update RBD mirroring bootstrap user: "
173 << cpp_strerror(r) << dendl;
174 return r;
175 }
176
177 // extract key from response
178 bool json_valid = false;
179 json_spirit::mValue json_root;
180 if(json_spirit::read(out_bl.to_str(), json_root)) {
181 try {
182 auto& json_obj = json_root.get_array()[0].get_obj();
183 *cephx_key = json_obj["key"].get_str();
184 json_valid = true;
185 } catch (std::runtime_error&) {
186 }
187 }
188
189 if (!json_valid) {
190 lderr(cct) << "invalid auth keyring JSON received" << dendl;
191 return -EBADMSG;
192 }
193
194 return 0;
195 }
196
197 int create_bootstrap_peer(CephContext* cct, librados::IoCtx& io_ctx,
198 mirror_peer_direction_t direction,
199 const std::string& site_name, const std::string& fsid,
200 const std::string& client_id, const std::string& key,
201 const std::string& mon_host,
202 const std::string& cluster1,
203 const std::string& cluster2) {
204 ldout(cct, 20) << dendl;
205
206 std::string peer_uuid;
207 std::vector<mirror_peer_site_t> peers;
208 int r = Mirror<>::peer_site_list(io_ctx, &peers);
209 if (r < 0 && r != -ENOENT) {
210 lderr(cct) << "failed to list mirror peers: " << cpp_strerror(r) << dendl;
211 return r;
212 }
213
214 if (peers.empty()) {
215 r = Mirror<>::peer_site_add(io_ctx, &peer_uuid, direction, site_name,
216 "client." + client_id);
217 if (r < 0) {
218 lderr(cct) << "failed to add " << cluster1 << " peer to "
219 << cluster2 << " " << "cluster: " << cpp_strerror(r) << dendl;
220 return r;
221 }
222 } else if (peers[0].site_name != site_name &&
223 peers[0].site_name != fsid) {
224 // only support a single peer
225 lderr(cct) << "multiple peers are not currently supported" << dendl;
226 return -EINVAL;
227 } else {
228 peer_uuid = peers[0].uuid;
229
230 if (peers[0].site_name != site_name) {
231 r = Mirror<>::peer_site_set_name(io_ctx, peer_uuid, site_name);
232 if (r < 0) {
233 // non-fatal attempt to update site name
234 lderr(cct) << "failed to update peer site name" << dendl;
235 }
236 }
237 }
238
239 Mirror<>::Attributes attributes {
240 {"mon_host", mon_host},
241 {"key", key}};
242 r = Mirror<>::peer_site_set_attributes(io_ctx, peer_uuid, attributes);
243 if (r < 0) {
244 lderr(cct) << "failed to update " << cluster1 << " cluster connection "
245 << "attributes in " << cluster2 << " cluster: "
246 << cpp_strerror(r) << dendl;
247 return r;
248 }
249
250 return 0;
251 }
252
253 int list_mirror_images(librados::IoCtx& io_ctx,
254 std::set<std::string>& mirror_image_ids) {
255 CephContext *cct = reinterpret_cast<CephContext *>(io_ctx.cct());
256
257 std::string last_read = "";
258 int max_read = 1024;
259 int r;
260 do {
261 std::map<std::string, std::string> mirror_images;
262 r = cls_client::mirror_image_list(&io_ctx, last_read, max_read,
263 &mirror_images);
264 if (r < 0 && r != -ENOENT) {
265 lderr(cct) << "error listing mirrored image directory: "
266 << cpp_strerror(r) << dendl;
267 return r;
268 }
269 for (auto it = mirror_images.begin(); it != mirror_images.end(); ++it) {
270 mirror_image_ids.insert(it->first);
271 }
272 if (!mirror_images.empty()) {
273 last_read = mirror_images.rbegin()->first;
274 }
275 r = mirror_images.size();
276 } while (r == max_read);
277
278 return 0;
279 }
280
281 struct C_ImageGetInfo : public Context {
282 mirror_image_info_t *mirror_image_info;
283 mirror_image_mode_t *mirror_image_mode;
284 Context *on_finish;
285
286 cls::rbd::MirrorImage mirror_image;
287 mirror::PromotionState promotion_state = mirror::PROMOTION_STATE_PRIMARY;
288 std::string primary_mirror_uuid;
289
290 C_ImageGetInfo(mirror_image_info_t *mirror_image_info,
291 mirror_image_mode_t *mirror_image_mode, Context *on_finish)
292 : mirror_image_info(mirror_image_info),
293 mirror_image_mode(mirror_image_mode), on_finish(on_finish) {
294 }
295
296 void finish(int r) override {
297 if (r < 0 && r != -ENOENT) {
298 on_finish->complete(r);
299 return;
300 }
301
302 if (mirror_image_info != nullptr) {
303 mirror_image_info->global_id = mirror_image.global_image_id;
304 mirror_image_info->state = static_cast<rbd_mirror_image_state_t>(
305 mirror_image.state);
306 mirror_image_info->primary = (
307 promotion_state == mirror::PROMOTION_STATE_PRIMARY);
308 }
309
310 if (mirror_image_mode != nullptr) {
311 *mirror_image_mode =
312 static_cast<rbd_mirror_image_mode_t>(mirror_image.mode);
313 }
314
315 on_finish->complete(0);
316 }
317 };
318
319 struct C_ImageGetGlobalStatus : public C_ImageGetInfo {
320 std::string image_name;
321 mirror_image_global_status_t *mirror_image_global_status;
322
323 cls::rbd::MirrorImageStatus mirror_image_status_internal;
324
325 C_ImageGetGlobalStatus(
326 const std::string &image_name,
327 mirror_image_global_status_t *mirror_image_global_status,
328 Context *on_finish)
329 : C_ImageGetInfo(&mirror_image_global_status->info, nullptr, on_finish),
330 image_name(image_name),
331 mirror_image_global_status(mirror_image_global_status) {
332 }
333
334 void finish(int r) override {
335 if (r < 0 && r != -ENOENT) {
336 on_finish->complete(r);
337 return;
338 }
339
340 mirror_image_global_status->name = image_name;
341 mirror_image_global_status->site_statuses.clear();
342 mirror_image_global_status->site_statuses.reserve(
343 mirror_image_status_internal.mirror_image_site_statuses.size());
344 for (auto& site_status :
345 mirror_image_status_internal.mirror_image_site_statuses) {
346 mirror_image_global_status->site_statuses.push_back({
347 site_status.mirror_uuid,
348 static_cast<mirror_image_status_state_t>(site_status.state),
349 site_status.description, site_status.last_update.sec(),
350 site_status.up});
351 }
352 C_ImageGetInfo::finish(0);
353 }
354 };
355
356 } // anonymous namespace
357
358 template <typename I>
359 int Mirror<I>::image_enable(I *ictx, mirror_image_mode_t mode,
360 bool relax_same_pool_parent_check) {
361 CephContext *cct = ictx->cct;
362 ldout(cct, 20) << "ictx=" << ictx << " mode=" << mode
363 << " relax_same_pool_parent_check="
364 << relax_same_pool_parent_check << dendl;
365
366 int r = ictx->state->refresh_if_required();
367 if (r < 0) {
368 return r;
369 }
370
371 cls::rbd::MirrorMode mirror_mode;
372 r = cls_client::mirror_mode_get(&ictx->md_ctx, &mirror_mode);
373 if (r < 0) {
374 lderr(cct) << "cannot enable mirroring: failed to retrieve mirror mode: "
375 << cpp_strerror(r) << dendl;
376 return r;
377 }
378
379 if (mirror_mode != cls::rbd::MIRROR_MODE_IMAGE) {
380 lderr(cct) << "cannot enable mirroring in the current pool mirroring mode"
381 << dendl;
382 return -EINVAL;
383 }
384
385 // is mirroring not enabled for the parent?
386 {
387 std::shared_lock image_locker{ictx->image_lock};
388 ImageCtx *parent = ictx->parent;
389 if (parent) {
390 if (parent->md_ctx.get_id() != ictx->md_ctx.get_id() ||
391 !relax_same_pool_parent_check) {
392 cls::rbd::MirrorImage mirror_image_internal;
393 r = cls_client::mirror_image_get(&(parent->md_ctx), parent->id,
394 &mirror_image_internal);
395 if (r == -ENOENT) {
396 lderr(cct) << "mirroring is not enabled for the parent" << dendl;
397 return -EINVAL;
398 }
399 }
400 }
401 }
402
403 if (mode == RBD_MIRROR_IMAGE_MODE_JOURNAL &&
404 !ictx->test_features(RBD_FEATURE_JOURNALING)) {
405 uint64_t features = RBD_FEATURE_JOURNALING;
406 if (!ictx->test_features(RBD_FEATURE_EXCLUSIVE_LOCK)) {
407 features |= RBD_FEATURE_EXCLUSIVE_LOCK;
408 }
409 r = ictx->operations->update_features(features, true);
410 if (r < 0) {
411 lderr(cct) << "cannot enable journaling: " << cpp_strerror(r) << dendl;
412 return r;
413 }
414 }
415
416 C_SaferCond ctx;
417 auto req = mirror::EnableRequest<ImageCtx>::create(
418 ictx, static_cast<cls::rbd::MirrorImageMode>(mode), "", false, &ctx);
419 req->send();
420
421 r = ctx.wait();
422 if (r < 0) {
423 lderr(cct) << "cannot enable mirroring: " << cpp_strerror(r) << dendl;
424 return r;
425 }
426
427 return 0;
428 }
429
430 template <typename I>
431 int Mirror<I>::image_disable(I *ictx, bool force) {
432 CephContext *cct = ictx->cct;
433 ldout(cct, 20) << "ictx=" << ictx << dendl;
434
435 int r = ictx->state->refresh_if_required();
436 if (r < 0) {
437 return r;
438 }
439
440 cls::rbd::MirrorMode mirror_mode;
441 r = cls_client::mirror_mode_get(&ictx->md_ctx, &mirror_mode);
442 if (r < 0) {
443 lderr(cct) << "cannot disable mirroring: failed to retrieve pool "
444 "mirroring mode: " << cpp_strerror(r) << dendl;
445 return r;
446 }
447
448 if (mirror_mode != cls::rbd::MIRROR_MODE_IMAGE) {
449 lderr(cct) << "cannot disable mirroring in the current pool mirroring "
450 "mode" << dendl;
451 return -EINVAL;
452 }
453
454 // is mirroring enabled for the image?
455 cls::rbd::MirrorImage mirror_image_internal;
456 r = cls_client::mirror_image_get(&ictx->md_ctx, ictx->id,
457 &mirror_image_internal);
458 if (r == -ENOENT) {
459 // mirroring is not enabled for this image
460 ldout(cct, 20) << "ignoring disable command: mirroring is not enabled for "
461 << "this image" << dendl;
462 return 0;
463 } else if (r == -EOPNOTSUPP) {
464 ldout(cct, 5) << "mirroring not supported by OSD" << dendl;
465 return r;
466 } else if (r < 0) {
467 lderr(cct) << "failed to retrieve mirror image metadata: "
468 << cpp_strerror(r) << dendl;
469 return r;
470 }
471
472 mirror_image_internal.state = cls::rbd::MIRROR_IMAGE_STATE_DISABLING;
473 r = cls_client::mirror_image_set(&ictx->md_ctx, ictx->id,
474 mirror_image_internal);
475 if (r < 0) {
476 lderr(cct) << "cannot disable mirroring: " << cpp_strerror(r) << dendl;
477 return r;
478 }
479
480 bool rollback = false;
481 BOOST_SCOPE_EXIT_ALL(ictx, &mirror_image_internal, &rollback) {
482 if (rollback) {
483 // restore the mask bit for treating the non-primary feature as read-only
484 ictx->image_lock.lock();
485 ictx->read_only_mask |= IMAGE_READ_ONLY_FLAG_NON_PRIMARY;
486 ictx->image_lock.unlock();
487
488 ictx->state->handle_update_notification();
489
490 // attempt to restore the image state
491 CephContext *cct = ictx->cct;
492 mirror_image_internal.state = cls::rbd::MIRROR_IMAGE_STATE_ENABLED;
493 int r = cls_client::mirror_image_set(&ictx->md_ctx, ictx->id,
494 mirror_image_internal);
495 if (r < 0) {
496 lderr(cct) << "failed to re-enable image mirroring: "
497 << cpp_strerror(r) << dendl;
498 }
499 }
500 };
501
502 std::unique_lock image_locker{ictx->image_lock};
503 map<librados::snap_t, SnapInfo> snap_info = ictx->snap_info;
504 for (auto &info : snap_info) {
505 cls::rbd::ParentImageSpec parent_spec{ictx->md_ctx.get_id(),
506 ictx->md_ctx.get_namespace(),
507 ictx->id, info.first};
508 std::vector<librbd::linked_image_spec_t> child_images;
509 r = Image<I>::list_children(ictx, parent_spec, &child_images);
510 if (r < 0) {
511 rollback = true;
512 return r;
513 }
514
515 if (child_images.empty()) {
516 continue;
517 }
518
519 librados::IoCtx child_io_ctx;
520 int64_t child_pool_id = -1;
521 for (auto &child_image : child_images){
522 std::string pool = child_image.pool_name;
523 if (child_pool_id == -1 ||
524 child_pool_id != child_image.pool_id ||
525 child_io_ctx.get_namespace() != child_image.pool_namespace) {
526 r = util::create_ioctx(ictx->md_ctx, "child image",
527 child_image.pool_id,
528 child_image.pool_namespace,
529 &child_io_ctx);
530 if (r < 0) {
531 rollback = true;
532 return r;
533 }
534
535 child_pool_id = child_image.pool_id;
536 }
537
538 cls::rbd::MirrorImage child_mirror_image_internal;
539 r = cls_client::mirror_image_get(&child_io_ctx, child_image.image_id,
540 &child_mirror_image_internal);
541 if (r != -ENOENT) {
542 rollback = true;
543 lderr(cct) << "mirroring is enabled on one or more children "
544 << dendl;
545 return -EBUSY;
546 }
547 }
548 }
549 image_locker.unlock();
550
551 if (mirror_image_internal.mode == cls::rbd::MIRROR_IMAGE_MODE_SNAPSHOT) {
552 // don't let the non-primary feature bit prevent image updates
553 ictx->image_lock.lock();
554 ictx->read_only_mask &= ~IMAGE_READ_ONLY_FLAG_NON_PRIMARY;
555 ictx->image_lock.unlock();
556
557 r = ictx->state->refresh();
558 if (r < 0) {
559 rollback = true;
560 return r;
561 }
562
563 // remove any snapshot-based mirroring image-meta from image
564 std::string mirror_uuid;
565 r = uuid_get(ictx->md_ctx, &mirror_uuid);
566 if (r < 0) {
567 rollback = true;
568 return r;
569 }
570
571 r = ictx->operations->metadata_remove(
572 mirror::snapshot::util::get_image_meta_key(mirror_uuid));
573 if (r < 0 && r != -ENOENT) {
574 lderr(cct) << "cannot remove snapshot image-meta key: " << cpp_strerror(r)
575 << dendl;
576 rollback = true;
577 return r;
578 }
579 }
580
581 C_SaferCond ctx;
582 auto req = mirror::DisableRequest<ImageCtx>::create(ictx, force, true,
583 &ctx);
584 req->send();
585
586 r = ctx.wait();
587 if (r < 0) {
588 lderr(cct) << "cannot disable mirroring: " << cpp_strerror(r) << dendl;
589 rollback = true;
590 return r;
591 }
592
593 if (mirror_image_internal.mode == cls::rbd::MIRROR_IMAGE_MODE_JOURNAL) {
594 r = ictx->operations->update_features(RBD_FEATURE_JOURNALING, false);
595 if (r < 0) {
596 lderr(cct) << "cannot disable journaling: " << cpp_strerror(r) << dendl;
597 // not fatal
598 }
599 }
600
601 return 0;
602 }
603
604 template <typename I>
605 int Mirror<I>::image_promote(I *ictx, bool force) {
606 CephContext *cct = ictx->cct;
607
608 C_SaferCond ctx;
609 Mirror<I>::image_promote(ictx, force, &ctx);
610 int r = ctx.wait();
611 if (r < 0) {
612 lderr(cct) << "failed to promote image" << dendl;
613 return r;
614 }
615
616 return 0;
617 }
618
619 template <typename I>
620 void Mirror<I>::image_promote(I *ictx, bool force, Context *on_finish) {
621 CephContext *cct = ictx->cct;
622 ldout(cct, 20) << "ictx=" << ictx << ", "
623 << "force=" << force << dendl;
624
625 // don't let the non-primary feature bit prevent image updates
626 ictx->image_lock.lock();
627 ictx->read_only_mask &= ~IMAGE_READ_ONLY_FLAG_NON_PRIMARY;
628 ictx->image_lock.unlock();
629
630 auto on_promote = new LambdaContext([ictx, on_finish](int r) {
631 ictx->image_lock.lock();
632 ictx->read_only_mask |= IMAGE_READ_ONLY_FLAG_NON_PRIMARY;
633 ictx->image_lock.unlock();
634
635 ictx->state->handle_update_notification();
636 on_finish->complete(r);
637 });
638
639 auto on_refresh = new LambdaContext([ictx, force, on_promote](int r) {
640 if (r < 0) {
641 lderr(ictx->cct) << "refresh failed: " << cpp_strerror(r) << dendl;
642 on_promote->complete(r);
643 return;
644 }
645
646 auto req = mirror::PromoteRequest<>::create(*ictx, force, on_promote);
647 req->send();
648 });
649 ictx->state->refresh(on_refresh);
650 }
651
652 template <typename I>
653 int Mirror<I>::image_demote(I *ictx) {
654 CephContext *cct = ictx->cct;
655
656 C_SaferCond ctx;
657 Mirror<I>::image_demote(ictx, &ctx);
658 int r = ctx.wait();
659 if (r < 0) {
660 lderr(cct) << "failed to demote image" << dendl;
661 return r;
662 }
663
664 return 0;
665 }
666
667 template <typename I>
668 void Mirror<I>::image_demote(I *ictx, Context *on_finish) {
669 CephContext *cct = ictx->cct;
670 ldout(cct, 20) << "ictx=" << ictx << dendl;
671
672 auto on_cleanup = new LambdaContext([ictx, on_finish](int r) {
673 ictx->image_lock.lock();
674 ictx->read_only_mask |= IMAGE_READ_ONLY_FLAG_NON_PRIMARY;
675 ictx->image_lock.unlock();
676
677 ictx->state->handle_update_notification();
678
679 on_finish->complete(r);
680 });
681 auto on_refresh = new LambdaContext([ictx, on_cleanup](int r) {
682 if (r < 0) {
683 lderr(ictx->cct) << "refresh failed: " << cpp_strerror(r) << dendl;
684 on_cleanup->complete(r);
685 return;
686 }
687
688 auto req = mirror::DemoteRequest<>::create(*ictx, on_cleanup);
689 req->send();
690 });
691
692 // ensure we can create a snapshot after setting the non-primary
693 // feature bit
694 ictx->image_lock.lock();
695 ictx->read_only_mask &= ~IMAGE_READ_ONLY_FLAG_NON_PRIMARY;
696 ictx->image_lock.unlock();
697
698 ictx->state->refresh(on_refresh);
699 }
700
701 template <typename I>
702 int Mirror<I>::image_resync(I *ictx) {
703 CephContext *cct = ictx->cct;
704 ldout(cct, 20) << "ictx=" << ictx << dendl;
705
706 int r = ictx->state->refresh_if_required();
707 if (r < 0) {
708 return r;
709 }
710
711 cls::rbd::MirrorImage mirror_image;
712 mirror::PromotionState promotion_state;
713 std::string primary_mirror_uuid;
714 C_SaferCond get_info_ctx;
715 auto req = mirror::GetInfoRequest<I>::create(*ictx, &mirror_image,
716 &promotion_state,
717 &primary_mirror_uuid,
718 &get_info_ctx);
719 req->send();
720
721 r = get_info_ctx.wait();
722 if (r < 0) {
723 return r;
724 }
725
726 if (promotion_state == mirror::PROMOTION_STATE_PRIMARY) {
727 lderr(cct) << "image is primary, cannot resync to itself" << dendl;
728 return -EINVAL;
729 }
730
731 if (mirror_image.mode == cls::rbd::MIRROR_IMAGE_MODE_JOURNAL) {
732 // flag the journal indicating that we want to rebuild the local image
733 r = Journal<I>::request_resync(ictx);
734 if (r < 0) {
735 lderr(cct) << "failed to request resync: " << cpp_strerror(r) << dendl;
736 return r;
737 }
738 } else if (mirror_image.mode == cls::rbd::MIRROR_IMAGE_MODE_SNAPSHOT) {
739 std::string mirror_uuid;
740 r = uuid_get(ictx->md_ctx, &mirror_uuid);
741 if (r < 0) {
742 return r;
743 }
744
745 mirror::snapshot::ImageMeta image_meta(ictx, mirror_uuid);
746
747 C_SaferCond load_meta_ctx;
748 image_meta.load(&load_meta_ctx);
749 r = load_meta_ctx.wait();
750 if (r < 0 && r != -ENOENT) {
751 lderr(cct) << "failed to load mirror image-meta: " << cpp_strerror(r)
752 << dendl;
753 return r;
754 }
755
756 image_meta.resync_requested = true;
757
758 C_SaferCond save_meta_ctx;
759 image_meta.save(&save_meta_ctx);
760 r = save_meta_ctx.wait();
761 if (r < 0) {
762 lderr(cct) << "failed to request resync: " << cpp_strerror(r) << dendl;
763 return r;
764 }
765 } else {
766 lderr(cct) << "unknown mirror mode" << dendl;
767 return -EINVAL;
768 }
769
770 return 0;
771 }
772
773 template <typename I>
774 void Mirror<I>::image_get_info(I *ictx, mirror_image_info_t *mirror_image_info,
775 Context *on_finish) {
776 CephContext *cct = ictx->cct;
777 ldout(cct, 20) << "ictx=" << ictx << dendl;
778
779 auto on_refresh = new LambdaContext(
780 [ictx, mirror_image_info, on_finish](int r) {
781 if (r < 0) {
782 lderr(ictx->cct) << "refresh failed: " << cpp_strerror(r) << dendl;
783 on_finish->complete(r);
784 return;
785 }
786
787 auto ctx = new C_ImageGetInfo(mirror_image_info, nullptr, on_finish);
788 auto req = mirror::GetInfoRequest<I>::create(*ictx, &ctx->mirror_image,
789 &ctx->promotion_state,
790 &ctx->primary_mirror_uuid,
791 ctx);
792 req->send();
793 });
794
795 if (ictx->state->is_refresh_required()) {
796 ictx->state->refresh(on_refresh);
797 } else {
798 on_refresh->complete(0);
799 }
800 }
801
802 template <typename I>
803 int Mirror<I>::image_get_info(I *ictx, mirror_image_info_t *mirror_image_info) {
804 C_SaferCond ctx;
805 image_get_info(ictx, mirror_image_info, &ctx);
806
807 int r = ctx.wait();
808 if (r < 0) {
809 return r;
810 }
811 return 0;
812 }
813
814 template <typename I>
815 void Mirror<I>::image_get_info(librados::IoCtx& io_ctx,
816 ContextWQ *op_work_queue,
817 const std::string &image_id,
818 mirror_image_info_t *mirror_image_info,
819 Context *on_finish) {
820 auto cct = reinterpret_cast<CephContext *>(io_ctx.cct());
821 ldout(cct, 20) << "pool_id=" << io_ctx.get_id() << ", image_id=" << image_id
822 << dendl;
823
824 auto ctx = new C_ImageGetInfo(mirror_image_info, nullptr, on_finish);
825 auto req = mirror::GetInfoRequest<I>::create(io_ctx, op_work_queue, image_id,
826 &ctx->mirror_image,
827 &ctx->promotion_state,
828 &ctx->primary_mirror_uuid, ctx);
829 req->send();
830 }
831
832 template <typename I>
833 int Mirror<I>::image_get_info(librados::IoCtx& io_ctx,
834 ContextWQ *op_work_queue,
835 const std::string &image_id,
836 mirror_image_info_t *mirror_image_info) {
837 C_SaferCond ctx;
838 image_get_info(io_ctx, op_work_queue, image_id, mirror_image_info, &ctx);
839
840 int r = ctx.wait();
841 if (r < 0) {
842 return r;
843 }
844 return 0;
845 }
846
847 template <typename I>
848 void Mirror<I>::image_get_mode(I *ictx, mirror_image_mode_t *mode,
849 Context *on_finish) {
850 CephContext *cct = ictx->cct;
851 ldout(cct, 20) << "ictx=" << ictx << dendl;
852
853 auto ctx = new C_ImageGetInfo(nullptr, mode, on_finish);
854 auto req = mirror::GetInfoRequest<I>::create(*ictx, &ctx->mirror_image,
855 &ctx->promotion_state,
856 &ctx->primary_mirror_uuid, ctx);
857 req->send();
858 }
859
860 template <typename I>
861 int Mirror<I>::image_get_mode(I *ictx, mirror_image_mode_t *mode) {
862 C_SaferCond ctx;
863 image_get_mode(ictx, mode, &ctx);
864
865 int r = ctx.wait();
866 if (r < 0) {
867 return r;
868 }
869 return 0;
870 }
871
872 template <typename I>
873 void Mirror<I>::image_get_global_status(I *ictx,
874 mirror_image_global_status_t *status,
875 Context *on_finish) {
876 CephContext *cct = ictx->cct;
877 ldout(cct, 20) << "ictx=" << ictx << dendl;
878
879 auto ctx = new C_ImageGetGlobalStatus(ictx->name, status, on_finish);
880 auto req = mirror::GetStatusRequest<I>::create(
881 *ictx, &ctx->mirror_image_status_internal, &ctx->mirror_image,
882 &ctx->promotion_state, ctx);
883 req->send();
884 }
885
886 template <typename I>
887 int Mirror<I>::image_get_global_status(I *ictx,
888 mirror_image_global_status_t *status) {
889 C_SaferCond ctx;
890 image_get_global_status(ictx, status, &ctx);
891
892 int r = ctx.wait();
893 if (r < 0) {
894 return r;
895 }
896 return 0;
897 }
898
899 template <typename I>
900 int Mirror<I>::image_get_instance_id(I *ictx, std::string *instance_id) {
901 CephContext *cct = ictx->cct;
902 ldout(cct, 20) << "ictx=" << ictx << dendl;
903
904 cls::rbd::MirrorImage mirror_image;
905 int r = cls_client::mirror_image_get(&ictx->md_ctx, ictx->id, &mirror_image);
906 if (r < 0 && r != -ENOENT) {
907 lderr(cct) << "failed to retrieve mirroring state: " << cpp_strerror(r)
908 << dendl;
909 return r;
910 } else if (mirror_image.state != cls::rbd::MIRROR_IMAGE_STATE_ENABLED) {
911 lderr(cct) << "mirroring is not currently enabled" << dendl;
912 return -EINVAL;
913 }
914
915 entity_inst_t instance;
916 r = cls_client::mirror_image_instance_get(&ictx->md_ctx,
917 mirror_image.global_image_id,
918 &instance);
919 if (r < 0) {
920 if (r != -ENOENT && r != -ESTALE) {
921 lderr(cct) << "failed to get mirror image instance: " << cpp_strerror(r)
922 << dendl;
923 }
924 return r;
925 }
926
927 *instance_id = stringify(instance.name.num());
928 return 0;
929 }
930
931 template <typename I>
932 int Mirror<I>::site_name_get(librados::Rados& rados, std::string* name) {
933 CephContext *cct = reinterpret_cast<CephContext *>(rados.cct());
934 ldout(cct, 20) << dendl;
935
936 int r = get_config_key(rados, RBD_MIRROR_SITE_NAME_CONFIG_KEY, name);
937 if (r == -EOPNOTSUPP) {
938 return r;
939 } else if (r == -ENOENT || name->empty()) {
940 // default to the cluster fsid
941 r = rados.cluster_fsid(name);
942 if (r < 0) {
943 lderr(cct) << "failed to retrieve cluster fsid: " << cpp_strerror(r)
944 << dendl;
945 }
946 return r;
947 } else if (r < 0) {
948 lderr(cct) << "failed to retrieve site name: " << cpp_strerror(r)
949 << dendl;
950 return r;
951 }
952
953 return 0;
954 }
955
956 template <typename I>
957 int Mirror<I>::site_name_set(librados::Rados& rados, const std::string& name) {
958 CephContext *cct = reinterpret_cast<CephContext *>(rados.cct());
959
960 std::string site_name{name};
961 boost::algorithm::trim(site_name);
962 ldout(cct, 20) << "site_name=" << site_name << dendl;
963
964 int r = set_config_key(rados, RBD_MIRROR_SITE_NAME_CONFIG_KEY, name);
965 if (r == -EOPNOTSUPP) {
966 return r;
967 } else if (r < 0 && r != -ENOENT) {
968 lderr(cct) << "failed to update site name: " << cpp_strerror(r)
969 << dendl;
970 return r;
971 }
972
973 return 0;
974 }
975
976 template <typename I>
977 int Mirror<I>::mode_get(librados::IoCtx& io_ctx,
978 rbd_mirror_mode_t *mirror_mode) {
979 CephContext *cct = reinterpret_cast<CephContext *>(io_ctx.cct());
980 ldout(cct, 20) << dendl;
981
982 cls::rbd::MirrorMode mirror_mode_internal;
983 int r = cls_client::mirror_mode_get(&io_ctx, &mirror_mode_internal);
984 if (r < 0) {
985 lderr(cct) << "failed to retrieve mirror mode: " << cpp_strerror(r)
986 << dendl;
987 return r;
988 }
989
990 switch (mirror_mode_internal) {
991 case cls::rbd::MIRROR_MODE_DISABLED:
992 case cls::rbd::MIRROR_MODE_IMAGE:
993 case cls::rbd::MIRROR_MODE_POOL:
994 *mirror_mode = static_cast<rbd_mirror_mode_t>(mirror_mode_internal);
995 break;
996 default:
997 lderr(cct) << "unknown mirror mode ("
998 << static_cast<uint32_t>(mirror_mode_internal) << ")"
999 << dendl;
1000 return -EINVAL;
1001 }
1002 return 0;
1003 }
1004
1005 template <typename I>
1006 int Mirror<I>::mode_set(librados::IoCtx& io_ctx,
1007 rbd_mirror_mode_t mirror_mode) {
1008 CephContext *cct = reinterpret_cast<CephContext *>(io_ctx.cct());
1009 ldout(cct, 20) << dendl;
1010
1011 cls::rbd::MirrorMode next_mirror_mode;
1012 switch (mirror_mode) {
1013 case RBD_MIRROR_MODE_DISABLED:
1014 case RBD_MIRROR_MODE_IMAGE:
1015 case RBD_MIRROR_MODE_POOL:
1016 next_mirror_mode = static_cast<cls::rbd::MirrorMode>(mirror_mode);
1017 break;
1018 default:
1019 lderr(cct) << "unknown mirror mode ("
1020 << static_cast<uint32_t>(mirror_mode) << ")" << dendl;
1021 return -EINVAL;
1022 }
1023
1024 int r;
1025 if (next_mirror_mode == cls::rbd::MIRROR_MODE_DISABLED) {
1026 // fail early if pool still has peers registered and attempting to disable
1027 std::vector<cls::rbd::MirrorPeer> mirror_peers;
1028 r = cls_client::mirror_peer_list(&io_ctx, &mirror_peers);
1029 if (r < 0 && r != -ENOENT) {
1030 lderr(cct) << "failed to list peers: " << cpp_strerror(r) << dendl;
1031 return r;
1032 } else if (!mirror_peers.empty()) {
1033 lderr(cct) << "mirror peers still registered" << dendl;
1034 return -EBUSY;
1035 }
1036 }
1037
1038 cls::rbd::MirrorMode current_mirror_mode;
1039 r = cls_client::mirror_mode_get(&io_ctx, &current_mirror_mode);
1040 if (r < 0) {
1041 lderr(cct) << "failed to retrieve mirror mode: " << cpp_strerror(r)
1042 << dendl;
1043 return r;
1044 }
1045
1046 if (current_mirror_mode == next_mirror_mode) {
1047 return 0;
1048 } else if (current_mirror_mode == cls::rbd::MIRROR_MODE_DISABLED) {
1049 uuid_d uuid_gen;
1050 uuid_gen.generate_random();
1051 r = cls_client::mirror_uuid_set(&io_ctx, uuid_gen.to_string());
1052 if (r < 0) {
1053 lderr(cct) << "failed to allocate mirroring uuid: " << cpp_strerror(r)
1054 << dendl;
1055 return r;
1056 }
1057 }
1058
1059 if (current_mirror_mode != cls::rbd::MIRROR_MODE_IMAGE) {
1060 r = cls_client::mirror_mode_set(&io_ctx, cls::rbd::MIRROR_MODE_IMAGE);
1061 if (r < 0) {
1062 lderr(cct) << "failed to set mirror mode to image: "
1063 << cpp_strerror(r) << dendl;
1064 return r;
1065 }
1066
1067 r = MirroringWatcher<>::notify_mode_updated(io_ctx,
1068 cls::rbd::MIRROR_MODE_IMAGE);
1069 if (r < 0) {
1070 lderr(cct) << "failed to send update notification: " << cpp_strerror(r)
1071 << dendl;
1072 }
1073 }
1074
1075 if (next_mirror_mode == cls::rbd::MIRROR_MODE_IMAGE) {
1076 return 0;
1077 }
1078
1079 if (next_mirror_mode == cls::rbd::MIRROR_MODE_POOL) {
1080 map<string, string> images;
1081 r = Image<I>::list_images_v2(io_ctx, &images);
1082 if (r < 0) {
1083 lderr(cct) << "failed listing images: " << cpp_strerror(r) << dendl;
1084 return r;
1085 }
1086
1087 for (const auto& img_pair : images) {
1088 uint64_t features;
1089 uint64_t incompatible_features;
1090 r = cls_client::get_features(&io_ctx, util::header_name(img_pair.second),
1091 true, &features, &incompatible_features);
1092 if (r < 0) {
1093 lderr(cct) << "error getting features for image " << img_pair.first
1094 << ": " << cpp_strerror(r) << dendl;
1095 return r;
1096 }
1097
1098 // Enable only journal based mirroring
1099
1100 if ((features & RBD_FEATURE_JOURNALING) != 0) {
1101 I *img_ctx = I::create("", img_pair.second, nullptr, io_ctx, false);
1102 r = img_ctx->state->open(0);
1103 if (r < 0) {
1104 lderr(cct) << "error opening image "<< img_pair.first << ": "
1105 << cpp_strerror(r) << dendl;
1106 return r;
1107 }
1108
1109 r = image_enable(img_ctx, RBD_MIRROR_IMAGE_MODE_JOURNAL, true);
1110 int close_r = img_ctx->state->close();
1111 if (r < 0) {
1112 lderr(cct) << "error enabling mirroring for image "
1113 << img_pair.first << ": " << cpp_strerror(r) << dendl;
1114 return r;
1115 } else if (close_r < 0) {
1116 lderr(cct) << "failed to close image " << img_pair.first << ": "
1117 << cpp_strerror(close_r) << dendl;
1118 return close_r;
1119 }
1120 }
1121 }
1122 } else if (next_mirror_mode == cls::rbd::MIRROR_MODE_DISABLED) {
1123 while (true) {
1124 bool retry_busy = false;
1125 bool pending_busy = false;
1126
1127 std::set<std::string> image_ids;
1128 r = list_mirror_images(io_ctx, image_ids);
1129 if (r < 0) {
1130 lderr(cct) << "failed listing images: " << cpp_strerror(r) << dendl;
1131 return r;
1132 }
1133
1134 for (const auto& img_id : image_ids) {
1135 if (current_mirror_mode == cls::rbd::MIRROR_MODE_IMAGE) {
1136 cls::rbd::MirrorImage mirror_image;
1137 r = cls_client::mirror_image_get(&io_ctx, img_id, &mirror_image);
1138 if (r < 0 && r != -ENOENT) {
1139 lderr(cct) << "failed to retrieve mirroring state for image id "
1140 << img_id << ": " << cpp_strerror(r) << dendl;
1141 return r;
1142 }
1143 if (mirror_image.state == cls::rbd::MIRROR_IMAGE_STATE_ENABLED) {
1144 lderr(cct) << "failed to disable mirror mode: there are still "
1145 << "images with mirroring enabled" << dendl;
1146 return -EINVAL;
1147 }
1148 } else {
1149 I *img_ctx = I::create("", img_id, nullptr, io_ctx, false);
1150 r = img_ctx->state->open(0);
1151 if (r < 0) {
1152 lderr(cct) << "error opening image id "<< img_id << ": "
1153 << cpp_strerror(r) << dendl;
1154 return r;
1155 }
1156
1157 r = image_disable(img_ctx, false);
1158 int close_r = img_ctx->state->close();
1159 if (r == -EBUSY) {
1160 pending_busy = true;
1161 } else if (r < 0) {
1162 lderr(cct) << "error disabling mirroring for image id " << img_id
1163 << cpp_strerror(r) << dendl;
1164 return r;
1165 } else if (close_r < 0) {
1166 lderr(cct) << "failed to close image id " << img_id << ": "
1167 << cpp_strerror(close_r) << dendl;
1168 return close_r;
1169 } else if (pending_busy) {
1170 // at least one mirrored image was successfully disabled, so we can
1171 // retry any failures caused by busy parent/child relationships
1172 retry_busy = true;
1173 }
1174 }
1175 }
1176
1177 if (!retry_busy && pending_busy) {
1178 lderr(cct) << "error disabling mirroring for one or more images"
1179 << dendl;
1180 return -EBUSY;
1181 } else if (!retry_busy) {
1182 break;
1183 }
1184 }
1185 }
1186
1187 r = cls_client::mirror_mode_set(&io_ctx, next_mirror_mode);
1188 if (r < 0) {
1189 lderr(cct) << "failed to set mirror mode: " << cpp_strerror(r) << dendl;
1190 return r;
1191 }
1192
1193 r = MirroringWatcher<>::notify_mode_updated(io_ctx, next_mirror_mode);
1194 if (r < 0) {
1195 lderr(cct) << "failed to send update notification: " << cpp_strerror(r)
1196 << dendl;
1197 }
1198 return 0;
1199 }
1200
1201 template <typename I>
1202 int Mirror<I>::uuid_get(librados::IoCtx& io_ctx, std::string* mirror_uuid) {
1203 CephContext *cct = reinterpret_cast<CephContext *>(io_ctx.cct());
1204 ldout(cct, 20) << dendl;
1205
1206 C_SaferCond ctx;
1207 uuid_get(io_ctx, mirror_uuid, &ctx);
1208 int r = ctx.wait();
1209 if (r < 0) {
1210 if (r != -ENOENT) {
1211 lderr(cct) << "failed to retrieve mirroring uuid: " << cpp_strerror(r)
1212 << dendl;
1213 }
1214 return r;
1215 }
1216
1217 return 0;
1218 }
1219
1220 template <typename I>
1221 void Mirror<I>::uuid_get(librados::IoCtx& io_ctx, std::string* mirror_uuid,
1222 Context* on_finish) {
1223 CephContext *cct = reinterpret_cast<CephContext *>(io_ctx.cct());
1224 ldout(cct, 20) << dendl;
1225
1226 auto req = mirror::GetUuidRequest<I>::create(io_ctx, mirror_uuid, on_finish);
1227 req->send();
1228 }
1229
1230 template <typename I>
1231 int Mirror<I>::peer_bootstrap_create(librados::IoCtx& io_ctx,
1232 std::string* token) {
1233 CephContext *cct = reinterpret_cast<CephContext *>(io_ctx.cct());
1234 ldout(cct, 20) << dendl;
1235
1236 auto mirror_mode = cls::rbd::MIRROR_MODE_DISABLED;
1237 int r = cls_client::mirror_mode_get(&io_ctx, &mirror_mode);
1238 if (r < 0 && r != -ENOENT) {
1239 lderr(cct) << "failed to retrieve mirroring mode: " << cpp_strerror(r)
1240 << dendl;
1241 return r;
1242 } else if (mirror_mode == cls::rbd::MIRROR_MODE_DISABLED) {
1243 return -EINVAL;
1244 }
1245
1246 // retrieve the cluster fsid
1247 std::string fsid;
1248 librados::Rados rados(io_ctx);
1249 r = rados.cluster_fsid(&fsid);
1250 if (r < 0) {
1251 lderr(cct) << "failed to retrieve cluster fsid: " << cpp_strerror(r)
1252 << dendl;
1253 return r;
1254 }
1255
1256 std::string peer_client_id;
1257 std::string cephx_key;
1258 r = create_bootstrap_user(cct, rados, &peer_client_id, &cephx_key);
1259 if (r < 0) {
1260 return r;
1261 }
1262
1263 std::string mon_host = cct->_conf.get_val<std::string>("mon_host");
1264 ldout(cct, 20) << "mon_host=" << mon_host << dendl;
1265
1266 // format the token response
1267 bufferlist token_bl;
1268 token_bl.append(
1269 R"({)" \
1270 R"("fsid":")" + fsid + R"(",)" + \
1271 R"("client_id":")" + peer_client_id + R"(",)" + \
1272 R"("key":")" + cephx_key + R"(",)" + \
1273 R"("mon_host":")" + \
1274 boost::replace_all_copy(mon_host, "\"", "\\\"") + R"(")" + \
1275 R"(})");
1276 ldout(cct, 20) << "token=" << token_bl.to_str() << dendl;
1277
1278 bufferlist base64_bl;
1279 token_bl.encode_base64(base64_bl);
1280 *token = base64_bl.to_str();
1281
1282 return 0;
1283 }
1284
1285 template <typename I>
1286 int Mirror<I>::peer_bootstrap_import(librados::IoCtx& io_ctx,
1287 rbd_mirror_peer_direction_t direction,
1288 const std::string& token) {
1289 CephContext *cct = reinterpret_cast<CephContext *>(io_ctx.cct());
1290 ldout(cct, 20) << dendl;
1291
1292 if (direction != RBD_MIRROR_PEER_DIRECTION_RX &&
1293 direction != RBD_MIRROR_PEER_DIRECTION_RX_TX) {
1294 lderr(cct) << "invalid mirror peer direction" << dendl;
1295 return -EINVAL;
1296 }
1297
1298 bufferlist token_bl;
1299 try {
1300 bufferlist base64_bl;
1301 base64_bl.append(token);
1302 token_bl.decode_base64(base64_bl);
1303 } catch (buffer::error& err) {
1304 lderr(cct) << "failed to decode base64" << dendl;
1305 return -EINVAL;
1306 }
1307
1308 ldout(cct, 20) << "token=" << token_bl.to_str() << dendl;
1309
1310 bool json_valid = false;
1311 std::string expected_remote_fsid;
1312 std::string remote_client_id;
1313 std::string remote_key;
1314 std::string remote_mon_host;
1315
1316 json_spirit::mValue json_root;
1317 if(json_spirit::read(token_bl.to_str(), json_root)) {
1318 try {
1319 auto& json_obj = json_root.get_obj();
1320 expected_remote_fsid = json_obj["fsid"].get_str();
1321 remote_client_id = json_obj["client_id"].get_str();
1322 remote_key = json_obj["key"].get_str();
1323 remote_mon_host = json_obj["mon_host"].get_str();
1324 json_valid = true;
1325 } catch (std::runtime_error&) {
1326 }
1327 }
1328
1329 if (!json_valid) {
1330 lderr(cct) << "invalid bootstrap token JSON received" << dendl;
1331 return -EINVAL;
1332 }
1333
1334 // sanity check import process
1335 std::string local_fsid;
1336 librados::Rados rados(io_ctx);
1337 int r = rados.cluster_fsid(&local_fsid);
1338 if (r < 0) {
1339 lderr(cct) << "failed to retrieve cluster fsid: " << cpp_strerror(r)
1340 << dendl;
1341 return r;
1342 }
1343
1344 std::string local_site_name;
1345 r = site_name_get(rados, &local_site_name);
1346 if (r < 0) {
1347 lderr(cct) << "failed to retrieve cluster site name: " << cpp_strerror(r)
1348 << dendl;
1349 return r;
1350 }
1351
1352 // attempt to connect to remote cluster
1353 librados::Rados remote_rados;
1354 remote_rados.init(remote_client_id.c_str());
1355
1356 auto remote_cct = reinterpret_cast<CephContext*>(remote_rados.cct());
1357 remote_cct->_conf.set_val("mon_host", remote_mon_host);
1358 remote_cct->_conf.set_val("key", remote_key);
1359
1360 r = remote_rados.connect();
1361 if (r < 0) {
1362 lderr(cct) << "failed to connect to peer cluster: " << cpp_strerror(r)
1363 << dendl;
1364 return r;
1365 }
1366
1367 std::string remote_fsid;
1368 r = remote_rados.cluster_fsid(&remote_fsid);
1369 if (r < 0) {
1370 lderr(cct) << "failed to retrieve remote cluster fsid: "
1371 << cpp_strerror(r) << dendl;
1372 return r;
1373 } else if (local_fsid == remote_fsid) {
1374 lderr(cct) << "cannot import token for local cluster" << dendl;
1375 return -EINVAL;
1376 } else if (expected_remote_fsid != remote_fsid) {
1377 lderr(cct) << "unexpected remote cluster fsid" << dendl;
1378 return -EINVAL;
1379 }
1380
1381 std::string remote_site_name;
1382 r = site_name_get(remote_rados, &remote_site_name);
1383 if (r < 0) {
1384 lderr(cct) << "failed to retrieve remote cluster site name: "
1385 << cpp_strerror(r) << dendl;
1386 return r;
1387 } else if (local_site_name == remote_site_name) {
1388 lderr(cct) << "cannot import token for duplicate site name" << dendl;
1389 return -EINVAL;
1390 }
1391
1392 librados::IoCtx remote_io_ctx;
1393 r = remote_rados.ioctx_create(io_ctx.get_pool_name().c_str(), remote_io_ctx);
1394 if (r == -ENOENT) {
1395 ldout(cct, 10) << "remote pool does not exist" << dendl;
1396 return r;
1397 } else if (r < 0) {
1398 lderr(cct) << "failed to open remote pool '" << io_ctx.get_pool_name()
1399 << "': " << cpp_strerror(r) << dendl;
1400 return r;
1401 }
1402
1403 auto remote_mirror_mode = cls::rbd::MIRROR_MODE_DISABLED;
1404 r = cls_client::mirror_mode_get(&remote_io_ctx, &remote_mirror_mode);
1405 if (r < 0 && r != -ENOENT) {
1406 lderr(cct) << "failed to retrieve remote mirroring mode: "
1407 << cpp_strerror(r) << dendl;
1408 return r;
1409 } else if (remote_mirror_mode == cls::rbd::MIRROR_MODE_DISABLED) {
1410 return -ENOSYS;
1411 }
1412
1413 auto local_mirror_mode = cls::rbd::MIRROR_MODE_DISABLED;
1414 r = cls_client::mirror_mode_get(&io_ctx, &local_mirror_mode);
1415 if (r < 0 && r != -ENOENT) {
1416 lderr(cct) << "failed to retrieve local mirroring mode: " << cpp_strerror(r)
1417 << dendl;
1418 return r;
1419 } else if (local_mirror_mode == cls::rbd::MIRROR_MODE_DISABLED) {
1420 // copy mirror mode from remote peer
1421 r = mode_set(io_ctx, static_cast<rbd_mirror_mode_t>(remote_mirror_mode));
1422 if (r < 0) {
1423 return r;
1424 }
1425 }
1426
1427 if (direction == RBD_MIRROR_PEER_DIRECTION_RX_TX) {
1428 // create a local mirror peer user and export it to the remote cluster
1429 std::string local_client_id;
1430 std::string local_key;
1431 r = create_bootstrap_user(cct, rados, &local_client_id, &local_key);
1432 if (r < 0) {
1433 return r;
1434 }
1435
1436 std::string local_mon_host = cct->_conf.get_val<std::string>("mon_host");
1437
1438 // create local cluster peer in remote cluster
1439 r = create_bootstrap_peer(cct, remote_io_ctx,
1440 RBD_MIRROR_PEER_DIRECTION_RX_TX, local_site_name,
1441 local_fsid, local_client_id, local_key,
1442 local_mon_host, "local", "remote");
1443 if (r < 0) {
1444 return r;
1445 }
1446 }
1447
1448 // create remote cluster peer in local cluster
1449 r = create_bootstrap_peer(cct, io_ctx, direction, remote_site_name,
1450 remote_fsid, remote_client_id, remote_key,
1451 remote_mon_host, "remote", "local");
1452 if (r < 0) {
1453 return r;
1454 }
1455
1456 return 0;
1457 }
1458
1459 template <typename I>
1460 int Mirror<I>::peer_site_add(librados::IoCtx& io_ctx, std::string *uuid,
1461 mirror_peer_direction_t direction,
1462 const std::string &site_name,
1463 const std::string &client_name) {
1464 CephContext *cct = reinterpret_cast<CephContext *>(io_ctx.cct());
1465 ldout(cct, 20) << "name=" << site_name << ", "
1466 << "client=" << client_name << dendl;
1467
1468 if (cct->_conf->cluster == site_name) {
1469 lderr(cct) << "cannot add self as remote peer" << dendl;
1470 return -EINVAL;
1471 }
1472
1473 if (direction == RBD_MIRROR_PEER_DIRECTION_TX) {
1474 return -EINVAL;
1475 }
1476
1477 int r;
1478 do {
1479 uuid_d uuid_gen;
1480 uuid_gen.generate_random();
1481
1482 *uuid = uuid_gen.to_string();
1483 r = cls_client::mirror_peer_add(
1484 &io_ctx, {*uuid, static_cast<cls::rbd::MirrorPeerDirection>(direction),
1485 site_name, client_name, ""});
1486 if (r == -ESTALE) {
1487 ldout(cct, 5) << "duplicate UUID detected, retrying" << dendl;
1488 } else if (r < 0) {
1489 lderr(cct) << "failed to add mirror peer '" << site_name << "': "
1490 << cpp_strerror(r) << dendl;
1491 return r;
1492 }
1493 } while (r == -ESTALE);
1494 return 0;
1495 }
1496
1497 template <typename I>
1498 int Mirror<I>::peer_site_remove(librados::IoCtx& io_ctx,
1499 const std::string &uuid) {
1500 CephContext *cct = reinterpret_cast<CephContext *>(io_ctx.cct());
1501 ldout(cct, 20) << "uuid=" << uuid << dendl;
1502
1503 int r = remove_peer_config_key(io_ctx, uuid);
1504 if (r < 0) {
1505 lderr(cct) << "failed to remove peer attributes '" << uuid << "': "
1506 << cpp_strerror(r) << dendl;
1507 return r;
1508 }
1509
1510 r = cls_client::mirror_peer_remove(&io_ctx, uuid);
1511 if (r < 0 && r != -ENOENT) {
1512 lderr(cct) << "failed to remove peer '" << uuid << "': "
1513 << cpp_strerror(r) << dendl;
1514 return r;
1515 }
1516
1517 vector<string> names;
1518 r = Namespace<I>::list(io_ctx, &names);
1519 if (r < 0) {
1520 return r;
1521 }
1522
1523 names.push_back("");
1524
1525 librados::IoCtx ns_io_ctx;
1526 ns_io_ctx.dup(io_ctx);
1527
1528 for (auto &name : names) {
1529 ns_io_ctx.set_namespace(name);
1530
1531 std::set<std::string> image_ids;
1532 r = list_mirror_images(ns_io_ctx, image_ids);
1533 if (r < 0) {
1534 lderr(cct) << "failed listing images in "
1535 << (name.empty() ? "default" : name) << " namespace : "
1536 << cpp_strerror(r) << dendl;
1537 return r;
1538 }
1539
1540 for (const auto& image_id : image_ids) {
1541 cls::rbd::MirrorImage mirror_image;
1542 r = cls_client::mirror_image_get(&ns_io_ctx, image_id, &mirror_image);
1543 if (r == -ENOENT) {
1544 continue;
1545 }
1546 if (r < 0) {
1547 lderr(cct) << "error getting mirror info for image " << image_id
1548 << ": " << cpp_strerror(r) << dendl;
1549 return r;
1550 }
1551 if (mirror_image.mode != cls::rbd::MIRROR_IMAGE_MODE_SNAPSHOT) {
1552 continue;
1553 }
1554
1555 // Snapshot based mirroring. Unlink the peer from mirroring snapshots.
1556 // TODO: optimize.
1557
1558 I *img_ctx = I::create("", image_id, nullptr, ns_io_ctx, false);
1559 img_ctx->read_only_mask &= ~IMAGE_READ_ONLY_FLAG_NON_PRIMARY;
1560
1561 r = img_ctx->state->open(0);
1562 if (r == -ENOENT) {
1563 continue;
1564 }
1565 if (r < 0) {
1566 lderr(cct) << "error opening image " << image_id << ": "
1567 << cpp_strerror(r) << dendl;
1568 return r;
1569 }
1570
1571 std::list<uint64_t> snap_ids;
1572 {
1573 std::shared_lock image_locker{img_ctx->image_lock};
1574 for (auto &it : img_ctx->snap_info) {
1575 auto info = boost::get<cls::rbd::MirrorSnapshotNamespace>(
1576 &it.second.snap_namespace);
1577 if (info && info->mirror_peer_uuids.count(uuid)) {
1578 snap_ids.push_back(it.first);
1579 }
1580 }
1581 }
1582 for (auto snap_id : snap_ids) {
1583 C_SaferCond cond;
1584 auto req = mirror::snapshot::UnlinkPeerRequest<I>::create(
1585 img_ctx, snap_id, uuid, &cond);
1586 req->send();
1587 r = cond.wait();
1588 if (r == -ENOENT) {
1589 r = 0;
1590 }
1591 if (r < 0) {
1592 break;
1593 }
1594 }
1595
1596 int close_r = img_ctx->state->close();
1597 if (r < 0) {
1598 lderr(cct) << "error unlinking peer for image " << image_id << ": "
1599 << cpp_strerror(r) << dendl;
1600 return r;
1601 } else if (close_r < 0) {
1602 lderr(cct) << "failed to close image " << image_id << ": "
1603 << cpp_strerror(close_r) << dendl;
1604 return close_r;
1605 }
1606 }
1607 }
1608
1609 return 0;
1610 }
1611
1612 template <typename I>
1613 int Mirror<I>::peer_site_list(librados::IoCtx& io_ctx,
1614 std::vector<mirror_peer_site_t> *peers) {
1615 CephContext *cct = reinterpret_cast<CephContext *>(io_ctx.cct());
1616 ldout(cct, 20) << dendl;
1617
1618 std::vector<cls::rbd::MirrorPeer> mirror_peers;
1619 int r = cls_client::mirror_peer_list(&io_ctx, &mirror_peers);
1620 if (r < 0 && r != -ENOENT) {
1621 lderr(cct) << "failed to list peers: " << cpp_strerror(r) << dendl;
1622 return r;
1623 }
1624
1625 peers->clear();
1626 peers->reserve(mirror_peers.size());
1627 for (auto &mirror_peer : mirror_peers) {
1628 mirror_peer_site_t peer;
1629 peer.uuid = mirror_peer.uuid;
1630 peer.direction = static_cast<mirror_peer_direction_t>(
1631 mirror_peer.mirror_peer_direction);
1632 peer.site_name = mirror_peer.site_name;
1633 peer.mirror_uuid = mirror_peer.mirror_uuid;
1634 peer.client_name = mirror_peer.client_name;
1635 peer.last_seen = mirror_peer.last_seen.sec();
1636 peers->push_back(peer);
1637 }
1638 return 0;
1639 }
1640
1641 template <typename I>
1642 int Mirror<I>::peer_site_set_client(librados::IoCtx& io_ctx,
1643 const std::string &uuid,
1644 const std::string &client_name) {
1645 CephContext *cct = reinterpret_cast<CephContext *>(io_ctx.cct());
1646 ldout(cct, 20) << "uuid=" << uuid << ", "
1647 << "client=" << client_name << dendl;
1648
1649 int r = cls_client::mirror_peer_set_client(&io_ctx, uuid, client_name);
1650 if (r < 0) {
1651 lderr(cct) << "failed to update client '" << uuid << "': "
1652 << cpp_strerror(r) << dendl;
1653 return r;
1654 }
1655 return 0;
1656 }
1657
1658 template <typename I>
1659 int Mirror<I>::peer_site_set_name(librados::IoCtx& io_ctx,
1660 const std::string &uuid,
1661 const std::string &site_name) {
1662 CephContext *cct = reinterpret_cast<CephContext *>(io_ctx.cct());
1663 ldout(cct, 20) << "uuid=" << uuid << ", "
1664 << "name=" << site_name << dendl;
1665
1666 if (cct->_conf->cluster == site_name) {
1667 lderr(cct) << "cannot set self as remote peer" << dendl;
1668 return -EINVAL;
1669 }
1670
1671 int r = cls_client::mirror_peer_set_cluster(&io_ctx, uuid, site_name);
1672 if (r < 0) {
1673 lderr(cct) << "failed to update site '" << uuid << "': "
1674 << cpp_strerror(r) << dendl;
1675 return r;
1676 }
1677 return 0;
1678 }
1679
1680 template <typename I>
1681 int Mirror<I>::peer_site_set_direction(librados::IoCtx& io_ctx,
1682 const std::string &uuid,
1683 mirror_peer_direction_t direction) {
1684 cls::rbd::MirrorPeerDirection mirror_peer_direction = static_cast<
1685 cls::rbd::MirrorPeerDirection>(direction);
1686
1687 CephContext *cct = reinterpret_cast<CephContext *>(io_ctx.cct());
1688 ldout(cct, 20) << "uuid=" << uuid << ", "
1689 << "direction=" << mirror_peer_direction << dendl;
1690
1691 int r = cls_client::mirror_peer_set_direction(&io_ctx, uuid,
1692 mirror_peer_direction);
1693 if (r < 0) {
1694 lderr(cct) << "failed to update direction '" << uuid << "': "
1695 << cpp_strerror(r) << dendl;
1696 return r;
1697 }
1698 return 0;
1699 }
1700
1701 template <typename I>
1702 int Mirror<I>::peer_site_get_attributes(librados::IoCtx& io_ctx,
1703 const std::string &uuid,
1704 Attributes* attributes) {
1705 CephContext *cct = reinterpret_cast<CephContext *>(io_ctx.cct());
1706 ldout(cct, 20) << "uuid=" << uuid << dendl;
1707
1708 attributes->clear();
1709
1710 librados::Rados rados(io_ctx);
1711 std::string value;
1712 int r = get_config_key(rados, get_peer_config_key_name(io_ctx.get_id(), uuid),
1713 &value);
1714 if (r == -ENOENT || value.empty()) {
1715 return -ENOENT;
1716 } else if (r < 0) {
1717 lderr(cct) << "failed to retrieve peer attributes: " << cpp_strerror(r)
1718 << dendl;
1719 return r;
1720 }
1721
1722 bool json_valid = false;
1723 json_spirit::mValue json_root;
1724 if(json_spirit::read(value, json_root)) {
1725 try {
1726 auto& json_obj = json_root.get_obj();
1727 for (auto& pairs : json_obj) {
1728 (*attributes)[pairs.first] = pairs.second.get_str();
1729 }
1730 json_valid = true;
1731 } catch (std::runtime_error&) {
1732 }
1733 }
1734
1735 if (!json_valid) {
1736 lderr(cct) << "invalid peer attributes JSON received" << dendl;
1737 return -EINVAL;
1738 }
1739 return 0;
1740 }
1741
1742 template <typename I>
1743 int Mirror<I>::peer_site_set_attributes(librados::IoCtx& io_ctx,
1744 const std::string &uuid,
1745 const Attributes& attributes) {
1746 CephContext *cct = reinterpret_cast<CephContext *>(io_ctx.cct());
1747 ldout(cct, 20) << "uuid=" << uuid << ", "
1748 << "attributes=" << attributes << dendl;
1749
1750 std::vector<mirror_peer_site_t> mirror_peers;
1751 int r = peer_site_list(io_ctx, &mirror_peers);
1752 if (r < 0) {
1753 return r;
1754 }
1755
1756 if (std::find_if(mirror_peers.begin(), mirror_peers.end(),
1757 [&uuid](const librbd::mirror_peer_site_t& peer) {
1758 return uuid == peer.uuid;
1759 }) == mirror_peers.end()) {
1760 ldout(cct, 5) << "mirror peer uuid " << uuid << " does not exist" << dendl;
1761 return -ENOENT;
1762 }
1763
1764 std::stringstream ss;
1765 ss << "{";
1766 for (auto& pair : attributes) {
1767 ss << "\\\"" << pair.first << "\\\": "
1768 << "\\\"" << pair.second << "\\\"";
1769 if (&pair != &(*attributes.rbegin())) {
1770 ss << ", ";
1771 }
1772 }
1773 ss << "}";
1774
1775 librados::Rados rados(io_ctx);
1776 r = set_config_key(rados, get_peer_config_key_name(io_ctx.get_id(), uuid),
1777 ss.str());
1778 if (r < 0 && r != -ENOENT) {
1779 lderr(cct) << "failed to update peer attributes: " << cpp_strerror(r)
1780 << dendl;
1781 return r;
1782 }
1783
1784 return 0;
1785 }
1786
1787 template <typename I>
1788 int Mirror<I>::image_global_status_list(
1789 librados::IoCtx& io_ctx, const std::string &start_id, size_t max,
1790 IdToMirrorImageGlobalStatus *images) {
1791 CephContext *cct = reinterpret_cast<CephContext *>(io_ctx.cct());
1792 int r;
1793
1794 map<string, string> id_to_name;
1795 {
1796 map<string, string> name_to_id;
1797 r = Image<I>::list_images_v2(io_ctx, &name_to_id);
1798 if (r < 0) {
1799 return r;
1800 }
1801 for (auto it : name_to_id) {
1802 id_to_name[it.second] = it.first;
1803 }
1804 }
1805
1806 map<std::string, cls::rbd::MirrorImage> images_;
1807 map<std::string, cls::rbd::MirrorImageStatus> statuses_;
1808
1809 r = librbd::cls_client::mirror_image_status_list(&io_ctx, start_id, max,
1810 &images_, &statuses_);
1811 if (r < 0 && r != -ENOENT) {
1812 lderr(cct) << "failed to list mirror image statuses: "
1813 << cpp_strerror(r) << dendl;
1814 return r;
1815 }
1816
1817 const std::string STATUS_NOT_FOUND("status not found");
1818 for (auto it = images_.begin(); it != images_.end(); ++it) {
1819 auto &image_id = it->first;
1820 auto &info = it->second;
1821 if (info.state == cls::rbd::MIRROR_IMAGE_STATE_DISABLED) {
1822 continue;
1823 }
1824
1825 auto &image_name = id_to_name[image_id];
1826 if (image_name.empty()) {
1827 lderr(cct) << "failed to find image name for image " << image_id << ", "
1828 << "using image id as name" << dendl;
1829 image_name = image_id;
1830 }
1831
1832 mirror_image_global_status_t& global_status = (*images)[image_id];
1833 global_status.name = image_name;
1834 global_status.info = mirror_image_info_t{
1835 info.global_image_id,
1836 static_cast<mirror_image_state_t>(info.state),
1837 false}; // XXX: To set "primary" right would require an additional call.
1838
1839 auto s_it = statuses_.find(image_id);
1840 if (s_it != statuses_.end()) {
1841 auto& status = s_it->second;
1842
1843 global_status.site_statuses.reserve(
1844 status.mirror_image_site_statuses.size());
1845 for (auto& site_status : status.mirror_image_site_statuses) {
1846 global_status.site_statuses.push_back(mirror_image_site_status_t{
1847 site_status.mirror_uuid,
1848 static_cast<mirror_image_status_state_t>(site_status.state),
1849 site_status.state == cls::rbd::MIRROR_IMAGE_STATUS_STATE_UNKNOWN ?
1850 STATUS_NOT_FOUND : site_status.description,
1851 site_status.last_update.sec(), site_status.up});
1852 }
1853 } else {
1854 // older OSD that only returns local status
1855 global_status.site_statuses.push_back(mirror_image_site_status_t{
1856 cls::rbd::MirrorImageSiteStatus::LOCAL_MIRROR_UUID,
1857 MIRROR_IMAGE_STATUS_STATE_UNKNOWN, STATUS_NOT_FOUND, 0, false});
1858 }
1859 }
1860
1861 return 0;
1862 }
1863
1864 template <typename I>
1865 int Mirror<I>::image_status_summary(librados::IoCtx& io_ctx,
1866 MirrorImageStatusStates *states) {
1867 CephContext *cct = reinterpret_cast<CephContext *>(io_ctx.cct());
1868
1869 std::vector<cls::rbd::MirrorPeer> mirror_peers;
1870 int r = cls_client::mirror_peer_list(&io_ctx, &mirror_peers);
1871 if (r < 0 && r != -ENOENT) {
1872 lderr(cct) << "failed to list mirror peers: " << cpp_strerror(r) << dendl;
1873 return r;
1874 }
1875
1876 std::map<cls::rbd::MirrorImageStatusState, int> states_;
1877 r = cls_client::mirror_image_status_get_summary(&io_ctx, mirror_peers,
1878 &states_);
1879 if (r < 0 && r != -ENOENT) {
1880 lderr(cct) << "failed to get mirror status summary: "
1881 << cpp_strerror(r) << dendl;
1882 return r;
1883 }
1884 for (auto &s : states_) {
1885 (*states)[static_cast<mirror_image_status_state_t>(s.first)] = s.second;
1886 }
1887 return 0;
1888 }
1889
1890 template <typename I>
1891 int Mirror<I>::image_instance_id_list(
1892 librados::IoCtx& io_ctx, const std::string &start_image_id, size_t max,
1893 std::map<std::string, std::string> *instance_ids) {
1894 CephContext *cct = reinterpret_cast<CephContext *>(io_ctx.cct());
1895 std::map<std::string, entity_inst_t> instances;
1896
1897 int r = librbd::cls_client::mirror_image_instance_list(
1898 &io_ctx, start_image_id, max, &instances);
1899 if (r < 0 && r != -ENOENT) {
1900 lderr(cct) << "failed to list mirror image instances: " << cpp_strerror(r)
1901 << dendl;
1902 return r;
1903 }
1904
1905 for (auto it : instances) {
1906 (*instance_ids)[it.first] = stringify(it.second.name.num());
1907 }
1908
1909 return 0;
1910 }
1911
1912 template <typename I>
1913 int Mirror<I>::image_info_list(
1914 librados::IoCtx& io_ctx, mirror_image_mode_t *mode_filter,
1915 const std::string &start_id, size_t max,
1916 std::map<std::string, std::pair<mirror_image_mode_t,
1917 mirror_image_info_t>> *entries) {
1918 CephContext *cct = reinterpret_cast<CephContext *>(io_ctx.cct());
1919 ldout(cct, 20) << "pool=" << io_ctx.get_pool_name() << ", mode_filter="
1920 << (mode_filter ? stringify(*mode_filter) : "null")
1921 << ", start_id=" << start_id << ", max=" << max << dendl;
1922
1923 std::string last_read = start_id;
1924 entries->clear();
1925
1926 while (entries->size() < max) {
1927 map<std::string, cls::rbd::MirrorImage> images;
1928 map<std::string, cls::rbd::MirrorImageStatus> statuses;
1929
1930 int r = librbd::cls_client::mirror_image_status_list(&io_ctx, last_read,
1931 max, &images,
1932 &statuses);
1933 if (r < 0 && r != -ENOENT) {
1934 lderr(cct) << "failed to list mirror image statuses: "
1935 << cpp_strerror(r) << dendl;
1936 return r;
1937 }
1938
1939 if (images.empty()) {
1940 break;
1941 }
1942
1943 ThreadPool *thread_pool;
1944 ContextWQ *op_work_queue;
1945 ImageCtx::get_thread_pool_instance(cct, &thread_pool, &op_work_queue);
1946
1947 for (auto &it : images) {
1948 auto &image_id = it.first;
1949 auto &image = it.second;
1950 auto mode = static_cast<mirror_image_mode_t>(image.mode);
1951
1952 if ((mode_filter && mode != *mode_filter) ||
1953 image.state != cls::rbd::MIRROR_IMAGE_STATE_ENABLED) {
1954 continue;
1955 }
1956
1957 // need to call get_info for every image to retrieve promotion state
1958
1959 mirror_image_info_t info;
1960 r = image_get_info(io_ctx, op_work_queue, image_id, &info);
1961 if (r >= 0) {
1962 (*entries)[image_id] = std::make_pair(mode, info);
1963 }
1964 }
1965
1966 last_read = images.rbegin()->first;
1967 }
1968
1969 return 0;
1970 }
1971
1972 template <typename I>
1973 int Mirror<I>::image_snapshot_create(I *ictx, uint64_t *snap_id) {
1974 CephContext *cct = ictx->cct;
1975 ldout(cct, 20) << "ictx=" << ictx << dendl;
1976
1977 int r = ictx->state->refresh_if_required();
1978 if (r < 0) {
1979 return r;
1980 }
1981
1982 cls::rbd::MirrorImage mirror_image;
1983 r = cls_client::mirror_image_get(&ictx->md_ctx, ictx->id,
1984 &mirror_image);
1985 if (r == -ENOENT) {
1986 return -EINVAL;
1987 } else if (r < 0) {
1988 lderr(cct) << "failed to retrieve mirror image" << dendl;
1989 return r;
1990 }
1991
1992 if (mirror_image.mode != cls::rbd::MIRROR_IMAGE_MODE_SNAPSHOT ||
1993 mirror_image.state != cls::rbd::MIRROR_IMAGE_STATE_ENABLED) {
1994 lderr(cct) << "snapshot based mirroring is not enabled" << dendl;
1995 return -EINVAL;
1996 }
1997
1998 C_SaferCond on_finish;
1999 auto req = mirror::snapshot::CreatePrimaryRequest<I>::create(
2000 ictx, mirror_image.global_image_id, CEPH_NOSNAP, 0U, snap_id, &on_finish);
2001 req->send();
2002 return on_finish.wait();
2003 }
2004
2005 } // namespace api
2006 } // namespace librbd
2007
2008 template class librbd::api::Mirror<librbd::ImageCtx>;