]>
Commit | Line | Data |
---|---|---|
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" | |
7c673cae | 6 | #include "CreateImageRequest.h" |
7c673cae FG |
7 | #include "OpenImageRequest.h" |
8 | #include "OpenLocalImageRequest.h" | |
9 | #include "common/debug.h" | |
10 | #include "common/dout.h" | |
11 | #include "common/errno.h" | |
7c673cae FG |
12 | #include "cls/rbd/cls_rbd_client.h" |
13 | #include "journal/Journaler.h" | |
9f95a23c | 14 | #include "journal/Settings.h" |
7c673cae FG |
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" | |
f67539c2 | 20 | #include "librbd/asio/ContextWQ.h" |
7c673cae | 21 | #include "librbd/journal/Types.h" |
9f95a23c | 22 | #include "tools/rbd_mirror/BaseRequest.h" |
31f18b77 | 23 | #include "tools/rbd_mirror/ImageSync.h" |
9f95a23c | 24 | #include "tools/rbd_mirror/ProgressContext.h" |
11fdf7f2 | 25 | #include "tools/rbd_mirror/Threads.h" |
9f95a23c TL |
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" | |
7c673cae FG |
30 | |
31 | #define dout_context g_ceph_context | |
32 | #define dout_subsys ceph_subsys_rbd_mirror | |
33 | #undef dout_prefix | |
9f95a23c TL |
34 | #define dout_prefix *_dout << "rbd::mirror::image_replayer::" \ |
35 | << "BootstrapRequest: " << this << " " \ | |
36 | << __func__ << ": " | |
7c673cae FG |
37 | |
38 | namespace rbd { | |
39 | namespace mirror { | |
40 | namespace image_replayer { | |
41 | ||
42 | using librbd::util::create_context_callback; | |
7c673cae FG |
43 | using librbd::util::unique_lock_name; |
44 | ||
45 | template <typename I> | |
46 | BootstrapRequest<I>::BootstrapRequest( | |
9f95a23c TL |
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), | |
7c673cae | 68 | m_local_mirror_uuid(local_mirror_uuid), |
9f95a23c TL |
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))) { | |
11fdf7f2 | 77 | dout(10) << dendl; |
7c673cae FG |
78 | } |
79 | ||
c07f9fc5 FG |
80 | template <typename I> |
81 | bool BootstrapRequest<I>::is_syncing() const { | |
9f95a23c | 82 | std::lock_guard locker{m_lock}; |
c07f9fc5 FG |
83 | return (m_image_sync != nullptr); |
84 | } | |
85 | ||
7c673cae FG |
86 | template <typename I> |
87 | void BootstrapRequest<I>::send() { | |
88 | *m_do_resync = false; | |
89 | ||
9f95a23c | 90 | prepare_local_image(); |
7c673cae FG |
91 | } |
92 | ||
93 | template <typename I> | |
94 | void BootstrapRequest<I>::cancel() { | |
11fdf7f2 | 95 | dout(10) << dendl; |
7c673cae | 96 | |
9f95a23c | 97 | std::lock_guard locker{m_lock}; |
7c673cae FG |
98 | m_canceled = true; |
99 | ||
31f18b77 FG |
100 | if (m_image_sync != nullptr) { |
101 | m_image_sync->cancel(); | |
102 | } | |
7c673cae FG |
103 | } |
104 | ||
105 | template <typename I> | |
9f95a23c TL |
106 | std::string BootstrapRequest<I>::get_local_image_name() const { |
107 | std::unique_lock locker{m_lock}; | |
108 | return m_local_image_name; | |
7c673cae FG |
109 | } |
110 | ||
111 | template <typename I> | |
9f95a23c TL |
112 | void BootstrapRequest<I>::prepare_local_image() { |
113 | dout(10) << dendl; | |
114 | update_progress("PREPARE_LOCAL_IMAGE"); | |
7c673cae | 115 | |
9f95a23c TL |
116 | { |
117 | std::unique_lock locker{m_lock}; | |
118 | m_local_image_name = m_global_image_id; | |
7c673cae FG |
119 | } |
120 | ||
9f95a23c TL |
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) { | |
2a845540 | 138 | derr << "error preparing local image for replay: " << cpp_strerror(r) |
7c673cae | 139 | << dendl; |
9f95a23c | 140 | finish(r); |
7c673cae FG |
141 | return; |
142 | } | |
143 | ||
9f95a23c TL |
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; | |
7c673cae FG |
149 | } |
150 | ||
9f95a23c | 151 | prepare_remote_image(); |
d2e6a577 FG |
152 | } |
153 | ||
154 | template <typename I> | |
9f95a23c TL |
155 | void BootstrapRequest<I>::prepare_remote_image() { |
156 | dout(10) << dendl; | |
157 | update_progress("PREPARE_REMOTE_IMAGE"); | |
d2e6a577 FG |
158 | |
159 | Context *ctx = create_context_callback< | |
9f95a23c TL |
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(); | |
d2e6a577 FG |
166 | } |
167 | ||
168 | template <typename I> | |
9f95a23c TL |
169 | void BootstrapRequest<I>::handle_prepare_remote_image(int r) { |
170 | dout(10) << "r=" << r << dendl; | |
d2e6a577 | 171 | |
9f95a23c TL |
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; | |
9f95a23c TL |
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() && | |
a4b75251 TL |
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 | |
9f95a23c TL |
197 | finish(-ENOLINK); |
198 | } else { | |
199 | finish(-ENOENT); | |
200 | } | |
201 | return; | |
202 | } else if (r < 0) { | |
2a845540 TL |
203 | derr << "error preparing remote image for replay: " << cpp_strerror(r) |
204 | << dendl; | |
d2e6a577 FG |
205 | finish(r); |
206 | return; | |
207 | } | |
208 | ||
2a845540 TL |
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 | ||
9f95a23c | 226 | open_remote_image(); |
7c673cae FG |
227 | } |
228 | ||
229 | template <typename I> | |
9f95a23c TL |
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; | |
7c673cae FG |
234 | |
235 | update_progress("OPEN_REMOTE_IMAGE"); | |
236 | ||
9f95a23c TL |
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); | |
7c673cae FG |
244 | request->send(); |
245 | } | |
246 | ||
247 | template <typename I> | |
9f95a23c | 248 | void BootstrapRequest<I>::handle_open_remote_image(int r) { |
11fdf7f2 | 249 | dout(15) << "r=" << r << dendl; |
7c673cae | 250 | |
9f95a23c TL |
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); | |
7c673cae FG |
256 | return; |
257 | } | |
258 | ||
9f95a23c TL |
259 | if ((*m_state_builder)->local_image_id.empty()) { |
260 | create_local_image(); | |
7c673cae FG |
261 | return; |
262 | } | |
263 | ||
264 | open_local_image(); | |
265 | } | |
266 | ||
7c673cae FG |
267 | template <typename I> |
268 | void BootstrapRequest<I>::open_local_image() { | |
9f95a23c TL |
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; | |
7c673cae FG |
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( | |
9f95a23c TL |
280 | m_local_io_ctx, &(*m_state_builder)->local_image_ctx, local_image_id, |
281 | m_threads->work_queue, ctx); | |
7c673cae FG |
282 | request->send(); |
283 | } | |
284 | ||
285 | template <typename I> | |
286 | void BootstrapRequest<I>::handle_open_local_image(int r) { | |
11fdf7f2 | 287 | dout(15) << "r=" << r << dendl; |
7c673cae | 288 | |
9f95a23c TL |
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 | ||
7c673cae | 294 | if (r == -ENOENT) { |
11fdf7f2 | 295 | dout(10) << "local image missing" << dendl; |
9f95a23c | 296 | create_local_image(); |
7c673cae FG |
297 | return; |
298 | } else if (r == -EREMOTEIO) { | |
7c673cae FG |
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) { | |
11fdf7f2 | 304 | derr << "failed to open local image: " << cpp_strerror(r) << dendl; |
7c673cae FG |
305 | m_ret_val = r; |
306 | close_remote_image(); | |
307 | return; | |
308 | } | |
309 | ||
9f95a23c | 310 | prepare_replay(); |
7c673cae FG |
311 | } |
312 | ||
b32b8144 | 313 | template <typename I> |
9f95a23c TL |
314 | void BootstrapRequest<I>::prepare_replay() { |
315 | dout(10) << dendl; | |
316 | update_progress("PREPARE_REPLAY"); | |
b32b8144 | 317 | |
9f95a23c TL |
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(); | |
b32b8144 FG |
324 | } |
325 | ||
326 | template <typename I> | |
9f95a23c TL |
327 | void BootstrapRequest<I>::handle_prepare_replay(int r) { |
328 | dout(10) << "r=" << r << dendl; | |
b32b8144 FG |
329 | |
330 | if (r < 0) { | |
2a845540 | 331 | derr << "failed to prepare local replay: " << cpp_strerror(r) << dendl; |
b32b8144 FG |
332 | m_ret_val = r; |
333 | close_remote_image(); | |
334 | return; | |
9f95a23c TL |
335 | } else if (*m_do_resync) { |
336 | dout(10) << "local image resync requested" << dendl; | |
d2e6a577 | 337 | close_remote_image(); |
7c673cae | 338 | return; |
9f95a23c TL |
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; | |
d2e6a577 | 343 | close_remote_image(); |
7c673cae | 344 | return; |
9f95a23c TL |
345 | } else if (m_syncing) { |
346 | dout(10) << "local image still syncing to remote image" << dendl; | |
347 | image_sync(); | |
348 | return; | |
7c673cae FG |
349 | } |
350 | ||
9f95a23c | 351 | close_remote_image(); |
d2e6a577 FG |
352 | } |
353 | ||
354 | template <typename I> | |
355 | void BootstrapRequest<I>::create_local_image() { | |
9f95a23c | 356 | dout(10) << dendl; |
d2e6a577 FG |
357 | update_progress("CREATE_LOCAL_IMAGE"); |
358 | ||
9f95a23c TL |
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); | |
d2e6a577 FG |
366 | request->send(); |
367 | } | |
368 | ||
369 | template <typename I> | |
370 | void BootstrapRequest<I>::handle_create_local_image(int r) { | |
11fdf7f2 | 371 | dout(15) << "r=" << r << dendl; |
d2e6a577 | 372 | |
9f95a23c | 373 | if (r < 0) { |
11fdf7f2 TL |
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 | } | |
d2e6a577 FG |
379 | m_ret_val = r; |
380 | close_remote_image(); | |
381 | return; | |
382 | } | |
383 | ||
384 | open_local_image(); | |
7c673cae FG |
385 | } |
386 | ||
387 | template <typename I> | |
9f95a23c TL |
388 | void BootstrapRequest<I>::image_sync() { |
389 | std::unique_lock locker{m_lock}; | |
7c673cae | 390 | if (m_canceled) { |
9f95a23c | 391 | locker.unlock(); |
7c673cae | 392 | |
9f95a23c TL |
393 | m_ret_val = -ECANCELED; |
394 | dout(10) << "request canceled" << dendl; | |
7c673cae FG |
395 | close_remote_image(); |
396 | return; | |
397 | } | |
398 | ||
9f95a23c TL |
399 | dout(15) << dendl; |
400 | ceph_assert(m_image_sync == nullptr); | |
c07f9fc5 | 401 | |
9f95a23c TL |
402 | auto state_builder = *m_state_builder; |
403 | auto sync_point_handler = state_builder->create_sync_point_handler(); | |
c07f9fc5 | 404 | |
9f95a23c TL |
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(); | |
7c673cae | 413 | |
9f95a23c TL |
414 | update_progress("IMAGE_SYNC"); |
415 | m_image_sync->send(); | |
7c673cae FG |
416 | } |
417 | ||
418 | template <typename I> | |
419 | void BootstrapRequest<I>::handle_image_sync(int r) { | |
11fdf7f2 | 420 | dout(15) << "r=" << r << dendl; |
7c673cae | 421 | |
31f18b77 | 422 | { |
9f95a23c | 423 | std::lock_guard locker{m_lock}; |
31f18b77 FG |
424 | m_image_sync->put(); |
425 | m_image_sync = nullptr; | |
426 | ||
9f95a23c TL |
427 | (*m_state_builder)->destroy_sync_point_handler(); |
428 | } | |
31f18b77 | 429 | |
9f95a23c TL |
430 | if (r < 0) { |
431 | if (r == -ECANCELED) { | |
432 | dout(10) << "request canceled" << dendl; | |
433 | } else { | |
11fdf7f2 | 434 | derr << "failed to sync remote image: " << cpp_strerror(r) << dendl; |
31f18b77 | 435 | } |
9f95a23c | 436 | m_ret_val = r; |
7c673cae FG |
437 | } |
438 | ||
439 | close_remote_image(); | |
440 | } | |
441 | ||
442 | template <typename I> | |
9f95a23c TL |
443 | void BootstrapRequest<I>::close_remote_image() { |
444 | if ((*m_state_builder)->replay_requires_remote_image()) { | |
445 | finish(m_ret_val); | |
446 | return; | |
7c673cae FG |
447 | } |
448 | ||
11fdf7f2 | 449 | dout(15) << dendl; |
7c673cae FG |
450 | |
451 | update_progress("CLOSE_REMOTE_IMAGE"); | |
452 | ||
9f95a23c TL |
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); | |
7c673cae FG |
458 | } |
459 | ||
460 | template <typename I> | |
461 | void BootstrapRequest<I>::handle_close_remote_image(int r) { | |
11fdf7f2 | 462 | dout(15) << "r=" << r << dendl; |
7c673cae FG |
463 | |
464 | if (r < 0) { | |
11fdf7f2 | 465 | derr << "error encountered closing remote image: " << cpp_strerror(r) |
7c673cae FG |
466 | << dendl; |
467 | } | |
468 | ||
469 | finish(m_ret_val); | |
470 | } | |
471 | ||
7c673cae FG |
472 | template <typename I> |
473 | void BootstrapRequest<I>::update_progress(const std::string &description) { | |
11fdf7f2 | 474 | dout(15) << description << dendl; |
7c673cae FG |
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>; |