]> git.proxmox.com Git - ceph.git/blob - ceph/src/tools/rbd_mirror/image_replayer/CreateImageRequest.cc
2c7a0f367e3d8597425c9f62f90672a72f21a02e
[ceph.git] / ceph / src / tools / rbd_mirror / image_replayer / CreateImageRequest.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 "CreateImageRequest.h"
5 #include "CloseImageRequest.h"
6 #include "OpenImageRequest.h"
7 #include "common/errno.h"
8 #include "common/WorkQueue.h"
9 #include "cls/rbd/cls_rbd_client.h"
10 #include "librbd/ImageCtx.h"
11 #include "librbd/ImageState.h"
12 #include "librbd/internal.h"
13 #include "librbd/Utils.h"
14 #include "librbd/image/CreateRequest.h"
15 #include "librbd/image/CloneRequest.h"
16
17 #define dout_context g_ceph_context
18 #define dout_subsys ceph_subsys_rbd_mirror
19 #undef dout_prefix
20 #define dout_prefix *_dout << "rbd::mirror::image_replayer::CreateImageRequest: " \
21 << this << " " << __func__
22
23 using librbd::util::create_context_callback;
24 using librbd::util::create_rados_callback;
25
26 namespace rbd {
27 namespace mirror {
28 namespace image_replayer {
29
30 template <typename I>
31 CreateImageRequest<I>::CreateImageRequest(librados::IoCtx &local_io_ctx,
32 ContextWQ *work_queue,
33 const std::string &global_image_id,
34 const std::string &remote_mirror_uuid,
35 const std::string &local_image_name,
36 I *remote_image_ctx,
37 std::string *local_image_id,
38 Context *on_finish)
39 : m_local_io_ctx(local_io_ctx), m_work_queue(work_queue),
40 m_global_image_id(global_image_id),
41 m_remote_mirror_uuid(remote_mirror_uuid),
42 m_local_image_name(local_image_name), m_remote_image_ctx(remote_image_ctx),
43 m_local_image_id(local_image_id), m_on_finish(on_finish) {
44 }
45
46 template <typename I>
47 void CreateImageRequest<I>::send() {
48 int r = validate_parent();
49 if (r < 0) {
50 error(r);
51 return;
52 }
53
54 if (m_remote_parent_spec.pool_id == -1) {
55 create_image();
56 } else {
57 get_parent_global_image_id();
58 }
59 }
60
61 template <typename I>
62 void CreateImageRequest<I>::create_image() {
63 dout(20) << dendl;
64
65 using klass = CreateImageRequest<I>;
66 Context *ctx = create_context_callback<klass, &klass::handle_create_image>(this);
67
68 RWLock::RLocker snap_locker(m_remote_image_ctx->snap_lock);
69
70 librbd::ImageOptions image_options;
71 image_options.set(RBD_IMAGE_OPTION_FEATURES, m_remote_image_ctx->features);
72 image_options.set(RBD_IMAGE_OPTION_ORDER, m_remote_image_ctx->order);
73 image_options.set(RBD_IMAGE_OPTION_STRIPE_UNIT,
74 m_remote_image_ctx->stripe_unit);
75 image_options.set(RBD_IMAGE_OPTION_STRIPE_COUNT,
76 m_remote_image_ctx->stripe_count);
77
78 *m_local_image_id = librbd::util::generate_image_id(m_local_io_ctx);;
79
80 librbd::image::CreateRequest<I> *req = librbd::image::CreateRequest<I>::create(
81 m_local_io_ctx, m_local_image_name, *m_local_image_id,
82 m_remote_image_ctx->size, image_options, m_global_image_id,
83 m_remote_mirror_uuid, false, m_remote_image_ctx->op_work_queue, ctx);
84 req->send();
85 }
86
87 template <typename I>
88 void CreateImageRequest<I>::handle_create_image(int r) {
89 dout(20) << ": r=" << r << dendl;
90 if (r < 0) {
91 derr << ": failed to create local image: " << cpp_strerror(r) << dendl;
92 finish(r);
93 return;
94 }
95
96 finish(0);
97 }
98
99 template <typename I>
100 void CreateImageRequest<I>::get_parent_global_image_id() {
101 dout(20) << dendl;
102
103 librados::ObjectReadOperation op;
104 librbd::cls_client::mirror_image_get_start(&op, m_remote_parent_spec.image_id);
105
106 librados::AioCompletion *aio_comp = create_rados_callback<
107 CreateImageRequest<I>,
108 &CreateImageRequest<I>::handle_get_parent_global_image_id>(this);
109 m_out_bl.clear();
110 int r = m_remote_parent_io_ctx.aio_operate(RBD_MIRRORING, aio_comp, &op,
111 &m_out_bl);
112 assert(r == 0);
113 aio_comp->release();
114 }
115
116 template <typename I>
117 void CreateImageRequest<I>::handle_get_parent_global_image_id(int r) {
118 dout(20) << ": r=" << r << dendl;
119 if (r == 0) {
120 cls::rbd::MirrorImage mirror_image;
121 bufferlist::iterator iter = m_out_bl.begin();
122 r = librbd::cls_client::mirror_image_get_finish(&iter, &mirror_image);
123 if (r == 0) {
124 m_parent_global_image_id = mirror_image.global_image_id;
125 dout(20) << ": parent_global_image_id=" << m_parent_global_image_id
126 << dendl;
127 }
128 }
129
130 if (r == -ENOENT) {
131 dout(10) << ": parent image " << m_remote_parent_spec.image_id << " not mirrored"
132 << dendl;
133 finish(r);
134 return;
135 } else if (r < 0) {
136 derr << ": failed to retrieve global image id for parent image "
137 << m_remote_parent_spec.image_id << ": " << cpp_strerror(r) << dendl;
138 finish(r);
139 return;
140 }
141
142 get_local_parent_image_id();
143 }
144
145 template <typename I>
146 void CreateImageRequest<I>::get_local_parent_image_id() {
147 dout(20) << dendl;
148
149 librados::ObjectReadOperation op;
150 librbd::cls_client::mirror_image_get_image_id_start(
151 &op, m_parent_global_image_id);
152
153 librados::AioCompletion *aio_comp = create_rados_callback<
154 CreateImageRequest<I>,
155 &CreateImageRequest<I>::handle_get_local_parent_image_id>(this);
156 m_out_bl.clear();
157 int r = m_local_parent_io_ctx.aio_operate(RBD_MIRRORING, aio_comp, &op,
158 &m_out_bl);
159 assert(r == 0);
160 aio_comp->release();
161 }
162
163 template <typename I>
164 void CreateImageRequest<I>::handle_get_local_parent_image_id(int r) {
165 dout(20) << ": r=" << r << dendl;
166
167 if (r == 0) {
168 bufferlist::iterator iter = m_out_bl.begin();
169 r = librbd::cls_client::mirror_image_get_image_id_finish(
170 &iter, &m_local_parent_spec.image_id);
171 }
172
173 if (r == -ENOENT) {
174 dout(10) << ": parent image " << m_parent_global_image_id << " not "
175 << "registered locally" << dendl;
176 finish(r);
177 return;
178 } else if (r < 0) {
179 derr << ": failed to retrieve local image id for parent image "
180 << m_parent_global_image_id << ": " << cpp_strerror(r) << dendl;
181 finish(r);
182 return;
183 }
184
185 open_remote_parent_image();
186 }
187
188 template <typename I>
189 void CreateImageRequest<I>::open_remote_parent_image() {
190 dout(20) << dendl;
191
192 Context *ctx = create_context_callback<
193 CreateImageRequest<I>,
194 &CreateImageRequest<I>::handle_open_remote_parent_image>(this);
195 OpenImageRequest<I> *request = OpenImageRequest<I>::create(
196 m_remote_parent_io_ctx, &m_remote_parent_image_ctx,
197 m_remote_parent_spec.image_id, true, ctx);
198 request->send();
199 }
200
201 template <typename I>
202 void CreateImageRequest<I>::handle_open_remote_parent_image(int r) {
203 dout(20) << ": r=" << r << dendl;
204 if (r < 0) {
205 derr << ": failed to open remote parent image " << m_parent_pool_name << "/"
206 << m_remote_parent_spec.image_id << dendl;
207 finish(r);
208 return;
209 }
210
211 open_local_parent_image();
212 }
213
214 template <typename I>
215 void CreateImageRequest<I>::open_local_parent_image() {
216 dout(20) << dendl;
217
218 Context *ctx = create_context_callback<
219 CreateImageRequest<I>,
220 &CreateImageRequest<I>::handle_open_local_parent_image>(this);
221 OpenImageRequest<I> *request = OpenImageRequest<I>::create(
222 m_local_parent_io_ctx, &m_local_parent_image_ctx,
223 m_local_parent_spec.image_id, true, ctx);
224 request->send();
225 }
226
227 template <typename I>
228 void CreateImageRequest<I>::handle_open_local_parent_image(int r) {
229 dout(20) << ": r=" << r << dendl;
230 if (r < 0) {
231 derr << ": failed to open local parent image " << m_parent_pool_name << "/"
232 << m_local_parent_spec.image_id << dendl;
233 m_ret_val = r;
234 close_remote_parent_image();
235 return;
236 }
237
238 set_local_parent_snap();
239 }
240
241 template <typename I>
242 void CreateImageRequest<I>::set_local_parent_snap() {
243 dout(20) << dendl;
244
245 {
246 RWLock::RLocker remote_snap_locker(m_remote_parent_image_ctx->snap_lock);
247 auto it = m_remote_parent_image_ctx->snap_info.find(
248 m_remote_parent_spec.snap_id);
249 if (it != m_remote_parent_image_ctx->snap_info.end()) {
250 m_parent_snap_name = it->second.name;
251 }
252 }
253
254 if (m_parent_snap_name.empty()) {
255 m_ret_val = -ENOENT;
256 close_local_parent_image();
257 return;
258 }
259 dout(20) << ": parent_snap_name=" << m_parent_snap_name << dendl;
260
261 Context *ctx = create_context_callback<
262 CreateImageRequest<I>,
263 &CreateImageRequest<I>::handle_set_local_parent_snap>(this);
264 m_local_parent_image_ctx->state->snap_set(cls::rbd::UserSnapshotNamespace(),
265 m_parent_snap_name,
266 ctx);
267 }
268
269 template <typename I>
270 void CreateImageRequest<I>::handle_set_local_parent_snap(int r) {
271 dout(20) << ": r=" << r << dendl;
272 if (r < 0) {
273 derr << ": failed to set parent snapshot " << m_parent_snap_name
274 << ": " << cpp_strerror(r) << dendl;
275 m_ret_val = r;
276 close_local_parent_image();
277 return;
278 }
279
280 clone_image();
281 }
282
283 template <typename I>
284 void CreateImageRequest<I>::clone_image() {
285 dout(20) << dendl;
286
287 librbd::ImageOptions opts;
288 opts.set(RBD_IMAGE_OPTION_FEATURES, m_remote_image_ctx->features);
289 opts.set(RBD_IMAGE_OPTION_ORDER, m_remote_image_ctx->order);
290 opts.set(RBD_IMAGE_OPTION_STRIPE_UNIT, m_remote_image_ctx->stripe_unit);
291 opts.set(RBD_IMAGE_OPTION_STRIPE_COUNT, m_remote_image_ctx->stripe_count);
292
293 *m_local_image_id = librbd::util::generate_image_id(m_local_io_ctx);;
294
295 using klass = CreateImageRequest<I>;
296 Context *ctx = create_context_callback<klass, &klass::handle_clone_image>(this);
297
298 librbd::image::CloneRequest<I> *req = librbd::image::CloneRequest<I>::create(
299 m_local_parent_image_ctx, m_local_io_ctx, m_local_image_name,
300 *m_local_image_id, opts, m_global_image_id, m_remote_mirror_uuid,
301 m_remote_image_ctx->op_work_queue, ctx);
302 req->send();
303 }
304
305 template <typename I>
306 void CreateImageRequest<I>::handle_clone_image(int r) {
307 dout(20) << ": r=" << r << dendl;
308 if (r < 0) {
309 derr << ": failed to clone image " << m_parent_pool_name << "/"
310 << m_local_parent_image_ctx->name << " to "
311 << m_local_image_name << dendl;
312 m_ret_val = r;
313 }
314
315 close_local_parent_image();
316 }
317
318 template <typename I>
319 void CreateImageRequest<I>::close_local_parent_image() {
320 dout(20) << dendl;
321 Context *ctx = create_context_callback<
322 CreateImageRequest<I>,
323 &CreateImageRequest<I>::handle_close_local_parent_image>(this);
324 CloseImageRequest<I> *request = CloseImageRequest<I>::create(
325 &m_local_parent_image_ctx, ctx);
326 request->send();
327 }
328
329 template <typename I>
330 void CreateImageRequest<I>::handle_close_local_parent_image(int r) {
331 dout(20) << ": r=" << r << dendl;
332 if (r < 0) {
333 derr << ": error encountered closing local parent image: "
334 << cpp_strerror(r) << dendl;
335 }
336
337 close_remote_parent_image();
338 }
339
340 template <typename I>
341 void CreateImageRequest<I>::close_remote_parent_image() {
342 dout(20) << dendl;
343 Context *ctx = create_context_callback<
344 CreateImageRequest<I>,
345 &CreateImageRequest<I>::handle_close_remote_parent_image>(this);
346 CloseImageRequest<I> *request = CloseImageRequest<I>::create(
347 &m_remote_parent_image_ctx, ctx);
348 request->send();
349 }
350
351 template <typename I>
352 void CreateImageRequest<I>::handle_close_remote_parent_image(int r) {
353 dout(20) << ": r=" << r << dendl;
354 if (r < 0) {
355 derr << ": error encountered closing remote parent image: "
356 << cpp_strerror(r) << dendl;
357 }
358
359 finish(m_ret_val);
360 }
361
362 template <typename I>
363 void CreateImageRequest<I>::error(int r) {
364 dout(20) << ": r=" << r << dendl;
365
366 m_work_queue->queue(create_context_callback<
367 CreateImageRequest<I>, &CreateImageRequest<I>::finish>(this), r);
368 }
369
370 template <typename I>
371 void CreateImageRequest<I>::finish(int r) {
372 dout(20) << ": r=" << r << dendl;
373 m_on_finish->complete(r);
374 delete this;
375 }
376
377 template <typename I>
378 int CreateImageRequest<I>::validate_parent() {
379 RWLock::RLocker owner_locker(m_remote_image_ctx->owner_lock);
380 RWLock::RLocker snap_locker(m_remote_image_ctx->snap_lock);
381
382 m_remote_parent_spec = m_remote_image_ctx->parent_md.spec;
383
384 // scan all remote snapshots for a linked parent
385 for (auto &snap_info_pair : m_remote_image_ctx->snap_info) {
386 auto &parent_spec = snap_info_pair.second.parent.spec;
387 if (parent_spec.pool_id == -1) {
388 continue;
389 } else if (m_remote_parent_spec.pool_id == -1) {
390 m_remote_parent_spec = parent_spec;
391 continue;
392 }
393
394 if (m_remote_parent_spec != parent_spec) {
395 derr << ": remote image parent spec mismatch" << dendl;
396 return -EINVAL;
397 }
398 }
399
400 if (m_remote_parent_spec.pool_id == -1) {
401 return 0;
402 }
403
404 // map remote parent pool to local parent pool
405 librados::Rados remote_rados(m_remote_image_ctx->md_ctx);
406 int r = remote_rados.ioctx_create2(m_remote_parent_spec.pool_id,
407 m_remote_parent_io_ctx);
408 if (r < 0) {
409 derr << ": failed to open remote parent pool " << m_remote_parent_spec.pool_id
410 << ": " << cpp_strerror(r) << dendl;
411 return r;
412 }
413
414 m_parent_pool_name = m_remote_parent_io_ctx.get_pool_name();
415
416 librados::Rados local_rados(m_local_io_ctx);
417 r = local_rados.ioctx_create(m_parent_pool_name.c_str(),
418 m_local_parent_io_ctx);
419 if (r < 0) {
420 derr << ": failed to open local parent pool " << m_parent_pool_name << ": "
421 << cpp_strerror(r) << dendl;
422 return r;
423 }
424
425 return 0;
426 }
427
428 } // namespace image_replayer
429 } // namespace mirror
430 } // namespace rbd
431
432 template class rbd::mirror::image_replayer::CreateImageRequest<librbd::ImageCtx>;