]>
Commit | Line | Data |
---|---|---|
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 FG |
9 | #include "librbd/ImageCtx.h" |
10 | #include "librbd/Utils.h" | |
11fdf7f2 | 11 | #include "librbd/cache/ObjectCacherObjectDispatch.h" |
9f95a23c TL |
12 | #include "librbd/cache/WriteAroundObjectDispatch.h" |
13 | #include "librbd/cache/ParentCacheObjectDispatch.cc" | |
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 | ||
25 | namespace librbd { | |
26 | namespace image { | |
27 | ||
7c673cae FG |
28 | using util::create_context_callback; |
29 | using util::create_rados_callback; | |
30 | ||
31 | template <typename I> | |
11fdf7f2 | 32 | OpenRequest<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 | ||
45 | template <typename I> | |
46 | void 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 | ||
54 | template <typename I> | |
55 | void 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 | ||
68 | template <typename I> | |
69 | Context *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 | ||
92 | template <typename I> | |
93 | void 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 | ||
113 | template <typename I> | |
114 | Context *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 | ||
131 | template <typename I> | |
132 | void 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 | ||
148 | template <typename I> | |
149 | Context *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 | ||
167 | template <typename I> | |
168 | void 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 | ||
183 | template <typename I> | |
184 | Context *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 | ||
207 | template <typename I> | |
208 | void 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 | ||
223 | template <typename I> | |
224 | Context *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 | ||
253 | template <typename I> | |
11fdf7f2 | 254 | void 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 | ||
275 | template <typename I> | |
11fdf7f2 | 276 | Context *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 | ||
313 | template <typename I> | |
314 | void 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 | ||
330 | template <typename I> | |
331 | Context *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 | ||
356 | template <typename I> | |
357 | void 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 | ||
373 | template <typename I> | |
374 | Context *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 | ||
395 | template <typename I> | |
11fdf7f2 | 396 | void 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 | ||
414 | template <typename I> | |
11fdf7f2 | 415 | Context *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 | ||
439 | template <typename I> | |
11fdf7f2 | 440 | void 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 | ||
456 | template <typename I> | |
11fdf7f2 | 457 | Context *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 { | |
486 | m_image_ctx->data_ctx.set_namespace(m_image_ctx->md_ctx.get_namespace()); | |
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 | ||
497 | template <typename I> | |
11fdf7f2 | 498 | void 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 | ||
514 | template <typename I> | |
11fdf7f2 | 515 | Context *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 | |
9f95a23c TL |
526 | return send_parent_cache(result); |
527 | } | |
528 | ||
529 | template <typename I> | |
530 | Context* OpenRequest<I>::send_parent_cache(int *result) { | |
531 | CephContext *cct = m_image_ctx->cct; | |
532 | ldout(cct, 10) << __func__ << ": r=" << *result << dendl; | |
533 | ||
534 | bool parent_cache_enabled = m_image_ctx->config.template get_val<bool>( | |
535 | "rbd_parent_cache_enabled"); | |
536 | ||
537 | if (m_image_ctx->child == nullptr || !parent_cache_enabled) { | |
538 | return send_init_cache(result); | |
539 | } | |
540 | ||
541 | auto parent_cache = cache::ParentCacheObjectDispatch<I>::create(m_image_ctx); | |
542 | using klass = OpenRequest<I>; | |
543 | Context *ctx = create_context_callback< | |
544 | klass, &klass::handle_parent_cache>(this); | |
545 | ||
546 | parent_cache->init(ctx); | |
547 | return nullptr; | |
548 | } | |
549 | ||
550 | template <typename I> | |
551 | Context* OpenRequest<I>::handle_parent_cache(int* result) { | |
552 | CephContext *cct = m_image_ctx->cct; | |
553 | ldout(cct, 10) << __func__ << ": r=" << *result << dendl; | |
554 | ||
555 | if (*result < 0) { | |
556 | lderr(cct) << "failed to parent cache " << dendl; | |
557 | send_close_image(*result); | |
558 | return nullptr; | |
559 | } | |
560 | ||
11fdf7f2 | 561 | return send_init_cache(result); |
7c673cae FG |
562 | } |
563 | ||
564 | template <typename I> | |
11fdf7f2 TL |
565 | Context *OpenRequest<I>::send_init_cache(int *result) { |
566 | // cache is disabled or parent image context | |
9f95a23c | 567 | if (!m_image_ctx->cache || m_image_ctx->child != nullptr) { |
11fdf7f2 TL |
568 | return send_register_watch(result); |
569 | } | |
570 | ||
571 | CephContext *cct = m_image_ctx->cct; | |
572 | ldout(cct, 10) << this << " " << __func__ << dendl; | |
573 | ||
9f95a23c TL |
574 | size_t max_dirty = m_image_ctx->config.template get_val<Option::size_t>( |
575 | "rbd_cache_max_dirty"); | |
576 | auto writethrough_until_flush = m_image_ctx->config.template get_val<bool>( | |
577 | "rbd_cache_writethrough_until_flush"); | |
578 | auto cache_policy = m_image_ctx->config.template get_val<std::string>( | |
579 | "rbd_cache_policy"); | |
580 | if (cache_policy == "writearound") { | |
581 | auto cache = cache::WriteAroundObjectDispatch<I>::create( | |
582 | m_image_ctx, max_dirty, writethrough_until_flush); | |
583 | cache->init(); | |
584 | } else if (cache_policy == "writethrough" || cache_policy == "writeback") { | |
585 | if (cache_policy == "writethrough") { | |
586 | max_dirty = 0; | |
587 | } | |
11fdf7f2 | 588 | |
9f95a23c TL |
589 | auto cache = cache::ObjectCacherObjectDispatch<I>::create( |
590 | m_image_ctx, max_dirty, writethrough_until_flush); | |
591 | cache->init(); | |
11fdf7f2 | 592 | |
9f95a23c TL |
593 | // readahead requires the object cacher cache |
594 | m_image_ctx->readahead.set_trigger_requests( | |
595 | m_image_ctx->config.template get_val<uint64_t>("rbd_readahead_trigger_requests")); | |
596 | m_image_ctx->readahead.set_max_readahead_size( | |
597 | m_image_ctx->config.template get_val<Option::size_t>("rbd_readahead_max_bytes")); | |
598 | } | |
11fdf7f2 TL |
599 | return send_register_watch(result); |
600 | } | |
601 | ||
602 | template <typename I> | |
603 | Context *OpenRequest<I>::send_register_watch(int *result) { | |
9f95a23c | 604 | if ((m_image_ctx->read_only_flags & IMAGE_READ_ONLY_FLAG_USER) != 0U) { |
11fdf7f2 TL |
605 | return send_set_snap(result); |
606 | } | |
607 | ||
7c673cae FG |
608 | CephContext *cct = m_image_ctx->cct; |
609 | ldout(cct, 10) << this << " " << __func__ << dendl; | |
610 | ||
611 | using klass = OpenRequest<I>; | |
11fdf7f2 TL |
612 | Context *ctx = create_context_callback< |
613 | klass, &klass::handle_register_watch>(this); | |
614 | m_image_ctx->register_watch(ctx); | |
615 | return nullptr; | |
7c673cae FG |
616 | } |
617 | ||
618 | template <typename I> | |
11fdf7f2 | 619 | Context *OpenRequest<I>::handle_register_watch(int *result) { |
7c673cae | 620 | CephContext *cct = m_image_ctx->cct; |
11fdf7f2 | 621 | ldout(cct, 10) << this << " " << __func__ << ": r=" << *result << dendl; |
7c673cae | 622 | |
11fdf7f2 TL |
623 | if (*result == -EPERM) { |
624 | ldout(cct, 5) << "user does not have write permission" << dendl; | |
625 | send_close_image(*result); | |
626 | return nullptr; | |
627 | } else if (*result < 0) { | |
628 | lderr(cct) << "failed to register watch: " << cpp_strerror(*result) | |
7c673cae FG |
629 | << dendl; |
630 | send_close_image(*result); | |
631 | return nullptr; | |
7c673cae | 632 | } |
11fdf7f2 TL |
633 | |
634 | return send_set_snap(result); | |
7c673cae FG |
635 | } |
636 | ||
637 | template <typename I> | |
638 | Context *OpenRequest<I>::send_set_snap(int *result) { | |
11fdf7f2 TL |
639 | if (m_image_ctx->snap_name.empty() && |
640 | m_image_ctx->open_snap_id == CEPH_NOSNAP) { | |
7c673cae | 641 | *result = 0; |
9f95a23c | 642 | return finalize(*result); |
7c673cae FG |
643 | } |
644 | ||
645 | CephContext *cct = m_image_ctx->cct; | |
646 | ldout(cct, 10) << this << " " << __func__ << dendl; | |
647 | ||
11fdf7f2 TL |
648 | uint64_t snap_id = CEPH_NOSNAP; |
649 | std::swap(m_image_ctx->open_snap_id, snap_id); | |
650 | if (snap_id == CEPH_NOSNAP) { | |
9f95a23c | 651 | std::shared_lock image_locker{m_image_ctx->image_lock}; |
11fdf7f2 TL |
652 | snap_id = m_image_ctx->get_snap_id(m_image_ctx->snap_namespace, |
653 | m_image_ctx->snap_name); | |
654 | } | |
655 | if (snap_id == CEPH_NOSNAP) { | |
656 | lderr(cct) << "failed to find snapshot " << m_image_ctx->snap_name << dendl; | |
657 | send_close_image(-ENOENT); | |
658 | return nullptr; | |
659 | } | |
660 | ||
7c673cae FG |
661 | using klass = OpenRequest<I>; |
662 | SetSnapRequest<I> *req = SetSnapRequest<I>::create( | |
11fdf7f2 | 663 | *m_image_ctx, snap_id, |
7c673cae FG |
664 | create_context_callback<klass, &klass::handle_set_snap>(this)); |
665 | req->send(); | |
666 | return nullptr; | |
667 | } | |
668 | ||
669 | template <typename I> | |
670 | Context *OpenRequest<I>::handle_set_snap(int *result) { | |
671 | CephContext *cct = m_image_ctx->cct; | |
672 | ldout(cct, 10) << __func__ << ": r=" << *result << dendl; | |
673 | ||
674 | if (*result < 0) { | |
675 | lderr(cct) << "failed to set image snapshot: " << cpp_strerror(*result) | |
676 | << dendl; | |
677 | send_close_image(*result); | |
678 | return nullptr; | |
679 | } | |
680 | ||
9f95a23c TL |
681 | return finalize(*result); |
682 | } | |
683 | ||
684 | template <typename I> | |
685 | Context *OpenRequest<I>::finalize(int r) { | |
686 | if (r == 0) { | |
687 | auto io_scheduler_cfg = | |
688 | m_image_ctx->config.template get_val<std::string>("rbd_io_scheduler"); | |
689 | ||
690 | if (io_scheduler_cfg == "simple" && !m_image_ctx->read_only) { | |
691 | auto io_scheduler = | |
692 | io::SimpleSchedulerObjectDispatch<I>::create(m_image_ctx); | |
693 | io_scheduler->init(); | |
694 | } | |
695 | } | |
696 | ||
7c673cae FG |
697 | return m_on_finish; |
698 | } | |
699 | ||
700 | template <typename I> | |
701 | void OpenRequest<I>::send_close_image(int error_result) { | |
702 | CephContext *cct = m_image_ctx->cct; | |
703 | ldout(cct, 10) << this << " " << __func__ << dendl; | |
704 | ||
705 | m_error_result = error_result; | |
706 | ||
707 | using klass = OpenRequest<I>; | |
708 | Context *ctx = create_context_callback<klass, &klass::handle_close_image>( | |
709 | this); | |
710 | CloseRequest<I> *req = CloseRequest<I>::create(m_image_ctx, ctx); | |
711 | req->send(); | |
712 | } | |
713 | ||
714 | template <typename I> | |
715 | Context *OpenRequest<I>::handle_close_image(int *result) { | |
716 | CephContext *cct = m_image_ctx->cct; | |
717 | ldout(cct, 10) << __func__ << ": r=" << *result << dendl; | |
718 | ||
719 | if (*result < 0) { | |
720 | lderr(cct) << "failed to close image: " << cpp_strerror(*result) << dendl; | |
721 | } | |
722 | if (m_error_result < 0) { | |
723 | *result = m_error_result; | |
724 | } | |
725 | return m_on_finish; | |
726 | } | |
727 | ||
728 | } // namespace image | |
729 | } // namespace librbd | |
730 | ||
731 | template class librbd::image::OpenRequest<librbd::ImageCtx>; |