]>
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 | 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 | ||
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 { | |
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 | ||
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 | |
f67539c2 TL |
526 | send_init_plugin_registry(); |
527 | return nullptr; | |
9f95a23c TL |
528 | } |
529 | ||
530 | template <typename I> | |
f67539c2 | 531 | void 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 | ||
543 | template <typename I> | |
f67539c2 | 544 | Context* 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 | ||
558 | template <typename I> | |
11fdf7f2 | 559 | Context *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 | ||
598 | template <typename I> | |
599 | Context *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 | ||
614 | template <typename I> | |
11fdf7f2 | 615 | Context *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 | ||
633 | template <typename I> | |
634 | Context *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 | ||
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 | ||
9f95a23c TL |
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 | ||
7c673cae FG |
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>; |