]> git.proxmox.com Git - ceph.git/blob - ceph/src/tools/rbd_mirror/image_replayer/BootstrapRequest.cc
bda5b5f9bd760c19a1938ff8d8bbf971205f7779
[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 "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"
30
31 #define dout_context g_ceph_context
32 #define dout_subsys ceph_subsys_rbd_mirror
33 #undef dout_prefix
34 #define dout_prefix *_dout << "rbd::mirror::image_replayer::" \
35 << "BootstrapRequest: " << this << " " \
36 << __func__ << ": "
37
38 namespace rbd {
39 namespace mirror {
40 namespace image_replayer {
41
42 using librbd::util::create_context_callback;
43 using librbd::util::unique_lock_name;
44
45 template <typename I>
46 BootstrapRequest<I>::BootstrapRequest(
47 Threads<I>* threads,
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,
58 bool* do_resync,
59 Context* on_finish)
60 : CancelableRequest("rbd::mirror::image_replayer::BootstrapRequest",
61 reinterpret_cast<CephContext*>(local_io_ctx.cct()),
62 on_finish),
63 m_threads(threads),
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",
76 this))) {
77 dout(10) << dendl;
78 }
79
80 template <typename I>
81 bool BootstrapRequest<I>::is_syncing() const {
82 std::lock_guard locker{m_lock};
83 return (m_image_sync != nullptr);
84 }
85
86 template <typename I>
87 void BootstrapRequest<I>::send() {
88 *m_do_resync = false;
89
90 prepare_local_image();
91 }
92
93 template <typename I>
94 void BootstrapRequest<I>::cancel() {
95 dout(10) << dendl;
96
97 std::lock_guard locker{m_lock};
98 m_canceled = true;
99
100 if (m_image_sync != nullptr) {
101 m_image_sync->cancel();
102 }
103 }
104
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;
109 }
110
111 template <typename I>
112 void BootstrapRequest<I>::prepare_local_image() {
113 dout(10) << dendl;
114 update_progress("PREPARE_LOCAL_IMAGE");
115
116 {
117 std::unique_lock locker{m_lock};
118 m_local_image_name = m_global_image_id;
119 }
120
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);
127 req->send();
128 }
129
130 template <typename I>
131 void BootstrapRequest<I>::handle_prepare_local_image(int r) {
132 dout(10) << "r=" << r << dendl;
133
134 ceph_assert(r < 0 || *m_state_builder != nullptr);
135 if (r == -ENOENT) {
136 dout(10) << "local image does not exist" << dendl;
137 } else if (r < 0) {
138 derr << "error preparing local image for replay: " << cpp_strerror(r)
139 << dendl;
140 finish(r);
141 return;
142 }
143
144 // image replayer will detect the name change (if any) at next
145 // status update
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;
149 }
150
151 prepare_remote_image();
152 }
153
154 template <typename I>
155 void BootstrapRequest<I>::prepare_remote_image() {
156 dout(10) << dendl;
157 update_progress("PREPARE_REMOTE_IMAGE");
158
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);
165 req->send();
166 }
167
168 template <typename I>
169 void BootstrapRequest<I>::handle_prepare_remote_image(int r) {
170 dout(10) << "r=" << r << dendl;
171
172 auto state_builder = *m_state_builder;
173 ceph_assert(state_builder == nullptr ||
174 !state_builder->remote_mirror_uuid.empty());
175
176 if (state_builder != nullptr && state_builder->is_local_primary()) {
177 dout(5) << "local image is primary" << dendl;
178 finish(-ENOMSG);
179 return;
180 } else if (r == -ENOENT || state_builder == nullptr) {
181 dout(10) << "remote image does not exist";
182 if (state_builder != nullptr) {
183 *_dout << ": "
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();
187 }
188 *_dout << dendl;
189
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
197 finish(-ENOLINK);
198 } else {
199 finish(-ENOENT);
200 }
201 return;
202 } else if (r < 0) {
203 derr << "error preparing remote image for replay: " << cpp_strerror(r)
204 << dendl;
205 finish(r);
206 return;
207 }
208
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"
213 << dendl;
214 finish(-EREMOTEIO);
215 return;
216 } else if (!state_builder->is_linked()) {
217 dout(10) << "local image is unlinked and remote image is not primary"
218 << dendl;
219 finish(-EREMOTEIO);
220 return;
221 }
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
224 }
225
226 open_remote_image();
227 }
228
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;
234
235 update_progress("OPEN_REMOTE_IMAGE");
236
237 auto ctx = create_context_callback<
238 BootstrapRequest<I>,
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,
243 false, ctx);
244 request->send();
245 }
246
247 template <typename I>
248 void BootstrapRequest<I>::handle_open_remote_image(int r) {
249 dout(15) << "r=" << r << dendl;
250
251 ceph_assert(*m_state_builder != nullptr);
252 if (r < 0) {
253 derr << "failed to open remote image: " << cpp_strerror(r) << dendl;
254 ceph_assert((*m_state_builder)->remote_image_ctx == nullptr);
255 finish(r);
256 return;
257 }
258
259 if ((*m_state_builder)->local_image_id.empty()) {
260 create_local_image();
261 return;
262 }
263
264 open_local_image();
265 }
266
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;
271
272 dout(15) << "local_image_id=" << local_image_id << dendl;
273
274 update_progress("OPEN_LOCAL_IMAGE");
275
276 Context *ctx = create_context_callback<
277 BootstrapRequest<I>, &BootstrapRequest<I>::handle_open_local_image>(
278 this);
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);
282 request->send();
283 }
284
285 template <typename I>
286 void BootstrapRequest<I>::handle_open_local_image(int r) {
287 dout(15) << "r=" << r << dendl;
288
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));
293
294 if (r == -ENOENT) {
295 dout(10) << "local image missing" << dendl;
296 create_local_image();
297 return;
298 } else if (r == -EREMOTEIO) {
299 dout(10) << "local image is primary -- skipping image replay" << dendl;
300 m_ret_val = r;
301 close_remote_image();
302 return;
303 } else if (r < 0) {
304 derr << "failed to open local image: " << cpp_strerror(r) << dendl;
305 m_ret_val = r;
306 close_remote_image();
307 return;
308 }
309
310 prepare_replay();
311 }
312
313 template <typename I>
314 void BootstrapRequest<I>::prepare_replay() {
315 dout(10) << dendl;
316 update_progress("PREPARE_REPLAY");
317
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);
323 request->send();
324 }
325
326 template <typename I>
327 void BootstrapRequest<I>::handle_prepare_replay(int r) {
328 dout(10) << "r=" << r << dendl;
329
330 if (r < 0) {
331 derr << "failed to prepare local replay: " << cpp_strerror(r) << dendl;
332 m_ret_val = r;
333 close_remote_image();
334 return;
335 } else if (*m_do_resync) {
336 dout(10) << "local image resync requested" << dendl;
337 close_remote_image();
338 return;
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.
342 m_ret_val = 0;
343 close_remote_image();
344 return;
345 } else if (m_syncing) {
346 dout(10) << "local image still syncing to remote image" << dendl;
347 image_sync();
348 return;
349 }
350
351 close_remote_image();
352 }
353
354 template <typename I>
355 void BootstrapRequest<I>::create_local_image() {
356 dout(10) << dendl;
357 update_progress("CREATE_LOCAL_IMAGE");
358
359 ceph_assert(*m_state_builder != nullptr);
360 auto ctx = create_context_callback<
361 BootstrapRequest<I>,
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);
366 request->send();
367 }
368
369 template <typename I>
370 void BootstrapRequest<I>::handle_create_local_image(int r) {
371 dout(15) << "r=" << r << dendl;
372
373 if (r < 0) {
374 if (r == -ENOENT) {
375 dout(10) << "parent image does not exist" << dendl;
376 } else {
377 derr << "failed to create local image: " << cpp_strerror(r) << dendl;
378 }
379 m_ret_val = r;
380 close_remote_image();
381 return;
382 }
383
384 open_local_image();
385 }
386
387 template <typename I>
388 void BootstrapRequest<I>::image_sync() {
389 std::unique_lock locker{m_lock};
390 if (m_canceled) {
391 locker.unlock();
392
393 m_ret_val = -ECANCELED;
394 dout(10) << "request canceled" << dendl;
395 close_remote_image();
396 return;
397 }
398
399 dout(15) << dendl;
400 ceph_assert(m_image_sync == nullptr);
401
402 auto state_builder = *m_state_builder;
403 auto sync_point_handler = state_builder->create_sync_point_handler();
404
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);
411 m_image_sync->get();
412 locker.unlock();
413
414 update_progress("IMAGE_SYNC");
415 m_image_sync->send();
416 }
417
418 template <typename I>
419 void BootstrapRequest<I>::handle_image_sync(int r) {
420 dout(15) << "r=" << r << dendl;
421
422 {
423 std::lock_guard locker{m_lock};
424 m_image_sync->put();
425 m_image_sync = nullptr;
426
427 (*m_state_builder)->destroy_sync_point_handler();
428 }
429
430 if (r < 0) {
431 if (r == -ECANCELED) {
432 dout(10) << "request canceled" << dendl;
433 } else {
434 derr << "failed to sync remote image: " << cpp_strerror(r) << dendl;
435 }
436 m_ret_val = r;
437 }
438
439 close_remote_image();
440 }
441
442 template <typename I>
443 void BootstrapRequest<I>::close_remote_image() {
444 if ((*m_state_builder)->replay_requires_remote_image()) {
445 finish(m_ret_val);
446 return;
447 }
448
449 dout(15) << dendl;
450
451 update_progress("CLOSE_REMOTE_IMAGE");
452
453 auto ctx = create_context_callback<
454 BootstrapRequest<I>,
455 &BootstrapRequest<I>::handle_close_remote_image>(this);
456 ceph_assert(*m_state_builder != nullptr);
457 (*m_state_builder)->close_remote_image(ctx);
458 }
459
460 template <typename I>
461 void BootstrapRequest<I>::handle_close_remote_image(int r) {
462 dout(15) << "r=" << r << dendl;
463
464 if (r < 0) {
465 derr << "error encountered closing remote image: " << cpp_strerror(r)
466 << dendl;
467 }
468
469 finish(m_ret_val);
470 }
471
472 template <typename I>
473 void BootstrapRequest<I>::update_progress(const std::string &description) {
474 dout(15) << description << dendl;
475
476 if (m_progress_ctx) {
477 m_progress_ctx->update_progress(description);
478 }
479 }
480
481 } // namespace image_replayer
482 } // namespace mirror
483 } // namespace rbd
484
485 template class rbd::mirror::image_replayer::BootstrapRequest<librbd::ImageCtx>;