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