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