1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 #include "include/compat.h"
5 #include "BootstrapRequest.h"
6 #include "CreateImageRequest.h"
7 #include "OpenImageRequest.h"
8 #include "OpenLocalImageRequest.h"
9 #include "common/debug.h"
10 #include "common/dout.h"
11 #include "common/errno.h"
12 #include "cls/rbd/cls_rbd_client.h"
13 #include "journal/Journaler.h"
14 #include "journal/Settings.h"
15 #include "librbd/ImageCtx.h"
16 #include "librbd/ImageState.h"
17 #include "librbd/internal.h"
18 #include "librbd/Journal.h"
19 #include "librbd/Utils.h"
20 #include "librbd/asio/ContextWQ.h"
21 #include "librbd/journal/Types.h"
22 #include "tools/rbd_mirror/BaseRequest.h"
23 #include "tools/rbd_mirror/ImageSync.h"
24 #include "tools/rbd_mirror/ProgressContext.h"
25 #include "tools/rbd_mirror/Threads.h"
26 #include "tools/rbd_mirror/image_replayer/PrepareLocalImageRequest.h"
27 #include "tools/rbd_mirror/image_replayer/PrepareRemoteImageRequest.h"
28 #include "tools/rbd_mirror/image_replayer/journal/StateBuilder.h"
29 #include "tools/rbd_mirror/image_replayer/journal/SyncPointHandler.h"
31 #define dout_context g_ceph_context
32 #define dout_subsys ceph_subsys_rbd_mirror
34 #define dout_prefix *_dout << "rbd::mirror::image_replayer::" \
35 << "BootstrapRequest: " << this << " " \
40 namespace image_replayer
{
42 using librbd::util::create_context_callback
;
43 using librbd::util::unique_lock_name
;
46 BootstrapRequest
<I
>::BootstrapRequest(
48 librados::IoCtx
& local_io_ctx
,
49 librados::IoCtx
& remote_io_ctx
,
50 InstanceWatcher
<I
>* instance_watcher
,
51 const std::string
& global_image_id
,
52 const std::string
& local_mirror_uuid
,
53 const RemotePoolMeta
& remote_pool_meta
,
54 ::journal::CacheManagerHandler
* cache_manager_handler
,
55 PoolMetaCache
* pool_meta_cache
,
56 ProgressContext
* progress_ctx
,
57 StateBuilder
<I
>** state_builder
,
60 : CancelableRequest("rbd::mirror::image_replayer::BootstrapRequest",
61 reinterpret_cast<CephContext
*>(local_io_ctx
.cct()),
64 m_local_io_ctx(local_io_ctx
),
65 m_remote_io_ctx(remote_io_ctx
),
66 m_instance_watcher(instance_watcher
),
67 m_global_image_id(global_image_id
),
68 m_local_mirror_uuid(local_mirror_uuid
),
69 m_remote_pool_meta(remote_pool_meta
),
70 m_cache_manager_handler(cache_manager_handler
),
71 m_pool_meta_cache(pool_meta_cache
),
72 m_progress_ctx(progress_ctx
),
73 m_state_builder(state_builder
),
74 m_do_resync(do_resync
),
75 m_lock(ceph::make_mutex(unique_lock_name("BootstrapRequest::m_lock",
81 bool BootstrapRequest
<I
>::is_syncing() const {
82 std::lock_guard locker
{m_lock
};
83 return (m_image_sync
!= nullptr);
87 void BootstrapRequest
<I
>::send() {
90 prepare_local_image();
94 void BootstrapRequest
<I
>::cancel() {
97 std::lock_guard locker
{m_lock
};
100 if (m_image_sync
!= nullptr) {
101 m_image_sync
->cancel();
105 template <typename I
>
106 std::string BootstrapRequest
<I
>::get_local_image_name() const {
107 std::unique_lock locker
{m_lock
};
108 return m_local_image_name
;
111 template <typename I
>
112 void BootstrapRequest
<I
>::prepare_local_image() {
114 update_progress("PREPARE_LOCAL_IMAGE");
117 std::unique_lock locker
{m_lock
};
118 m_local_image_name
= m_global_image_id
;
121 ceph_assert(*m_state_builder
== nullptr);
122 auto ctx
= create_context_callback
<
123 BootstrapRequest
, &BootstrapRequest
<I
>::handle_prepare_local_image
>(this);
124 auto req
= image_replayer::PrepareLocalImageRequest
<I
>::create(
125 m_local_io_ctx
, m_global_image_id
, &m_prepare_local_image_name
,
126 m_state_builder
, m_threads
->work_queue
, ctx
);
130 template <typename I
>
131 void BootstrapRequest
<I
>::handle_prepare_local_image(int r
) {
132 dout(10) << "r=" << r
<< dendl
;
134 ceph_assert(r
< 0 || *m_state_builder
!= nullptr);
136 dout(10) << "local image does not exist" << dendl
;
138 derr
<< "error preparing local image for replay: " << cpp_strerror(r
)
144 // image replayer will detect the name change (if any) at next
146 if (r
>= 0 && !m_prepare_local_image_name
.empty()) {
147 std::unique_lock locker
{m_lock
};
148 m_local_image_name
= m_prepare_local_image_name
;
151 prepare_remote_image();
154 template <typename I
>
155 void BootstrapRequest
<I
>::prepare_remote_image() {
157 update_progress("PREPARE_REMOTE_IMAGE");
159 Context
*ctx
= create_context_callback
<
160 BootstrapRequest
, &BootstrapRequest
<I
>::handle_prepare_remote_image
>(this);
161 auto req
= image_replayer::PrepareRemoteImageRequest
<I
>::create(
162 m_threads
, m_local_io_ctx
, m_remote_io_ctx
, m_global_image_id
,
163 m_local_mirror_uuid
, m_remote_pool_meta
, m_cache_manager_handler
,
164 m_state_builder
, ctx
);
168 template <typename I
>
169 void BootstrapRequest
<I
>::handle_prepare_remote_image(int r
) {
170 dout(10) << "r=" << r
<< dendl
;
172 auto state_builder
= *m_state_builder
;
173 ceph_assert(state_builder
== nullptr ||
174 !state_builder
->remote_mirror_uuid
.empty());
176 if (state_builder
!= nullptr && state_builder
->is_local_primary()) {
177 dout(5) << "local image is primary" << dendl
;
180 } else if (r
== -ENOENT
|| state_builder
== nullptr) {
181 dout(10) << "remote image does not exist";
182 if (state_builder
!= nullptr) {
184 << "local_image_id=" << state_builder
->local_image_id
<< ", "
185 << "remote_image_id=" << state_builder
->remote_image_id
<< ", "
186 << "is_linked=" << state_builder
->is_linked();
190 // TODO need to support multiple remote images
191 if (state_builder
!= nullptr &&
192 state_builder
->remote_image_id
.empty() &&
193 (state_builder
->local_image_id
.empty() ||
194 state_builder
->is_linked())) {
195 // both images doesn't exist or local image exists and is non-primary
196 // and linked to the missing remote image
203 derr
<< "error preparing remote image for replay: " << cpp_strerror(r
)
209 if (!state_builder
->is_remote_primary()) {
210 ceph_assert(!state_builder
->remote_image_id
.empty());
211 if (state_builder
->local_image_id
.empty()) {
212 dout(10) << "local image does not exist and remote image is not primary"
216 } else if (!state_builder
->is_linked()) {
217 dout(10) << "local image is unlinked and remote image is not primary"
222 // if the local image is linked to the remote image, we ignore that
223 // the remote image is not primary so that we can replay demotion
229 template <typename I
>
230 void BootstrapRequest
<I
>::open_remote_image() {
231 ceph_assert(*m_state_builder
!= nullptr);
232 auto remote_image_id
= (*m_state_builder
)->remote_image_id
;
233 dout(15) << "remote_image_id=" << remote_image_id
<< dendl
;
235 update_progress("OPEN_REMOTE_IMAGE");
237 auto ctx
= create_context_callback
<
239 &BootstrapRequest
<I
>::handle_open_remote_image
>(this);
240 ceph_assert(*m_state_builder
!= nullptr);
241 OpenImageRequest
<I
> *request
= OpenImageRequest
<I
>::create(
242 m_remote_io_ctx
, &(*m_state_builder
)->remote_image_ctx
, remote_image_id
,
247 template <typename I
>
248 void BootstrapRequest
<I
>::handle_open_remote_image(int r
) {
249 dout(15) << "r=" << r
<< dendl
;
251 ceph_assert(*m_state_builder
!= nullptr);
253 derr
<< "failed to open remote image: " << cpp_strerror(r
) << dendl
;
254 ceph_assert((*m_state_builder
)->remote_image_ctx
== nullptr);
259 if ((*m_state_builder
)->local_image_id
.empty()) {
260 create_local_image();
267 template <typename I
>
268 void BootstrapRequest
<I
>::open_local_image() {
269 ceph_assert(*m_state_builder
!= nullptr);
270 auto local_image_id
= (*m_state_builder
)->local_image_id
;
272 dout(15) << "local_image_id=" << local_image_id
<< dendl
;
274 update_progress("OPEN_LOCAL_IMAGE");
276 Context
*ctx
= create_context_callback
<
277 BootstrapRequest
<I
>, &BootstrapRequest
<I
>::handle_open_local_image
>(
279 OpenLocalImageRequest
<I
> *request
= OpenLocalImageRequest
<I
>::create(
280 m_local_io_ctx
, &(*m_state_builder
)->local_image_ctx
, local_image_id
,
281 m_threads
->work_queue
, ctx
);
285 template <typename I
>
286 void BootstrapRequest
<I
>::handle_open_local_image(int r
) {
287 dout(15) << "r=" << r
<< dendl
;
289 ceph_assert(*m_state_builder
!= nullptr);
290 auto local_image_ctx
= (*m_state_builder
)->local_image_ctx
;
291 ceph_assert((r
>= 0 && local_image_ctx
!= nullptr) ||
292 (r
< 0 && local_image_ctx
== nullptr));
295 dout(10) << "local image missing" << dendl
;
296 create_local_image();
298 } else if (r
== -EREMOTEIO
) {
299 dout(10) << "local image is primary -- skipping image replay" << dendl
;
301 close_remote_image();
304 derr
<< "failed to open local image: " << cpp_strerror(r
) << dendl
;
306 close_remote_image();
313 template <typename I
>
314 void BootstrapRequest
<I
>::prepare_replay() {
316 update_progress("PREPARE_REPLAY");
318 ceph_assert(*m_state_builder
!= nullptr);
319 auto ctx
= create_context_callback
<
320 BootstrapRequest
<I
>, &BootstrapRequest
<I
>::handle_prepare_replay
>(this);
321 auto request
= (*m_state_builder
)->create_prepare_replay_request(
322 m_local_mirror_uuid
, m_progress_ctx
, m_do_resync
, &m_syncing
, ctx
);
326 template <typename I
>
327 void BootstrapRequest
<I
>::handle_prepare_replay(int r
) {
328 dout(10) << "r=" << r
<< dendl
;
331 derr
<< "failed to prepare local replay: " << cpp_strerror(r
) << dendl
;
333 close_remote_image();
335 } else if (*m_do_resync
) {
336 dout(10) << "local image resync requested" << dendl
;
337 close_remote_image();
339 } else if ((*m_state_builder
)->is_disconnected()) {
340 dout(10) << "client flagged disconnected -- skipping bootstrap" << dendl
;
341 // The caller is expected to detect disconnect initializing remote journal.
343 close_remote_image();
345 } else if (m_syncing
) {
346 dout(10) << "local image still syncing to remote image" << dendl
;
351 close_remote_image();
354 template <typename I
>
355 void BootstrapRequest
<I
>::create_local_image() {
357 update_progress("CREATE_LOCAL_IMAGE");
359 ceph_assert(*m_state_builder
!= nullptr);
360 auto ctx
= create_context_callback
<
362 &BootstrapRequest
<I
>::handle_create_local_image
>(this);
363 auto request
= (*m_state_builder
)->create_local_image_request(
364 m_threads
, m_local_io_ctx
, m_global_image_id
, m_pool_meta_cache
,
365 m_progress_ctx
, ctx
);
369 template <typename I
>
370 void BootstrapRequest
<I
>::handle_create_local_image(int r
) {
371 dout(15) << "r=" << r
<< dendl
;
375 dout(10) << "parent image does not exist" << dendl
;
377 derr
<< "failed to create local image: " << cpp_strerror(r
) << dendl
;
380 close_remote_image();
387 template <typename I
>
388 void BootstrapRequest
<I
>::image_sync() {
389 std::unique_lock locker
{m_lock
};
393 m_ret_val
= -ECANCELED
;
394 dout(10) << "request canceled" << dendl
;
395 close_remote_image();
400 ceph_assert(m_image_sync
== nullptr);
402 auto state_builder
= *m_state_builder
;
403 auto sync_point_handler
= state_builder
->create_sync_point_handler();
405 Context
*ctx
= create_context_callback
<
406 BootstrapRequest
<I
>, &BootstrapRequest
<I
>::handle_image_sync
>(this);
407 m_image_sync
= ImageSync
<I
>::create(
408 m_threads
, state_builder
->local_image_ctx
, state_builder
->remote_image_ctx
,
409 m_local_mirror_uuid
, sync_point_handler
, m_instance_watcher
,
410 m_progress_ctx
, ctx
);
414 update_progress("IMAGE_SYNC");
415 m_image_sync
->send();
418 template <typename I
>
419 void BootstrapRequest
<I
>::handle_image_sync(int r
) {
420 dout(15) << "r=" << r
<< dendl
;
423 std::lock_guard locker
{m_lock
};
425 m_image_sync
= nullptr;
427 (*m_state_builder
)->destroy_sync_point_handler();
431 if (r
== -ECANCELED
) {
432 dout(10) << "request canceled" << dendl
;
434 derr
<< "failed to sync remote image: " << cpp_strerror(r
) << dendl
;
439 close_remote_image();
442 template <typename I
>
443 void BootstrapRequest
<I
>::close_remote_image() {
444 if ((*m_state_builder
)->replay_requires_remote_image()) {
451 update_progress("CLOSE_REMOTE_IMAGE");
453 auto ctx
= create_context_callback
<
455 &BootstrapRequest
<I
>::handle_close_remote_image
>(this);
456 ceph_assert(*m_state_builder
!= nullptr);
457 (*m_state_builder
)->close_remote_image(ctx
);
460 template <typename I
>
461 void BootstrapRequest
<I
>::handle_close_remote_image(int r
) {
462 dout(15) << "r=" << r
<< dendl
;
465 derr
<< "error encountered closing remote image: " << cpp_strerror(r
)
472 template <typename I
>
473 void BootstrapRequest
<I
>::update_progress(const std::string
&description
) {
474 dout(15) << description
<< dendl
;
476 if (m_progress_ctx
) {
477 m_progress_ctx
->update_progress(description
);
481 } // namespace image_replayer
482 } // namespace mirror
485 template class rbd::mirror::image_replayer::BootstrapRequest
<librbd::ImageCtx
>;