1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 #include "librbd/image/OpenRequest.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/CloseRequest.h"
11 #include "librbd/image/RefreshRequest.h"
12 #include "librbd/image/SetSnapRequest.h"
13 #include <boost/algorithm/string/predicate.hpp>
14 #include "include/assert.h"
16 #define dout_subsys ceph_subsys_rbd
18 #define dout_prefix *_dout << "librbd::image::OpenRequest: "
25 static uint64_t MAX_METADATA_ITEMS
= 128;
29 using util::create_context_callback
;
30 using util::create_rados_callback
;
33 OpenRequest
<I
>::OpenRequest(I
*image_ctx
, bool skip_open_parent
,
35 : m_image_ctx(image_ctx
), m_skip_open_parent_image(skip_open_parent
),
36 m_on_finish(on_finish
), m_error_result(0),
37 m_last_metadata_key(ImageCtx::METADATA_CONF_PREFIX
) {
41 void OpenRequest
<I
>::send() {
42 send_v2_detect_header();
46 void OpenRequest
<I
>::send_v1_detect_header() {
47 librados::ObjectReadOperation op
;
48 op
.stat(NULL
, NULL
, NULL
);
50 using klass
= OpenRequest
<I
>;
51 librados::AioCompletion
*comp
=
52 create_rados_callback
<klass
, &klass::handle_v1_detect_header
>(this);
54 m_image_ctx
->md_ctx
.aio_operate(util::old_header_name(m_image_ctx
->name
),
55 comp
, &op
, &m_out_bl
);
60 Context
*OpenRequest
<I
>::handle_v1_detect_header(int *result
) {
61 CephContext
*cct
= m_image_ctx
->cct
;
62 ldout(cct
, 10) << __func__
<< ": r=" << *result
<< dendl
;
65 if (*result
!= -ENOENT
) {
66 lderr(cct
) << "failed to stat image header: " << cpp_strerror(*result
)
69 send_close_image(*result
);
71 ldout(cct
, 1) << "RBD image format 1 is deprecated. "
72 << "Please copy this image to image format 2." << dendl
;
74 m_image_ctx
->old_format
= true;
75 m_image_ctx
->header_oid
= util::old_header_name(m_image_ctx
->name
);
76 m_image_ctx
->apply_metadata({});
78 send_register_watch();
84 void OpenRequest
<I
>::send_v2_detect_header() {
85 if (m_image_ctx
->id
.empty()) {
86 CephContext
*cct
= m_image_ctx
->cct
;
87 ldout(cct
, 10) << this << " " << __func__
<< dendl
;
89 librados::ObjectReadOperation op
;
90 op
.stat(NULL
, NULL
, NULL
);
92 using klass
= OpenRequest
<I
>;
93 librados::AioCompletion
*comp
=
94 create_rados_callback
<klass
, &klass::handle_v2_detect_header
>(this);
96 m_image_ctx
->md_ctx
.aio_operate(util::id_obj_name(m_image_ctx
->name
),
97 comp
, &op
, &m_out_bl
);
104 template <typename I
>
105 Context
*OpenRequest
<I
>::handle_v2_detect_header(int *result
) {
106 CephContext
*cct
= m_image_ctx
->cct
;
107 ldout(cct
, 10) << __func__
<< ": r=" << *result
<< dendl
;
109 if (*result
== -ENOENT
) {
110 send_v1_detect_header();
111 } else if (*result
< 0) {
112 lderr(cct
) << "failed to stat v2 image header: " << cpp_strerror(*result
)
114 send_close_image(*result
);
116 m_image_ctx
->old_format
= false;
122 template <typename I
>
123 void OpenRequest
<I
>::send_v2_get_id() {
124 CephContext
*cct
= m_image_ctx
->cct
;
125 ldout(cct
, 10) << this << " " << __func__
<< dendl
;
127 librados::ObjectReadOperation op
;
128 cls_client::get_id_start(&op
);
130 using klass
= OpenRequest
<I
>;
131 librados::AioCompletion
*comp
=
132 create_rados_callback
<klass
, &klass::handle_v2_get_id
>(this);
134 m_image_ctx
->md_ctx
.aio_operate(util::id_obj_name(m_image_ctx
->name
),
135 comp
, &op
, &m_out_bl
);
139 template <typename I
>
140 Context
*OpenRequest
<I
>::handle_v2_get_id(int *result
) {
141 CephContext
*cct
= m_image_ctx
->cct
;
142 ldout(cct
, 10) << __func__
<< ": r=" << *result
<< dendl
;
145 bufferlist::iterator it
= m_out_bl
.begin();
146 *result
= cls_client::get_id_finish(&it
, &m_image_ctx
->id
);
149 lderr(cct
) << "failed to retrieve image id: " << cpp_strerror(*result
)
151 send_close_image(*result
);
153 send_v2_get_immutable_metadata();
158 template <typename I
>
159 void OpenRequest
<I
>::send_v2_get_name() {
160 CephContext
*cct
= m_image_ctx
->cct
;
161 ldout(cct
, 10) << this << " " << __func__
<< dendl
;
163 librados::ObjectReadOperation op
;
164 cls_client::dir_get_name_start(&op
, m_image_ctx
->id
);
166 using klass
= OpenRequest
<I
>;
167 librados::AioCompletion
*comp
= create_rados_callback
<
168 klass
, &klass::handle_v2_get_name
>(this);
170 m_image_ctx
->md_ctx
.aio_operate(RBD_DIRECTORY
, comp
, &op
, &m_out_bl
);
174 template <typename I
>
175 Context
*OpenRequest
<I
>::handle_v2_get_name(int *result
) {
176 CephContext
*cct
= m_image_ctx
->cct
;
177 ldout(cct
, 10) << __func__
<< ": r=" << *result
<< dendl
;
180 bufferlist::iterator it
= m_out_bl
.begin();
181 *result
= cls_client::dir_get_name_finish(&it
, &m_image_ctx
->name
);
183 if (*result
< 0 && *result
!= -ENOENT
) {
184 lderr(cct
) << "failed to retreive name: "
185 << cpp_strerror(*result
) << dendl
;
186 send_close_image(*result
);
187 } else if (*result
== -ENOENT
) {
188 // image does not exist in directory, look in the trash bin
189 ldout(cct
, 10) << "image id " << m_image_ctx
->id
<< " does not exist in "
190 << "rbd directory, searching in rbd trash..." << dendl
;
191 send_v2_get_name_from_trash();
193 send_v2_get_immutable_metadata();
199 template <typename I
>
200 void OpenRequest
<I
>::send_v2_get_name_from_trash() {
201 CephContext
*cct
= m_image_ctx
->cct
;
202 ldout(cct
, 10) << this << " " << __func__
<< dendl
;
204 librados::ObjectReadOperation op
;
205 cls_client::trash_get_start(&op
, m_image_ctx
->id
);
207 using klass
= OpenRequest
<I
>;
208 librados::AioCompletion
*comp
= create_rados_callback
<
209 klass
, &klass::handle_v2_get_name_from_trash
>(this);
211 m_image_ctx
->md_ctx
.aio_operate(RBD_TRASH
, comp
, &op
, &m_out_bl
);
215 template <typename I
>
216 Context
*OpenRequest
<I
>::handle_v2_get_name_from_trash(int *result
) {
217 CephContext
*cct
= m_image_ctx
->cct
;
218 ldout(cct
, 10) << __func__
<< ": r=" << *result
<< dendl
;
220 cls::rbd::TrashImageSpec trash_spec
;
222 bufferlist::iterator it
= m_out_bl
.begin();
223 *result
= cls_client::trash_get_finish(&it
, &trash_spec
);
224 m_image_ctx
->name
= trash_spec
.name
;
227 if (*result
== -EOPNOTSUPP
) {
230 if (*result
== -ENOENT
) {
231 ldout(cct
, 5) << "failed to retrieve name for image id "
232 << m_image_ctx
->id
<< dendl
;
234 lderr(cct
) << "failed to retreive name from trash: "
235 << cpp_strerror(*result
) << dendl
;
237 send_close_image(*result
);
239 send_v2_get_immutable_metadata();
245 template <typename I
>
246 void OpenRequest
<I
>::send_v2_get_immutable_metadata() {
247 CephContext
*cct
= m_image_ctx
->cct
;
248 ldout(cct
, 10) << this << " " << __func__
<< dendl
;
250 m_image_ctx
->old_format
= false;
251 m_image_ctx
->header_oid
= util::header_name(m_image_ctx
->id
);
253 librados::ObjectReadOperation op
;
254 cls_client::get_immutable_metadata_start(&op
);
256 using klass
= OpenRequest
<I
>;
257 librados::AioCompletion
*comp
= create_rados_callback
<
258 klass
, &klass::handle_v2_get_immutable_metadata
>(this);
260 m_image_ctx
->md_ctx
.aio_operate(m_image_ctx
->header_oid
, comp
, &op
,
265 template <typename I
>
266 Context
*OpenRequest
<I
>::handle_v2_get_immutable_metadata(int *result
) {
267 CephContext
*cct
= m_image_ctx
->cct
;
268 ldout(cct
, 10) << __func__
<< ": r=" << *result
<< dendl
;
271 bufferlist::iterator it
= m_out_bl
.begin();
272 *result
= cls_client::get_immutable_metadata_finish(
273 &it
, &m_image_ctx
->object_prefix
, &m_image_ctx
->order
);
276 lderr(cct
) << "failed to retreive immutable metadata: "
277 << cpp_strerror(*result
) << dendl
;
278 send_close_image(*result
);
280 send_v2_get_stripe_unit_count();
286 template <typename I
>
287 void OpenRequest
<I
>::send_v2_get_stripe_unit_count() {
288 CephContext
*cct
= m_image_ctx
->cct
;
289 ldout(cct
, 10) << this << " " << __func__
<< dendl
;
291 librados::ObjectReadOperation op
;
292 cls_client::get_stripe_unit_count_start(&op
);
294 using klass
= OpenRequest
<I
>;
295 librados::AioCompletion
*comp
= create_rados_callback
<
296 klass
, &klass::handle_v2_get_stripe_unit_count
>(this);
298 m_image_ctx
->md_ctx
.aio_operate(m_image_ctx
->header_oid
, comp
, &op
,
303 template <typename I
>
304 Context
*OpenRequest
<I
>::handle_v2_get_stripe_unit_count(int *result
) {
305 CephContext
*cct
= m_image_ctx
->cct
;
306 ldout(cct
, 10) << __func__
<< ": r=" << *result
<< dendl
;
309 bufferlist::iterator it
= m_out_bl
.begin();
310 *result
= cls_client::get_stripe_unit_count_finish(
311 &it
, &m_image_ctx
->stripe_unit
, &m_image_ctx
->stripe_count
);
314 if (*result
== -ENOEXEC
|| *result
== -EINVAL
) {
319 lderr(cct
) << "failed to read striping metadata: " << cpp_strerror(*result
)
321 send_close_image(*result
);
325 send_v2_get_create_timestamp();
329 template <typename I
>
330 void OpenRequest
<I
>::send_v2_get_create_timestamp() {
331 CephContext
*cct
= m_image_ctx
->cct
;
332 ldout(cct
, 10) << this << " " << __func__
<< dendl
;
334 librados::ObjectReadOperation op
;
335 cls_client::get_create_timestamp_start(&op
);
337 using klass
= OpenRequest
<I
>;
338 librados::AioCompletion
*comp
= create_rados_callback
<
339 klass
, &klass::handle_v2_get_create_timestamp
>(this);
341 m_image_ctx
->md_ctx
.aio_operate(m_image_ctx
->header_oid
, comp
, &op
,
346 template <typename I
>
347 Context
*OpenRequest
<I
>::handle_v2_get_create_timestamp(int *result
) {
348 CephContext
*cct
= m_image_ctx
->cct
;
349 ldout(cct
, 10) << this << " " << __func__
<< ": r=" << *result
<< dendl
;
352 bufferlist::iterator it
= m_out_bl
.begin();
353 *result
= cls_client::get_create_timestamp_finish(&it
,
354 &m_image_ctx
->create_timestamp
);
356 if (*result
< 0 && *result
!= -EOPNOTSUPP
) {
357 lderr(cct
) << "failed to retrieve create_timestamp: "
358 << cpp_strerror(*result
)
360 send_close_image(*result
);
364 send_v2_get_data_pool();
368 template <typename I
>
369 void OpenRequest
<I
>::send_v2_get_data_pool() {
370 CephContext
*cct
= m_image_ctx
->cct
;
371 ldout(cct
, 10) << this << " " << __func__
<< dendl
;
373 librados::ObjectReadOperation op
;
374 cls_client::get_data_pool_start(&op
);
376 using klass
= OpenRequest
<I
>;
377 librados::AioCompletion
*comp
= create_rados_callback
<
378 klass
, &klass::handle_v2_get_data_pool
>(this);
380 m_image_ctx
->md_ctx
.aio_operate(m_image_ctx
->header_oid
, comp
, &op
,
385 template <typename I
>
386 Context
*OpenRequest
<I
>::handle_v2_get_data_pool(int *result
) {
387 CephContext
*cct
= m_image_ctx
->cct
;
388 ldout(cct
, 10) << this << " " << __func__
<< ": r=" << *result
<< dendl
;
390 int64_t data_pool_id
= -1;
392 bufferlist::iterator it
= m_out_bl
.begin();
393 *result
= cls_client::get_data_pool_finish(&it
, &data_pool_id
);
394 } else if (*result
== -EOPNOTSUPP
) {
399 lderr(cct
) << "failed to read data pool: " << cpp_strerror(*result
)
401 send_close_image(*result
);
405 if (data_pool_id
!= -1) {
406 librados::Rados
rados(m_image_ctx
->md_ctx
);
407 *result
= rados
.ioctx_create2(data_pool_id
, m_image_ctx
->data_ctx
);
409 lderr(cct
) << "failed to initialize data pool IO context: "
410 << cpp_strerror(*result
) << dendl
;
411 send_close_image(*result
);
416 m_image_ctx
->init_layout();
417 send_v2_apply_metadata();
421 template <typename I
>
422 void OpenRequest
<I
>::send_v2_apply_metadata() {
423 CephContext
*cct
= m_image_ctx
->cct
;
424 ldout(cct
, 10) << this << " " << __func__
<< ": "
425 << "start_key=" << m_last_metadata_key
<< dendl
;
427 librados::ObjectReadOperation op
;
428 cls_client::metadata_list_start(&op
, m_last_metadata_key
, MAX_METADATA_ITEMS
);
430 using klass
= OpenRequest
<I
>;
431 librados::AioCompletion
*comp
=
432 create_rados_callback
<klass
, &klass::handle_v2_apply_metadata
>(this);
434 m_image_ctx
->md_ctx
.aio_operate(m_image_ctx
->header_oid
, comp
, &op
,
439 template <typename I
>
440 Context
*OpenRequest
<I
>::handle_v2_apply_metadata(int *result
) {
441 CephContext
*cct
= m_image_ctx
->cct
;
442 ldout(cct
, 10) << this << " " << __func__
<< ": r=" << *result
<< dendl
;
444 std::map
<std::string
, bufferlist
> metadata
;
446 bufferlist::iterator it
= m_out_bl
.begin();
447 *result
= cls_client::metadata_list_finish(&it
, &metadata
);
450 if (*result
== -EOPNOTSUPP
|| *result
== -EIO
) {
451 ldout(cct
, 10) << "config metadata not supported by OSD" << dendl
;
452 } else if (*result
< 0) {
453 lderr(cct
) << "failed to retrieve metadata: " << cpp_strerror(*result
)
455 send_close_image(*result
);
459 if (!metadata
.empty()) {
460 m_metadata
.insert(metadata
.begin(), metadata
.end());
461 m_last_metadata_key
= metadata
.rbegin()->first
;
462 if (boost::starts_with(m_last_metadata_key
,
463 ImageCtx::METADATA_CONF_PREFIX
)) {
464 send_v2_apply_metadata();
469 m_image_ctx
->apply_metadata(m_metadata
);
471 send_register_watch();
475 template <typename I
>
476 void OpenRequest
<I
>::send_register_watch() {
479 if (m_image_ctx
->read_only
) {
484 CephContext
*cct
= m_image_ctx
->cct
;
485 ldout(cct
, 10) << this << " " << __func__
<< dendl
;
487 using klass
= OpenRequest
<I
>;
488 Context
*ctx
= create_context_callback
<
489 klass
, &klass::handle_register_watch
>(this);
490 m_image_ctx
->register_watch(ctx
);
493 template <typename I
>
494 Context
*OpenRequest
<I
>::handle_register_watch(int *result
) {
495 CephContext
*cct
= m_image_ctx
->cct
;
496 ldout(cct
, 10) << this << " " << __func__
<< ": r=" << *result
<< dendl
;
499 lderr(cct
) << "failed to register watch: " << cpp_strerror(*result
)
501 send_close_image(*result
);
508 template <typename I
>
509 void OpenRequest
<I
>::send_refresh() {
510 CephContext
*cct
= m_image_ctx
->cct
;
511 ldout(cct
, 10) << this << " " << __func__
<< dendl
;
513 using klass
= OpenRequest
<I
>;
514 RefreshRequest
<I
> *req
= RefreshRequest
<I
>::create(
515 *m_image_ctx
, false, m_skip_open_parent_image
,
516 create_context_callback
<klass
, &klass::handle_refresh
>(this));
520 template <typename I
>
521 Context
*OpenRequest
<I
>::handle_refresh(int *result
) {
522 CephContext
*cct
= m_image_ctx
->cct
;
523 ldout(cct
, 10) << __func__
<< ": r=" << *result
<< dendl
;
526 lderr(cct
) << "failed to refresh image: " << cpp_strerror(*result
)
528 send_close_image(*result
);
531 return send_set_snap(result
);
535 template <typename I
>
536 Context
*OpenRequest
<I
>::send_set_snap(int *result
) {
537 if (m_image_ctx
->snap_name
.empty()) {
542 CephContext
*cct
= m_image_ctx
->cct
;
543 ldout(cct
, 10) << this << " " << __func__
<< dendl
;
545 using klass
= OpenRequest
<I
>;
546 SetSnapRequest
<I
> *req
= SetSnapRequest
<I
>::create(
547 *m_image_ctx
, m_image_ctx
->snap_namespace
, m_image_ctx
->snap_name
,
548 create_context_callback
<klass
, &klass::handle_set_snap
>(this));
553 template <typename I
>
554 Context
*OpenRequest
<I
>::handle_set_snap(int *result
) {
555 CephContext
*cct
= m_image_ctx
->cct
;
556 ldout(cct
, 10) << __func__
<< ": r=" << *result
<< dendl
;
559 lderr(cct
) << "failed to set image snapshot: " << cpp_strerror(*result
)
561 send_close_image(*result
);
568 template <typename I
>
569 void OpenRequest
<I
>::send_close_image(int error_result
) {
570 CephContext
*cct
= m_image_ctx
->cct
;
571 ldout(cct
, 10) << this << " " << __func__
<< dendl
;
573 m_error_result
= error_result
;
575 using klass
= OpenRequest
<I
>;
576 Context
*ctx
= create_context_callback
<klass
, &klass::handle_close_image
>(
578 CloseRequest
<I
> *req
= CloseRequest
<I
>::create(m_image_ctx
, ctx
);
582 template <typename I
>
583 Context
*OpenRequest
<I
>::handle_close_image(int *result
) {
584 CephContext
*cct
= m_image_ctx
->cct
;
585 ldout(cct
, 10) << __func__
<< ": r=" << *result
<< dendl
;
588 lderr(cct
) << "failed to close image: " << cpp_strerror(*result
) << dendl
;
590 if (m_error_result
< 0) {
591 *result
= m_error_result
;
597 } // namespace librbd
599 template class librbd::image::OpenRequest
<librbd::ImageCtx
>;