1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 #include "librbd/image/DetachChildRequest.h"
5 #include "common/dout.h"
6 #include "common/errno.h"
7 #include "common/WorkQueue.h"
8 #include "cls/rbd/cls_rbd_client.h"
9 #include "librbd/ImageCtx.h"
10 #include "librbd/ImageState.h"
11 #include "librbd/Operations.h"
12 #include "librbd/Utils.h"
15 #define dout_subsys ceph_subsys_rbd
17 #define dout_prefix *_dout << "librbd::image::DetachChildRequest: " << this \
18 << " " << __func__ << ": "
23 using util::create_context_callback
;
24 using util::create_rados_callback
;
27 DetachChildRequest
<I
>::~DetachChildRequest() {
28 ceph_assert(m_parent_image_ctx
== nullptr);
32 void DetachChildRequest
<I
>::send() {
34 RWLock::RLocker
snap_locker(m_image_ctx
.snap_lock
);
35 RWLock::RLocker
parent_locker(m_image_ctx
.parent_lock
);
37 // use oldest snapshot or HEAD for parent spec
38 if (!m_image_ctx
.snap_info
.empty()) {
39 m_parent_spec
= m_image_ctx
.snap_info
.begin()->second
.parent
.spec
;
41 m_parent_spec
= m_image_ctx
.parent_md
.spec
;
45 if (m_parent_spec
.pool_id
== -1) {
46 // ignore potential race with parent disappearing
47 m_image_ctx
.op_work_queue
->queue(create_context_callback
<
48 DetachChildRequest
<I
>,
49 &DetachChildRequest
<I
>::finish
>(this), 0);
51 } else if (!m_image_ctx
.test_op_features(RBD_OPERATION_FEATURE_CLONE_CHILD
)) {
52 clone_v1_remove_child();
56 clone_v2_child_detach();
60 void DetachChildRequest
<I
>::clone_v2_child_detach() {
61 auto cct
= m_image_ctx
.cct
;
62 ldout(cct
, 5) << dendl
;
64 librados::ObjectWriteOperation op
;
65 cls_client::child_detach(&op
, m_parent_spec
.snap_id
,
66 {m_image_ctx
.md_ctx
.get_id(),
67 m_image_ctx
.md_ctx
.get_namespace(),
70 int r
= util::create_ioctx(m_image_ctx
.md_ctx
, "parent image",
71 m_parent_spec
.pool_id
,
72 m_parent_spec
.pool_namespace
, &m_parent_io_ctx
);
78 m_parent_header_name
= util::header_name(m_parent_spec
.image_id
);
80 auto aio_comp
= create_rados_callback
<
81 DetachChildRequest
<I
>,
82 &DetachChildRequest
<I
>::handle_clone_v2_child_detach
>(this);
83 r
= m_parent_io_ctx
.aio_operate(m_parent_header_name
, aio_comp
, &op
);
89 void DetachChildRequest
<I
>::handle_clone_v2_child_detach(int r
) {
90 auto cct
= m_image_ctx
.cct
;
91 ldout(cct
, 5) << "r=" << r
<< dendl
;
93 if (r
< 0 && r
!= -ENOENT
) {
94 lderr(cct
) << "error detaching child from parent: " << cpp_strerror(r
)
100 clone_v2_get_snapshot();
103 template <typename I
>
104 void DetachChildRequest
<I
>::clone_v2_get_snapshot() {
105 auto cct
= m_image_ctx
.cct
;
106 ldout(cct
, 5) << dendl
;
108 librados::ObjectReadOperation op
;
109 cls_client::snapshot_get_start(&op
, m_parent_spec
.snap_id
);
112 auto aio_comp
= create_rados_callback
<
113 DetachChildRequest
<I
>,
114 &DetachChildRequest
<I
>::handle_clone_v2_get_snapshot
>(this);
115 int r
= m_parent_io_ctx
.aio_operate(m_parent_header_name
, aio_comp
, &op
,
121 template <typename I
>
122 void DetachChildRequest
<I
>::handle_clone_v2_get_snapshot(int r
) {
123 auto cct
= m_image_ctx
.cct
;
124 ldout(cct
, 5) << "r=" << r
<< dendl
;
126 bool remove_snapshot
= false;
128 cls::rbd::SnapshotInfo snap_info
;
129 auto it
= m_out_bl
.cbegin();
130 r
= cls_client::snapshot_get_finish(&it
, &snap_info
);
132 m_parent_snap_namespace
= snap_info
.snapshot_namespace
;
133 m_parent_snap_name
= snap_info
.name
;
135 if (cls::rbd::get_snap_namespace_type(m_parent_snap_namespace
) ==
136 cls::rbd::SNAPSHOT_NAMESPACE_TYPE_TRASH
&&
137 snap_info
.child_count
== 0) {
138 // snapshot is in trash w/ zero children, so remove it
139 remove_snapshot
= true;
145 ldout(cct
, 5) << "failed to retrieve snapshot: " << cpp_strerror(r
)
149 if (!remove_snapshot
) {
154 clone_v2_open_parent();
158 void DetachChildRequest
<I
>::clone_v2_open_parent() {
159 auto cct
= m_image_ctx
.cct
;
160 ldout(cct
, 5) << dendl
;
162 m_parent_image_ctx
= I::create("", m_parent_spec
.image_id
, nullptr,
163 m_parent_io_ctx
, false);
165 auto ctx
= create_context_callback
<
166 DetachChildRequest
<I
>,
167 &DetachChildRequest
<I
>::handle_clone_v2_open_parent
>(this);
168 m_parent_image_ctx
->state
->open(OPEN_FLAG_SKIP_OPEN_PARENT
, ctx
);
172 void DetachChildRequest
<I
>::handle_clone_v2_open_parent(int r
) {
173 auto cct
= m_image_ctx
.cct
;
174 ldout(cct
, 5) << "r=" << r
<< dendl
;
177 ldout(cct
, 5) << "failed to open parent for read/write: "
178 << cpp_strerror(r
) << dendl
;
179 m_parent_image_ctx
->destroy();
180 m_parent_image_ctx
= nullptr;
185 clone_v2_remove_snapshot();
189 void DetachChildRequest
<I
>::clone_v2_remove_snapshot() {
190 auto cct
= m_image_ctx
.cct
;
191 ldout(cct
, 5) << dendl
;
193 auto ctx
= create_context_callback
<
194 DetachChildRequest
<I
>,
195 &DetachChildRequest
<I
>::handle_clone_v2_remove_snapshot
>(this);
196 m_parent_image_ctx
->operations
->snap_remove(m_parent_snap_namespace
,
197 m_parent_snap_name
, ctx
);
201 void DetachChildRequest
<I
>::handle_clone_v2_remove_snapshot(int r
) {
202 auto cct
= m_image_ctx
.cct
;
203 ldout(cct
, 5) << "r=" << r
<< dendl
;
205 if (r
< 0 && r
!= -ENOENT
) {
206 ldout(cct
, 5) << "failed to remove trashed clone snapshot: "
207 << cpp_strerror(r
) << dendl
;
210 clone_v2_close_parent();
214 void DetachChildRequest
<I
>::clone_v2_close_parent() {
215 auto cct
= m_image_ctx
.cct
;
216 ldout(cct
, 5) << dendl
;
218 auto ctx
= create_context_callback
<
219 DetachChildRequest
<I
>,
220 &DetachChildRequest
<I
>::handle_clone_v2_close_parent
>(this);
221 m_parent_image_ctx
->state
->close(ctx
);
225 void DetachChildRequest
<I
>::handle_clone_v2_close_parent(int r
) {
226 auto cct
= m_image_ctx
.cct
;
227 ldout(cct
, 5) << "r=" << r
<< dendl
;
230 ldout(cct
, 5) << "failed to close parent image:" << cpp_strerror(r
)
234 m_parent_image_ctx
->destroy();
235 m_parent_image_ctx
= nullptr;
240 void DetachChildRequest
<I
>::clone_v1_remove_child() {
241 auto cct
= m_image_ctx
.cct
;
242 ldout(cct
, 5) << dendl
;
244 m_parent_spec
.pool_namespace
= "";
246 librados::ObjectWriteOperation op
;
247 librbd::cls_client::remove_child(&op
, m_parent_spec
, m_image_ctx
.id
);
249 auto aio_comp
= create_rados_callback
<
250 DetachChildRequest
<I
>,
251 &DetachChildRequest
<I
>::handle_clone_v1_remove_child
>(this);
252 int r
= m_image_ctx
.md_ctx
.aio_operate(RBD_CHILDREN
, aio_comp
, &op
);
258 void DetachChildRequest
<I
>::handle_clone_v1_remove_child(int r
) {
259 auto cct
= m_image_ctx
.cct
;
260 ldout(cct
, 5) << "r=" << r
<< dendl
;
265 lderr(cct
) << "failed to remove child from children list: "
266 << cpp_strerror(r
) << dendl
;
274 template <typename I
>
275 void DetachChildRequest
<I
>::finish(int r
) {
276 auto cct
= m_image_ctx
.cct
;
277 ldout(cct
, 5) << "r=" << r
<< dendl
;
279 m_on_finish
->complete(r
);
284 } // namespace librbd
286 template class librbd::image::DetachChildRequest
<librbd::ImageCtx
>;