]>
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 "cls/rbd/cls_rbd_client.h" | |
5 | #include "cls/rbd/cls_rbd_types.h" | |
6 | #include "common/dout.h" | |
7 | #include "common/errno.h" | |
8 | #include "include/assert.h" | |
9 | #include "librbd/ImageState.h" | |
10 | #include "librbd/Journal.h" | |
11 | #include "librbd/image/CloneRequest.h" | |
12 | #include "librbd/image/CreateRequest.h" | |
13 | #include "librbd/image/RemoveRequest.h" | |
14 | #include "librbd/image/RefreshRequest.h" | |
15 | #include "librbd/mirror/EnableRequest.h" | |
16 | ||
17 | #define dout_subsys ceph_subsys_rbd | |
18 | #undef dout_prefix | |
19 | #define dout_prefix *_dout << "librbd::image::CloneRequest: " | |
20 | ||
b32b8144 FG |
21 | #define MAX_KEYS 64 |
22 | ||
7c673cae FG |
23 | namespace librbd { |
24 | namespace image { | |
25 | ||
26 | using util::create_rados_callback; | |
27 | using util::create_context_callback; | |
28 | using util::create_async_context_callback; | |
29 | ||
30 | template <typename I> | |
31 | CloneRequest<I>::CloneRequest(I *p_imctx, IoCtx &c_ioctx, | |
32 | const std::string &c_name, | |
33 | const std::string &c_id, | |
34 | ImageOptions c_options, | |
35 | const std::string &non_primary_global_image_id, | |
36 | const std::string &primary_mirror_uuid, | |
37 | ContextWQ *op_work_queue, Context *on_finish) | |
38 | : m_p_imctx(p_imctx), m_ioctx(c_ioctx), m_name(c_name), m_id(c_id), | |
39 | m_opts(c_options), | |
40 | m_pspec(m_p_imctx->md_ctx.get_id(), m_p_imctx->id, m_p_imctx->snap_id), | |
41 | m_non_primary_global_image_id(non_primary_global_image_id), | |
42 | m_primary_mirror_uuid(primary_mirror_uuid), | |
43 | m_op_work_queue(op_work_queue), m_on_finish(on_finish), | |
44 | m_use_p_features(true) { | |
45 | ||
46 | m_cct = reinterpret_cast<CephContext *>(m_ioctx.cct()); | |
47 | ||
48 | bool default_format_set; | |
49 | m_opts.is_set(RBD_IMAGE_OPTION_FORMAT, &default_format_set); | |
50 | if (!default_format_set) { | |
51 | m_opts.set(RBD_IMAGE_OPTION_FORMAT, static_cast<uint64_t>(2)); | |
52 | } | |
53 | ||
54 | ldout(m_cct, 20) << "clone " << &m_p_imctx->md_ctx << " name " << m_p_imctx->name | |
55 | << " snap " << m_p_imctx->snap_name << " to child " << &m_ioctx | |
56 | << " name " << m_name << " opts = " << &m_opts << dendl; | |
57 | return; | |
58 | } | |
59 | ||
60 | template <typename I> | |
61 | void CloneRequest<I>::send() { | |
62 | ldout(m_cct, 20) << this << " " << __func__ << dendl; | |
63 | validate_options(); | |
64 | } | |
65 | ||
66 | template <typename I> | |
67 | void CloneRequest<I>::validate_options() { | |
68 | ldout(m_cct, 20) << this << " " << __func__ << dendl; | |
69 | ||
70 | uint64_t format = 0; | |
71 | m_opts.get(RBD_IMAGE_OPTION_FORMAT, &format); | |
72 | if (format < 2) { | |
73 | lderr(m_cct) << "format 2 or later required for clone" << dendl; | |
74 | return complete(-EINVAL); | |
75 | } | |
76 | ||
77 | if (m_opts.get(RBD_IMAGE_OPTION_FEATURES, &m_features) == 0) { | |
78 | if (m_features & ~RBD_FEATURES_ALL) { | |
79 | lderr(m_cct) << "librbd does not support requested features" << dendl; | |
80 | return complete(-ENOSYS); | |
81 | } | |
82 | m_use_p_features = false; | |
83 | } | |
84 | ||
85 | send_validate_parent(); | |
86 | } | |
87 | ||
88 | template <typename I> | |
89 | void CloneRequest<I>::send_validate_parent() { | |
90 | ldout(m_cct, 20) << this << " " << __func__ << dendl; | |
91 | ||
92 | if (m_p_imctx->snap_id == CEPH_NOSNAP) { | |
93 | lderr(m_cct) << "image to be cloned must be a snapshot" << dendl; | |
94 | return complete(-EINVAL); | |
95 | } | |
96 | ||
97 | if (m_p_imctx->old_format) { | |
98 | lderr(m_cct) << "parent image must be in new format" << dendl; | |
99 | return complete(-EINVAL); | |
100 | } | |
101 | ||
102 | int r = 0; | |
103 | bool snap_protected; | |
104 | m_p_imctx->snap_lock.get_read(); | |
105 | m_p_features = m_p_imctx->features; | |
106 | m_size = m_p_imctx->get_image_size(m_p_imctx->snap_id); | |
107 | r = m_p_imctx->is_snap_protected(m_p_imctx->snap_id, &snap_protected); | |
108 | m_p_imctx->snap_lock.put_read(); | |
109 | ||
110 | if ((m_p_features & RBD_FEATURE_LAYERING) != RBD_FEATURE_LAYERING) { | |
111 | lderr(m_cct) << "parent image must support layering" << dendl; | |
112 | return complete(-ENOSYS); | |
113 | } | |
114 | ||
115 | if (r < 0) { | |
116 | lderr(m_cct) << "unable to locate parent's snapshot" << dendl; | |
117 | return complete(r); | |
118 | } | |
119 | ||
120 | if (!snap_protected) { | |
121 | lderr(m_cct) << "parent snapshot must be protected" << dendl; | |
122 | return complete(-EINVAL); | |
123 | } | |
124 | ||
125 | if ((m_p_features & RBD_FEATURE_JOURNALING) != 0) { | |
126 | m_force_non_primary = !m_non_primary_global_image_id.empty(); | |
127 | using klass = CloneRequest<I>; | |
128 | Context *ctx = create_context_callback< | |
129 | klass, &klass::handle_validate_parent>(this); | |
130 | ||
131 | Journal<I>::is_tag_owner(m_p_imctx, &m_is_primary, ctx); | |
132 | return; | |
133 | } | |
134 | ||
135 | send_validate_child(); | |
136 | } | |
137 | ||
138 | template <typename I> | |
139 | void CloneRequest<I>::handle_validate_parent(int r) { | |
140 | ldout(m_cct, 20) << this << " " << __func__ << " r=" << r << dendl; | |
141 | ||
142 | if (r < 0) { | |
143 | lderr(m_cct) << "failed to determine tag ownership: " << cpp_strerror(r) | |
144 | << dendl; | |
145 | return complete(r); | |
146 | } | |
147 | ||
148 | if ((m_p_features & RBD_FEATURE_JOURNALING) != 0) { | |
149 | if (!m_is_primary && !m_force_non_primary) { | |
150 | lderr(m_cct) << "parent is non-primary mirrored image" << dendl; | |
151 | return complete(-EINVAL); | |
152 | } | |
153 | } | |
154 | ||
155 | send_validate_child(); | |
156 | } | |
157 | ||
158 | template <typename I> | |
159 | void CloneRequest<I>::send_validate_child() { | |
160 | ldout(m_cct, 20) << this << " " << __func__ << dendl; | |
161 | ||
162 | using klass = CloneRequest<I>; | |
163 | librados::AioCompletion *comp = create_rados_callback<klass, &klass::handle_validate_child>(this); | |
164 | ||
165 | librados::ObjectReadOperation op; | |
166 | op.stat(NULL, NULL, NULL); | |
167 | ||
168 | int r = m_ioctx.aio_operate(util::old_header_name(m_name), comp, &op, &m_out_bl); | |
169 | assert(r == 0); | |
170 | comp->release(); | |
171 | } | |
172 | ||
173 | template <typename I> | |
174 | void CloneRequest<I>::handle_validate_child(int r) { | |
175 | ldout(m_cct, 20) << this << " " << __func__ << " r=" << r << dendl; | |
176 | ||
177 | if (r != -ENOENT) { | |
178 | lderr(m_cct) << "rbd image " << m_name << " already exists" << dendl; | |
179 | return complete(r); | |
180 | } | |
181 | ||
182 | send_create(); | |
183 | } | |
184 | ||
185 | template <typename I> | |
186 | void CloneRequest<I>::send_create() { | |
187 | ldout(m_cct, 20) << this << " " << __func__ << dendl; | |
188 | ||
189 | if (m_use_p_features) { | |
190 | m_features = m_p_features; | |
191 | } | |
192 | ||
193 | uint64_t order = m_p_imctx->order; | |
194 | if (m_opts.get(RBD_IMAGE_OPTION_ORDER, &order) != 0) { | |
195 | m_opts.set(RBD_IMAGE_OPTION_ORDER, order); | |
196 | } | |
197 | if ((m_features & RBD_FEATURE_LAYERING) != RBD_FEATURE_LAYERING) { | |
198 | lderr(m_cct) << "cloning image must support layering" << dendl; | |
199 | return complete(-ENOSYS); | |
200 | } | |
201 | m_opts.set(RBD_IMAGE_OPTION_FEATURES, m_features); | |
202 | ||
203 | using klass = CloneRequest<I>; | |
204 | Context *ctx = create_context_callback<klass, &klass::handle_create>(this); | |
205 | ||
206 | RWLock::RLocker snap_locker(m_p_imctx->snap_lock); | |
207 | CreateRequest<I> *req = CreateRequest<I>::create( | |
208 | m_ioctx, m_name, m_id, m_size, m_opts, m_non_primary_global_image_id, | |
209 | m_primary_mirror_uuid, true, m_op_work_queue, ctx); | |
210 | req->send(); | |
211 | } | |
212 | ||
213 | template <typename I> | |
214 | void CloneRequest<I>::handle_create(int r) { | |
215 | ldout(m_cct, 20) << this << " " << __func__ << " r=" << r << dendl; | |
216 | ||
217 | if (r < 0) { | |
218 | lderr(m_cct) << "error creating child: " << cpp_strerror(r) << dendl; | |
219 | return complete(r); | |
220 | } | |
221 | send_open(); | |
222 | } | |
223 | ||
224 | template <typename I> | |
225 | void CloneRequest<I>::send_open() { | |
226 | ldout(m_cct, 20) << this << " " << __func__ << dendl; | |
227 | ||
228 | m_imctx = I::create(m_name, "", NULL, m_ioctx, false); | |
229 | ||
230 | using klass = CloneRequest<I>; | |
231 | Context *ctx = create_context_callback<klass, &klass::handle_open>(this); | |
232 | ||
233 | m_imctx->state->open(true, ctx); | |
234 | } | |
235 | ||
236 | template <typename I> | |
237 | void CloneRequest<I>::handle_open(int r) { | |
238 | ldout(m_cct, 20) << this << " " << __func__ << " r=" << r << dendl; | |
239 | ||
240 | if (r < 0) { | |
241 | lderr(m_cct) << "Error opening new image: " << cpp_strerror(r) << dendl; | |
242 | m_r_saved = r; | |
243 | return send_remove(); | |
244 | } | |
245 | ||
246 | send_set_parent(); | |
247 | } | |
248 | ||
249 | template <typename I> | |
250 | void CloneRequest<I>::send_set_parent() { | |
251 | ldout(m_cct, 20) << this << " " << __func__ << dendl; | |
252 | ||
253 | librados::ObjectWriteOperation op; | |
254 | librbd::cls_client::set_parent(&op, m_pspec, m_size); | |
255 | ||
256 | using klass = CloneRequest<I>; | |
257 | librados::AioCompletion *comp = | |
258 | create_rados_callback<klass, &klass::handle_set_parent>(this); | |
259 | int r = m_imctx->md_ctx.aio_operate(m_imctx->header_oid, | |
260 | comp, &op); | |
261 | assert(r == 0); | |
262 | comp->release(); | |
263 | } | |
264 | ||
265 | template <typename I> | |
266 | void CloneRequest<I>::handle_set_parent(int r) { | |
267 | ldout(m_cct, 20) << this << " " << __func__ << " r=" << r << dendl; | |
268 | ||
269 | if (r < 0) { | |
270 | lderr(m_cct) << "couldn't set parent: " << cpp_strerror(r) << dendl; | |
271 | m_r_saved = r; | |
272 | return send_close(); | |
273 | } | |
274 | ||
275 | send_add_child(); | |
276 | } | |
277 | ||
278 | template <typename I> | |
279 | void CloneRequest<I>::send_add_child() { | |
280 | ldout(m_cct, 20) << this << " " << __func__ << dendl; | |
281 | ||
282 | librados::ObjectWriteOperation op; | |
283 | cls_client::add_child(&op, m_pspec, m_id); | |
284 | ||
285 | using klass = CloneRequest<I>; | |
286 | librados::AioCompletion *comp = | |
287 | create_rados_callback<klass, &klass::handle_add_child>(this); | |
288 | int r = m_ioctx.aio_operate(RBD_CHILDREN, comp, &op); | |
289 | assert(r == 0); | |
290 | comp->release(); | |
291 | } | |
292 | ||
293 | template <typename I> | |
294 | void CloneRequest<I>::handle_add_child(int r) { | |
295 | ldout(m_cct, 20) << this << " " << __func__ << " r=" << r << dendl; | |
296 | ||
297 | if (r < 0) { | |
298 | lderr(m_cct) << "couldn't add child: " << cpp_strerror(r) << dendl; | |
299 | m_r_saved = r; | |
300 | return send_close(); | |
301 | } | |
302 | ||
303 | send_refresh(); | |
304 | } | |
305 | ||
306 | template <typename I> | |
307 | void CloneRequest<I>::send_refresh() { | |
308 | ldout(m_cct, 20) << this << " " << __func__ << dendl; | |
309 | ||
310 | using klass = CloneRequest<I>; | |
311 | RefreshRequest<I> *req = RefreshRequest<I>::create( | |
312 | *m_imctx, false, false, | |
313 | create_context_callback<klass, &klass::handle_refresh>(this)); | |
314 | req->send(); | |
315 | } | |
316 | ||
317 | template <typename I> | |
318 | void CloneRequest<I>::handle_refresh(int r) { | |
319 | ldout(m_cct, 20) << this << " " << __func__ << " r=" << r << dendl; | |
320 | ||
d2e6a577 | 321 | bool snap_protected = false; |
7c673cae FG |
322 | if (r == 0) { |
323 | m_p_imctx->snap_lock.get_read(); | |
324 | r = m_p_imctx->is_snap_protected(m_p_imctx->snap_id, &snap_protected); | |
325 | m_p_imctx->snap_lock.put_read(); | |
326 | } | |
327 | ||
328 | if (r < 0 || !snap_protected) { | |
329 | m_r_saved = -EINVAL; | |
330 | return send_close(); | |
331 | } | |
332 | ||
333 | send_metadata_list(); | |
334 | } | |
335 | ||
336 | template <typename I> | |
337 | void CloneRequest<I>::send_metadata_list() { | |
b32b8144 FG |
338 | ldout(m_cct, 20) << this << " " << __func__ << ": " |
339 | << "start_key=" << m_last_metadata_key << dendl; | |
7c673cae FG |
340 | |
341 | librados::ObjectReadOperation op; | |
b32b8144 | 342 | cls_client::metadata_list_start(&op, m_last_metadata_key, 0); |
7c673cae FG |
343 | |
344 | using klass = CloneRequest<I>; | |
345 | librados::AioCompletion *comp = | |
346 | create_rados_callback<klass, &klass::handle_metadata_list>(this); | |
347 | m_out_bl.clear(); | |
348 | m_p_imctx->md_ctx.aio_operate(m_p_imctx->header_oid, | |
349 | comp, &op, &m_out_bl); | |
350 | comp->release(); | |
351 | } | |
352 | ||
353 | template <typename I> | |
354 | void CloneRequest<I>::handle_metadata_list(int r) { | |
355 | ldout(m_cct, 20) << this << " " << __func__ << " r=" << r << dendl; | |
356 | ||
b32b8144 | 357 | map<string, bufferlist> metadata; |
7c673cae FG |
358 | if (r == 0) { |
359 | bufferlist::iterator it = m_out_bl.begin(); | |
b32b8144 | 360 | r = cls_client::metadata_list_finish(&it, &metadata); |
7c673cae FG |
361 | } |
362 | ||
b32b8144 FG |
363 | if (r < 0) { |
364 | if (r == -EOPNOTSUPP || r == -EIO) { | |
365 | ldout(m_cct, 10) << "config metadata not supported by OSD" << dendl; | |
366 | get_mirror_mode(); | |
367 | } else { | |
368 | lderr(m_cct) << "couldn't list metadata: " << cpp_strerror(r) << dendl; | |
369 | m_r_saved = r; | |
370 | send_remove_child(); | |
371 | } | |
372 | ||
373 | return; | |
374 | } | |
375 | ||
376 | if (!metadata.empty()) { | |
377 | m_pairs.insert(metadata.begin(), metadata.end()); | |
378 | m_last_metadata_key = m_pairs.rbegin()->first; | |
379 | } | |
380 | ||
381 | if (metadata.size() == MAX_KEYS) { | |
382 | send_metadata_list(); | |
7c673cae | 383 | } else { |
b32b8144 | 384 | send_metadata_set(); |
7c673cae FG |
385 | } |
386 | } | |
387 | ||
388 | template <typename I> | |
389 | void CloneRequest<I>::send_metadata_set() { | |
390 | ldout(m_cct, 20) << this << " " << __func__ << dendl; | |
391 | ||
392 | librados::ObjectWriteOperation op; | |
393 | cls_client::metadata_set(&op, m_pairs); | |
394 | ||
395 | using klass = CloneRequest<I>; | |
396 | librados::AioCompletion *comp = | |
397 | create_rados_callback<klass, &klass::handle_metadata_set>(this); | |
398 | int r = m_ioctx.aio_operate(m_imctx->header_oid, comp, &op); | |
399 | assert(r == 0); | |
400 | comp->release(); | |
401 | } | |
402 | ||
403 | template <typename I> | |
404 | void CloneRequest<I>::handle_metadata_set(int r) { | |
405 | ldout(m_cct, 20) << this << " " << __func__ << " r=" << r << dendl; | |
406 | ||
407 | if (r < 0) { | |
408 | lderr(m_cct) << "couldn't set metadata: " << cpp_strerror(r) << dendl; | |
409 | m_r_saved = r; | |
410 | send_remove_child(); | |
411 | } else { | |
412 | get_mirror_mode(); | |
413 | } | |
414 | } | |
415 | ||
416 | template <typename I> | |
417 | void CloneRequest<I>::get_mirror_mode() { | |
418 | ldout(m_cct, 20) << this << " " << __func__ << dendl; | |
419 | ||
420 | if (!m_imctx->test_features(RBD_FEATURE_JOURNALING)) { | |
421 | send_close(); | |
422 | return; | |
423 | } | |
424 | ||
425 | librados::ObjectReadOperation op; | |
426 | cls_client::mirror_mode_get_start(&op); | |
427 | ||
428 | using klass = CloneRequest<I>; | |
429 | librados::AioCompletion *comp = | |
430 | create_rados_callback<klass, &klass::handle_get_mirror_mode>(this); | |
431 | m_out_bl.clear(); | |
432 | m_imctx->md_ctx.aio_operate(RBD_MIRRORING, | |
433 | comp, &op, &m_out_bl); | |
434 | comp->release(); | |
435 | } | |
436 | ||
437 | template <typename I> | |
438 | void CloneRequest<I>::handle_get_mirror_mode(int r) { | |
439 | ldout(m_cct, 20) << this << " " << __func__ << " r=" << r << dendl; | |
440 | ||
441 | if (r == 0) { | |
7c673cae FG |
442 | bufferlist::iterator it = m_out_bl.begin(); |
443 | r = cls_client::mirror_mode_get_finish(&it, &m_mirror_mode); | |
444 | } | |
445 | ||
446 | if (r < 0 && r != -ENOENT) { | |
c07f9fc5 FG |
447 | lderr(m_cct) << "failed to retrieve mirror mode: " << cpp_strerror(r) |
448 | << dendl; | |
449 | ||
7c673cae FG |
450 | m_r_saved = r; |
451 | send_remove_child(); | |
452 | } else { | |
453 | if (m_mirror_mode == cls::rbd::MIRROR_MODE_POOL || | |
454 | !m_non_primary_global_image_id.empty()) { | |
455 | send_enable_mirror(); | |
456 | } else { | |
457 | send_close(); | |
458 | } | |
459 | } | |
460 | } | |
461 | ||
462 | template <typename I> | |
463 | void CloneRequest<I>::send_enable_mirror() { | |
464 | ldout(m_cct, 20) << this << " " << __func__ << dendl; | |
465 | ||
466 | using klass = CloneRequest<I>; | |
467 | Context *ctx = create_context_callback<klass, &klass::handle_enable_mirror>(this); | |
468 | ||
469 | mirror::EnableRequest<I> *req = mirror::EnableRequest<I>::create( | |
470 | m_imctx->md_ctx, m_id, m_non_primary_global_image_id, | |
471 | m_imctx->op_work_queue, ctx); | |
472 | req->send(); | |
473 | } | |
474 | ||
475 | template <typename I> | |
476 | void CloneRequest<I>::handle_enable_mirror(int r) { | |
477 | ldout(m_cct, 20) << this << " " << __func__ << " r=" << r << dendl; | |
478 | ||
479 | if (r < 0) { | |
480 | lderr(m_cct) << "failed to enable mirroring: " << cpp_strerror(r) | |
481 | << dendl; | |
482 | m_r_saved = r; | |
483 | send_remove_child(); | |
484 | } else { | |
485 | send_close(); | |
486 | } | |
487 | } | |
488 | ||
489 | template <typename I> | |
490 | void CloneRequest<I>::send_close() { | |
491 | ldout(m_cct, 20) << this << " " << __func__ << dendl; | |
492 | ||
493 | assert(m_imctx != nullptr); | |
494 | ||
495 | using klass = CloneRequest<I>; | |
496 | Context *ctx = create_async_context_callback( | |
497 | *m_imctx, create_context_callback< | |
498 | klass, &klass::handle_close>(this)); | |
499 | m_imctx->state->close(ctx); | |
500 | } | |
501 | ||
502 | template <typename I> | |
503 | void CloneRequest<I>::handle_close(int r) { | |
504 | ldout(m_cct, 20) << this << " " << __func__ << dendl; | |
505 | ||
506 | m_imctx->destroy(); | |
507 | m_imctx = nullptr; | |
508 | ||
509 | if (r < 0) { | |
510 | lderr(m_cct) << "couldn't close image: " << cpp_strerror(r) << dendl; | |
511 | return complete(r); | |
512 | } | |
513 | ||
514 | if (m_r_saved == 0) { | |
515 | complete(0); | |
516 | } else { | |
517 | send_remove(); | |
518 | } | |
519 | } | |
520 | ||
521 | template <typename I> | |
522 | void CloneRequest<I>::send_remove_child() { | |
523 | ldout(m_cct, 20) << this << " " << __func__ << dendl; | |
524 | ||
525 | librados::ObjectWriteOperation op; | |
526 | cls_client::remove_child(&op, m_pspec, m_id); | |
527 | ||
528 | using klass = CloneRequest<I>; | |
529 | librados::AioCompletion *comp = | |
530 | create_rados_callback<klass, &klass::handle_remove_child>(this); | |
531 | int r = m_p_imctx->md_ctx.aio_operate(RBD_CHILDREN, comp, &op); | |
532 | assert(r == 0); | |
533 | comp->release(); | |
534 | } | |
535 | ||
536 | template <typename I> | |
537 | void CloneRequest<I>::handle_remove_child(int r) { | |
538 | ldout(m_cct, 20) << this << " " << __func__ << " r=" << r << dendl; | |
539 | ||
540 | if (r < 0) { | |
541 | lderr(m_cct) << "Error removing failed clone from list of children: " | |
542 | << cpp_strerror(r) << dendl; | |
543 | } | |
544 | ||
545 | send_close(); | |
546 | } | |
547 | ||
548 | template <typename I> | |
549 | void CloneRequest<I>::send_remove() { | |
550 | ldout(m_cct, 20) << this << " " << __func__ << dendl; | |
551 | ||
552 | using klass = CloneRequest<I>; | |
553 | Context *ctx = create_context_callback<klass, &klass::handle_remove>(this); | |
554 | ||
555 | librbd::image::RemoveRequest<> *req = librbd::image::RemoveRequest<>::create( | |
556 | m_ioctx, m_name, m_id, false, false, m_no_op, m_op_work_queue, ctx); | |
557 | req->send(); | |
558 | } | |
559 | ||
560 | template <typename I> | |
561 | void CloneRequest<I>::handle_remove(int r) { | |
562 | ldout(m_cct, 20) << this << " " << __func__ << " r=" << r << dendl; | |
563 | ||
564 | if (r < 0) { | |
565 | lderr(m_cct) << "Error removing failed clone: " | |
566 | << cpp_strerror(r) << dendl; | |
567 | } | |
568 | complete(r); | |
569 | } | |
570 | ||
571 | template <typename I> | |
572 | void CloneRequest<I>::complete(int r) { | |
573 | ldout(m_cct, 20) << this << " " << __func__ << " r=" << r << dendl; | |
574 | ||
575 | if (r == 0) { | |
576 | ldout(m_cct, 20) << "done." << dendl; | |
577 | } | |
578 | ||
579 | m_on_finish->complete(r); | |
580 | delete this; | |
581 | } | |
582 | ||
583 | } //namespace image | |
584 | } //namespace librbd | |
585 | ||
586 | template class librbd::image::CloneRequest<librbd::ImageCtx>; |