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: "
24 using util::create_rados_callback
;
25 using util::create_context_callback
;
26 using util::create_async_context_callback
;
29 CloneRequest
<I
>::CloneRequest(I
*p_imctx
, IoCtx
&c_ioctx
,
30 const std::string
&c_name
,
31 const std::string
&c_id
,
32 ImageOptions c_options
,
33 const std::string
&non_primary_global_image_id
,
34 const std::string
&primary_mirror_uuid
,
35 ContextWQ
*op_work_queue
, Context
*on_finish
)
36 : m_p_imctx(p_imctx
), m_ioctx(c_ioctx
), m_name(c_name
), m_id(c_id
),
38 m_pspec(m_p_imctx
->md_ctx
.get_id(), m_p_imctx
->id
, m_p_imctx
->snap_id
),
39 m_non_primary_global_image_id(non_primary_global_image_id
),
40 m_primary_mirror_uuid(primary_mirror_uuid
),
41 m_op_work_queue(op_work_queue
), m_on_finish(on_finish
),
42 m_use_p_features(true) {
44 m_cct
= reinterpret_cast<CephContext
*>(m_ioctx
.cct());
46 bool default_format_set
;
47 m_opts
.is_set(RBD_IMAGE_OPTION_FORMAT
, &default_format_set
);
48 if (!default_format_set
) {
49 m_opts
.set(RBD_IMAGE_OPTION_FORMAT
, static_cast<uint64_t>(2));
52 ldout(m_cct
, 20) << "clone " << &m_p_imctx
->md_ctx
<< " name " << m_p_imctx
->name
53 << " snap " << m_p_imctx
->snap_name
<< " to child " << &m_ioctx
54 << " name " << m_name
<< " opts = " << &m_opts
<< dendl
;
59 void CloneRequest
<I
>::send() {
60 ldout(m_cct
, 20) << this << " " << __func__
<< dendl
;
65 void CloneRequest
<I
>::validate_options() {
66 ldout(m_cct
, 20) << this << " " << __func__
<< dendl
;
69 m_opts
.get(RBD_IMAGE_OPTION_FORMAT
, &format
);
71 lderr(m_cct
) << "format 2 or later required for clone" << dendl
;
72 return complete(-EINVAL
);
75 if (m_opts
.get(RBD_IMAGE_OPTION_FEATURES
, &m_features
) == 0) {
76 if (m_features
& ~RBD_FEATURES_ALL
) {
77 lderr(m_cct
) << "librbd does not support requested features" << dendl
;
78 return complete(-ENOSYS
);
80 m_use_p_features
= false;
83 send_validate_parent();
87 void CloneRequest
<I
>::send_validate_parent() {
88 ldout(m_cct
, 20) << this << " " << __func__
<< dendl
;
90 if (m_p_imctx
->snap_id
== CEPH_NOSNAP
) {
91 lderr(m_cct
) << "image to be cloned must be a snapshot" << dendl
;
92 return complete(-EINVAL
);
95 if (m_p_imctx
->old_format
) {
96 lderr(m_cct
) << "parent image must be in new format" << dendl
;
97 return complete(-EINVAL
);
102 m_p_imctx
->snap_lock
.get_read();
103 m_p_features
= m_p_imctx
->features
;
104 m_size
= m_p_imctx
->get_image_size(m_p_imctx
->snap_id
);
105 r
= m_p_imctx
->is_snap_protected(m_p_imctx
->snap_id
, &snap_protected
);
106 m_p_imctx
->snap_lock
.put_read();
108 if ((m_p_features
& RBD_FEATURE_LAYERING
) != RBD_FEATURE_LAYERING
) {
109 lderr(m_cct
) << "parent image must support layering" << dendl
;
110 return complete(-ENOSYS
);
114 lderr(m_cct
) << "unable to locate parent's snapshot" << dendl
;
118 if (!snap_protected
) {
119 lderr(m_cct
) << "parent snapshot must be protected" << dendl
;
120 return complete(-EINVAL
);
123 if ((m_p_features
& RBD_FEATURE_JOURNALING
) != 0) {
124 m_force_non_primary
= !m_non_primary_global_image_id
.empty();
125 using klass
= CloneRequest
<I
>;
126 Context
*ctx
= create_context_callback
<
127 klass
, &klass::handle_validate_parent
>(this);
129 Journal
<I
>::is_tag_owner(m_p_imctx
, &m_is_primary
, ctx
);
133 send_validate_child();
136 template <typename I
>
137 void CloneRequest
<I
>::handle_validate_parent(int r
) {
138 ldout(m_cct
, 20) << this << " " << __func__
<< " r=" << r
<< dendl
;
141 lderr(m_cct
) << "failed to determine tag ownership: " << cpp_strerror(r
)
146 if ((m_p_features
& RBD_FEATURE_JOURNALING
) != 0) {
147 if (!m_is_primary
&& !m_force_non_primary
) {
148 lderr(m_cct
) << "parent is non-primary mirrored image" << dendl
;
149 return complete(-EINVAL
);
153 send_validate_child();
156 template <typename I
>
157 void CloneRequest
<I
>::send_validate_child() {
158 ldout(m_cct
, 20) << this << " " << __func__
<< dendl
;
160 using klass
= CloneRequest
<I
>;
161 librados::AioCompletion
*comp
= create_rados_callback
<klass
, &klass::handle_validate_child
>(this);
163 librados::ObjectReadOperation op
;
164 op
.stat(NULL
, NULL
, NULL
);
166 int r
= m_ioctx
.aio_operate(util::old_header_name(m_name
), comp
, &op
, &m_out_bl
);
171 template <typename I
>
172 void CloneRequest
<I
>::handle_validate_child(int r
) {
173 ldout(m_cct
, 20) << this << " " << __func__
<< " r=" << r
<< dendl
;
176 lderr(m_cct
) << "rbd image " << m_name
<< " already exists" << dendl
;
183 template <typename I
>
184 void CloneRequest
<I
>::send_create() {
185 ldout(m_cct
, 20) << this << " " << __func__
<< dendl
;
187 if (m_use_p_features
) {
188 m_features
= m_p_features
;
191 uint64_t order
= m_p_imctx
->order
;
192 if (m_opts
.get(RBD_IMAGE_OPTION_ORDER
, &order
) != 0) {
193 m_opts
.set(RBD_IMAGE_OPTION_ORDER
, order
);
195 if ((m_features
& RBD_FEATURE_LAYERING
) != RBD_FEATURE_LAYERING
) {
196 lderr(m_cct
) << "cloning image must support layering" << dendl
;
197 return complete(-ENOSYS
);
199 m_opts
.set(RBD_IMAGE_OPTION_FEATURES
, m_features
);
201 using klass
= CloneRequest
<I
>;
202 Context
*ctx
= create_context_callback
<klass
, &klass::handle_create
>(this);
204 RWLock::RLocker
snap_locker(m_p_imctx
->snap_lock
);
205 CreateRequest
<I
> *req
= CreateRequest
<I
>::create(
206 m_ioctx
, m_name
, m_id
, m_size
, m_opts
, m_non_primary_global_image_id
,
207 m_primary_mirror_uuid
, true, m_op_work_queue
, ctx
);
211 template <typename I
>
212 void CloneRequest
<I
>::handle_create(int r
) {
213 ldout(m_cct
, 20) << this << " " << __func__
<< " r=" << r
<< dendl
;
216 lderr(m_cct
) << "error creating child: " << cpp_strerror(r
) << dendl
;
222 template <typename I
>
223 void CloneRequest
<I
>::send_open() {
224 ldout(m_cct
, 20) << this << " " << __func__
<< dendl
;
226 m_imctx
= I::create(m_name
, "", NULL
, m_ioctx
, false);
228 using klass
= CloneRequest
<I
>;
229 Context
*ctx
= create_context_callback
<klass
, &klass::handle_open
>(this);
231 m_imctx
->state
->open(true, ctx
);
234 template <typename I
>
235 void CloneRequest
<I
>::handle_open(int r
) {
236 ldout(m_cct
, 20) << this << " " << __func__
<< " r=" << r
<< dendl
;
239 lderr(m_cct
) << "Error opening new image: " << cpp_strerror(r
) << dendl
;
241 return send_remove();
247 template <typename I
>
248 void CloneRequest
<I
>::send_set_parent() {
249 ldout(m_cct
, 20) << this << " " << __func__
<< dendl
;
251 librados::ObjectWriteOperation op
;
252 librbd::cls_client::set_parent(&op
, m_pspec
, m_size
);
254 using klass
= CloneRequest
<I
>;
255 librados::AioCompletion
*comp
=
256 create_rados_callback
<klass
, &klass::handle_set_parent
>(this);
257 int r
= m_imctx
->md_ctx
.aio_operate(m_imctx
->header_oid
,
263 template <typename I
>
264 void CloneRequest
<I
>::handle_set_parent(int r
) {
265 ldout(m_cct
, 20) << this << " " << __func__
<< " r=" << r
<< dendl
;
268 lderr(m_cct
) << "couldn't set parent: " << cpp_strerror(r
) << dendl
;
276 template <typename I
>
277 void CloneRequest
<I
>::send_add_child() {
278 ldout(m_cct
, 20) << this << " " << __func__
<< dendl
;
280 librados::ObjectWriteOperation op
;
281 cls_client::add_child(&op
, m_pspec
, m_id
);
283 using klass
= CloneRequest
<I
>;
284 librados::AioCompletion
*comp
=
285 create_rados_callback
<klass
, &klass::handle_add_child
>(this);
286 int r
= m_ioctx
.aio_operate(RBD_CHILDREN
, comp
, &op
);
291 template <typename I
>
292 void CloneRequest
<I
>::handle_add_child(int r
) {
293 ldout(m_cct
, 20) << this << " " << __func__
<< " r=" << r
<< dendl
;
296 lderr(m_cct
) << "couldn't add child: " << cpp_strerror(r
) << dendl
;
304 template <typename I
>
305 void CloneRequest
<I
>::send_refresh() {
306 ldout(m_cct
, 20) << this << " " << __func__
<< dendl
;
308 using klass
= CloneRequest
<I
>;
309 RefreshRequest
<I
> *req
= RefreshRequest
<I
>::create(
310 *m_imctx
, false, false,
311 create_context_callback
<klass
, &klass::handle_refresh
>(this));
315 template <typename I
>
316 void CloneRequest
<I
>::handle_refresh(int r
) {
317 ldout(m_cct
, 20) << this << " " << __func__
<< " r=" << r
<< dendl
;
321 m_p_imctx
->snap_lock
.get_read();
322 r
= m_p_imctx
->is_snap_protected(m_p_imctx
->snap_id
, &snap_protected
);
323 m_p_imctx
->snap_lock
.put_read();
326 if (r
< 0 || !snap_protected
) {
331 send_metadata_list();
334 template <typename I
>
335 void CloneRequest
<I
>::send_metadata_list() {
336 ldout(m_cct
, 20) << this << " " << __func__
<< dendl
;
338 librados::ObjectReadOperation op
;
339 cls_client::metadata_list_start(&op
, "", 0);
341 using klass
= CloneRequest
<I
>;
342 librados::AioCompletion
*comp
=
343 create_rados_callback
<klass
, &klass::handle_metadata_list
>(this);
345 m_p_imctx
->md_ctx
.aio_operate(m_p_imctx
->header_oid
,
346 comp
, &op
, &m_out_bl
);
350 template <typename I
>
351 void CloneRequest
<I
>::handle_metadata_list(int r
) {
352 ldout(m_cct
, 20) << this << " " << __func__
<< " r=" << r
<< dendl
;
355 bufferlist::iterator it
= m_out_bl
.begin();
356 r
= cls_client::metadata_list_finish(&it
, &m_pairs
);
359 if (r
< 0 && r
!= -EOPNOTSUPP
&& r
!= -EIO
) {
360 lderr(m_cct
) << "couldn't list metadata: " << cpp_strerror(r
) << dendl
;
363 } else if (r
== 0 && !m_pairs
.empty()) {
370 template <typename I
>
371 void CloneRequest
<I
>::send_metadata_set() {
372 ldout(m_cct
, 20) << this << " " << __func__
<< dendl
;
374 librados::ObjectWriteOperation op
;
375 cls_client::metadata_set(&op
, m_pairs
);
377 using klass
= CloneRequest
<I
>;
378 librados::AioCompletion
*comp
=
379 create_rados_callback
<klass
, &klass::handle_metadata_set
>(this);
380 int r
= m_ioctx
.aio_operate(m_imctx
->header_oid
, comp
, &op
);
385 template <typename I
>
386 void CloneRequest
<I
>::handle_metadata_set(int r
) {
387 ldout(m_cct
, 20) << this << " " << __func__
<< " r=" << r
<< dendl
;
390 lderr(m_cct
) << "couldn't set metadata: " << cpp_strerror(r
) << dendl
;
398 template <typename I
>
399 void CloneRequest
<I
>::get_mirror_mode() {
400 ldout(m_cct
, 20) << this << " " << __func__
<< dendl
;
402 if (!m_imctx
->test_features(RBD_FEATURE_JOURNALING
)) {
407 librados::ObjectReadOperation op
;
408 cls_client::mirror_mode_get_start(&op
);
410 using klass
= CloneRequest
<I
>;
411 librados::AioCompletion
*comp
=
412 create_rados_callback
<klass
, &klass::handle_get_mirror_mode
>(this);
414 m_imctx
->md_ctx
.aio_operate(RBD_MIRRORING
,
415 comp
, &op
, &m_out_bl
);
419 template <typename I
>
420 void CloneRequest
<I
>::handle_get_mirror_mode(int r
) {
421 ldout(m_cct
, 20) << this << " " << __func__
<< " r=" << r
<< dendl
;
424 lderr(m_cct
) << "failed to retrieve mirror mode: " << cpp_strerror(r
)
426 bufferlist::iterator it
= m_out_bl
.begin();
427 r
= cls_client::mirror_mode_get_finish(&it
, &m_mirror_mode
);
430 if (r
< 0 && r
!= -ENOENT
) {
434 if (m_mirror_mode
== cls::rbd::MIRROR_MODE_POOL
||
435 !m_non_primary_global_image_id
.empty()) {
436 send_enable_mirror();
443 template <typename I
>
444 void CloneRequest
<I
>::send_enable_mirror() {
445 ldout(m_cct
, 20) << this << " " << __func__
<< dendl
;
447 using klass
= CloneRequest
<I
>;
448 Context
*ctx
= create_context_callback
<klass
, &klass::handle_enable_mirror
>(this);
450 mirror::EnableRequest
<I
> *req
= mirror::EnableRequest
<I
>::create(
451 m_imctx
->md_ctx
, m_id
, m_non_primary_global_image_id
,
452 m_imctx
->op_work_queue
, ctx
);
456 template <typename I
>
457 void CloneRequest
<I
>::handle_enable_mirror(int r
) {
458 ldout(m_cct
, 20) << this << " " << __func__
<< " r=" << r
<< dendl
;
461 lderr(m_cct
) << "failed to enable mirroring: " << cpp_strerror(r
)
470 template <typename I
>
471 void CloneRequest
<I
>::send_close() {
472 ldout(m_cct
, 20) << this << " " << __func__
<< dendl
;
474 assert(m_imctx
!= nullptr);
476 using klass
= CloneRequest
<I
>;
477 Context
*ctx
= create_async_context_callback(
478 *m_imctx
, create_context_callback
<
479 klass
, &klass::handle_close
>(this));
480 m_imctx
->state
->close(ctx
);
483 template <typename I
>
484 void CloneRequest
<I
>::handle_close(int r
) {
485 ldout(m_cct
, 20) << this << " " << __func__
<< dendl
;
491 lderr(m_cct
) << "couldn't close image: " << cpp_strerror(r
) << dendl
;
495 if (m_r_saved
== 0) {
502 template <typename I
>
503 void CloneRequest
<I
>::send_remove_child() {
504 ldout(m_cct
, 20) << this << " " << __func__
<< dendl
;
506 librados::ObjectWriteOperation op
;
507 cls_client::remove_child(&op
, m_pspec
, m_id
);
509 using klass
= CloneRequest
<I
>;
510 librados::AioCompletion
*comp
=
511 create_rados_callback
<klass
, &klass::handle_remove_child
>(this);
512 int r
= m_p_imctx
->md_ctx
.aio_operate(RBD_CHILDREN
, comp
, &op
);
517 template <typename I
>
518 void CloneRequest
<I
>::handle_remove_child(int r
) {
519 ldout(m_cct
, 20) << this << " " << __func__
<< " r=" << r
<< dendl
;
522 lderr(m_cct
) << "Error removing failed clone from list of children: "
523 << cpp_strerror(r
) << dendl
;
529 template <typename I
>
530 void CloneRequest
<I
>::send_remove() {
531 ldout(m_cct
, 20) << this << " " << __func__
<< dendl
;
533 using klass
= CloneRequest
<I
>;
534 Context
*ctx
= create_context_callback
<klass
, &klass::handle_remove
>(this);
536 librbd::image::RemoveRequest
<> *req
= librbd::image::RemoveRequest
<>::create(
537 m_ioctx
, m_name
, m_id
, false, false, m_no_op
, m_op_work_queue
, ctx
);
541 template <typename I
>
542 void CloneRequest
<I
>::handle_remove(int r
) {
543 ldout(m_cct
, 20) << this << " " << __func__
<< " r=" << r
<< dendl
;
546 lderr(m_cct
) << "Error removing failed clone: "
547 << cpp_strerror(r
) << dendl
;
552 template <typename I
>
553 void CloneRequest
<I
>::complete(int r
) {
554 ldout(m_cct
, 20) << this << " " << __func__
<< " r=" << r
<< dendl
;
557 ldout(m_cct
, 20) << "done." << dendl
;
560 m_on_finish
->complete(r
);
567 template class librbd::image::CloneRequest
<librbd::ImageCtx
>;