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