]>
Commit | Line | Data |
---|---|---|
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 | ||
26 | namespace rbd { | |
27 | namespace mirror { | |
28 | ||
29 | using namespace image_sync; | |
30 | using librbd::util::create_context_callback; | |
31 | using librbd::util::unique_lock_name; | |
32 | ||
33 | template <typename I> | |
34 | ImageSync<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 | ||
50 | template <typename I> | |
51 | ImageSync<I>::~ImageSync() { | |
52 | assert(m_snapshot_copy_request == nullptr); | |
53 | assert(m_image_copy_request == nullptr); | |
54 | } | |
55 | ||
56 | template <typename I> | |
57 | void ImageSync<I>::send() { | |
31f18b77 | 58 | send_notify_sync_request(); |
7c673cae FG |
59 | } |
60 | ||
61 | template <typename I> | |
62 | void 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 |
82 | template <typename I> |
83 | void 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 | ||
93 | template <typename I> | |
94 | void 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 |
105 | template <typename I> |
106 | void 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 | ||
126 | template <typename I> | |
127 | void 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 | ||
140 | template <typename I> | |
141 | void 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 | ||
160 | template <typename I> | |
161 | void 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 | ||
174 | template <typename I> | |
175 | void 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 | ||
198 | template <typename I> | |
199 | void 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 | ||
224 | template <typename I> | |
225 | void 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 | ||
249 | template <typename I> | |
250 | void 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 | ||
275 | template <typename I> | |
276 | void 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 | ||
325 | template <typename I> | |
326 | void ImageSync<I>::handle_copy_object_map(int r) { | |
327 | dout(20) << dendl; | |
328 | ||
329 | assert(r == 0); | |
330 | send_refresh_object_map(); | |
331 | } | |
332 | ||
333 | template <typename I> | |
334 | void 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 | ||
345 | template <typename I> | |
346 | void 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 | ||
359 | template <typename I> | |
360 | void 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 | ||
372 | template <typename I> | |
373 | void 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 | ||
391 | template <typename I> | |
392 | void 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 | ||
403 | template <typename I> | |
404 | void 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 | ||
415 | template <typename I> | |
416 | void 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 |
424 | template <typename I> |
425 | void 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 | ||
435 | template class rbd::mirror::ImageSync<librbd::ImageCtx>; |