]> git.proxmox.com Git - ceph.git/blame - ceph/src/librbd/image/AttachChildRequest.cc
import ceph 14.2.5
[ceph.git] / ceph / src / librbd / image / AttachChildRequest.cc
CommitLineData
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
17namespace librbd {
18namespace image {
19
20using util::create_context_callback;
21using util::create_rados_callback;
22
23template <typename I>
24AttachChildRequest<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
35template <typename I>
36void AttachChildRequest<I>::send() {
37 if (m_clone_format == 1) {
38 v1_add_child();
39 } else {
40 v2_set_op_feature();
41 }
42}
43
44template <typename I>
45void 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
61template <typename I>
62void 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
78template <typename I>
79void 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
89template <typename I>
90void 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
109template <typename I>
110void 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
132template <typename I>
133void 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
145template <typename I>
146void 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
162template <typename I>
163void 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
175template <typename I>
176void 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
194template <typename I>
195void 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
212template <typename I>
213void 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
236template <typename I>
237void 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
250template <typename I>
251void 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
261template class librbd::image::AttachChildRequest<librbd::ImageCtx>;