]> git.proxmox.com Git - ceph.git/blob - ceph/src/librbd/image/DetachChildRequest.cc
import ceph 14.2.5
[ceph.git] / ceph / src / librbd / image / DetachChildRequest.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3
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"
13 #include <string>
14
15 #define dout_subsys ceph_subsys_rbd
16 #undef dout_prefix
17 #define dout_prefix *_dout << "librbd::image::DetachChildRequest: " << this \
18 << " " << __func__ << ": "
19
20 namespace librbd {
21 namespace image {
22
23 using util::create_context_callback;
24 using util::create_rados_callback;
25
26 template <typename I>
27 DetachChildRequest<I>::~DetachChildRequest() {
28 ceph_assert(m_parent_image_ctx == nullptr);
29 }
30
31 template <typename I>
32 void DetachChildRequest<I>::send() {
33 {
34 RWLock::RLocker snap_locker(m_image_ctx.snap_lock);
35 RWLock::RLocker parent_locker(m_image_ctx.parent_lock);
36
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;
40 } else {
41 m_parent_spec = m_image_ctx.parent_md.spec;
42 }
43 }
44
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);
50 return;
51 } else if (!m_image_ctx.test_op_features(RBD_OPERATION_FEATURE_CLONE_CHILD)) {
52 clone_v1_remove_child();
53 return;
54 }
55
56 clone_v2_child_detach();
57 }
58
59 template <typename I>
60 void DetachChildRequest<I>::clone_v2_child_detach() {
61 auto cct = m_image_ctx.cct;
62 ldout(cct, 5) << dendl;
63
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(),
68 m_image_ctx.id});
69
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);
73 if (r < 0) {
74 finish(r);
75 return;
76 }
77
78 m_parent_header_name = util::header_name(m_parent_spec.image_id);
79
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);
84 ceph_assert(r == 0);
85 aio_comp->release();
86 }
87
88 template <typename I>
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;
92
93 if (r < 0 && r != -ENOENT) {
94 lderr(cct) << "error detaching child from parent: " << cpp_strerror(r)
95 << dendl;
96 finish(r);
97 return;
98 }
99
100 clone_v2_get_snapshot();
101 }
102
103 template <typename I>
104 void DetachChildRequest<I>::clone_v2_get_snapshot() {
105 auto cct = m_image_ctx.cct;
106 ldout(cct, 5) << dendl;
107
108 librados::ObjectReadOperation op;
109 cls_client::snapshot_get_start(&op, m_parent_spec.snap_id);
110
111 m_out_bl.clear();
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,
116 &m_out_bl);
117 ceph_assert(r == 0);
118 aio_comp->release();
119 }
120
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;
125
126 bool remove_snapshot = false;
127 if (r == 0) {
128 cls::rbd::SnapshotInfo snap_info;
129 auto it = m_out_bl.cbegin();
130 r = cls_client::snapshot_get_finish(&it, &snap_info);
131 if (r == 0) {
132 m_parent_snap_namespace = snap_info.snapshot_namespace;
133 m_parent_snap_name = snap_info.name;
134
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;
140 }
141 }
142 }
143
144 if (r < 0) {
145 ldout(cct, 5) << "failed to retrieve snapshot: " << cpp_strerror(r)
146 << dendl;
147 }
148
149 if (!remove_snapshot) {
150 finish(0);
151 return;
152 }
153
154 clone_v2_open_parent();
155 }
156
157 template<typename I>
158 void DetachChildRequest<I>::clone_v2_open_parent() {
159 auto cct = m_image_ctx.cct;
160 ldout(cct, 5) << dendl;
161
162 m_parent_image_ctx = I::create("", m_parent_spec.image_id, nullptr,
163 m_parent_io_ctx, false);
164
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);
169 }
170
171 template<typename I>
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;
175
176 if (r < 0) {
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;
181 finish(0);
182 return;
183 }
184
185 clone_v2_remove_snapshot();
186 }
187
188 template<typename I>
189 void DetachChildRequest<I>::clone_v2_remove_snapshot() {
190 auto cct = m_image_ctx.cct;
191 ldout(cct, 5) << dendl;
192
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);
198 }
199
200 template<typename I>
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;
204
205 if (r < 0 && r != -ENOENT) {
206 ldout(cct, 5) << "failed to remove trashed clone snapshot: "
207 << cpp_strerror(r) << dendl;
208 }
209
210 clone_v2_close_parent();
211 }
212
213 template<typename I>
214 void DetachChildRequest<I>::clone_v2_close_parent() {
215 auto cct = m_image_ctx.cct;
216 ldout(cct, 5) << dendl;
217
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);
222 }
223
224 template<typename I>
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;
228
229 if (r < 0) {
230 ldout(cct, 5) << "failed to close parent image:" << cpp_strerror(r)
231 << dendl;
232 }
233
234 m_parent_image_ctx->destroy();
235 m_parent_image_ctx = nullptr;
236 finish(0);
237 }
238
239 template<typename I>
240 void DetachChildRequest<I>::clone_v1_remove_child() {
241 auto cct = m_image_ctx.cct;
242 ldout(cct, 5) << dendl;
243
244 m_parent_spec.pool_namespace = "";
245
246 librados::ObjectWriteOperation op;
247 librbd::cls_client::remove_child(&op, m_parent_spec, m_image_ctx.id);
248
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);
253 ceph_assert(r == 0);
254 aio_comp->release();
255 }
256
257 template<typename I>
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;
261
262 if (r == -ENOENT) {
263 r = 0;
264 } else if (r < 0) {
265 lderr(cct) << "failed to remove child from children list: "
266 << cpp_strerror(r) << dendl;
267 finish(r);
268 return;
269 }
270
271 finish(0);
272 }
273
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;
278
279 m_on_finish->complete(r);
280 delete this;
281 }
282
283 } // namespace image
284 } // namespace librbd
285
286 template class librbd::image::DetachChildRequest<librbd::ImageCtx>;