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