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