Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / 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/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
25 namespace rbd {
26 namespace mirror {
27
28 using namespace image_sync;
29 using librbd::util::create_context_callback;
30 using librbd::util::unique_lock_name;
31
32 template <typename I>
33 ImageSync<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,
37                         ContextWQ *work_queue,
38                         InstanceWatcher<I> *instance_watcher,
39                         Context *on_finish, ProgressContext *progress_ctx)
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),
44     m_work_queue(work_queue), m_instance_watcher(instance_watcher),
45     m_progress_ctx(progress_ctx),
46     m_lock(unique_lock_name("ImageSync::m_lock", this)) {
47 }
48
49 template <typename I>
50 ImageSync<I>::~ImageSync() {
51   assert(m_snapshot_copy_request == nullptr);
52   assert(m_image_copy_request == nullptr);
53 }
54
55 template <typename I>
56 void ImageSync<I>::send() {
57   send_notify_sync_request();
58 }
59
60 template <typename I>
61 void ImageSync<I>::cancel() {
62   Mutex::Locker locker(m_lock);
63
64   dout(20) << dendl;
65
66   m_canceled = true;
67
68   if (m_instance_watcher->cancel_sync_request(m_local_image_ctx->id)) {
69     return;
70   }
71
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
81 template <typename I>
82 void 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
92 template <typename I>
93 void 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
104 template <typename I>
105 void 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
125 template <typename I>
126 void 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
139 template <typename I>
140 void 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
159 template <typename I>
160 void 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
173 template <typename I>
174 void 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
197 template <typename I>
198 void 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
223 template <typename I>
224 void 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
248 template <typename I>
249 void 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
274 template <typename I>
275 void ImageSync<I>::send_copy_object_map() {
276   update_progress("COPY_OBJECT_MAP");
277
278   m_local_image_ctx->owner_lock.get_read();
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();
283     m_local_image_ctx->owner_lock.put_read();
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();
293   auto snap_id_it = m_local_image_ctx->snap_ids.find(
294     {cls::rbd::UserSnapshotNamespace(), sync_point.snap_name});
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
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
313   // rollback the object map (copy snapshot object map to HEAD)
314   RWLock::WLocker object_map_locker(m_local_image_ctx->object_map_lock);
315   auto ctx = new FunctionContext([this, finish_op_ctx](int r) {
316       handle_copy_object_map(r);
317       finish_op_ctx->complete(0);
318     });
319   m_local_image_ctx->object_map->rollback(snap_id, ctx);
320   m_local_image_ctx->snap_lock.put_read();
321   m_local_image_ctx->owner_lock.put_read();
322 }
323
324 template <typename I>
325 void ImageSync<I>::handle_copy_object_map(int r) {
326   dout(20) << dendl;
327
328   assert(r == 0);
329   send_refresh_object_map();
330 }
331
332 template <typename I>
333 void 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
344 template <typename I>
345 void 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
358 template <typename I>
359 void 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
371 template <typename I>
372 void 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
390 template <typename I>
391 void 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
399 template <typename I>
400 void 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
407 } // namespace mirror
408 } // namespace rbd
409
410 template class rbd::mirror::ImageSync<librbd::ImageCtx>;