]>
Commit | Line | Data |
---|---|---|
11fdf7f2 TL |
1 | // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- |
2 | // vim: ts=8 sw=2 smarttab | |
3 | ||
4 | #include "DeepCopyRequest.h" | |
5 | #include "common/errno.h" | |
6 | #include "librbd/ExclusiveLock.h" | |
7 | #include "librbd/ImageCtx.h" | |
8 | #include "librbd/ObjectMap.h" | |
9 | #include "librbd/Utils.h" | |
10 | #include "librbd/deep_copy/ImageCopyRequest.h" | |
11 | #include "librbd/deep_copy/MetadataCopyRequest.h" | |
12 | #include "librbd/deep_copy/SnapshotCopyRequest.h" | |
13 | #include "librbd/internal.h" | |
14 | ||
15 | #define dout_subsys ceph_subsys_rbd | |
16 | #undef dout_prefix | |
17 | #define dout_prefix *_dout << "librbd::DeepCopyRequest: " \ | |
18 | << this << " " << __func__ << ": " | |
19 | ||
20 | namespace librbd { | |
21 | ||
22 | using namespace librbd::deep_copy; | |
23 | ||
24 | using librbd::util::create_context_callback; | |
25 | using librbd::util::create_rados_callback; | |
26 | using librbd::util::unique_lock_name; | |
27 | ||
28 | template <typename I> | |
29 | DeepCopyRequest<I>::DeepCopyRequest(I *src_image_ctx, I *dst_image_ctx, | |
9f95a23c TL |
30 | librados::snap_t src_snap_id_start, |
31 | librados::snap_t src_snap_id_end, | |
32 | librados::snap_t dst_snap_id_start, | |
33 | bool flatten, | |
11fdf7f2 TL |
34 | const ObjectNumber &object_number, |
35 | ContextWQ *work_queue, SnapSeqs *snap_seqs, | |
1911f103 | 36 | deep_copy::Handler *handler, |
11fdf7f2 | 37 | Context *on_finish) |
9f95a23c TL |
38 | : RefCountedObject(dst_image_ctx->cct), m_src_image_ctx(src_image_ctx), |
39 | m_dst_image_ctx(dst_image_ctx), m_src_snap_id_start(src_snap_id_start), | |
40 | m_src_snap_id_end(src_snap_id_end), m_dst_snap_id_start(dst_snap_id_start), | |
41 | m_flatten(flatten), m_object_number(object_number), | |
1911f103 | 42 | m_work_queue(work_queue), m_snap_seqs(snap_seqs), m_handler(handler), |
9f95a23c TL |
43 | m_on_finish(on_finish), m_cct(dst_image_ctx->cct), |
44 | m_lock(ceph::make_mutex(unique_lock_name("DeepCopyRequest::m_lock", this))) { | |
11fdf7f2 TL |
45 | } |
46 | ||
47 | template <typename I> | |
48 | DeepCopyRequest<I>::~DeepCopyRequest() { | |
49 | ceph_assert(m_snapshot_copy_request == nullptr); | |
50 | ceph_assert(m_image_copy_request == nullptr); | |
51 | } | |
52 | ||
53 | template <typename I> | |
54 | void DeepCopyRequest<I>::send() { | |
eafe8130 TL |
55 | if (!m_src_image_ctx->data_ctx.is_valid()) { |
56 | lderr(m_cct) << "missing data pool for source image" << dendl; | |
57 | finish(-ENODEV); | |
58 | return; | |
59 | } | |
60 | ||
61 | if (!m_dst_image_ctx->data_ctx.is_valid()) { | |
62 | lderr(m_cct) << "missing data pool for destination image" << dendl; | |
63 | finish(-ENODEV); | |
64 | return; | |
65 | } | |
66 | ||
11fdf7f2 TL |
67 | int r = validate_copy_points(); |
68 | if (r < 0) { | |
69 | finish(r); | |
70 | return; | |
71 | } | |
72 | ||
73 | send_copy_snapshots(); | |
74 | } | |
75 | ||
76 | template <typename I> | |
77 | void DeepCopyRequest<I>::cancel() { | |
9f95a23c | 78 | std::lock_guard locker{m_lock}; |
11fdf7f2 TL |
79 | |
80 | ldout(m_cct, 20) << dendl; | |
81 | ||
82 | m_canceled = true; | |
83 | ||
84 | if (m_snapshot_copy_request != nullptr) { | |
85 | m_snapshot_copy_request->cancel(); | |
86 | } | |
87 | ||
88 | if (m_image_copy_request != nullptr) { | |
89 | m_image_copy_request->cancel(); | |
90 | } | |
91 | } | |
92 | ||
93 | template <typename I> | |
94 | void DeepCopyRequest<I>::send_copy_snapshots() { | |
9f95a23c | 95 | m_lock.lock(); |
11fdf7f2 | 96 | if (m_canceled) { |
9f95a23c | 97 | m_lock.unlock(); |
11fdf7f2 TL |
98 | finish(-ECANCELED); |
99 | return; | |
100 | } | |
101 | ||
102 | ldout(m_cct, 20) << dendl; | |
103 | ||
104 | Context *ctx = create_context_callback< | |
105 | DeepCopyRequest<I>, &DeepCopyRequest<I>::handle_copy_snapshots>(this); | |
106 | m_snapshot_copy_request = SnapshotCopyRequest<I>::create( | |
9f95a23c TL |
107 | m_src_image_ctx, m_dst_image_ctx, m_src_snap_id_start, m_src_snap_id_end, |
108 | m_dst_snap_id_start, m_flatten, m_work_queue, m_snap_seqs, ctx); | |
11fdf7f2 | 109 | m_snapshot_copy_request->get(); |
9f95a23c | 110 | m_lock.unlock(); |
11fdf7f2 TL |
111 | |
112 | m_snapshot_copy_request->send(); | |
113 | } | |
114 | ||
115 | template <typename I> | |
116 | void DeepCopyRequest<I>::handle_copy_snapshots(int r) { | |
117 | ldout(m_cct, 20) << "r=" << r << dendl; | |
118 | ||
119 | { | |
9f95a23c | 120 | std::lock_guard locker{m_lock}; |
11fdf7f2 TL |
121 | m_snapshot_copy_request->put(); |
122 | m_snapshot_copy_request = nullptr; | |
123 | if (r == 0 && m_canceled) { | |
124 | r = -ECANCELED; | |
125 | } | |
126 | } | |
127 | ||
128 | if (r == -ECANCELED) { | |
129 | ldout(m_cct, 10) << "snapshot copy canceled" << dendl; | |
130 | finish(r); | |
131 | return; | |
132 | } else if (r < 0) { | |
133 | lderr(m_cct) << "failed to copy snapshot metadata: " << cpp_strerror(r) | |
134 | << dendl; | |
135 | finish(r); | |
136 | return; | |
137 | } | |
138 | ||
9f95a23c | 139 | if (m_src_snap_id_end == CEPH_NOSNAP) { |
11fdf7f2 TL |
140 | (*m_snap_seqs)[CEPH_NOSNAP] = CEPH_NOSNAP; |
141 | } | |
142 | ||
143 | send_copy_image(); | |
144 | } | |
145 | ||
146 | template <typename I> | |
147 | void DeepCopyRequest<I>::send_copy_image() { | |
9f95a23c | 148 | m_lock.lock(); |
11fdf7f2 | 149 | if (m_canceled) { |
9f95a23c | 150 | m_lock.unlock(); |
11fdf7f2 TL |
151 | finish(-ECANCELED); |
152 | return; | |
153 | } | |
154 | ||
155 | ldout(m_cct, 20) << dendl; | |
156 | ||
157 | Context *ctx = create_context_callback< | |
158 | DeepCopyRequest<I>, &DeepCopyRequest<I>::handle_copy_image>(this); | |
159 | m_image_copy_request = ImageCopyRequest<I>::create( | |
9f95a23c | 160 | m_src_image_ctx, m_dst_image_ctx, m_src_snap_id_start, m_src_snap_id_end, |
1911f103 | 161 | m_dst_snap_id_start, m_flatten, m_object_number, *m_snap_seqs, m_handler, |
9f95a23c | 162 | ctx); |
11fdf7f2 | 163 | m_image_copy_request->get(); |
9f95a23c | 164 | m_lock.unlock(); |
11fdf7f2 TL |
165 | |
166 | m_image_copy_request->send(); | |
167 | } | |
168 | ||
169 | template <typename I> | |
170 | void DeepCopyRequest<I>::handle_copy_image(int r) { | |
171 | ldout(m_cct, 20) << "r=" << r << dendl; | |
172 | ||
173 | { | |
9f95a23c | 174 | std::lock_guard locker{m_lock}; |
11fdf7f2 TL |
175 | m_image_copy_request->put(); |
176 | m_image_copy_request = nullptr; | |
177 | if (r == 0 && m_canceled) { | |
178 | r = -ECANCELED; | |
179 | } | |
180 | } | |
181 | ||
182 | if (r == -ECANCELED) { | |
183 | ldout(m_cct, 10) << "image copy canceled" << dendl; | |
184 | finish(r); | |
185 | return; | |
186 | } else if (r < 0) { | |
187 | lderr(m_cct) << "failed to copy image: " << cpp_strerror(r) << dendl; | |
188 | finish(r); | |
189 | return; | |
190 | } | |
191 | ||
192 | send_copy_object_map(); | |
193 | } | |
194 | ||
195 | template <typename I> | |
196 | void DeepCopyRequest<I>::send_copy_object_map() { | |
9f95a23c TL |
197 | m_dst_image_ctx->owner_lock.lock_shared(); |
198 | m_dst_image_ctx->image_lock.lock_shared(); | |
11fdf7f2 TL |
199 | |
200 | if (!m_dst_image_ctx->test_features(RBD_FEATURE_OBJECT_MAP, | |
9f95a23c TL |
201 | m_dst_image_ctx->image_lock)) { |
202 | m_dst_image_ctx->image_lock.unlock_shared(); | |
203 | m_dst_image_ctx->owner_lock.unlock_shared(); | |
11fdf7f2 TL |
204 | send_copy_metadata(); |
205 | return; | |
206 | } | |
9f95a23c TL |
207 | if (m_src_snap_id_end == CEPH_NOSNAP) { |
208 | m_dst_image_ctx->image_lock.unlock_shared(); | |
209 | m_dst_image_ctx->owner_lock.unlock_shared(); | |
11fdf7f2 TL |
210 | send_refresh_object_map(); |
211 | return; | |
212 | } | |
213 | ||
214 | ceph_assert(m_dst_image_ctx->object_map != nullptr); | |
215 | ||
216 | ldout(m_cct, 20) << dendl; | |
217 | ||
218 | Context *finish_op_ctx = nullptr; | |
219 | int r; | |
220 | if (m_dst_image_ctx->exclusive_lock != nullptr) { | |
221 | finish_op_ctx = m_dst_image_ctx->exclusive_lock->start_op(&r); | |
222 | } | |
223 | if (finish_op_ctx == nullptr) { | |
224 | lderr(m_cct) << "lost exclusive lock" << dendl; | |
9f95a23c TL |
225 | m_dst_image_ctx->image_lock.unlock_shared(); |
226 | m_dst_image_ctx->owner_lock.unlock_shared(); | |
11fdf7f2 TL |
227 | finish(r); |
228 | return; | |
229 | } | |
230 | ||
231 | // rollback the object map (copy snapshot object map to HEAD) | |
9f95a23c | 232 | auto ctx = new LambdaContext([this, finish_op_ctx](int r) { |
11fdf7f2 TL |
233 | handle_copy_object_map(r); |
234 | finish_op_ctx->complete(0); | |
235 | }); | |
9f95a23c TL |
236 | ceph_assert(m_snap_seqs->count(m_src_snap_id_end) > 0); |
237 | librados::snap_t copy_snap_id = (*m_snap_seqs)[m_src_snap_id_end]; | |
11fdf7f2 | 238 | m_dst_image_ctx->object_map->rollback(copy_snap_id, ctx); |
9f95a23c TL |
239 | m_dst_image_ctx->image_lock.unlock_shared(); |
240 | m_dst_image_ctx->owner_lock.unlock_shared(); | |
11fdf7f2 TL |
241 | } |
242 | ||
243 | template <typename I> | |
244 | void DeepCopyRequest<I>::handle_copy_object_map(int r) { | |
245 | ldout(m_cct, 20) << dendl; | |
246 | ||
247 | if (r < 0) { | |
248 | lderr(m_cct) << "failed to roll back object map: " << cpp_strerror(r) | |
249 | << dendl; | |
250 | finish(r); | |
251 | return; | |
252 | } | |
253 | ||
254 | send_refresh_object_map(); | |
255 | } | |
256 | ||
257 | template <typename I> | |
258 | void DeepCopyRequest<I>::send_refresh_object_map() { | |
259 | int r; | |
260 | Context *finish_op_ctx = nullptr; | |
261 | { | |
9f95a23c | 262 | std::shared_lock owner_locker{m_dst_image_ctx->owner_lock}; |
11fdf7f2 TL |
263 | if (m_dst_image_ctx->exclusive_lock != nullptr) { |
264 | finish_op_ctx = m_dst_image_ctx->exclusive_lock->start_op(&r); | |
265 | } | |
266 | } | |
267 | if (finish_op_ctx == nullptr) { | |
268 | lderr(m_cct) << "lost exclusive lock" << dendl; | |
269 | finish(r); | |
270 | return; | |
271 | } | |
272 | ||
273 | ldout(m_cct, 20) << dendl; | |
274 | ||
9f95a23c | 275 | auto ctx = new LambdaContext([this, finish_op_ctx](int r) { |
11fdf7f2 TL |
276 | handle_refresh_object_map(r); |
277 | finish_op_ctx->complete(0); | |
278 | }); | |
279 | m_object_map = m_dst_image_ctx->create_object_map(CEPH_NOSNAP); | |
280 | m_object_map->open(ctx); | |
281 | } | |
282 | ||
283 | template <typename I> | |
284 | void DeepCopyRequest<I>::handle_refresh_object_map(int r) { | |
285 | ldout(m_cct, 20) << "r=" << r << dendl; | |
286 | ||
287 | if (r < 0) { | |
288 | lderr(m_cct) << "failed to open object map: " << cpp_strerror(r) | |
289 | << dendl; | |
290 | delete m_object_map; | |
291 | ||
292 | finish(r); | |
293 | return; | |
294 | } | |
295 | ||
296 | { | |
9f95a23c | 297 | std::unique_lock image_locker{m_dst_image_ctx->image_lock}; |
11fdf7f2 TL |
298 | std::swap(m_dst_image_ctx->object_map, m_object_map); |
299 | } | |
9f95a23c | 300 | m_object_map->put(); |
11fdf7f2 TL |
301 | |
302 | send_copy_metadata(); | |
303 | } | |
304 | ||
305 | template <typename I> | |
306 | void DeepCopyRequest<I>::send_copy_metadata() { | |
307 | ldout(m_cct, 20) << dendl; | |
308 | ||
309 | Context *ctx = create_context_callback< | |
310 | DeepCopyRequest<I>, &DeepCopyRequest<I>::handle_copy_metadata>(this); | |
311 | auto request = MetadataCopyRequest<I>::create(m_src_image_ctx, | |
312 | m_dst_image_ctx, ctx); | |
313 | request->send(); | |
314 | } | |
315 | ||
316 | template <typename I> | |
317 | void DeepCopyRequest<I>::handle_copy_metadata(int r) { | |
318 | ldout(m_cct, 20) << "r=" << r << dendl; | |
319 | ||
320 | if (r < 0) { | |
321 | lderr(m_cct) << "failed to copy metadata: " << cpp_strerror(r) << dendl; | |
322 | finish(r); | |
323 | return; | |
324 | } | |
325 | ||
326 | finish(0); | |
327 | } | |
328 | ||
329 | template <typename I> | |
330 | int DeepCopyRequest<I>::validate_copy_points() { | |
9f95a23c | 331 | std::shared_lock image_locker{m_src_image_ctx->image_lock}; |
11fdf7f2 | 332 | |
9f95a23c TL |
333 | if (m_src_snap_id_start != 0 && |
334 | m_src_image_ctx->snap_info.find(m_src_snap_id_start) == | |
11fdf7f2 | 335 | m_src_image_ctx->snap_info.end()) { |
9f95a23c | 336 | lderr(m_cct) << "invalid start snap_id " << m_src_snap_id_start << dendl; |
11fdf7f2 TL |
337 | return -EINVAL; |
338 | } | |
339 | ||
9f95a23c TL |
340 | if (m_src_snap_id_end != CEPH_NOSNAP && |
341 | m_src_image_ctx->snap_info.find(m_src_snap_id_end) == | |
11fdf7f2 | 342 | m_src_image_ctx->snap_info.end()) { |
9f95a23c | 343 | lderr(m_cct) << "invalid end snap_id " << m_src_snap_id_end << dendl; |
11fdf7f2 TL |
344 | return -EINVAL; |
345 | } | |
346 | ||
347 | return 0; | |
348 | } | |
349 | ||
350 | template <typename I> | |
351 | void DeepCopyRequest<I>::finish(int r) { | |
352 | ldout(m_cct, 20) << "r=" << r << dendl; | |
353 | ||
354 | m_on_finish->complete(r); | |
355 | put(); | |
356 | } | |
357 | ||
358 | } // namespace librbd | |
359 | ||
360 | template class librbd::DeepCopyRequest<librbd::ImageCtx>; |