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