]> git.proxmox.com Git - ceph.git/blame - ceph/src/tools/rbd_mirror/image_replayer/BootstrapRequest.cc
add subtree-ish sources for 12.0.3
[ceph.git] / ceph / src / tools / rbd_mirror / image_replayer / BootstrapRequest.cc
CommitLineData
7c673cae
FG
1// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2// vim: ts=8 sw=2 smarttab
3
4#include "include/compat.h"
5#include "BootstrapRequest.h"
6#include "CloseImageRequest.h"
7#include "CreateImageRequest.h"
8#include "IsPrimaryRequest.h"
9#include "OpenImageRequest.h"
10#include "OpenLocalImageRequest.h"
11#include "common/debug.h"
12#include "common/dout.h"
13#include "common/errno.h"
14#include "common/WorkQueue.h"
15#include "cls/rbd/cls_rbd_client.h"
16#include "journal/Journaler.h"
17#include "librbd/ImageCtx.h"
18#include "librbd/ImageState.h"
19#include "librbd/internal.h"
20#include "librbd/Journal.h"
21#include "librbd/Utils.h"
22#include "librbd/journal/Types.h"
23#include "tools/rbd_mirror/ProgressContext.h"
24#include "tools/rbd_mirror/ImageSyncThrottler.h"
25
26#define dout_context g_ceph_context
27#define dout_subsys ceph_subsys_rbd_mirror
28#undef dout_prefix
29#define dout_prefix *_dout << "rbd::mirror::image_replayer::BootstrapRequest: " \
30 << this << " " << __func__
31
32namespace rbd {
33namespace mirror {
34namespace image_replayer {
35
36using librbd::util::create_context_callback;
37using librbd::util::create_rados_callback;
38using librbd::util::unique_lock_name;
39
40template <typename I>
41BootstrapRequest<I>::BootstrapRequest(
42 librados::IoCtx &local_io_ctx,
43 librados::IoCtx &remote_io_ctx,
44 std::shared_ptr<ImageSyncThrottler<I>> image_sync_throttler,
45 I **local_image_ctx,
46 const std::string &local_image_id,
47 const std::string &remote_image_id,
48 const std::string &global_image_id,
49 ContextWQ *work_queue, SafeTimer *timer,
50 Mutex *timer_lock,
51 const std::string &local_mirror_uuid,
52 const std::string &remote_mirror_uuid,
53 Journaler *journaler,
54 MirrorPeerClientMeta *client_meta,
55 Context *on_finish,
56 bool *do_resync,
57 rbd::mirror::ProgressContext *progress_ctx)
58 : BaseRequest("rbd::mirror::image_replayer::BootstrapRequest",
59 reinterpret_cast<CephContext*>(local_io_ctx.cct()), on_finish),
60 m_local_io_ctx(local_io_ctx), m_remote_io_ctx(remote_io_ctx),
61 m_image_sync_throttler(image_sync_throttler),
62 m_local_image_ctx(local_image_ctx), m_local_image_id(local_image_id),
63 m_remote_image_id(remote_image_id), m_global_image_id(global_image_id),
64 m_work_queue(work_queue), m_timer(timer), m_timer_lock(timer_lock),
65 m_local_mirror_uuid(local_mirror_uuid),
66 m_remote_mirror_uuid(remote_mirror_uuid), m_journaler(journaler),
67 m_client_meta(client_meta), m_progress_ctx(progress_ctx),
68 m_do_resync(do_resync),
69 m_lock(unique_lock_name("BootstrapRequest::m_lock", this)) {
70}
71
72template <typename I>
73BootstrapRequest<I>::~BootstrapRequest() {
74 assert(m_remote_image_ctx == nullptr);
75}
76
77template <typename I>
78void BootstrapRequest<I>::send() {
79 *m_do_resync = false;
80
81 get_remote_tag_class();
82}
83
84template <typename I>
85void BootstrapRequest<I>::cancel() {
86 dout(20) << dendl;
87
88 Mutex::Locker locker(m_lock);
89 m_canceled = true;
90
91 m_image_sync_throttler->cancel_sync(m_local_io_ctx, m_local_image_id);
92}
93
94template <typename I>
95void BootstrapRequest<I>::get_remote_tag_class() {
96 dout(20) << dendl;
97
98 update_progress("GET_REMOTE_TAG_CLASS");
99
100 Context *ctx = create_context_callback<
101 BootstrapRequest<I>, &BootstrapRequest<I>::handle_get_remote_tag_class>(
102 this);
103 m_journaler->get_client(librbd::Journal<>::IMAGE_CLIENT_ID, &m_client, ctx);
104}
105
106template <typename I>
107void BootstrapRequest<I>::handle_get_remote_tag_class(int r) {
108 dout(20) << ": r=" << r << dendl;
109
110 if (r < 0) {
111 derr << ": failed to retrieve remote client: " << cpp_strerror(r) << dendl;
112 finish(r);
113 return;
114 }
115
116 librbd::journal::ClientData client_data;
117 bufferlist::iterator it = m_client.data.begin();
118 try {
119 ::decode(client_data, it);
120 } catch (const buffer::error &err) {
121 derr << ": failed to decode remote client meta data: " << err.what()
122 << dendl;
123 finish(-EBADMSG);
124 return;
125 }
126
127 librbd::journal::ImageClientMeta *client_meta =
128 boost::get<librbd::journal::ImageClientMeta>(&client_data.client_meta);
129 if (client_meta == nullptr) {
130 derr << ": unknown remote client registration" << dendl;
131 finish(-EINVAL);
132 return;
133 }
134
135 m_remote_tag_class = client_meta->tag_class;
136 dout(10) << ": remote tag class=" << m_remote_tag_class << dendl;
137
138 get_client();
139}
140
141template <typename I>
142void BootstrapRequest<I>::get_client() {
143 dout(20) << dendl;
144
145 update_progress("GET_CLIENT");
146
147 Context *ctx = create_context_callback<
148 BootstrapRequest<I>, &BootstrapRequest<I>::handle_get_client>(
149 this);
150 m_journaler->get_client(m_local_mirror_uuid, &m_client, ctx);
151}
152
153template <typename I>
154void BootstrapRequest<I>::handle_get_client(int r) {
155 dout(20) << ": r=" << r << dendl;
156
157 if (r == -ENOENT) {
158 dout(10) << ": client not registered" << dendl;
159 } else if (r < 0) {
160 derr << ": failed to retrieve client: " << cpp_strerror(r) << dendl;
161 finish(r);
162 return;
163 } else if (decode_client_meta()) {
164 // skip registration if it already exists
165 open_remote_image();
166 return;
167 }
168
169 register_client();
170}
171
172template <typename I>
173void BootstrapRequest<I>::register_client() {
174 dout(20) << dendl;
175
176 update_progress("REGISTER_CLIENT");
177
178 // record an place-holder record
179 librbd::journal::ClientData client_data{
180 librbd::journal::MirrorPeerClientMeta{m_local_image_id}};
181 bufferlist client_data_bl;
182 ::encode(client_data, client_data_bl);
183
184 Context *ctx = create_context_callback<
185 BootstrapRequest<I>, &BootstrapRequest<I>::handle_register_client>(
186 this);
187 m_journaler->register_client(client_data_bl, ctx);
188}
189
190template <typename I>
191void BootstrapRequest<I>::handle_register_client(int r) {
192 dout(20) << ": r=" << r << dendl;
193
194 if (r < 0) {
195 derr << ": failed to register with remote journal: " << cpp_strerror(r)
196 << dendl;
197 finish(r);
198 return;
199 }
200
201 *m_client_meta = librbd::journal::MirrorPeerClientMeta(m_local_image_id);
202 open_remote_image();
203}
204
205template <typename I>
206void BootstrapRequest<I>::open_remote_image() {
207 dout(20) << dendl;
208
209 update_progress("OPEN_REMOTE_IMAGE");
210
211 Context *ctx = create_context_callback<
212 BootstrapRequest<I>, &BootstrapRequest<I>::handle_open_remote_image>(
213 this);
214 OpenImageRequest<I> *request = OpenImageRequest<I>::create(
215 m_remote_io_ctx, &m_remote_image_ctx, m_remote_image_id, false,
216 ctx);
217 request->send();
218}
219
220template <typename I>
221void BootstrapRequest<I>::handle_open_remote_image(int r) {
222 dout(20) << ": r=" << r << dendl;
223
224 if (r < 0) {
225 derr << ": failed to open remote image: " << cpp_strerror(r) << dendl;
226 assert(m_remote_image_ctx == nullptr);
227 finish(r);
228 return;
229 }
230
231 is_primary();
232}
233
234template <typename I>
235void BootstrapRequest<I>::is_primary() {
236 dout(20) << dendl;
237
238 update_progress("OPEN_REMOTE_IMAGE");
239
240 Context *ctx = create_context_callback<
241 BootstrapRequest<I>, &BootstrapRequest<I>::handle_is_primary>(
242 this);
243 IsPrimaryRequest<I> *request = IsPrimaryRequest<I>::create(m_remote_image_ctx,
244 &m_primary, ctx);
245 request->send();
246}
247
248template <typename I>
249void BootstrapRequest<I>::handle_is_primary(int r) {
250 dout(20) << ": r=" << r << dendl;
251
252 if (r < 0) {
253 derr << ": error querying remote image primary status: " << cpp_strerror(r)
254 << dendl;
255 m_ret_val = r;
256 close_remote_image();
257 return;
258 }
259
260 if (!m_primary) {
261 dout(5) << ": remote image is not primary -- skipping image replay"
262 << dendl;
263 m_ret_val = -EREMOTEIO;
264 update_client_state();
265 return;
266 }
267
268 if (m_local_image_id.empty()) {
269 create_local_image();
270 return;
271 }
272
273 open_local_image();
274}
275
276template <typename I>
277void BootstrapRequest<I>::update_client_state() {
278 if (m_client_meta->state == librbd::journal::MIRROR_PEER_STATE_REPLAYING) {
279 // state already set for replaying upon failover
280 close_remote_image();
281 return;
282 }
283
284 dout(20) << dendl;
285 update_progress("UPDATE_CLIENT_STATE");
286
287 librbd::journal::MirrorPeerClientMeta client_meta(*m_client_meta);
288 client_meta.state = librbd::journal::MIRROR_PEER_STATE_REPLAYING;
289
290 librbd::journal::ClientData client_data(client_meta);
291 bufferlist data_bl;
292 ::encode(client_data, data_bl);
293
294 Context *ctx = create_context_callback<
295 BootstrapRequest<I>, &BootstrapRequest<I>::handle_update_client_state>(
296 this);
297 m_journaler->update_client(data_bl, ctx);
298}
299
300template <typename I>
301void BootstrapRequest<I>::handle_update_client_state(int r) {
302 dout(20) << ": r=" << r << dendl;
303 if (r < 0) {
304 derr << ": failed to update client: " << cpp_strerror(r) << dendl;
305 } else {
306 m_client_meta->state = librbd::journal::MIRROR_PEER_STATE_REPLAYING;;
307 }
308
309 close_remote_image();
310}
311
312template <typename I>
313void BootstrapRequest<I>::open_local_image() {
314 dout(20) << dendl;
315
316 update_progress("OPEN_LOCAL_IMAGE");
317
318 Context *ctx = create_context_callback<
319 BootstrapRequest<I>, &BootstrapRequest<I>::handle_open_local_image>(
320 this);
321 OpenLocalImageRequest<I> *request = OpenLocalImageRequest<I>::create(
322 m_local_io_ctx, m_local_image_ctx, m_local_image_id, m_work_queue,
323 ctx);
324 request->send();
325}
326
327template <typename I>
328void BootstrapRequest<I>::handle_open_local_image(int r) {
329 dout(20) << ": r=" << r << dendl;
330
331 if (r == -ENOENT) {
332 assert(*m_local_image_ctx == nullptr);
333 dout(10) << ": local image missing" << dendl;
334 create_local_image();
335 return;
336 } else if (r == -EREMOTEIO) {
337 assert(*m_local_image_ctx == nullptr);
338 dout(10) << "local image is primary -- skipping image replay" << dendl;
339 m_ret_val = r;
340 close_remote_image();
341 return;
342 } else if (r < 0) {
343 assert(*m_local_image_ctx == nullptr);
344 derr << ": failed to open local image: " << cpp_strerror(r) << dendl;
345 m_ret_val = r;
346 close_remote_image();
347 return;
348 }
349
350 I *local_image_ctx = (*m_local_image_ctx);
351 {
352 RWLock::RLocker snap_locker(local_image_ctx->snap_lock);
353 if (local_image_ctx->journal == nullptr) {
354 derr << ": local image does not support journaling" << dendl;
355 m_ret_val = -EINVAL;
356 close_local_image();
357 return;
358 }
359
360 r = (*m_local_image_ctx)->journal->is_resync_requested(m_do_resync);
361 if (r < 0) {
362 derr << ": failed to check if a resync was requested" << dendl;
363 m_ret_val = r;
364 close_local_image();
365 return;
366 }
367 }
368
369 if (*m_do_resync) {
370 close_remote_image();
371 return;
372 }
373
374 if (m_client.state == cls::journal::CLIENT_STATE_DISCONNECTED) {
375 dout(10) << ": client flagged disconnected -- skipping bootstrap" << dendl;
376 // The caller is expected to detect disconnect initializing remote journal.
377 m_ret_val = 0;
378 close_remote_image();
379 return;
380 }
381
382 update_client_image();
383}
384
385template <typename I>
386void BootstrapRequest<I>::create_local_image() {
387 dout(20) << dendl;
388
389 m_local_image_id = "";
390 update_progress("CREATE_LOCAL_IMAGE");
391
392 m_remote_image_ctx->snap_lock.get_read();
393 std::string image_name = m_remote_image_ctx->name;
394 m_remote_image_ctx->snap_lock.put_read();
395
396 Context *ctx = create_context_callback<
397 BootstrapRequest<I>, &BootstrapRequest<I>::handle_create_local_image>(
398 this);
399 CreateImageRequest<I> *request = CreateImageRequest<I>::create(
400 m_local_io_ctx, m_work_queue, m_global_image_id, m_remote_mirror_uuid,
401 image_name, m_remote_image_ctx, &m_local_image_id, ctx);
402 request->send();
403}
404
405template <typename I>
406void BootstrapRequest<I>::handle_create_local_image(int r) {
407 dout(20) << ": r=" << r << dendl;
408
409 if (r < 0) {
410 derr << ": failed to create local image: " << cpp_strerror(r) << dendl;
411 m_ret_val = r;
412 close_remote_image();
413 return;
414 }
415
416 open_local_image();
417}
418
419template <typename I>
420void BootstrapRequest<I>::update_client_image() {
421 dout(20) << dendl;
422
423 update_progress("UPDATE_CLIENT_IMAGE");
424
425 if (m_client_meta->image_id == (*m_local_image_ctx)->id) {
426 // already registered local image with remote journal
427 get_remote_tags();
428 return;
429 }
430 m_local_image_id = (*m_local_image_ctx)->id;
431
432 dout(20) << dendl;
433
434 librbd::journal::MirrorPeerClientMeta client_meta{m_local_image_id};
435 client_meta.state = librbd::journal::MIRROR_PEER_STATE_SYNCING;
436
437 librbd::journal::ClientData client_data(client_meta);
438 bufferlist data_bl;
439 ::encode(client_data, data_bl);
440
441 Context *ctx = create_context_callback<
442 BootstrapRequest<I>, &BootstrapRequest<I>::handle_update_client_image>(
443 this);
444 m_journaler->update_client(data_bl, ctx);
445}
446
447template <typename I>
448void BootstrapRequest<I>::handle_update_client_image(int r) {
449 dout(20) << ": r=" << r << dendl;
450
451 if (r < 0) {
452 derr << ": failed to update client: " << cpp_strerror(r) << dendl;
453 m_ret_val = r;
454 close_local_image();
455 return;
456 }
457
458 if (m_canceled) {
459 dout(10) << ": request canceled" << dendl;
460 m_ret_val = -ECANCELED;
461 close_local_image();
462 return;
463 }
464
465 *m_client_meta = {m_local_image_id};
466 m_client_meta->state = librbd::journal::MIRROR_PEER_STATE_SYNCING;
467 get_remote_tags();
468}
469
470template <typename I>
471void BootstrapRequest<I>::get_remote_tags() {
472 dout(20) << dendl;
473
474 update_progress("GET_REMOTE_TAGS");
475
476 if (m_client_meta->state == librbd::journal::MIRROR_PEER_STATE_SYNCING) {
477 // optimization -- no need to compare remote tags if we just created
478 // the image locally or sync was interrupted
479 image_sync();
480 return;
481 }
482
483 dout(20) << dendl;
484
485 Context *ctx = create_context_callback<
486 BootstrapRequest<I>, &BootstrapRequest<I>::handle_get_remote_tags>(this);
487 m_journaler->get_tags(m_remote_tag_class, &m_remote_tags, ctx);
488}
489
490template <typename I>
491void BootstrapRequest<I>::handle_get_remote_tags(int r) {
492 dout(20) << ": r=" << r << dendl;
493
494 if (r < 0) {
495 derr << ": failed to retrieve remote tags: " << cpp_strerror(r) << dendl;
496 m_ret_val = r;
497 close_local_image();
498 return;
499 }
500
501 if (m_canceled) {
502 dout(10) << ": request canceled" << dendl;
503 m_ret_val = -ECANCELED;
504 close_local_image();
505 return;
506 }
507
508 // At this point, the local image was existing, non-primary, and replaying;
509 // and the remote image is primary. Attempt to link the local image's most
510 // recent tag to the remote image's tag chain.
511 uint64_t local_tag_tid;
512 librbd::journal::TagData local_tag_data;
513 I *local_image_ctx = (*m_local_image_ctx);
514 {
515 RWLock::RLocker snap_locker(local_image_ctx->snap_lock);
516 if (local_image_ctx->journal == nullptr) {
517 derr << ": local image does not support journaling" << dendl;
518 m_ret_val = -EINVAL;
519 close_local_image();
520 return;
521 }
522
523 local_tag_tid = local_image_ctx->journal->get_tag_tid();
524 local_tag_data = local_image_ctx->journal->get_tag_data();
525 dout(20) << ": local tag " << local_tag_tid << ": "
526 << local_tag_data << dendl;
527 }
528
529 bool remote_tag_data_valid = false;
530 librbd::journal::TagData remote_tag_data;
531 boost::optional<uint64_t> remote_orphan_tag_tid =
532 boost::make_optional<uint64_t>(false, 0U);
533 bool reconnect_orphan = false;
534
535 // decode the remote tags
536 for (auto &remote_tag : m_remote_tags) {
537 if (local_tag_data.predecessor.commit_valid &&
538 local_tag_data.predecessor.mirror_uuid == m_remote_mirror_uuid &&
539 local_tag_data.predecessor.tag_tid > remote_tag.tid) {
540 dout(20) << ": skipping processed predecessor remote tag "
541 << remote_tag.tid << dendl;
542 continue;
543 }
544
545 try {
546 bufferlist::iterator it = remote_tag.data.begin();
547 ::decode(remote_tag_data, it);
548 remote_tag_data_valid = true;
549 } catch (const buffer::error &err) {
550 derr << ": failed to decode remote tag " << remote_tag.tid << ": "
551 << err.what() << dendl;
552 m_ret_val = -EBADMSG;
553 close_local_image();
554 return;
555 }
556
557 dout(10) << ": decoded remote tag " << remote_tag.tid << ": "
558 << remote_tag_data << dendl;
559
560 if (!local_tag_data.predecessor.commit_valid) {
561 // newly synced local image (no predecessor) replays from the first tag
562 if (remote_tag_data.mirror_uuid != librbd::Journal<>::LOCAL_MIRROR_UUID) {
563 dout(20) << ": skipping non-primary remote tag" << dendl;
564 continue;
565 }
566
567 dout(20) << ": using initial primary remote tag" << dendl;
568 break;
569 }
570
571 if (local_tag_data.mirror_uuid == librbd::Journal<>::ORPHAN_MIRROR_UUID) {
572 // demotion last available local epoch
573
574 if (remote_tag_data.mirror_uuid == local_tag_data.mirror_uuid &&
575 remote_tag_data.predecessor.commit_valid &&
576 remote_tag_data.predecessor.tag_tid ==
577 local_tag_data.predecessor.tag_tid) {
578 // demotion matches remote epoch
579
580 if (remote_tag_data.predecessor.mirror_uuid == m_local_mirror_uuid &&
581 local_tag_data.predecessor.mirror_uuid ==
582 librbd::Journal<>::LOCAL_MIRROR_UUID) {
583 // local demoted and remote has matching event
584 dout(20) << ": found matching local demotion tag" << dendl;
585 remote_orphan_tag_tid = remote_tag.tid;
586 continue;
587 }
588
589 if (local_tag_data.predecessor.mirror_uuid == m_remote_mirror_uuid &&
590 remote_tag_data.predecessor.mirror_uuid ==
591 librbd::Journal<>::LOCAL_MIRROR_UUID) {
592 // remote demoted and local has matching event
593 dout(20) << ": found matching remote demotion tag" << dendl;
594 remote_orphan_tag_tid = remote_tag.tid;
595 continue;
596 }
597 }
598
599 if (remote_tag_data.mirror_uuid == librbd::Journal<>::LOCAL_MIRROR_UUID &&
600 remote_tag_data.predecessor.mirror_uuid == librbd::Journal<>::ORPHAN_MIRROR_UUID &&
601 remote_tag_data.predecessor.commit_valid && remote_orphan_tag_tid &&
602 remote_tag_data.predecessor.tag_tid == *remote_orphan_tag_tid) {
603 // remote promotion tag chained to remote/local demotion tag
604 dout(20) << ": found chained remote promotion tag" << dendl;
605 reconnect_orphan = true;
606 break;
607 }
608
609 // promotion must follow demotion
610 remote_orphan_tag_tid = boost::none;
611 }
612 }
613
614 if (remote_tag_data_valid &&
615 local_tag_data.mirror_uuid == m_remote_mirror_uuid) {
616 dout(20) << ": local image is in clean replay state" << dendl;
617 } else if (reconnect_orphan) {
618 dout(20) << ": remote image was demoted/promoted" << dendl;
619 } else {
620 derr << ": split-brain detected -- skipping image replay" << dendl;
621 m_ret_val = -EEXIST;
622 close_local_image();
623 return;
624 }
625
626 image_sync();
627}
628
629template <typename I>
630void BootstrapRequest<I>::image_sync() {
631 if (m_client_meta->state == librbd::journal::MIRROR_PEER_STATE_REPLAYING) {
632 // clean replay state -- no image sync required
633 close_remote_image();
634 return;
635 }
636
637 dout(20) << dendl;
638 update_progress("IMAGE_SYNC");
639
640 Context *ctx = create_context_callback<
641 BootstrapRequest<I>, &BootstrapRequest<I>::handle_image_sync>(
642 this);
643
644 {
645 Mutex::Locker locker(m_lock);
646 if (!m_canceled) {
647 m_image_sync_throttler->start_sync(*m_local_image_ctx,
648 m_remote_image_ctx, m_timer,
649 m_timer_lock,
650 m_local_mirror_uuid, m_journaler,
651 m_client_meta, m_work_queue, ctx,
652 m_progress_ctx);
653 return;
654 }
655 }
656
657 dout(10) << ": request canceled" << dendl;
658 m_ret_val = -ECANCELED;
659 close_remote_image();
660}
661
662template <typename I>
663void BootstrapRequest<I>::handle_image_sync(int r) {
664 dout(20) << ": r=" << r << dendl;
665
666 if (m_canceled) {
667 dout(10) << ": request canceled" << dendl;
668 m_ret_val = -ECANCELED;
669 }
670
671 if (r < 0) {
672 derr << ": failed to sync remote image: " << cpp_strerror(r) << dendl;
673 m_ret_val = r;
674 }
675
676 close_remote_image();
677}
678
679template <typename I>
680void BootstrapRequest<I>::close_local_image() {
681 dout(20) << dendl;
682
683 update_progress("CLOSE_LOCAL_IMAGE");
684
685 Context *ctx = create_context_callback<
686 BootstrapRequest<I>, &BootstrapRequest<I>::handle_close_local_image>(
687 this);
688 CloseImageRequest<I> *request = CloseImageRequest<I>::create(
689 m_local_image_ctx, ctx);
690 request->send();
691}
692
693template <typename I>
694void BootstrapRequest<I>::handle_close_local_image(int r) {
695 dout(20) << ": r=" << r << dendl;
696
697 if (r < 0) {
698 derr << ": error encountered closing local image: " << cpp_strerror(r)
699 << dendl;
700 }
701
702 close_remote_image();
703}
704
705template <typename I>
706void BootstrapRequest<I>::close_remote_image() {
707 dout(20) << dendl;
708
709 update_progress("CLOSE_REMOTE_IMAGE");
710
711 Context *ctx = create_context_callback<
712 BootstrapRequest<I>, &BootstrapRequest<I>::handle_close_remote_image>(
713 this);
714 CloseImageRequest<I> *request = CloseImageRequest<I>::create(
715 &m_remote_image_ctx, ctx);
716 request->send();
717}
718
719template <typename I>
720void BootstrapRequest<I>::handle_close_remote_image(int r) {
721 dout(20) << ": r=" << r << dendl;
722
723 if (r < 0) {
724 derr << ": error encountered closing remote image: " << cpp_strerror(r)
725 << dendl;
726 }
727
728 finish(m_ret_val);
729}
730
731template <typename I>
732bool BootstrapRequest<I>::decode_client_meta() {
733 dout(20) << dendl;
734
735 librbd::journal::ClientData client_data;
736 bufferlist::iterator it = m_client.data.begin();
737 try {
738 ::decode(client_data, it);
739 } catch (const buffer::error &err) {
740 derr << ": failed to decode client meta data: " << err.what() << dendl;
741 return false;
742 }
743
744 librbd::journal::MirrorPeerClientMeta *client_meta =
745 boost::get<librbd::journal::MirrorPeerClientMeta>(&client_data.client_meta);
746 if (client_meta == nullptr) {
747 derr << ": unknown peer registration" << dendl;
748 return false;
749 } else if (!client_meta->image_id.empty()) {
750 // have an image id -- use that to open the image
751 m_local_image_id = client_meta->image_id;
752 }
753
754 *m_client_meta = *client_meta;
755
756 dout(20) << ": client found: image_id=" << m_local_image_id
757 << ", client_meta=" << *m_client_meta << dendl;
758 return true;
759}
760
761template <typename I>
762void BootstrapRequest<I>::update_progress(const std::string &description) {
763 dout(20) << ": " << description << dendl;
764
765 if (m_progress_ctx) {
766 m_progress_ctx->update_progress(description);
767 }
768}
769
770} // namespace image_replayer
771} // namespace mirror
772} // namespace rbd
773
774template class rbd::mirror::image_replayer::BootstrapRequest<librbd::ImageCtx>;