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