1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
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"
17 #define dout_context g_ceph_context
18 #define dout_subsys ceph_subsys_rbd_mirror
20 #define dout_prefix *_dout << "rbd::mirror::image_replayer::CreateImageRequest: " \
21 << this << " " << __func__
23 using librbd::util::create_context_callback
;
24 using librbd::util::create_rados_callback
;
28 namespace image_replayer
{
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
,
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
) {
47 void CreateImageRequest
<I
>::send() {
48 int r
= validate_parent();
54 if (m_remote_parent_spec
.pool_id
== -1) {
57 get_parent_global_image_id();
62 void CreateImageRequest
<I
>::create_image() {
65 using klass
= CreateImageRequest
<I
>;
66 Context
*ctx
= create_context_callback
<klass
, &klass::handle_create_image
>(this);
68 RWLock::RLocker
snap_locker(m_remote_image_ctx
->snap_lock
);
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
);
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();
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
;
97 if (data_pool
!= "") {
98 image_options
.set(RBD_IMAGE_OPTION_DATA_POOL
, data_pool
);
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
);
108 template <typename I
>
109 void CreateImageRequest
<I
>::handle_create_image(int r
) {
110 dout(20) << ": r=" << r
<< dendl
;
112 derr
<< ": failed to create local image: " << cpp_strerror(r
) << dendl
;
120 template <typename I
>
121 void CreateImageRequest
<I
>::get_parent_global_image_id() {
124 librados::ObjectReadOperation op
;
125 librbd::cls_client::mirror_image_get_start(&op
, m_remote_parent_spec
.image_id
);
127 librados::AioCompletion
*aio_comp
= create_rados_callback
<
128 CreateImageRequest
<I
>,
129 &CreateImageRequest
<I
>::handle_get_parent_global_image_id
>(this);
131 int r
= m_remote_parent_io_ctx
.aio_operate(RBD_MIRRORING
, aio_comp
, &op
,
137 template <typename I
>
138 void CreateImageRequest
<I
>::handle_get_parent_global_image_id(int r
) {
139 dout(20) << ": r=" << r
<< dendl
;
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
);
145 m_parent_global_image_id
= mirror_image
.global_image_id
;
146 dout(20) << ": parent_global_image_id=" << m_parent_global_image_id
152 dout(10) << ": parent image " << m_remote_parent_spec
.image_id
<< " not mirrored"
157 derr
<< ": failed to retrieve global image id for parent image "
158 << m_remote_parent_spec
.image_id
<< ": " << cpp_strerror(r
) << dendl
;
163 get_local_parent_image_id();
166 template <typename I
>
167 void CreateImageRequest
<I
>::get_local_parent_image_id() {
170 librados::ObjectReadOperation op
;
171 librbd::cls_client::mirror_image_get_image_id_start(
172 &op
, m_parent_global_image_id
);
174 librados::AioCompletion
*aio_comp
= create_rados_callback
<
175 CreateImageRequest
<I
>,
176 &CreateImageRequest
<I
>::handle_get_local_parent_image_id
>(this);
178 int r
= m_local_parent_io_ctx
.aio_operate(RBD_MIRRORING
, aio_comp
, &op
,
184 template <typename I
>
185 void CreateImageRequest
<I
>::handle_get_local_parent_image_id(int r
) {
186 dout(20) << ": r=" << r
<< dendl
;
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
);
195 dout(10) << ": parent image " << m_parent_global_image_id
<< " not "
196 << "registered locally" << dendl
;
200 derr
<< ": failed to retrieve local image id for parent image "
201 << m_parent_global_image_id
<< ": " << cpp_strerror(r
) << dendl
;
206 open_remote_parent_image();
209 template <typename I
>
210 void CreateImageRequest
<I
>::open_remote_parent_image() {
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
);
222 template <typename I
>
223 void CreateImageRequest
<I
>::handle_open_remote_parent_image(int r
) {
224 dout(20) << ": r=" << r
<< dendl
;
226 derr
<< ": failed to open remote parent image " << m_parent_pool_name
<< "/"
227 << m_remote_parent_spec
.image_id
<< dendl
;
232 open_local_parent_image();
235 template <typename I
>
236 void CreateImageRequest
<I
>::open_local_parent_image() {
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
);
248 template <typename I
>
249 void CreateImageRequest
<I
>::handle_open_local_parent_image(int r
) {
250 dout(20) << ": r=" << r
<< dendl
;
252 derr
<< ": failed to open local parent image " << m_parent_pool_name
<< "/"
253 << m_local_parent_spec
.image_id
<< dendl
;
255 close_remote_parent_image();
259 set_local_parent_snap();
262 template <typename I
>
263 void CreateImageRequest
<I
>::set_local_parent_snap() {
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
;
275 if (m_parent_snap_name
.empty()) {
277 close_local_parent_image();
280 dout(20) << ": parent_snap_name=" << m_parent_snap_name
<< dendl
;
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(),
290 template <typename I
>
291 void CreateImageRequest
<I
>::handle_set_local_parent_snap(int r
) {
292 dout(20) << ": r=" << r
<< dendl
;
294 derr
<< ": failed to set parent snapshot " << m_parent_snap_name
295 << ": " << cpp_strerror(r
) << dendl
;
297 close_local_parent_image();
304 template <typename I
>
305 void CreateImageRequest
<I
>::clone_image() {
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
);
314 using klass
= CreateImageRequest
<I
>;
315 Context
*ctx
= create_context_callback
<klass
, &klass::handle_clone_image
>(this);
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
);
324 template <typename I
>
325 void CreateImageRequest
<I
>::handle_clone_image(int r
) {
326 dout(20) << ": r=" << r
<< dendl
;
328 derr
<< ": failed to clone image " << m_parent_pool_name
<< "/"
329 << m_local_parent_image_ctx
->name
<< " to "
330 << m_local_image_name
<< dendl
;
334 close_local_parent_image();
337 template <typename I
>
338 void CreateImageRequest
<I
>::close_local_parent_image() {
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
);
348 template <typename I
>
349 void CreateImageRequest
<I
>::handle_close_local_parent_image(int r
) {
350 dout(20) << ": r=" << r
<< dendl
;
352 derr
<< ": error encountered closing local parent image: "
353 << cpp_strerror(r
) << dendl
;
356 close_remote_parent_image();
359 template <typename I
>
360 void CreateImageRequest
<I
>::close_remote_parent_image() {
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
);
370 template <typename I
>
371 void CreateImageRequest
<I
>::handle_close_remote_parent_image(int r
) {
372 dout(20) << ": r=" << r
<< dendl
;
374 derr
<< ": error encountered closing remote parent image: "
375 << cpp_strerror(r
) << dendl
;
381 template <typename I
>
382 void CreateImageRequest
<I
>::error(int r
) {
383 dout(20) << ": r=" << r
<< dendl
;
385 m_work_queue
->queue(create_context_callback
<
386 CreateImageRequest
<I
>, &CreateImageRequest
<I
>::finish
>(this), r
);
389 template <typename I
>
390 void CreateImageRequest
<I
>::finish(int r
) {
391 dout(20) << ": r=" << r
<< dendl
;
392 m_on_finish
->complete(r
);
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
);
401 m_remote_parent_spec
= m_remote_image_ctx
->parent_md
.spec
;
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) {
408 } else if (m_remote_parent_spec
.pool_id
== -1) {
409 m_remote_parent_spec
= parent_spec
;
413 if (m_remote_parent_spec
!= parent_spec
) {
414 derr
<< ": remote image parent spec mismatch" << dendl
;
419 if (m_remote_parent_spec
.pool_id
== -1) {
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
);
428 derr
<< ": failed to open remote parent pool " << m_remote_parent_spec
.pool_id
429 << ": " << cpp_strerror(r
) << dendl
;
433 m_parent_pool_name
= m_remote_parent_io_ctx
.get_pool_name();
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
);
439 derr
<< ": failed to open local parent pool " << m_parent_pool_name
<< ": "
440 << cpp_strerror(r
) << dendl
;
447 } // namespace image_replayer
448 } // namespace mirror
451 template class rbd::mirror::image_replayer::CreateImageRequest
<librbd::ImageCtx
>;