]> git.proxmox.com Git - ceph.git/blame - ceph/src/tools/rbd_mirror/ImageSync.cc
add subtree-ish sources for 12.0.3
[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"
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
23namespace rbd {
24namespace mirror {
25
26using namespace image_sync;
27using librbd::util::create_context_callback;
28using librbd::util::unique_lock_name;
29
30template <typename I>
31ImageSync<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
45template <typename I>
46ImageSync<I>::~ImageSync() {
47 assert(m_snapshot_copy_request == nullptr);
48 assert(m_image_copy_request == nullptr);
49}
50
51template <typename I>
52void ImageSync<I>::send() {
53 send_prune_catch_up_sync_point();
54}
55
56template <typename I>
57void 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
73template <typename I>
74void 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
94template <typename I>
95void 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
108template <typename I>
109void 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
128template <typename I>
129void 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
142template <typename I>
143void 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
166template <typename I>
167void 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
192template <typename I>
193void 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
217template <typename I>
218void 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
243template <typename I>
244void 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
276template <typename I>
277void ImageSync<I>::handle_copy_object_map(int r) {
278 dout(20) << dendl;
279
280 assert(r == 0);
281 send_refresh_object_map();
282}
283
284template <typename I>
285void 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
296template <typename I>
297void 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
310template <typename I>
311void 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
323template <typename I>
324void 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
342template <typename I>
343void 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
354template class rbd::mirror::ImageSync<librbd::ImageCtx>;