]> git.proxmox.com Git - ceph.git/blame - ceph/src/librbd/image/CloneRequest.cc
update sources to v12.2.3
[ceph.git] / ceph / src / librbd / image / CloneRequest.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 "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
23namespace librbd {
24namespace image {
25
26using util::create_rados_callback;
27using util::create_context_callback;
28using util::create_async_context_callback;
29
30template <typename I>
31CloneRequest<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
60template <typename I>
61void CloneRequest<I>::send() {
62 ldout(m_cct, 20) << this << " " << __func__ << dendl;
63 validate_options();
64}
65
66template <typename I>
67void 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
88template <typename I>
89void 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
138template <typename I>
139void 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
158template <typename I>
159void 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
173template <typename I>
174void 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
185template <typename I>
186void 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
213template <typename I>
214void 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
224template <typename I>
225void 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
236template <typename I>
237void 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
249template <typename I>
250void 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
265template <typename I>
266void 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
278template <typename I>
279void 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
293template <typename I>
294void 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
306template <typename I>
307void 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
317template <typename I>
318void 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
336template <typename I>
337void 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
353template <typename I>
354void 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
388template <typename I>
389void 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
403template <typename I>
404void 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
416template <typename I>
417void 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
437template <typename I>
438void 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
462template <typename I>
463void 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
475template <typename I>
476void 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
489template <typename I>
490void 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
502template <typename I>
503void 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
521template <typename I>
522void 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
536template <typename I>
537void 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
548template <typename I>
549void 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
560template <typename I>
561void 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
571template <typename I>
572void 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
586template class librbd::image::CloneRequest<librbd::ImageCtx>;