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