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>;