]> git.proxmox.com Git - ceph.git/blob - ceph/src/tools/rbd_mirror/ImageSync.cc
update sources to 12.2.7
[ceph.git] / ceph / src / tools / rbd_mirror / ImageSync.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 "ImageSync.h"
5 #include "InstanceWatcher.h"
6 #include "ProgressContext.h"
7 #include "common/errno.h"
8 #include "journal/Journaler.h"
9 #include "librbd/ExclusiveLock.h"
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"
15 #include "tools/rbd_mirror/image_sync/MetadataCopyRequest.h"
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
26 namespace rbd {
27 namespace mirror {
28
29 using namespace image_sync;
30 using librbd::util::create_async_context_callback;
31 using librbd::util::create_context_callback;
32 using librbd::util::unique_lock_name;
33
34 template <typename I>
35 ImageSync<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,
39 ContextWQ *work_queue,
40 InstanceWatcher<I> *instance_watcher,
41 Context *on_finish, ProgressContext *progress_ctx)
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),
46 m_work_queue(work_queue), m_instance_watcher(instance_watcher),
47 m_progress_ctx(progress_ctx),
48 m_lock(unique_lock_name("ImageSync::m_lock", this)) {
49 }
50
51 template <typename I>
52 ImageSync<I>::~ImageSync() {
53 assert(m_snapshot_copy_request == nullptr);
54 assert(m_image_copy_request == nullptr);
55 }
56
57 template <typename I>
58 void ImageSync<I>::send() {
59 send_notify_sync_request();
60 }
61
62 template <typename I>
63 void ImageSync<I>::cancel() {
64 Mutex::Locker locker(m_lock);
65
66 dout(20) << dendl;
67
68 m_canceled = true;
69
70 if (m_instance_watcher->cancel_sync_request(m_local_image_ctx->id)) {
71 return;
72 }
73
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
83 template <typename I>
84 void ImageSync<I>::send_notify_sync_request() {
85 update_progress("NOTIFY_SYNC_REQUEST");
86
87 dout(20) << dendl;
88
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));
99 m_instance_watcher->notify_sync_request(m_local_image_ctx->id, ctx);
100 m_lock.Unlock();
101 }
102
103 template <typename I>
104 void ImageSync<I>::handle_notify_sync_request(int r) {
105 dout(20) << ": r=" << r << dendl;
106
107 m_lock.Lock();
108 if (r == 0 && m_canceled) {
109 r = -ECANCELED;
110 }
111 m_lock.Unlock();
112
113 if (r < 0) {
114 BaseRequest::finish(r);
115 return;
116 }
117
118 send_prune_catch_up_sync_point();
119 }
120
121 template <typename I>
122 void 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
142 template <typename I>
143 void 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
156 template <typename I>
157 void 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
176 template <typename I>
177 void 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
190 template <typename I>
191 void 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
214 template <typename I>
215 void 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
240 template <typename I>
241 void 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
265 template <typename I>
266 void 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
291 template <typename I>
292 void ImageSync<I>::send_copy_object_map() {
293 update_progress("COPY_OBJECT_MAP");
294
295 m_local_image_ctx->owner_lock.get_read();
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();
300 m_local_image_ctx->owner_lock.put_read();
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();
310 auto snap_id_it = m_local_image_ctx->snap_ids.find(
311 {cls::rbd::UserSnapshotNamespace(), sync_point.snap_name});
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
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
330 // rollback the object map (copy snapshot object map to HEAD)
331 RWLock::WLocker object_map_locker(m_local_image_ctx->object_map_lock);
332 auto ctx = new FunctionContext([this, finish_op_ctx](int r) {
333 handle_copy_object_map(r);
334 finish_op_ctx->complete(0);
335 });
336 m_local_image_ctx->object_map->rollback(snap_id, ctx);
337 m_local_image_ctx->snap_lock.put_read();
338 m_local_image_ctx->owner_lock.put_read();
339 }
340
341 template <typename I>
342 void ImageSync<I>::handle_copy_object_map(int r) {
343 dout(20) << dendl;
344
345 assert(r == 0);
346 send_refresh_object_map();
347 }
348
349 template <typename I>
350 void 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
361 template <typename I>
362 void 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
375 template <typename I>
376 void 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
388 template <typename I>
389 void 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
404 send_copy_metadata();
405 }
406
407 template <typename I>
408 void 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
419 template <typename I>
420 void 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
428 finish(0);
429 }
430
431 template <typename I>
432 void 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
440 template <typename I>
441 void 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
448 } // namespace mirror
449 } // namespace rbd
450
451 template class rbd::mirror::ImageSync<librbd::ImageCtx>;