]>
Commit | Line | Data |
---|---|---|
11fdf7f2 TL |
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/AttachChildRequest.h" | |
5 | #include "common/dout.h" | |
6 | #include "common/errno.h" | |
7 | #include "cls/rbd/cls_rbd_client.h" | |
8 | #include "librbd/ImageCtx.h" | |
9 | #include "librbd/Utils.h" | |
10 | #include "librbd/image/RefreshRequest.h" | |
11 | ||
12 | #define dout_subsys ceph_subsys_rbd | |
13 | #undef dout_prefix | |
14 | #define dout_prefix *_dout << "librbd::image::AttachChildRequest: " << this \ | |
15 | << " " << __func__ << ": " | |
16 | ||
17 | namespace librbd { | |
18 | namespace image { | |
19 | ||
20 | using util::create_context_callback; | |
21 | using util::create_rados_callback; | |
22 | ||
23 | template <typename I> | |
24 | AttachChildRequest<I>::AttachChildRequest( | |
25 | I *image_ctx, I *parent_image_ctx, const librados::snap_t &parent_snap_id, | |
26 | I *old_parent_image_ctx, const librados::snap_t &old_parent_snap_id, | |
27 | uint32_t clone_format, Context* on_finish) | |
28 | : m_image_ctx(image_ctx), m_parent_image_ctx(parent_image_ctx), | |
29 | m_parent_snap_id(parent_snap_id), | |
30 | m_old_parent_image_ctx(old_parent_image_ctx), | |
31 | m_old_parent_snap_id(old_parent_snap_id), m_clone_format(clone_format), | |
32 | m_on_finish(on_finish), m_cct(m_image_ctx->cct) { | |
33 | } | |
34 | ||
35 | template <typename I> | |
36 | void AttachChildRequest<I>::send() { | |
37 | if (m_clone_format == 1) { | |
38 | v1_add_child(); | |
39 | } else { | |
40 | v2_set_op_feature(); | |
41 | } | |
42 | } | |
43 | ||
44 | template <typename I> | |
45 | void AttachChildRequest<I>::v1_add_child() { | |
46 | ldout(m_cct, 15) << dendl; | |
47 | ||
48 | librados::ObjectWriteOperation op; | |
eafe8130 | 49 | cls_client::add_child(&op, {m_parent_image_ctx->md_ctx.get_id(), "", |
11fdf7f2 TL |
50 | m_parent_image_ctx->id, |
51 | m_parent_snap_id}, m_image_ctx->id); | |
52 | ||
53 | using klass = AttachChildRequest<I>; | |
54 | librados::AioCompletion *comp = | |
55 | create_rados_callback<klass, &klass::handle_v1_add_child>(this); | |
56 | int r = m_image_ctx->md_ctx.aio_operate(RBD_CHILDREN, comp, &op); | |
57 | ceph_assert(r == 0); | |
58 | comp->release(); | |
59 | } | |
60 | ||
61 | template <typename I> | |
62 | void AttachChildRequest<I>::handle_v1_add_child(int r) { | |
63 | ldout(m_cct, 15) << "r=" << r << dendl; | |
64 | ||
65 | if (r < 0) { | |
66 | if (r == -EEXIST && m_old_parent_image_ctx != nullptr) { | |
67 | ldout(m_cct, 5) << "child already exists" << dendl; | |
68 | } else { | |
69 | lderr(m_cct) << "couldn't add child: " << cpp_strerror(r) << dendl; | |
70 | finish(r); | |
71 | return; | |
72 | } | |
73 | } | |
74 | ||
75 | v1_refresh(); | |
76 | } | |
77 | ||
78 | template <typename I> | |
79 | void AttachChildRequest<I>::v1_refresh() { | |
80 | ldout(m_cct, 15) << dendl; | |
81 | ||
82 | using klass = AttachChildRequest<I>; | |
83 | RefreshRequest<I> *req = RefreshRequest<I>::create( | |
84 | *m_parent_image_ctx, false, false, | |
85 | create_context_callback<klass, &klass::handle_v1_refresh>(this)); | |
86 | req->send(); | |
87 | } | |
88 | ||
89 | template <typename I> | |
90 | void AttachChildRequest<I>::handle_v1_refresh(int r) { | |
91 | ldout(m_cct, 15) << "r=" << r << dendl; | |
92 | ||
93 | bool snap_protected = false; | |
94 | if (r == 0) { | |
95 | RWLock::RLocker snap_locker(m_parent_image_ctx->snap_lock); | |
96 | r = m_parent_image_ctx->is_snap_protected(m_parent_snap_id, | |
97 | &snap_protected); | |
98 | } | |
99 | ||
100 | if (r < 0 || !snap_protected) { | |
101 | lderr(m_cct) << "validate protected failed" << dendl; | |
102 | finish(-EINVAL); | |
103 | return; | |
104 | } | |
105 | ||
106 | v1_remove_child_from_old_parent(); | |
107 | } | |
108 | ||
109 | template <typename I> | |
110 | void AttachChildRequest<I>::v1_remove_child_from_old_parent() { | |
111 | if (m_old_parent_image_ctx == nullptr) { | |
112 | finish(0); | |
113 | return; | |
114 | } | |
115 | ||
116 | ldout(m_cct, 15) << dendl; | |
117 | ||
118 | librados::ObjectWriteOperation op; | |
119 | cls_client::remove_child(&op, {m_old_parent_image_ctx->md_ctx.get_id(), | |
120 | m_old_parent_image_ctx->md_ctx.get_namespace(), | |
121 | m_old_parent_image_ctx->id, | |
122 | m_old_parent_snap_id}, m_image_ctx->id); | |
123 | ||
124 | using klass = AttachChildRequest<I>; | |
125 | librados::AioCompletion *comp = create_rados_callback< | |
126 | klass, &klass::handle_v1_remove_child_from_old_parent>(this); | |
127 | int r = m_image_ctx->md_ctx.aio_operate(RBD_CHILDREN, comp, &op); | |
128 | ceph_assert(r == 0); | |
129 | comp->release(); | |
130 | } | |
131 | ||
132 | template <typename I> | |
133 | void AttachChildRequest<I>::handle_v1_remove_child_from_old_parent(int r) { | |
134 | ldout(m_cct, 15) << "r=" << r << dendl; | |
135 | ||
136 | if (r < 0 && r != -ENOENT) { | |
137 | lderr(m_cct) << "couldn't remove child: " << cpp_strerror(r) << dendl; | |
138 | finish(r); | |
139 | return; | |
140 | } | |
141 | ||
142 | finish(0); | |
143 | } | |
144 | ||
145 | template <typename I> | |
146 | void AttachChildRequest<I>::v2_set_op_feature() { | |
147 | ldout(m_cct, 15) << dendl; | |
148 | ||
149 | librados::ObjectWriteOperation op; | |
150 | cls_client::op_features_set(&op, RBD_OPERATION_FEATURE_CLONE_CHILD, | |
151 | RBD_OPERATION_FEATURE_CLONE_CHILD); | |
152 | ||
153 | using klass = AttachChildRequest<I>; | |
154 | auto aio_comp = create_rados_callback< | |
155 | klass, &klass::handle_v2_set_op_feature>(this); | |
156 | int r = m_image_ctx->md_ctx.aio_operate(m_image_ctx->header_oid, aio_comp, | |
157 | &op); | |
158 | ceph_assert(r == 0); | |
159 | aio_comp->release(); | |
160 | } | |
161 | ||
162 | template <typename I> | |
163 | void AttachChildRequest<I>::handle_v2_set_op_feature(int r) { | |
164 | ldout(m_cct, 15) << "r=" << r << dendl; | |
165 | ||
166 | if (r < 0) { | |
167 | lderr(m_cct) << "failed to enable clone v2: " << cpp_strerror(r) << dendl; | |
168 | finish(r); | |
169 | return; | |
170 | } | |
171 | ||
172 | v2_child_attach(); | |
173 | } | |
174 | ||
175 | template <typename I> | |
176 | void AttachChildRequest<I>::v2_child_attach() { | |
177 | ldout(m_cct, 15) << dendl; | |
178 | ||
179 | librados::ObjectWriteOperation op; | |
180 | cls_client::child_attach(&op, m_parent_snap_id, | |
181 | {m_image_ctx->md_ctx.get_id(), | |
182 | m_image_ctx->md_ctx.get_namespace(), | |
183 | m_image_ctx->id}); | |
184 | ||
185 | using klass = AttachChildRequest<I>; | |
186 | auto aio_comp = create_rados_callback< | |
187 | klass, &klass::handle_v2_child_attach>(this); | |
188 | int r = m_parent_image_ctx->md_ctx.aio_operate(m_parent_image_ctx->header_oid, | |
189 | aio_comp, &op); | |
190 | ceph_assert(r == 0); | |
191 | aio_comp->release(); | |
192 | } | |
193 | ||
194 | template <typename I> | |
195 | void AttachChildRequest<I>::handle_v2_child_attach(int r) { | |
196 | ldout(m_cct, 15) << "r=" << r << dendl; | |
197 | ||
198 | if (r < 0) { | |
199 | if (r == -EEXIST && m_old_parent_image_ctx != nullptr) { | |
200 | ldout(m_cct, 5) << "child already exists" << dendl; | |
201 | } else { | |
202 | lderr(m_cct) << "failed to attach child image: " << cpp_strerror(r) | |
203 | << dendl; | |
204 | finish(r); | |
205 | return; | |
206 | } | |
207 | } | |
208 | ||
209 | v2_child_detach_from_old_parent(); | |
210 | } | |
211 | ||
212 | template <typename I> | |
213 | void AttachChildRequest<I>::v2_child_detach_from_old_parent() { | |
214 | if (m_old_parent_image_ctx == nullptr) { | |
215 | finish(0); | |
216 | return; | |
217 | } | |
218 | ||
219 | ldout(m_cct, 15) << dendl; | |
220 | ||
221 | librados::ObjectWriteOperation op; | |
222 | cls_client::child_detach(&op, m_old_parent_snap_id, | |
223 | {m_image_ctx->md_ctx.get_id(), | |
224 | m_image_ctx->md_ctx.get_namespace(), | |
225 | m_image_ctx->id}); | |
226 | ||
227 | using klass = AttachChildRequest<I>; | |
228 | auto aio_comp = create_rados_callback< | |
229 | klass, &klass::handle_v2_child_detach_from_old_parent>(this); | |
230 | int r = m_old_parent_image_ctx->md_ctx.aio_operate( | |
231 | m_old_parent_image_ctx->header_oid, aio_comp, &op); | |
232 | ceph_assert(r == 0); | |
233 | aio_comp->release(); | |
234 | } | |
235 | ||
236 | template <typename I> | |
237 | void AttachChildRequest<I>::handle_v2_child_detach_from_old_parent(int r) { | |
238 | ldout(m_cct, 15) << "r=" << r << dendl; | |
239 | ||
240 | if (r < 0 && r != -ENOENT) { | |
241 | lderr(m_cct) << "failed to detach child image: " << cpp_strerror(r) | |
242 | << dendl; | |
243 | finish(r); | |
244 | return; | |
245 | } | |
246 | ||
247 | finish(0); | |
248 | } | |
249 | ||
250 | template <typename I> | |
251 | void AttachChildRequest<I>::finish(int r) { | |
252 | ldout(m_cct, 5) << "r=" << r << dendl; | |
253 | ||
254 | m_on_finish->complete(r); | |
255 | delete this; | |
256 | } | |
257 | ||
258 | } // namespace image | |
259 | } // namespace librbd | |
260 | ||
261 | template class librbd::image::AttachChildRequest<librbd::ImageCtx>; |