]> git.proxmox.com Git - ceph.git/blame - ceph/src/tools/rbd_mirror/ImageSync.cc
update sources to 12.2.7
[ceph.git] / ceph / src / tools / rbd_mirror / ImageSync.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 "ImageSync.h"
31f18b77 5#include "InstanceWatcher.h"
7c673cae
FG
6#include "ProgressContext.h"
7#include "common/errno.h"
8#include "journal/Journaler.h"
31f18b77 9#include "librbd/ExclusiveLock.h"
7c673cae
FG
10#include "librbd/ImageCtx.h"
11#include "librbd/ObjectMap.h"
12#include "librbd/Utils.h"
13#include "librbd/journal/Types.h"
14#include "tools/rbd_mirror/image_sync/ImageCopyRequest.h"
b32b8144 15#include "tools/rbd_mirror/image_sync/MetadataCopyRequest.h"
7c673cae
FG
16#include "tools/rbd_mirror/image_sync/SnapshotCopyRequest.h"
17#include "tools/rbd_mirror/image_sync/SyncPointCreateRequest.h"
18#include "tools/rbd_mirror/image_sync/SyncPointPruneRequest.h"
19
20#define dout_context g_ceph_context
21#define dout_subsys ceph_subsys_rbd_mirror
22#undef dout_prefix
23#define dout_prefix *_dout << "rbd::mirror::ImageSync: " \
24 << this << " " << __func__
25
26namespace rbd {
27namespace mirror {
28
29using namespace image_sync;
28e407b8 30using librbd::util::create_async_context_callback;
7c673cae
FG
31using librbd::util::create_context_callback;
32using librbd::util::unique_lock_name;
33
34template <typename I>
35ImageSync<I>::ImageSync(I *local_image_ctx, I *remote_image_ctx,
36 SafeTimer *timer, Mutex *timer_lock,
37 const std::string &mirror_uuid, Journaler *journaler,
38 MirrorPeerClientMeta *client_meta,
31f18b77
FG
39 ContextWQ *work_queue,
40 InstanceWatcher<I> *instance_watcher,
41 Context *on_finish, ProgressContext *progress_ctx)
7c673cae
FG
42 : BaseRequest("rbd::mirror::ImageSync", local_image_ctx->cct, on_finish),
43 m_local_image_ctx(local_image_ctx), m_remote_image_ctx(remote_image_ctx),
44 m_timer(timer), m_timer_lock(timer_lock), m_mirror_uuid(mirror_uuid),
45 m_journaler(journaler), m_client_meta(client_meta),
31f18b77
FG
46 m_work_queue(work_queue), m_instance_watcher(instance_watcher),
47 m_progress_ctx(progress_ctx),
7c673cae
FG
48 m_lock(unique_lock_name("ImageSync::m_lock", this)) {
49}
50
51template <typename I>
52ImageSync<I>::~ImageSync() {
53 assert(m_snapshot_copy_request == nullptr);
54 assert(m_image_copy_request == nullptr);
55}
56
57template <typename I>
58void ImageSync<I>::send() {
31f18b77 59 send_notify_sync_request();
7c673cae
FG
60}
61
62template <typename I>
63void ImageSync<I>::cancel() {
64 Mutex::Locker locker(m_lock);
65
66 dout(20) << dendl;
67
68 m_canceled = true;
69
31f18b77
FG
70 if (m_instance_watcher->cancel_sync_request(m_local_image_ctx->id)) {
71 return;
72 }
73
7c673cae
FG
74 if (m_snapshot_copy_request != nullptr) {
75 m_snapshot_copy_request->cancel();
76 }
77
78 if (m_image_copy_request != nullptr) {
79 m_image_copy_request->cancel();
80 }
81}
82
31f18b77
FG
83template <typename I>
84void ImageSync<I>::send_notify_sync_request() {
85 update_progress("NOTIFY_SYNC_REQUEST");
86
87 dout(20) << dendl;
88
28e407b8
AA
89 m_lock.Lock();
90 if (m_canceled) {
91 m_lock.Unlock();
92 BaseRequest::finish(-ECANCELED);
93 return;
94 }
95
96 Context *ctx = create_async_context_callback(
97 m_work_queue, create_context_callback<
98 ImageSync<I>, &ImageSync<I>::handle_notify_sync_request>(this));
31f18b77 99 m_instance_watcher->notify_sync_request(m_local_image_ctx->id, ctx);
28e407b8 100 m_lock.Unlock();
31f18b77
FG
101}
102
103template <typename I>
104void ImageSync<I>::handle_notify_sync_request(int r) {
105 dout(20) << ": r=" << r << dendl;
106
28e407b8
AA
107 m_lock.Lock();
108 if (r == 0 && m_canceled) {
109 r = -ECANCELED;
110 }
111 m_lock.Unlock();
112
31f18b77
FG
113 if (r < 0) {
114 BaseRequest::finish(r);
115 return;
116 }
117
118 send_prune_catch_up_sync_point();
119}
120
7c673cae
FG
121template <typename I>
122void ImageSync<I>::send_prune_catch_up_sync_point() {
123 update_progress("PRUNE_CATCH_UP_SYNC_POINT");
124
125 if (m_client_meta->sync_points.empty()) {
126 send_create_sync_point();
127 return;
128 }
129
130 dout(20) << dendl;
131
132 // prune will remove sync points with missing snapshots and
133 // ensure we have a maximum of one sync point (in case we
134 // restarted)
135 Context *ctx = create_context_callback<
136 ImageSync<I>, &ImageSync<I>::handle_prune_catch_up_sync_point>(this);
137 SyncPointPruneRequest<I> *request = SyncPointPruneRequest<I>::create(
138 m_remote_image_ctx, false, m_journaler, m_client_meta, ctx);
139 request->send();
140}
141
142template <typename I>
143void ImageSync<I>::handle_prune_catch_up_sync_point(int r) {
144 dout(20) << ": r=" << r << dendl;
145
146 if (r < 0) {
147 derr << ": failed to prune catch-up sync point: "
148 << cpp_strerror(r) << dendl;
149 finish(r);
150 return;
151 }
152
153 send_create_sync_point();
154}
155
156template <typename I>
157void ImageSync<I>::send_create_sync_point() {
158 update_progress("CREATE_SYNC_POINT");
159
160 // TODO: when support for disconnecting laggy clients is added,
161 // re-connect and create catch-up sync point
162 if (m_client_meta->sync_points.size() > 0) {
163 send_copy_snapshots();
164 return;
165 }
166
167 dout(20) << dendl;
168
169 Context *ctx = create_context_callback<
170 ImageSync<I>, &ImageSync<I>::handle_create_sync_point>(this);
171 SyncPointCreateRequest<I> *request = SyncPointCreateRequest<I>::create(
172 m_remote_image_ctx, m_mirror_uuid, m_journaler, m_client_meta, ctx);
173 request->send();
174}
175
176template <typename I>
177void ImageSync<I>::handle_create_sync_point(int r) {
178 dout(20) << ": r=" << r << dendl;
179
180 if (r < 0) {
181 derr << ": failed to create sync point: " << cpp_strerror(r)
182 << dendl;
183 finish(r);
184 return;
185 }
186
187 send_copy_snapshots();
188}
189
190template <typename I>
191void ImageSync<I>::send_copy_snapshots() {
192 m_lock.Lock();
193 if (m_canceled) {
194 m_lock.Unlock();
195 finish(-ECANCELED);
196 return;
197 }
198
199 dout(20) << dendl;
200
201 Context *ctx = create_context_callback<
202 ImageSync<I>, &ImageSync<I>::handle_copy_snapshots>(this);
203 m_snapshot_copy_request = SnapshotCopyRequest<I>::create(
204 m_local_image_ctx, m_remote_image_ctx, &m_snap_map, m_journaler,
205 m_client_meta, m_work_queue, ctx);
206 m_snapshot_copy_request->get();
207 m_lock.Unlock();
208
209 update_progress("COPY_SNAPSHOTS");
210
211 m_snapshot_copy_request->send();
212}
213
214template <typename I>
215void ImageSync<I>::handle_copy_snapshots(int r) {
216 dout(20) << ": r=" << r << dendl;
217
218 {
219 Mutex::Locker locker(m_lock);
220 m_snapshot_copy_request->put();
221 m_snapshot_copy_request = nullptr;
222 if (r == 0 && m_canceled) {
223 r = -ECANCELED;
224 }
225 }
226
227 if (r == -ECANCELED) {
228 dout(10) << ": snapshot copy canceled" << dendl;
229 finish(r);
230 return;
231 } else if (r < 0) {
232 derr << ": failed to copy snapshot metadata: " << cpp_strerror(r) << dendl;
233 finish(r);
234 return;
235 }
236
237 send_copy_image();
238}
239
240template <typename I>
241void ImageSync<I>::send_copy_image() {
242 m_lock.Lock();
243 if (m_canceled) {
244 m_lock.Unlock();
245 finish(-ECANCELED);
246 return;
247 }
248
249 dout(20) << dendl;
250
251 Context *ctx = create_context_callback<
252 ImageSync<I>, &ImageSync<I>::handle_copy_image>(this);
253 m_image_copy_request = ImageCopyRequest<I>::create(
254 m_local_image_ctx, m_remote_image_ctx, m_timer, m_timer_lock,
255 m_journaler, m_client_meta, &m_client_meta->sync_points.front(),
256 ctx, m_progress_ctx);
257 m_image_copy_request->get();
258 m_lock.Unlock();
259
260 update_progress("COPY_IMAGE");
261
262 m_image_copy_request->send();
263}
264
265template <typename I>
266void ImageSync<I>::handle_copy_image(int r) {
267 dout(20) << ": r=" << r << dendl;
268
269 {
270 Mutex::Locker locker(m_lock);
271 m_image_copy_request->put();
272 m_image_copy_request = nullptr;
273 if (r == 0 && m_canceled) {
274 r = -ECANCELED;
275 }
276 }
277
278 if (r == -ECANCELED) {
279 dout(10) << ": image copy canceled" << dendl;
280 finish(r);
281 return;
282 } else if (r < 0) {
283 derr << ": failed to copy image: " << cpp_strerror(r) << dendl;
284 finish(r);
285 return;
286 }
287
288 send_copy_object_map();
289}
290
291template <typename I>
292void ImageSync<I>::send_copy_object_map() {
293 update_progress("COPY_OBJECT_MAP");
294
31f18b77 295 m_local_image_ctx->owner_lock.get_read();
7c673cae
FG
296 m_local_image_ctx->snap_lock.get_read();
297 if (!m_local_image_ctx->test_features(RBD_FEATURE_OBJECT_MAP,
298 m_local_image_ctx->snap_lock)) {
299 m_local_image_ctx->snap_lock.put_read();
31f18b77 300 m_local_image_ctx->owner_lock.put_read();
7c673cae
FG
301 send_prune_sync_points();
302 return;
303 }
304
305 assert(m_local_image_ctx->object_map != nullptr);
306
307 assert(!m_client_meta->sync_points.empty());
308 librbd::journal::MirrorPeerSyncPoint &sync_point =
309 m_client_meta->sync_points.front();
31f18b77
FG
310 auto snap_id_it = m_local_image_ctx->snap_ids.find(
311 {cls::rbd::UserSnapshotNamespace(), sync_point.snap_name});
7c673cae
FG
312 assert(snap_id_it != m_local_image_ctx->snap_ids.end());
313 librados::snap_t snap_id = snap_id_it->second;
314
315 dout(20) << ": snap_id=" << snap_id << ", "
316 << "snap_name=" << sync_point.snap_name << dendl;
317
31f18b77
FG
318 Context *finish_op_ctx = nullptr;
319 if (m_local_image_ctx->exclusive_lock != nullptr) {
320 finish_op_ctx = m_local_image_ctx->exclusive_lock->start_op();
321 }
322 if (finish_op_ctx == nullptr) {
323 derr << ": lost exclusive lock" << dendl;
324 m_local_image_ctx->snap_lock.put_read();
325 m_local_image_ctx->owner_lock.put_read();
326 finish(-EROFS);
327 return;
328 }
329
7c673cae
FG
330 // rollback the object map (copy snapshot object map to HEAD)
331 RWLock::WLocker object_map_locker(m_local_image_ctx->object_map_lock);
31f18b77
FG
332 auto ctx = new FunctionContext([this, finish_op_ctx](int r) {
333 handle_copy_object_map(r);
334 finish_op_ctx->complete(0);
335 });
7c673cae
FG
336 m_local_image_ctx->object_map->rollback(snap_id, ctx);
337 m_local_image_ctx->snap_lock.put_read();
31f18b77 338 m_local_image_ctx->owner_lock.put_read();
7c673cae
FG
339}
340
341template <typename I>
342void ImageSync<I>::handle_copy_object_map(int r) {
343 dout(20) << dendl;
344
345 assert(r == 0);
346 send_refresh_object_map();
347}
348
349template <typename I>
350void ImageSync<I>::send_refresh_object_map() {
351 dout(20) << dendl;
352
353 update_progress("REFRESH_OBJECT_MAP");
354
355 Context *ctx = create_context_callback<
356 ImageSync<I>, &ImageSync<I>::handle_refresh_object_map>(this);
357 m_object_map = m_local_image_ctx->create_object_map(CEPH_NOSNAP);
358 m_object_map->open(ctx);
359}
360
361template <typename I>
362void ImageSync<I>::handle_refresh_object_map(int r) {
363 dout(20) << dendl;
364
365 assert(r == 0);
366 {
367 RWLock::WLocker snap_locker(m_local_image_ctx->snap_lock);
368 std::swap(m_local_image_ctx->object_map, m_object_map);
369 }
370 delete m_object_map;
371
372 send_prune_sync_points();
373}
374
375template <typename I>
376void ImageSync<I>::send_prune_sync_points() {
377 dout(20) << dendl;
378
379 update_progress("PRUNE_SYNC_POINTS");
380
381 Context *ctx = create_context_callback<
382 ImageSync<I>, &ImageSync<I>::handle_prune_sync_points>(this);
383 SyncPointPruneRequest<I> *request = SyncPointPruneRequest<I>::create(
384 m_remote_image_ctx, true, m_journaler, m_client_meta, ctx);
385 request->send();
386}
387
388template <typename I>
389void ImageSync<I>::handle_prune_sync_points(int r) {
390 dout(20) << ": r=" << r << dendl;
391
392 if (r < 0) {
393 derr << ": failed to prune sync point: "
394 << cpp_strerror(r) << dendl;
395 finish(r);
396 return;
397 }
398
399 if (!m_client_meta->sync_points.empty()) {
400 send_copy_image();
401 return;
402 }
403
b32b8144
FG
404 send_copy_metadata();
405}
406
407template <typename I>
408void ImageSync<I>::send_copy_metadata() {
409 dout(20) << dendl;
410 update_progress("COPY_METADATA");
411
412 Context *ctx = create_context_callback<
413 ImageSync<I>, &ImageSync<I>::handle_copy_metadata>(this);
414 auto request = MetadataCopyRequest<I>::create(
415 m_local_image_ctx, m_remote_image_ctx, ctx);
416 request->send();
417}
418
419template <typename I>
420void ImageSync<I>::handle_copy_metadata(int r) {
421 dout(20) << ": r=" << r << dendl;
422 if (r < 0) {
423 derr << ": failed to copy metadata: " << cpp_strerror(r) << dendl;
424 finish(r);
425 return;
426 }
427
7c673cae
FG
428 finish(0);
429}
430
431template <typename I>
432void ImageSync<I>::update_progress(const std::string &description) {
433 dout(20) << ": " << description << dendl;
434
435 if (m_progress_ctx) {
436 m_progress_ctx->update_progress("IMAGE_SYNC/" + description);
437 }
438}
439
31f18b77
FG
440template <typename I>
441void ImageSync<I>::finish(int r) {
442 dout(20) << ": r=" << r << dendl;
443
444 m_instance_watcher->notify_sync_complete(m_local_image_ctx->id);
445 BaseRequest::finish(r);
446}
447
7c673cae
FG
448} // namespace mirror
449} // namespace rbd
450
451template class rbd::mirror::ImageSync<librbd::ImageCtx>;