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/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"
17 #define dout_subsys ceph_subsys_rbd
19 #define dout_prefix *_dout << "librbd::image::CloneRequest: "
26 using util::create_rados_callback
;
27 using util::create_context_callback
;
28 using util::create_async_context_callback
;
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
),
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) {
46 m_cct
= reinterpret_cast<CephContext
*>(m_ioctx
.cct());
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));
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
;
61 void CloneRequest
<I
>::send() {
62 ldout(m_cct
, 20) << this << " " << __func__
<< dendl
;
67 void CloneRequest
<I
>::validate_options() {
68 ldout(m_cct
, 20) << this << " " << __func__
<< dendl
;
71 m_opts
.get(RBD_IMAGE_OPTION_FORMAT
, &format
);
73 lderr(m_cct
) << "format 2 or later required for clone" << dendl
;
74 return complete(-EINVAL
);
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
);
82 m_use_p_features
= false;
85 send_validate_parent();
89 void CloneRequest
<I
>::send_validate_parent() {
90 ldout(m_cct
, 20) << this << " " << __func__
<< dendl
;
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
);
97 if (m_p_imctx
->old_format
) {
98 lderr(m_cct
) << "parent image must be in new format" << dendl
;
99 return complete(-EINVAL
);
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();
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
);
116 lderr(m_cct
) << "unable to locate parent's snapshot" << dendl
;
120 if (!snap_protected
) {
121 lderr(m_cct
) << "parent snapshot must be protected" << dendl
;
122 return complete(-EINVAL
);
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);
131 Journal
<I
>::is_tag_owner(m_p_imctx
, &m_is_primary
, ctx
);
135 send_validate_child();
138 template <typename I
>
139 void CloneRequest
<I
>::handle_validate_parent(int r
) {
140 ldout(m_cct
, 20) << this << " " << __func__
<< " r=" << r
<< dendl
;
143 lderr(m_cct
) << "failed to determine tag ownership: " << cpp_strerror(r
)
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
);
155 send_validate_child();
158 template <typename I
>
159 void CloneRequest
<I
>::send_validate_child() {
160 ldout(m_cct
, 20) << this << " " << __func__
<< dendl
;
162 using klass
= CloneRequest
<I
>;
163 librados::AioCompletion
*comp
= create_rados_callback
<klass
, &klass::handle_validate_child
>(this);
165 librados::ObjectReadOperation op
;
166 op
.stat(NULL
, NULL
, NULL
);
168 int r
= m_ioctx
.aio_operate(util::old_header_name(m_name
), comp
, &op
, &m_out_bl
);
173 template <typename I
>
174 void CloneRequest
<I
>::handle_validate_child(int r
) {
175 ldout(m_cct
, 20) << this << " " << __func__
<< " r=" << r
<< dendl
;
178 lderr(m_cct
) << "rbd image " << m_name
<< " already exists" << dendl
;
185 template <typename I
>
186 void CloneRequest
<I
>::send_create() {
187 ldout(m_cct
, 20) << this << " " << __func__
<< dendl
;
189 if (m_use_p_features
) {
190 m_features
= m_p_features
;
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
);
197 if ((m_features
& RBD_FEATURE_LAYERING
) != RBD_FEATURE_LAYERING
) {
198 lderr(m_cct
) << "cloning image must support layering" << dendl
;
199 return complete(-ENOSYS
);
201 m_opts
.set(RBD_IMAGE_OPTION_FEATURES
, m_features
);
203 using klass
= CloneRequest
<I
>;
204 Context
*ctx
= create_context_callback
<klass
, &klass::handle_create
>(this);
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
);
213 template <typename I
>
214 void CloneRequest
<I
>::handle_create(int r
) {
215 ldout(m_cct
, 20) << this << " " << __func__
<< " r=" << r
<< dendl
;
218 lderr(m_cct
) << "error creating child: " << cpp_strerror(r
) << dendl
;
224 template <typename I
>
225 void CloneRequest
<I
>::send_open() {
226 ldout(m_cct
, 20) << this << " " << __func__
<< dendl
;
228 m_imctx
= I::create(m_name
, "", NULL
, m_ioctx
, false);
230 using klass
= CloneRequest
<I
>;
231 Context
*ctx
= create_context_callback
<klass
, &klass::handle_open
>(this);
233 m_imctx
->state
->open(true, ctx
);
236 template <typename I
>
237 void CloneRequest
<I
>::handle_open(int r
) {
238 ldout(m_cct
, 20) << this << " " << __func__
<< " r=" << r
<< dendl
;
241 lderr(m_cct
) << "Error opening new image: " << cpp_strerror(r
) << dendl
;
243 return send_remove();
249 template <typename I
>
250 void CloneRequest
<I
>::send_set_parent() {
251 ldout(m_cct
, 20) << this << " " << __func__
<< dendl
;
253 librados::ObjectWriteOperation op
;
254 librbd::cls_client::set_parent(&op
, m_pspec
, m_size
);
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
,
265 template <typename I
>
266 void CloneRequest
<I
>::handle_set_parent(int r
) {
267 ldout(m_cct
, 20) << this << " " << __func__
<< " r=" << r
<< dendl
;
270 lderr(m_cct
) << "couldn't set parent: " << cpp_strerror(r
) << dendl
;
278 template <typename I
>
279 void CloneRequest
<I
>::send_add_child() {
280 ldout(m_cct
, 20) << this << " " << __func__
<< dendl
;
282 librados::ObjectWriteOperation op
;
283 cls_client::add_child(&op
, m_pspec
, m_id
);
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
);
293 template <typename I
>
294 void CloneRequest
<I
>::handle_add_child(int r
) {
295 ldout(m_cct
, 20) << this << " " << __func__
<< " r=" << r
<< dendl
;
298 lderr(m_cct
) << "couldn't add child: " << cpp_strerror(r
) << dendl
;
306 template <typename I
>
307 void CloneRequest
<I
>::send_refresh() {
308 ldout(m_cct
, 20) << this << " " << __func__
<< dendl
;
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));
317 template <typename I
>
318 void CloneRequest
<I
>::handle_refresh(int r
) {
319 ldout(m_cct
, 20) << this << " " << __func__
<< " r=" << r
<< dendl
;
321 bool snap_protected
= false;
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();
328 if (r
< 0 || !snap_protected
) {
333 send_metadata_list();
336 template <typename I
>
337 void CloneRequest
<I
>::send_metadata_list() {
338 ldout(m_cct
, 20) << this << " " << __func__
<< ": "
339 << "start_key=" << m_last_metadata_key
<< dendl
;
341 librados::ObjectReadOperation op
;
342 cls_client::metadata_list_start(&op
, m_last_metadata_key
, 0);
344 using klass
= CloneRequest
<I
>;
345 librados::AioCompletion
*comp
=
346 create_rados_callback
<klass
, &klass::handle_metadata_list
>(this);
348 m_p_imctx
->md_ctx
.aio_operate(m_p_imctx
->header_oid
,
349 comp
, &op
, &m_out_bl
);
353 template <typename I
>
354 void CloneRequest
<I
>::handle_metadata_list(int r
) {
355 ldout(m_cct
, 20) << this << " " << __func__
<< " r=" << r
<< dendl
;
357 map
<string
, bufferlist
> metadata
;
359 bufferlist::iterator it
= m_out_bl
.begin();
360 r
= cls_client::metadata_list_finish(&it
, &metadata
);
364 if (r
== -EOPNOTSUPP
|| r
== -EIO
) {
365 ldout(m_cct
, 10) << "config metadata not supported by OSD" << dendl
;
368 lderr(m_cct
) << "couldn't list metadata: " << cpp_strerror(r
) << dendl
;
376 if (!metadata
.empty()) {
377 m_pairs
.insert(metadata
.begin(), metadata
.end());
378 m_last_metadata_key
= m_pairs
.rbegin()->first
;
381 if (metadata
.size() == MAX_KEYS
) {
382 send_metadata_list();
388 template <typename I
>
389 void CloneRequest
<I
>::send_metadata_set() {
390 ldout(m_cct
, 20) << this << " " << __func__
<< dendl
;
392 librados::ObjectWriteOperation op
;
393 cls_client::metadata_set(&op
, m_pairs
);
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
);
403 template <typename I
>
404 void CloneRequest
<I
>::handle_metadata_set(int r
) {
405 ldout(m_cct
, 20) << this << " " << __func__
<< " r=" << r
<< dendl
;
408 lderr(m_cct
) << "couldn't set metadata: " << cpp_strerror(r
) << dendl
;
416 template <typename I
>
417 void CloneRequest
<I
>::get_mirror_mode() {
418 ldout(m_cct
, 20) << this << " " << __func__
<< dendl
;
420 if (!m_imctx
->test_features(RBD_FEATURE_JOURNALING
)) {
425 librados::ObjectReadOperation op
;
426 cls_client::mirror_mode_get_start(&op
);
428 using klass
= CloneRequest
<I
>;
429 librados::AioCompletion
*comp
=
430 create_rados_callback
<klass
, &klass::handle_get_mirror_mode
>(this);
432 m_imctx
->md_ctx
.aio_operate(RBD_MIRRORING
,
433 comp
, &op
, &m_out_bl
);
437 template <typename I
>
438 void CloneRequest
<I
>::handle_get_mirror_mode(int r
) {
439 ldout(m_cct
, 20) << this << " " << __func__
<< " r=" << r
<< dendl
;
442 bufferlist::iterator it
= m_out_bl
.begin();
443 r
= cls_client::mirror_mode_get_finish(&it
, &m_mirror_mode
);
446 if (r
< 0 && r
!= -ENOENT
) {
447 lderr(m_cct
) << "failed to retrieve mirror mode: " << cpp_strerror(r
)
453 if (m_mirror_mode
== cls::rbd::MIRROR_MODE_POOL
||
454 !m_non_primary_global_image_id
.empty()) {
455 send_enable_mirror();
462 template <typename I
>
463 void CloneRequest
<I
>::send_enable_mirror() {
464 ldout(m_cct
, 20) << this << " " << __func__
<< dendl
;
466 using klass
= CloneRequest
<I
>;
467 Context
*ctx
= create_context_callback
<klass
, &klass::handle_enable_mirror
>(this);
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
);
475 template <typename I
>
476 void CloneRequest
<I
>::handle_enable_mirror(int r
) {
477 ldout(m_cct
, 20) << this << " " << __func__
<< " r=" << r
<< dendl
;
480 lderr(m_cct
) << "failed to enable mirroring: " << cpp_strerror(r
)
489 template <typename I
>
490 void CloneRequest
<I
>::send_close() {
491 ldout(m_cct
, 20) << this << " " << __func__
<< dendl
;
493 assert(m_imctx
!= nullptr);
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
);
502 template <typename I
>
503 void CloneRequest
<I
>::handle_close(int r
) {
504 ldout(m_cct
, 20) << this << " " << __func__
<< dendl
;
510 lderr(m_cct
) << "couldn't close image: " << cpp_strerror(r
) << dendl
;
514 if (m_r_saved
== 0) {
521 template <typename I
>
522 void CloneRequest
<I
>::send_remove_child() {
523 ldout(m_cct
, 20) << this << " " << __func__
<< dendl
;
525 librados::ObjectWriteOperation op
;
526 cls_client::remove_child(&op
, m_pspec
, m_id
);
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
);
536 template <typename I
>
537 void CloneRequest
<I
>::handle_remove_child(int r
) {
538 ldout(m_cct
, 20) << this << " " << __func__
<< " r=" << r
<< dendl
;
541 lderr(m_cct
) << "Error removing failed clone from list of children: "
542 << cpp_strerror(r
) << dendl
;
548 template <typename I
>
549 void CloneRequest
<I
>::send_remove() {
550 ldout(m_cct
, 20) << this << " " << __func__
<< dendl
;
552 using klass
= CloneRequest
<I
>;
553 Context
*ctx
= create_context_callback
<klass
, &klass::handle_remove
>(this);
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
);
560 template <typename I
>
561 void CloneRequest
<I
>::handle_remove(int r
) {
562 ldout(m_cct
, 20) << this << " " << __func__
<< " r=" << r
<< dendl
;
565 lderr(m_cct
) << "Error removing failed clone: "
566 << cpp_strerror(r
) << dendl
;
571 template <typename I
>
572 void CloneRequest
<I
>::complete(int r
) {
573 ldout(m_cct
, 20) << this << " " << __func__
<< " r=" << r
<< dendl
;
576 ldout(m_cct
, 20) << "done." << dendl
;
579 m_on_finish
->complete(r
);
586 template class librbd::image::CloneRequest
<librbd::ImageCtx
>;