1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
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/ceph_assert.h"
9 #include "librbd/ImageState.h"
10 #include "librbd/Utils.h"
11 #include "librbd/image/AttachChildRequest.h"
12 #include "librbd/image/AttachParentRequest.h"
13 #include "librbd/image/CloneRequest.h"
14 #include "librbd/image/CreateRequest.h"
15 #include "librbd/image/RemoveRequest.h"
16 #include "librbd/mirror/EnableRequest.h"
18 #define dout_subsys ceph_subsys_rbd
20 #define dout_prefix *_dout << "librbd::image::CloneRequest: " << this << " " \
28 using util::create_rados_callback
;
29 using util::create_context_callback
;
30 using util::create_async_context_callback
;
33 CloneRequest
<I
>::CloneRequest(ConfigProxy
& config
,
35 const std::string
& parent_image_id
,
36 const std::string
& parent_snap_name
,
37 uint64_t parent_snap_id
,
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
)
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
),
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) {
54 m_cct
= reinterpret_cast<CephContext
*>(m_ioctx
.cct());
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));
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
;
72 void CloneRequest
<I
>::send() {
73 ldout(m_cct
, 20) << dendl
;
78 void CloneRequest
<I
>::validate_options() {
79 ldout(m_cct
, 20) << dendl
;
82 m_opts
.get(RBD_IMAGE_OPTION_FORMAT
, &format
);
84 lderr(m_cct
) << "format 2 or later required for clone" << dendl
;
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
;
95 m_use_p_features
= false;
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") {
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
);
113 if (std::max(min_compat_client
, require_min_compat_client
) <
114 CEPH_RELEASE_MIMIC
) {
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
;
130 template <typename I
>
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
));
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);
139 m_parent_image_ctx
= I::create("", m_parent_image_id
,
140 m_parent_snap_name
.c_str(), m_parent_io_ctx
,
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
);
149 template <typename I
>
150 void CloneRequest
<I
>::handle_open_parent(int r
) {
151 ldout(m_cct
, 20) << "r=" << r
<< dendl
;
154 m_parent_image_ctx
->destroy();
155 m_parent_image_ctx
= nullptr;
157 lderr(m_cct
) << "failed to open parent image: " << cpp_strerror(r
) << dendl
;
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
};
168 template <typename I
>
169 void CloneRequest
<I
>::validate_parent() {
170 ldout(m_cct
, 20) << dendl
;
172 if (m_parent_image_ctx
->operations_disabled
) {
173 lderr(m_cct
) << "image operations disabled due to unsupported op features"
180 if (m_parent_image_ctx
->snap_id
== CEPH_NOSNAP
) {
181 lderr(m_cct
) << "image to be cloned must be a snapshot" << dendl
;
187 if (m_parent_image_ctx
->old_format
) {
188 lderr(m_cct
) << "parent image must be in new format" << dendl
;
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
);
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();
202 if ((p_features
& RBD_FEATURE_LAYERING
) != RBD_FEATURE_LAYERING
) {
203 lderr(m_cct
) << "parent image must support layering" << dendl
;
208 if (m_use_p_features
) {
209 m_features
= (p_features
& ~RBD_FEATURES_IMPLICIT_ENABLE
);
213 lderr(m_cct
) << "unable to locate parent's snapshot" << dendl
;
219 if (m_clone_format
== 1 && !snap_protected
) {
220 lderr(m_cct
) << "parent snapshot must be protected" << dendl
;
229 template <typename I
>
230 void CloneRequest
<I
>::validate_child() {
231 ldout(m_cct
, 15) << dendl
;
233 if ((m_features
& RBD_FEATURE_LAYERING
) != RBD_FEATURE_LAYERING
) {
234 lderr(m_cct
) << "cloning image must support layering" << dendl
;
240 using klass
= CloneRequest
<I
>;
241 librados::AioCompletion
*comp
= create_rados_callback
<
242 klass
, &klass::handle_validate_child
>(this);
244 librados::ObjectReadOperation op
;
245 op
.stat(NULL
, NULL
, NULL
);
247 int r
= m_ioctx
.aio_operate(util::old_header_name(m_name
), comp
, &op
,
253 template <typename I
>
254 void CloneRequest
<I
>::handle_validate_child(int r
) {
255 ldout(m_cct
, 15) << "r=" << r
<< dendl
;
258 lderr(m_cct
) << "rbd image " << m_name
<< " already exists" << dendl
;
267 template <typename I
>
268 void CloneRequest
<I
>::create_child() {
269 ldout(m_cct
, 15) << dendl
;
271 uint64_t order
= m_parent_image_ctx
->order
;
272 if (m_opts
.get(RBD_IMAGE_OPTION_ORDER
, &order
) != 0) {
273 m_opts
.set(RBD_IMAGE_OPTION_ORDER
, order
);
275 m_opts
.set(RBD_IMAGE_OPTION_FEATURES
, m_features
);
277 using klass
= CloneRequest
<I
>;
278 Context
*ctx
= create_context_callback
<
279 klass
, &klass::handle_create_child
>(this);
281 RWLock::RLocker
snap_locker(m_parent_image_ctx
->snap_lock
);
282 CreateRequest
<I
> *req
= CreateRequest
<I
>::create(
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
);
289 template <typename I
>
290 void CloneRequest
<I
>::handle_create_child(int r
) {
291 ldout(m_cct
, 15) << "r=" << r
<< dendl
;
294 ldout(m_cct
, 5) << "image id already in-use" << dendl
;
298 lderr(m_cct
) << "error creating child: " << cpp_strerror(r
) << dendl
;
306 template <typename I
>
307 void CloneRequest
<I
>::open_child() {
308 ldout(m_cct
, 15) << dendl
;
310 m_imctx
= I::create(m_name
, "", nullptr, m_ioctx
, false);
312 using klass
= CloneRequest
<I
>;
313 Context
*ctx
= create_context_callback
<
314 klass
, &klass::handle_open_child
>(this);
316 uint64_t flags
= OPEN_FLAG_SKIP_OPEN_PARENT
;
317 if ((m_features
& RBD_FEATURE_MIGRATING
) != 0) {
318 flags
|= OPEN_FLAG_IGNORE_MIGRATING
;
321 m_imctx
->state
->open(flags
, ctx
);
324 template <typename I
>
325 void CloneRequest
<I
>::handle_open_child(int r
) {
326 ldout(m_cct
, 15) << "r=" << r
<< dendl
;
332 lderr(m_cct
) << "Error opening new image: " << cpp_strerror(r
) << dendl
;
341 template <typename I
>
342 void CloneRequest
<I
>::attach_parent() {
343 ldout(m_cct
, 15) << dendl
;
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
);
352 template <typename I
>
353 void CloneRequest
<I
>::handle_attach_parent(int r
) {
354 ldout(m_cct
, 15) << "r=" << r
<< dendl
;
357 lderr(m_cct
) << "failed to attach parent: " << cpp_strerror(r
) << dendl
;
366 template <typename I
>
367 void CloneRequest
<I
>::attach_child() {
368 ldout(m_cct
, 15) << dendl
;
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
);
378 template <typename I
>
379 void CloneRequest
<I
>::handle_attach_child(int r
) {
380 ldout(m_cct
, 15) << "r=" << r
<< dendl
;
383 lderr(m_cct
) << "failed to attach parent: " << cpp_strerror(r
) << dendl
;
392 template <typename I
>
393 void CloneRequest
<I
>::metadata_list() {
394 ldout(m_cct
, 15) << "start_key=" << m_last_metadata_key
<< dendl
;
396 librados::ObjectReadOperation op
;
397 cls_client::metadata_list_start(&op
, m_last_metadata_key
, 0);
399 using klass
= CloneRequest
<I
>;
400 librados::AioCompletion
*comp
=
401 create_rados_callback
<klass
, &klass::handle_metadata_list
>(this);
403 m_parent_image_ctx
->md_ctx
.aio_operate(m_parent_image_ctx
->header_oid
,
404 comp
, &op
, &m_out_bl
);
408 template <typename I
>
409 void CloneRequest
<I
>::handle_metadata_list(int r
) {
410 ldout(m_cct
, 15) << "r=" << r
<< dendl
;
412 map
<string
, bufferlist
> metadata
;
414 auto it
= m_out_bl
.cbegin();
415 r
= cls_client::metadata_list_finish(&it
, &metadata
);
419 if (r
== -EOPNOTSUPP
|| r
== -EIO
) {
420 ldout(m_cct
, 10) << "config metadata not supported by OSD" << dendl
;
423 lderr(m_cct
) << "couldn't list metadata: " << cpp_strerror(r
) << dendl
;
430 if (!metadata
.empty()) {
431 m_pairs
.insert(metadata
.begin(), metadata
.end());
432 m_last_metadata_key
= m_pairs
.rbegin()->first
;
435 if (metadata
.size() == MAX_KEYS
) {
442 template <typename I
>
443 void CloneRequest
<I
>::metadata_set() {
444 if (m_pairs
.empty()) {
449 ldout(m_cct
, 15) << dendl
;
451 librados::ObjectWriteOperation op
;
452 cls_client::metadata_set(&op
, m_pairs
);
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
);
462 template <typename I
>
463 void CloneRequest
<I
>::handle_metadata_set(int r
) {
464 ldout(m_cct
, 15) << "r=" << r
<< dendl
;
467 lderr(m_cct
) << "couldn't set metadata: " << cpp_strerror(r
) << dendl
;
475 template <typename I
>
476 void CloneRequest
<I
>::get_mirror_mode() {
477 ldout(m_cct
, 15) << dendl
;
479 if (!m_imctx
->test_features(RBD_FEATURE_JOURNALING
)) {
484 librados::ObjectReadOperation op
;
485 cls_client::mirror_mode_get_start(&op
);
487 using klass
= CloneRequest
<I
>;
488 librados::AioCompletion
*comp
=
489 create_rados_callback
<klass
, &klass::handle_get_mirror_mode
>(this);
491 m_imctx
->md_ctx
.aio_operate(RBD_MIRRORING
,
492 comp
, &op
, &m_out_bl
);
496 template <typename I
>
497 void CloneRequest
<I
>::handle_get_mirror_mode(int r
) {
498 ldout(m_cct
, 15) << "r=" << r
<< dendl
;
501 auto it
= m_out_bl
.cbegin();
502 r
= cls_client::mirror_mode_get_finish(&it
, &m_mirror_mode
);
505 if (r
< 0 && r
!= -ENOENT
) {
506 lderr(m_cct
) << "failed to retrieve mirror mode: " << cpp_strerror(r
)
512 if (m_mirror_mode
== cls::rbd::MIRROR_MODE_POOL
||
513 !m_non_primary_global_image_id
.empty()) {
521 template <typename I
>
522 void CloneRequest
<I
>::enable_mirror() {
523 ldout(m_cct
, 15) << dendl
;
525 using klass
= CloneRequest
<I
>;
526 Context
*ctx
= create_context_callback
<
527 klass
, &klass::handle_enable_mirror
>(this);
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
);
535 template <typename I
>
536 void CloneRequest
<I
>::handle_enable_mirror(int r
) {
537 ldout(m_cct
, 15) << "r=" << r
<< dendl
;
540 lderr(m_cct
) << "failed to enable mirroring: " << cpp_strerror(r
)
547 template <typename I
>
548 void CloneRequest
<I
>::close_child() {
549 ldout(m_cct
, 15) << dendl
;
551 ceph_assert(m_imctx
!= nullptr);
553 using klass
= CloneRequest
<I
>;
554 Context
*ctx
= create_async_context_callback(
555 *m_imctx
, create_context_callback
<
556 klass
, &klass::handle_close_child
>(this));
557 m_imctx
->state
->close(ctx
);
560 template <typename I
>
561 void CloneRequest
<I
>::handle_close_child(int r
) {
562 ldout(m_cct
, 15) << dendl
;
568 lderr(m_cct
) << "couldn't close image: " << cpp_strerror(r
) << dendl
;
569 if (m_r_saved
== 0) {
582 template <typename I
>
583 void CloneRequest
<I
>::remove_child() {
584 ldout(m_cct
, 15) << dendl
;
586 using klass
= CloneRequest
<I
>;
587 Context
*ctx
= create_context_callback
<
588 klass
, &klass::handle_remove_child
>(this);
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
);
595 template <typename I
>
596 void CloneRequest
<I
>::handle_remove_child(int r
) {
597 ldout(m_cct
, 15) << "r=" << r
<< dendl
;
600 lderr(m_cct
) << "Error removing failed clone: "
601 << cpp_strerror(r
) << dendl
;
607 template <typename I
>
608 void CloneRequest
<I
>::close_parent() {
609 ldout(m_cct
, 20) << dendl
;
610 ceph_assert(m_parent_image_ctx
!= nullptr);
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
);
618 template <typename I
>
619 void CloneRequest
<I
>::handle_close_parent(int r
) {
620 ldout(m_cct
, 20) << "r=" << r
<< dendl
;
622 m_parent_image_ctx
->destroy();
623 m_parent_image_ctx
= nullptr;
626 lderr(m_cct
) << "failed to close parent image: "
627 << cpp_strerror(r
) << dendl
;
628 if (m_r_saved
== 0) {
636 template <typename I
>
637 void CloneRequest
<I
>::complete(int r
) {
638 ldout(m_cct
, 15) << "r=" << r
<< dendl
;
640 m_on_finish
->complete(r
);
647 template class librbd::image::CloneRequest
<librbd::ImageCtx
>;