]> git.proxmox.com Git - ceph.git/blob - ceph/src/tools/rbd_mirror/image_replayer/CreateImageRequest.cc
update sources to v12.2.3
[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 const std::string &local_image_id,
37 I *remote_image_ctx,
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_local_image_id(local_image_id),
43 m_remote_image_ctx(remote_image_ctx), 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 // Determine the data pool for the local image as follows:
79 // 1. If the local pool has a default data pool, use it.
80 // 2. If the remote image has a data pool different from its metadata pool and
81 // a pool with the same name exists locally, use it.
82 // 3. Don't set the data pool explicitly.
83 std::string data_pool;
84 librados::Rados local_rados(m_local_io_ctx);
85 auto default_data_pool = g_ceph_context->_conf->get_val<std::string>("rbd_default_data_pool");
86 auto remote_md_pool = m_remote_image_ctx->md_ctx.get_pool_name();
87 auto remote_data_pool = m_remote_image_ctx->data_ctx.get_pool_name();
88
89 if (default_data_pool != "") {
90 data_pool = default_data_pool;
91 } else if (remote_data_pool != remote_md_pool) {
92 if (local_rados.pool_lookup(remote_data_pool.c_str()) >= 0) {
93 data_pool = remote_data_pool;
94 }
95 }
96
97 if (data_pool != "") {
98 image_options.set(RBD_IMAGE_OPTION_DATA_POOL, data_pool);
99 }
100
101 librbd::image::CreateRequest<I> *req = librbd::image::CreateRequest<I>::create(
102 m_local_io_ctx, m_local_image_name, m_local_image_id,
103 m_remote_image_ctx->size, image_options, m_global_image_id,
104 m_remote_mirror_uuid, false, m_remote_image_ctx->op_work_queue, ctx);
105 req->send();
106 }
107
108 template <typename I>
109 void CreateImageRequest<I>::handle_create_image(int r) {
110 dout(20) << ": r=" << r << dendl;
111 if (r < 0) {
112 derr << ": failed to create local image: " << cpp_strerror(r) << dendl;
113 finish(r);
114 return;
115 }
116
117 finish(0);
118 }
119
120 template <typename I>
121 void CreateImageRequest<I>::get_parent_global_image_id() {
122 dout(20) << dendl;
123
124 librados::ObjectReadOperation op;
125 librbd::cls_client::mirror_image_get_start(&op, m_remote_parent_spec.image_id);
126
127 librados::AioCompletion *aio_comp = create_rados_callback<
128 CreateImageRequest<I>,
129 &CreateImageRequest<I>::handle_get_parent_global_image_id>(this);
130 m_out_bl.clear();
131 int r = m_remote_parent_io_ctx.aio_operate(RBD_MIRRORING, aio_comp, &op,
132 &m_out_bl);
133 assert(r == 0);
134 aio_comp->release();
135 }
136
137 template <typename I>
138 void CreateImageRequest<I>::handle_get_parent_global_image_id(int r) {
139 dout(20) << ": r=" << r << dendl;
140 if (r == 0) {
141 cls::rbd::MirrorImage mirror_image;
142 bufferlist::iterator iter = m_out_bl.begin();
143 r = librbd::cls_client::mirror_image_get_finish(&iter, &mirror_image);
144 if (r == 0) {
145 m_parent_global_image_id = mirror_image.global_image_id;
146 dout(20) << ": parent_global_image_id=" << m_parent_global_image_id
147 << dendl;
148 }
149 }
150
151 if (r == -ENOENT) {
152 dout(10) << ": parent image " << m_remote_parent_spec.image_id << " not mirrored"
153 << dendl;
154 finish(r);
155 return;
156 } else if (r < 0) {
157 derr << ": failed to retrieve global image id for parent image "
158 << m_remote_parent_spec.image_id << ": " << cpp_strerror(r) << dendl;
159 finish(r);
160 return;
161 }
162
163 get_local_parent_image_id();
164 }
165
166 template <typename I>
167 void CreateImageRequest<I>::get_local_parent_image_id() {
168 dout(20) << dendl;
169
170 librados::ObjectReadOperation op;
171 librbd::cls_client::mirror_image_get_image_id_start(
172 &op, m_parent_global_image_id);
173
174 librados::AioCompletion *aio_comp = create_rados_callback<
175 CreateImageRequest<I>,
176 &CreateImageRequest<I>::handle_get_local_parent_image_id>(this);
177 m_out_bl.clear();
178 int r = m_local_parent_io_ctx.aio_operate(RBD_MIRRORING, aio_comp, &op,
179 &m_out_bl);
180 assert(r == 0);
181 aio_comp->release();
182 }
183
184 template <typename I>
185 void CreateImageRequest<I>::handle_get_local_parent_image_id(int r) {
186 dout(20) << ": r=" << r << dendl;
187
188 if (r == 0) {
189 bufferlist::iterator iter = m_out_bl.begin();
190 r = librbd::cls_client::mirror_image_get_image_id_finish(
191 &iter, &m_local_parent_spec.image_id);
192 }
193
194 if (r == -ENOENT) {
195 dout(10) << ": parent image " << m_parent_global_image_id << " not "
196 << "registered locally" << dendl;
197 finish(r);
198 return;
199 } else if (r < 0) {
200 derr << ": failed to retrieve local image id for parent image "
201 << m_parent_global_image_id << ": " << cpp_strerror(r) << dendl;
202 finish(r);
203 return;
204 }
205
206 open_remote_parent_image();
207 }
208
209 template <typename I>
210 void CreateImageRequest<I>::open_remote_parent_image() {
211 dout(20) << dendl;
212
213 Context *ctx = create_context_callback<
214 CreateImageRequest<I>,
215 &CreateImageRequest<I>::handle_open_remote_parent_image>(this);
216 OpenImageRequest<I> *request = OpenImageRequest<I>::create(
217 m_remote_parent_io_ctx, &m_remote_parent_image_ctx,
218 m_remote_parent_spec.image_id, true, ctx);
219 request->send();
220 }
221
222 template <typename I>
223 void CreateImageRequest<I>::handle_open_remote_parent_image(int r) {
224 dout(20) << ": r=" << r << dendl;
225 if (r < 0) {
226 derr << ": failed to open remote parent image " << m_parent_pool_name << "/"
227 << m_remote_parent_spec.image_id << dendl;
228 finish(r);
229 return;
230 }
231
232 open_local_parent_image();
233 }
234
235 template <typename I>
236 void CreateImageRequest<I>::open_local_parent_image() {
237 dout(20) << dendl;
238
239 Context *ctx = create_context_callback<
240 CreateImageRequest<I>,
241 &CreateImageRequest<I>::handle_open_local_parent_image>(this);
242 OpenImageRequest<I> *request = OpenImageRequest<I>::create(
243 m_local_parent_io_ctx, &m_local_parent_image_ctx,
244 m_local_parent_spec.image_id, true, ctx);
245 request->send();
246 }
247
248 template <typename I>
249 void CreateImageRequest<I>::handle_open_local_parent_image(int r) {
250 dout(20) << ": r=" << r << dendl;
251 if (r < 0) {
252 derr << ": failed to open local parent image " << m_parent_pool_name << "/"
253 << m_local_parent_spec.image_id << dendl;
254 m_ret_val = r;
255 close_remote_parent_image();
256 return;
257 }
258
259 set_local_parent_snap();
260 }
261
262 template <typename I>
263 void CreateImageRequest<I>::set_local_parent_snap() {
264 dout(20) << dendl;
265
266 {
267 RWLock::RLocker remote_snap_locker(m_remote_parent_image_ctx->snap_lock);
268 auto it = m_remote_parent_image_ctx->snap_info.find(
269 m_remote_parent_spec.snap_id);
270 if (it != m_remote_parent_image_ctx->snap_info.end()) {
271 m_parent_snap_name = it->second.name;
272 }
273 }
274
275 if (m_parent_snap_name.empty()) {
276 m_ret_val = -ENOENT;
277 close_local_parent_image();
278 return;
279 }
280 dout(20) << ": parent_snap_name=" << m_parent_snap_name << dendl;
281
282 Context *ctx = create_context_callback<
283 CreateImageRequest<I>,
284 &CreateImageRequest<I>::handle_set_local_parent_snap>(this);
285 m_local_parent_image_ctx->state->snap_set(cls::rbd::UserSnapshotNamespace(),
286 m_parent_snap_name,
287 ctx);
288 }
289
290 template <typename I>
291 void CreateImageRequest<I>::handle_set_local_parent_snap(int r) {
292 dout(20) << ": r=" << r << dendl;
293 if (r < 0) {
294 derr << ": failed to set parent snapshot " << m_parent_snap_name
295 << ": " << cpp_strerror(r) << dendl;
296 m_ret_val = r;
297 close_local_parent_image();
298 return;
299 }
300
301 clone_image();
302 }
303
304 template <typename I>
305 void CreateImageRequest<I>::clone_image() {
306 dout(20) << dendl;
307
308 librbd::ImageOptions opts;
309 opts.set(RBD_IMAGE_OPTION_FEATURES, m_remote_image_ctx->features);
310 opts.set(RBD_IMAGE_OPTION_ORDER, m_remote_image_ctx->order);
311 opts.set(RBD_IMAGE_OPTION_STRIPE_UNIT, m_remote_image_ctx->stripe_unit);
312 opts.set(RBD_IMAGE_OPTION_STRIPE_COUNT, m_remote_image_ctx->stripe_count);
313
314 using klass = CreateImageRequest<I>;
315 Context *ctx = create_context_callback<klass, &klass::handle_clone_image>(this);
316
317 librbd::image::CloneRequest<I> *req = librbd::image::CloneRequest<I>::create(
318 m_local_parent_image_ctx, m_local_io_ctx, m_local_image_name,
319 m_local_image_id, opts, m_global_image_id, m_remote_mirror_uuid,
320 m_remote_image_ctx->op_work_queue, ctx);
321 req->send();
322 }
323
324 template <typename I>
325 void CreateImageRequest<I>::handle_clone_image(int r) {
326 dout(20) << ": r=" << r << dendl;
327 if (r < 0) {
328 derr << ": failed to clone image " << m_parent_pool_name << "/"
329 << m_local_parent_image_ctx->name << " to "
330 << m_local_image_name << dendl;
331 m_ret_val = r;
332 }
333
334 close_local_parent_image();
335 }
336
337 template <typename I>
338 void CreateImageRequest<I>::close_local_parent_image() {
339 dout(20) << dendl;
340 Context *ctx = create_context_callback<
341 CreateImageRequest<I>,
342 &CreateImageRequest<I>::handle_close_local_parent_image>(this);
343 CloseImageRequest<I> *request = CloseImageRequest<I>::create(
344 &m_local_parent_image_ctx, ctx);
345 request->send();
346 }
347
348 template <typename I>
349 void CreateImageRequest<I>::handle_close_local_parent_image(int r) {
350 dout(20) << ": r=" << r << dendl;
351 if (r < 0) {
352 derr << ": error encountered closing local parent image: "
353 << cpp_strerror(r) << dendl;
354 }
355
356 close_remote_parent_image();
357 }
358
359 template <typename I>
360 void CreateImageRequest<I>::close_remote_parent_image() {
361 dout(20) << dendl;
362 Context *ctx = create_context_callback<
363 CreateImageRequest<I>,
364 &CreateImageRequest<I>::handle_close_remote_parent_image>(this);
365 CloseImageRequest<I> *request = CloseImageRequest<I>::create(
366 &m_remote_parent_image_ctx, ctx);
367 request->send();
368 }
369
370 template <typename I>
371 void CreateImageRequest<I>::handle_close_remote_parent_image(int r) {
372 dout(20) << ": r=" << r << dendl;
373 if (r < 0) {
374 derr << ": error encountered closing remote parent image: "
375 << cpp_strerror(r) << dendl;
376 }
377
378 finish(m_ret_val);
379 }
380
381 template <typename I>
382 void CreateImageRequest<I>::error(int r) {
383 dout(20) << ": r=" << r << dendl;
384
385 m_work_queue->queue(create_context_callback<
386 CreateImageRequest<I>, &CreateImageRequest<I>::finish>(this), r);
387 }
388
389 template <typename I>
390 void CreateImageRequest<I>::finish(int r) {
391 dout(20) << ": r=" << r << dendl;
392 m_on_finish->complete(r);
393 delete this;
394 }
395
396 template <typename I>
397 int CreateImageRequest<I>::validate_parent() {
398 RWLock::RLocker owner_locker(m_remote_image_ctx->owner_lock);
399 RWLock::RLocker snap_locker(m_remote_image_ctx->snap_lock);
400
401 m_remote_parent_spec = m_remote_image_ctx->parent_md.spec;
402
403 // scan all remote snapshots for a linked parent
404 for (auto &snap_info_pair : m_remote_image_ctx->snap_info) {
405 auto &parent_spec = snap_info_pair.second.parent.spec;
406 if (parent_spec.pool_id == -1) {
407 continue;
408 } else if (m_remote_parent_spec.pool_id == -1) {
409 m_remote_parent_spec = parent_spec;
410 continue;
411 }
412
413 if (m_remote_parent_spec != parent_spec) {
414 derr << ": remote image parent spec mismatch" << dendl;
415 return -EINVAL;
416 }
417 }
418
419 if (m_remote_parent_spec.pool_id == -1) {
420 return 0;
421 }
422
423 // map remote parent pool to local parent pool
424 librados::Rados remote_rados(m_remote_image_ctx->md_ctx);
425 int r = remote_rados.ioctx_create2(m_remote_parent_spec.pool_id,
426 m_remote_parent_io_ctx);
427 if (r < 0) {
428 derr << ": failed to open remote parent pool " << m_remote_parent_spec.pool_id
429 << ": " << cpp_strerror(r) << dendl;
430 return r;
431 }
432
433 m_parent_pool_name = m_remote_parent_io_ctx.get_pool_name();
434
435 librados::Rados local_rados(m_local_io_ctx);
436 r = local_rados.ioctx_create(m_parent_pool_name.c_str(),
437 m_local_parent_io_ctx);
438 if (r < 0) {
439 derr << ": failed to open local parent pool " << m_parent_pool_name << ": "
440 << cpp_strerror(r) << dendl;
441 return r;
442 }
443
444 return 0;
445 }
446
447 } // namespace image_replayer
448 } // namespace mirror
449 } // namespace rbd
450
451 template class rbd::mirror::image_replayer::CreateImageRequest<librbd::ImageCtx>;