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