]> git.proxmox.com Git - ceph.git/blob - ceph/src/librbd/image/OpenRequest.cc
import 15.2.0 Octopus source
[ceph.git] / ceph / src / librbd / image / OpenRequest.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 "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/cache/ObjectCacherObjectDispatch.h"
11 #include "librbd/cache/WriteAroundObjectDispatch.h"
12 #include "librbd/cache/ParentCacheObjectDispatch.cc"
13 #include "librbd/image/CloseRequest.h"
14 #include "librbd/image/RefreshRequest.h"
15 #include "librbd/image/SetSnapRequest.h"
16 #include "librbd/io/SimpleSchedulerObjectDispatch.h"
17 #include <boost/algorithm/string/predicate.hpp>
18 #include "include/ceph_assert.h"
19
20 #define dout_subsys ceph_subsys_rbd
21 #undef dout_prefix
22 #define dout_prefix *_dout << "librbd::image::OpenRequest: "
23
24 namespace librbd {
25 namespace image {
26
27 using util::create_context_callback;
28 using util::create_rados_callback;
29
30 template <typename I>
31 OpenRequest<I>::OpenRequest(I *image_ctx, uint64_t flags,
32 Context *on_finish)
33 : m_image_ctx(image_ctx),
34 m_skip_open_parent_image(flags & OPEN_FLAG_SKIP_OPEN_PARENT),
35 m_on_finish(on_finish), m_error_result(0) {
36 if ((flags & OPEN_FLAG_OLD_FORMAT) != 0) {
37 m_image_ctx->old_format = true;
38 }
39 if ((flags & OPEN_FLAG_IGNORE_MIGRATING) != 0) {
40 m_image_ctx->ignore_migrating = true;
41 }
42 }
43
44 template <typename I>
45 void OpenRequest<I>::send() {
46 if (m_image_ctx->old_format) {
47 send_v1_detect_header();
48 } else {
49 send_v2_detect_header();
50 }
51 }
52
53 template <typename I>
54 void OpenRequest<I>::send_v1_detect_header() {
55 librados::ObjectReadOperation op;
56 op.stat(NULL, NULL, NULL);
57
58 using klass = OpenRequest<I>;
59 librados::AioCompletion *comp =
60 create_rados_callback<klass, &klass::handle_v1_detect_header>(this);
61 m_out_bl.clear();
62 m_image_ctx->md_ctx.aio_operate(util::old_header_name(m_image_ctx->name),
63 comp, &op, &m_out_bl);
64 comp->release();
65 }
66
67 template <typename I>
68 Context *OpenRequest<I>::handle_v1_detect_header(int *result) {
69 CephContext *cct = m_image_ctx->cct;
70 ldout(cct, 10) << __func__ << ": r=" << *result << dendl;
71
72 if (*result < 0) {
73 if (*result != -ENOENT) {
74 lderr(cct) << "failed to stat image header: " << cpp_strerror(*result)
75 << dendl;
76 }
77 send_close_image(*result);
78 } else {
79 ldout(cct, 1) << "RBD image format 1 is deprecated. "
80 << "Please copy this image to image format 2." << dendl;
81
82 m_image_ctx->old_format = true;
83 m_image_ctx->header_oid = util::old_header_name(m_image_ctx->name);
84 m_image_ctx->apply_metadata({}, true);
85
86 send_refresh();
87 }
88 return nullptr;
89 }
90
91 template <typename I>
92 void OpenRequest<I>::send_v2_detect_header() {
93 if (m_image_ctx->id.empty()) {
94 CephContext *cct = m_image_ctx->cct;
95 ldout(cct, 10) << this << " " << __func__ << dendl;
96
97 librados::ObjectReadOperation op;
98 op.stat(NULL, NULL, NULL);
99
100 using klass = OpenRequest<I>;
101 librados::AioCompletion *comp =
102 create_rados_callback<klass, &klass::handle_v2_detect_header>(this);
103 m_out_bl.clear();
104 m_image_ctx->md_ctx.aio_operate(util::id_obj_name(m_image_ctx->name),
105 comp, &op, &m_out_bl);
106 comp->release();
107 } else {
108 send_v2_get_name();
109 }
110 }
111
112 template <typename I>
113 Context *OpenRequest<I>::handle_v2_detect_header(int *result) {
114 CephContext *cct = m_image_ctx->cct;
115 ldout(cct, 10) << __func__ << ": r=" << *result << dendl;
116
117 if (*result == -ENOENT) {
118 send_v1_detect_header();
119 } else if (*result < 0) {
120 lderr(cct) << "failed to stat v2 image header: " << cpp_strerror(*result)
121 << dendl;
122 send_close_image(*result);
123 } else {
124 m_image_ctx->old_format = false;
125 send_v2_get_id();
126 }
127 return nullptr;
128 }
129
130 template <typename I>
131 void OpenRequest<I>::send_v2_get_id() {
132 CephContext *cct = m_image_ctx->cct;
133 ldout(cct, 10) << this << " " << __func__ << dendl;
134
135 librados::ObjectReadOperation op;
136 cls_client::get_id_start(&op);
137
138 using klass = OpenRequest<I>;
139 librados::AioCompletion *comp =
140 create_rados_callback<klass, &klass::handle_v2_get_id>(this);
141 m_out_bl.clear();
142 m_image_ctx->md_ctx.aio_operate(util::id_obj_name(m_image_ctx->name),
143 comp, &op, &m_out_bl);
144 comp->release();
145 }
146
147 template <typename I>
148 Context *OpenRequest<I>::handle_v2_get_id(int *result) {
149 CephContext *cct = m_image_ctx->cct;
150 ldout(cct, 10) << __func__ << ": r=" << *result << dendl;
151
152 if (*result == 0) {
153 auto it = m_out_bl.cbegin();
154 *result = cls_client::get_id_finish(&it, &m_image_ctx->id);
155 }
156 if (*result < 0) {
157 lderr(cct) << "failed to retrieve image id: " << cpp_strerror(*result)
158 << dendl;
159 send_close_image(*result);
160 } else {
161 send_v2_get_initial_metadata();
162 }
163 return nullptr;
164 }
165
166 template <typename I>
167 void OpenRequest<I>::send_v2_get_name() {
168 CephContext *cct = m_image_ctx->cct;
169 ldout(cct, 10) << this << " " << __func__ << dendl;
170
171 librados::ObjectReadOperation op;
172 cls_client::dir_get_name_start(&op, m_image_ctx->id);
173
174 using klass = OpenRequest<I>;
175 librados::AioCompletion *comp = create_rados_callback<
176 klass, &klass::handle_v2_get_name>(this);
177 m_out_bl.clear();
178 m_image_ctx->md_ctx.aio_operate(RBD_DIRECTORY, comp, &op, &m_out_bl);
179 comp->release();
180 }
181
182 template <typename I>
183 Context *OpenRequest<I>::handle_v2_get_name(int *result) {
184 CephContext *cct = m_image_ctx->cct;
185 ldout(cct, 10) << __func__ << ": r=" << *result << dendl;
186
187 if (*result == 0) {
188 auto it = m_out_bl.cbegin();
189 *result = cls_client::dir_get_name_finish(&it, &m_image_ctx->name);
190 }
191 if (*result < 0 && *result != -ENOENT) {
192 lderr(cct) << "failed to retrieve name: "
193 << cpp_strerror(*result) << dendl;
194 send_close_image(*result);
195 } else if (*result == -ENOENT) {
196 // image does not exist in directory, look in the trash bin
197 ldout(cct, 10) << "image id " << m_image_ctx->id << " does not exist in "
198 << "rbd directory, searching in rbd trash..." << dendl;
199 send_v2_get_name_from_trash();
200 } else {
201 send_v2_get_initial_metadata();
202 }
203 return nullptr;
204 }
205
206 template <typename I>
207 void OpenRequest<I>::send_v2_get_name_from_trash() {
208 CephContext *cct = m_image_ctx->cct;
209 ldout(cct, 10) << this << " " << __func__ << dendl;
210
211 librados::ObjectReadOperation op;
212 cls_client::trash_get_start(&op, m_image_ctx->id);
213
214 using klass = OpenRequest<I>;
215 librados::AioCompletion *comp = create_rados_callback<
216 klass, &klass::handle_v2_get_name_from_trash>(this);
217 m_out_bl.clear();
218 m_image_ctx->md_ctx.aio_operate(RBD_TRASH, comp, &op, &m_out_bl);
219 comp->release();
220 }
221
222 template <typename I>
223 Context *OpenRequest<I>::handle_v2_get_name_from_trash(int *result) {
224 CephContext *cct = m_image_ctx->cct;
225 ldout(cct, 10) << __func__ << ": r=" << *result << dendl;
226
227 cls::rbd::TrashImageSpec trash_spec;
228 if (*result == 0) {
229 auto it = m_out_bl.cbegin();
230 *result = cls_client::trash_get_finish(&it, &trash_spec);
231 m_image_ctx->name = trash_spec.name;
232 }
233 if (*result < 0) {
234 if (*result == -EOPNOTSUPP) {
235 *result = -ENOENT;
236 }
237 if (*result == -ENOENT) {
238 ldout(cct, 5) << "failed to retrieve name for image id "
239 << m_image_ctx->id << dendl;
240 } else {
241 lderr(cct) << "failed to retrieve name from trash: "
242 << cpp_strerror(*result) << dendl;
243 }
244 send_close_image(*result);
245 } else {
246 send_v2_get_initial_metadata();
247 }
248
249 return nullptr;
250 }
251
252 template <typename I>
253 void OpenRequest<I>::send_v2_get_initial_metadata() {
254 CephContext *cct = m_image_ctx->cct;
255 ldout(cct, 10) << this << " " << __func__ << dendl;
256
257 m_image_ctx->old_format = false;
258 m_image_ctx->header_oid = util::header_name(m_image_ctx->id);
259
260 librados::ObjectReadOperation op;
261 cls_client::get_size_start(&op, CEPH_NOSNAP);
262 cls_client::get_object_prefix_start(&op);
263 cls_client::get_features_start(&op, true);
264
265 using klass = OpenRequest<I>;
266 librados::AioCompletion *comp = create_rados_callback<
267 klass, &klass::handle_v2_get_initial_metadata>(this);
268 m_out_bl.clear();
269 m_image_ctx->md_ctx.aio_operate(m_image_ctx->header_oid, comp, &op,
270 &m_out_bl);
271 comp->release();
272 }
273
274 template <typename I>
275 Context *OpenRequest<I>::handle_v2_get_initial_metadata(int *result) {
276 CephContext *cct = m_image_ctx->cct;
277 ldout(cct, 10) << __func__ << ": r=" << *result << dendl;
278
279 auto it = m_out_bl.cbegin();
280 if (*result >= 0) {
281 uint64_t size;
282 *result = cls_client::get_size_finish(&it, &size, &m_image_ctx->order);
283 }
284
285 if (*result >= 0) {
286 *result = cls_client::get_object_prefix_finish(&it,
287 &m_image_ctx->object_prefix);
288 }
289
290 if (*result >= 0) {
291 uint64_t incompatible_features;
292 *result = cls_client::get_features_finish(&it, &m_image_ctx->features,
293 &incompatible_features);
294 }
295
296 if (*result < 0) {
297 lderr(cct) << "failed to retrieve initial metadata: "
298 << cpp_strerror(*result) << dendl;
299 send_close_image(*result);
300 return nullptr;
301 }
302
303 if (m_image_ctx->test_features(RBD_FEATURE_STRIPINGV2)) {
304 send_v2_get_stripe_unit_count();
305 } else {
306 send_v2_get_create_timestamp();
307 }
308
309 return nullptr;
310 }
311
312 template <typename I>
313 void OpenRequest<I>::send_v2_get_stripe_unit_count() {
314 CephContext *cct = m_image_ctx->cct;
315 ldout(cct, 10) << this << " " << __func__ << dendl;
316
317 librados::ObjectReadOperation op;
318 cls_client::get_stripe_unit_count_start(&op);
319
320 using klass = OpenRequest<I>;
321 librados::AioCompletion *comp = create_rados_callback<
322 klass, &klass::handle_v2_get_stripe_unit_count>(this);
323 m_out_bl.clear();
324 m_image_ctx->md_ctx.aio_operate(m_image_ctx->header_oid, comp, &op,
325 &m_out_bl);
326 comp->release();
327 }
328
329 template <typename I>
330 Context *OpenRequest<I>::handle_v2_get_stripe_unit_count(int *result) {
331 CephContext *cct = m_image_ctx->cct;
332 ldout(cct, 10) << __func__ << ": r=" << *result << dendl;
333
334 if (*result == 0) {
335 auto it = m_out_bl.cbegin();
336 *result = cls_client::get_stripe_unit_count_finish(
337 &it, &m_image_ctx->stripe_unit, &m_image_ctx->stripe_count);
338 }
339
340 if (*result == -ENOEXEC || *result == -EINVAL) {
341 *result = 0;
342 }
343
344 if (*result < 0) {
345 lderr(cct) << "failed to read striping metadata: " << cpp_strerror(*result)
346 << dendl;
347 send_close_image(*result);
348 return nullptr;
349 }
350
351 send_v2_get_create_timestamp();
352 return nullptr;
353 }
354
355 template <typename I>
356 void OpenRequest<I>::send_v2_get_create_timestamp() {
357 CephContext *cct = m_image_ctx->cct;
358 ldout(cct, 10) << this << " " << __func__ << dendl;
359
360 librados::ObjectReadOperation op;
361 cls_client::get_create_timestamp_start(&op);
362
363 using klass = OpenRequest<I>;
364 librados::AioCompletion *comp = create_rados_callback<
365 klass, &klass::handle_v2_get_create_timestamp>(this);
366 m_out_bl.clear();
367 m_image_ctx->md_ctx.aio_operate(m_image_ctx->header_oid, comp, &op,
368 &m_out_bl);
369 comp->release();
370 }
371
372 template <typename I>
373 Context *OpenRequest<I>::handle_v2_get_create_timestamp(int *result) {
374 CephContext *cct = m_image_ctx->cct;
375 ldout(cct, 10) << this << " " << __func__ << ": r=" << *result << dendl;
376
377 if (*result == 0) {
378 auto it = m_out_bl.cbegin();
379 *result = cls_client::get_create_timestamp_finish(&it,
380 &m_image_ctx->create_timestamp);
381 }
382 if (*result < 0 && *result != -EOPNOTSUPP) {
383 lderr(cct) << "failed to retrieve create_timestamp: "
384 << cpp_strerror(*result)
385 << dendl;
386 send_close_image(*result);
387 return nullptr;
388 }
389
390 send_v2_get_access_modify_timestamp();
391 return nullptr;
392 }
393
394 template <typename I>
395 void OpenRequest<I>::send_v2_get_access_modify_timestamp() {
396 CephContext *cct = m_image_ctx->cct;
397 ldout(cct, 10) << this << " " << __func__ << dendl;
398
399 librados::ObjectReadOperation op;
400 cls_client::get_access_timestamp_start(&op);
401 cls_client::get_modify_timestamp_start(&op);
402 //TODO: merge w/ create timestamp query after luminous EOLed
403
404 using klass = OpenRequest<I>;
405 librados::AioCompletion *comp = create_rados_callback<
406 klass, &klass::handle_v2_get_access_modify_timestamp>(this);
407 m_out_bl.clear();
408 m_image_ctx->md_ctx.aio_operate(m_image_ctx->header_oid, comp, &op,
409 &m_out_bl);
410 comp->release();
411 }
412
413 template <typename I>
414 Context *OpenRequest<I>::handle_v2_get_access_modify_timestamp(int *result) {
415 CephContext *cct = m_image_ctx->cct;
416 ldout(cct, 10) << this << " " << __func__ << ": r=" << *result << dendl;
417
418 if (*result == 0) {
419 auto it = m_out_bl.cbegin();
420 *result = cls_client::get_access_timestamp_finish(&it,
421 &m_image_ctx->access_timestamp);
422 if (*result == 0)
423 *result = cls_client::get_modify_timestamp_finish(&it,
424 &m_image_ctx->modify_timestamp);
425 }
426 if (*result < 0 && *result != -EOPNOTSUPP) {
427 lderr(cct) << "failed to retrieve access/modify_timestamp: "
428 << cpp_strerror(*result)
429 << dendl;
430 send_close_image(*result);
431 return nullptr;
432 }
433
434 send_v2_get_data_pool();
435 return nullptr;
436 }
437
438 template <typename I>
439 void OpenRequest<I>::send_v2_get_data_pool() {
440 CephContext *cct = m_image_ctx->cct;
441 ldout(cct, 10) << this << " " << __func__ << dendl;
442
443 librados::ObjectReadOperation op;
444 cls_client::get_data_pool_start(&op);
445
446 using klass = OpenRequest<I>;
447 librados::AioCompletion *comp = create_rados_callback<
448 klass, &klass::handle_v2_get_data_pool>(this);
449 m_out_bl.clear();
450 m_image_ctx->md_ctx.aio_operate(m_image_ctx->header_oid, comp, &op,
451 &m_out_bl);
452 comp->release();
453 }
454
455 template <typename I>
456 Context *OpenRequest<I>::handle_v2_get_data_pool(int *result) {
457 CephContext *cct = m_image_ctx->cct;
458 ldout(cct, 10) << this << " " << __func__ << ": r=" << *result << dendl;
459
460 int64_t data_pool_id = -1;
461 if (*result == 0) {
462 auto it = m_out_bl.cbegin();
463 *result = cls_client::get_data_pool_finish(&it, &data_pool_id);
464 } else if (*result == -EOPNOTSUPP) {
465 *result = 0;
466 }
467
468 if (*result < 0) {
469 lderr(cct) << "failed to read data pool: " << cpp_strerror(*result)
470 << dendl;
471 send_close_image(*result);
472 return nullptr;
473 }
474
475 if (data_pool_id != -1) {
476 *result = util::create_ioctx(m_image_ctx->md_ctx, "data pool", data_pool_id,
477 {}, &m_image_ctx->data_ctx);
478 if (*result < 0) {
479 if (*result != -ENOENT) {
480 send_close_image(*result);
481 return nullptr;
482 }
483 m_image_ctx->data_ctx.close();
484 } else {
485 m_image_ctx->data_ctx.set_namespace(m_image_ctx->md_ctx.get_namespace());
486 }
487 } else {
488 data_pool_id = m_image_ctx->md_ctx.get_id();
489 }
490
491 m_image_ctx->init_layout(data_pool_id);
492 send_refresh();
493 return nullptr;
494 }
495
496 template <typename I>
497 void OpenRequest<I>::send_refresh() {
498 m_image_ctx->init();
499
500 CephContext *cct = m_image_ctx->cct;
501 ldout(cct, 10) << this << " " << __func__ << dendl;
502
503 using klass = OpenRequest<I>;
504 RefreshRequest<I> *req = RefreshRequest<I>::create(
505 *m_image_ctx, false, m_skip_open_parent_image,
506 create_context_callback<klass, &klass::handle_refresh>(this));
507 req->send();
508 }
509
510 template <typename I>
511 Context *OpenRequest<I>::handle_refresh(int *result) {
512 CephContext *cct = m_image_ctx->cct;
513 ldout(cct, 10) << __func__ << ": r=" << *result << dendl;
514
515 if (*result < 0) {
516 lderr(cct) << "failed to refresh image: " << cpp_strerror(*result)
517 << dendl;
518 send_close_image(*result);
519 return nullptr;
520 }
521
522 return send_parent_cache(result);
523 }
524
525 template <typename I>
526 Context* OpenRequest<I>::send_parent_cache(int *result) {
527 CephContext *cct = m_image_ctx->cct;
528 ldout(cct, 10) << __func__ << ": r=" << *result << dendl;
529
530 bool parent_cache_enabled = m_image_ctx->config.template get_val<bool>(
531 "rbd_parent_cache_enabled");
532
533 if (m_image_ctx->child == nullptr || !parent_cache_enabled) {
534 return send_init_cache(result);
535 }
536
537 auto parent_cache = cache::ParentCacheObjectDispatch<I>::create(m_image_ctx);
538 using klass = OpenRequest<I>;
539 Context *ctx = create_context_callback<
540 klass, &klass::handle_parent_cache>(this);
541
542 parent_cache->init(ctx);
543 return nullptr;
544 }
545
546 template <typename I>
547 Context* OpenRequest<I>::handle_parent_cache(int* result) {
548 CephContext *cct = m_image_ctx->cct;
549 ldout(cct, 10) << __func__ << ": r=" << *result << dendl;
550
551 if (*result < 0) {
552 lderr(cct) << "failed to parent cache " << dendl;
553 send_close_image(*result);
554 return nullptr;
555 }
556
557 return send_init_cache(result);
558 }
559
560 template <typename I>
561 Context *OpenRequest<I>::send_init_cache(int *result) {
562 // cache is disabled or parent image context
563 if (!m_image_ctx->cache || m_image_ctx->child != nullptr) {
564 return send_register_watch(result);
565 }
566
567 CephContext *cct = m_image_ctx->cct;
568 ldout(cct, 10) << this << " " << __func__ << dendl;
569
570 size_t max_dirty = m_image_ctx->config.template get_val<Option::size_t>(
571 "rbd_cache_max_dirty");
572 auto writethrough_until_flush = m_image_ctx->config.template get_val<bool>(
573 "rbd_cache_writethrough_until_flush");
574 auto cache_policy = m_image_ctx->config.template get_val<std::string>(
575 "rbd_cache_policy");
576 if (cache_policy == "writearound") {
577 auto cache = cache::WriteAroundObjectDispatch<I>::create(
578 m_image_ctx, max_dirty, writethrough_until_flush);
579 cache->init();
580 } else if (cache_policy == "writethrough" || cache_policy == "writeback") {
581 if (cache_policy == "writethrough") {
582 max_dirty = 0;
583 }
584
585 auto cache = cache::ObjectCacherObjectDispatch<I>::create(
586 m_image_ctx, max_dirty, writethrough_until_flush);
587 cache->init();
588
589 // readahead requires the object cacher cache
590 m_image_ctx->readahead.set_trigger_requests(
591 m_image_ctx->config.template get_val<uint64_t>("rbd_readahead_trigger_requests"));
592 m_image_ctx->readahead.set_max_readahead_size(
593 m_image_ctx->config.template get_val<Option::size_t>("rbd_readahead_max_bytes"));
594 }
595 return send_register_watch(result);
596 }
597
598 template <typename I>
599 Context *OpenRequest<I>::send_register_watch(int *result) {
600 if ((m_image_ctx->read_only_flags & IMAGE_READ_ONLY_FLAG_USER) != 0U) {
601 return send_set_snap(result);
602 }
603
604 CephContext *cct = m_image_ctx->cct;
605 ldout(cct, 10) << this << " " << __func__ << dendl;
606
607 using klass = OpenRequest<I>;
608 Context *ctx = create_context_callback<
609 klass, &klass::handle_register_watch>(this);
610 m_image_ctx->register_watch(ctx);
611 return nullptr;
612 }
613
614 template <typename I>
615 Context *OpenRequest<I>::handle_register_watch(int *result) {
616 CephContext *cct = m_image_ctx->cct;
617 ldout(cct, 10) << this << " " << __func__ << ": r=" << *result << dendl;
618
619 if (*result == -EPERM) {
620 ldout(cct, 5) << "user does not have write permission" << dendl;
621 send_close_image(*result);
622 return nullptr;
623 } else if (*result < 0) {
624 lderr(cct) << "failed to register watch: " << cpp_strerror(*result)
625 << dendl;
626 send_close_image(*result);
627 return nullptr;
628 }
629
630 return send_set_snap(result);
631 }
632
633 template <typename I>
634 Context *OpenRequest<I>::send_set_snap(int *result) {
635 if (m_image_ctx->snap_name.empty() &&
636 m_image_ctx->open_snap_id == CEPH_NOSNAP) {
637 *result = 0;
638 return finalize(*result);
639 }
640
641 CephContext *cct = m_image_ctx->cct;
642 ldout(cct, 10) << this << " " << __func__ << dendl;
643
644 uint64_t snap_id = CEPH_NOSNAP;
645 std::swap(m_image_ctx->open_snap_id, snap_id);
646 if (snap_id == CEPH_NOSNAP) {
647 std::shared_lock image_locker{m_image_ctx->image_lock};
648 snap_id = m_image_ctx->get_snap_id(m_image_ctx->snap_namespace,
649 m_image_ctx->snap_name);
650 }
651 if (snap_id == CEPH_NOSNAP) {
652 lderr(cct) << "failed to find snapshot " << m_image_ctx->snap_name << dendl;
653 send_close_image(-ENOENT);
654 return nullptr;
655 }
656
657 using klass = OpenRequest<I>;
658 SetSnapRequest<I> *req = SetSnapRequest<I>::create(
659 *m_image_ctx, snap_id,
660 create_context_callback<klass, &klass::handle_set_snap>(this));
661 req->send();
662 return nullptr;
663 }
664
665 template <typename I>
666 Context *OpenRequest<I>::handle_set_snap(int *result) {
667 CephContext *cct = m_image_ctx->cct;
668 ldout(cct, 10) << __func__ << ": r=" << *result << dendl;
669
670 if (*result < 0) {
671 lderr(cct) << "failed to set image snapshot: " << cpp_strerror(*result)
672 << dendl;
673 send_close_image(*result);
674 return nullptr;
675 }
676
677 return finalize(*result);
678 }
679
680 template <typename I>
681 Context *OpenRequest<I>::finalize(int r) {
682 if (r == 0) {
683 auto io_scheduler_cfg =
684 m_image_ctx->config.template get_val<std::string>("rbd_io_scheduler");
685
686 if (io_scheduler_cfg == "simple" && !m_image_ctx->read_only) {
687 auto io_scheduler =
688 io::SimpleSchedulerObjectDispatch<I>::create(m_image_ctx);
689 io_scheduler->init();
690 }
691 }
692
693 return m_on_finish;
694 }
695
696 template <typename I>
697 void OpenRequest<I>::send_close_image(int error_result) {
698 CephContext *cct = m_image_ctx->cct;
699 ldout(cct, 10) << this << " " << __func__ << dendl;
700
701 m_error_result = error_result;
702
703 using klass = OpenRequest<I>;
704 Context *ctx = create_context_callback<klass, &klass::handle_close_image>(
705 this);
706 CloseRequest<I> *req = CloseRequest<I>::create(m_image_ctx, ctx);
707 req->send();
708 }
709
710 template <typename I>
711 Context *OpenRequest<I>::handle_close_image(int *result) {
712 CephContext *cct = m_image_ctx->cct;
713 ldout(cct, 10) << __func__ << ": r=" << *result << dendl;
714
715 if (*result < 0) {
716 lderr(cct) << "failed to close image: " << cpp_strerror(*result) << dendl;
717 }
718 if (m_error_result < 0) {
719 *result = m_error_result;
720 }
721 return m_on_finish;
722 }
723
724 } // namespace image
725 } // namespace librbd
726
727 template class librbd::image::OpenRequest<librbd::ImageCtx>;