]> git.proxmox.com Git - ceph.git/blame - ceph/src/librbd/image/OpenRequest.cc
add subtree-ish sources for 12.0.3
[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"
8#include "librbd/ImageCtx.h"
9#include "librbd/Utils.h"
10#include "librbd/image/CloseRequest.h"
11#include "librbd/image/RefreshRequest.h"
12#include "librbd/image/SetSnapRequest.h"
13#include <boost/algorithm/string/predicate.hpp>
14#include "include/assert.h"
15
16#define dout_subsys ceph_subsys_rbd
17#undef dout_prefix
18#define dout_prefix *_dout << "librbd::image::OpenRequest: "
19
20namespace librbd {
21namespace image {
22
23namespace {
24
25static uint64_t MAX_METADATA_ITEMS = 128;
26
27}
28
29using util::create_context_callback;
30using util::create_rados_callback;
31
32template <typename I>
33OpenRequest<I>::OpenRequest(I *image_ctx, bool skip_open_parent,
34 Context *on_finish)
35 : m_image_ctx(image_ctx), m_skip_open_parent_image(skip_open_parent),
36 m_on_finish(on_finish), m_error_result(0),
37 m_last_metadata_key(ImageCtx::METADATA_CONF_PREFIX) {
38}
39
40template <typename I>
41void OpenRequest<I>::send() {
42 send_v2_detect_header();
43}
44
45template <typename I>
46void OpenRequest<I>::send_v1_detect_header() {
47 librados::ObjectReadOperation op;
48 op.stat(NULL, NULL, NULL);
49
50 using klass = OpenRequest<I>;
51 librados::AioCompletion *comp =
52 create_rados_callback<klass, &klass::handle_v1_detect_header>(this);
53 m_out_bl.clear();
54 m_image_ctx->md_ctx.aio_operate(util::old_header_name(m_image_ctx->name),
55 comp, &op, &m_out_bl);
56 comp->release();
57}
58
59template <typename I>
60Context *OpenRequest<I>::handle_v1_detect_header(int *result) {
61 CephContext *cct = m_image_ctx->cct;
62 ldout(cct, 10) << __func__ << ": r=" << *result << dendl;
63
64 if (*result < 0) {
65 if (*result != -ENOENT) {
66 lderr(cct) << "failed to stat image header: " << cpp_strerror(*result)
67 << dendl;
68 }
69 send_close_image(*result);
70 } else {
71 ldout(cct, 1) << "RBD image format 1 is deprecated. "
72 << "Please copy this image to image format 2." << dendl;
73
74 m_image_ctx->old_format = true;
75 m_image_ctx->header_oid = util::old_header_name(m_image_ctx->name);
76 m_image_ctx->apply_metadata({});
77
78 send_register_watch();
79 }
80 return nullptr;
81}
82
83template <typename I>
84void OpenRequest<I>::send_v2_detect_header() {
85 if (m_image_ctx->id.empty()) {
86 CephContext *cct = m_image_ctx->cct;
87 ldout(cct, 10) << this << " " << __func__ << dendl;
88
89 librados::ObjectReadOperation op;
90 op.stat(NULL, NULL, NULL);
91
92 using klass = OpenRequest<I>;
93 librados::AioCompletion *comp =
94 create_rados_callback<klass, &klass::handle_v2_detect_header>(this);
95 m_out_bl.clear();
96 m_image_ctx->md_ctx.aio_operate(util::id_obj_name(m_image_ctx->name),
97 comp, &op, &m_out_bl);
98 comp->release();
99 } else {
100 send_v2_get_name();
101 }
102}
103
104template <typename I>
105Context *OpenRequest<I>::handle_v2_detect_header(int *result) {
106 CephContext *cct = m_image_ctx->cct;
107 ldout(cct, 10) << __func__ << ": r=" << *result << dendl;
108
109 if (*result == -ENOENT) {
110 send_v1_detect_header();
111 } else if (*result < 0) {
112 lderr(cct) << "failed to stat v2 image header: " << cpp_strerror(*result)
113 << dendl;
114 send_close_image(*result);
115 } else {
116 m_image_ctx->old_format = false;
117 send_v2_get_id();
118 }
119 return nullptr;
120}
121
122template <typename I>
123void OpenRequest<I>::send_v2_get_id() {
124 CephContext *cct = m_image_ctx->cct;
125 ldout(cct, 10) << this << " " << __func__ << dendl;
126
127 librados::ObjectReadOperation op;
128 cls_client::get_id_start(&op);
129
130 using klass = OpenRequest<I>;
131 librados::AioCompletion *comp =
132 create_rados_callback<klass, &klass::handle_v2_get_id>(this);
133 m_out_bl.clear();
134 m_image_ctx->md_ctx.aio_operate(util::id_obj_name(m_image_ctx->name),
135 comp, &op, &m_out_bl);
136 comp->release();
137}
138
139template <typename I>
140Context *OpenRequest<I>::handle_v2_get_id(int *result) {
141 CephContext *cct = m_image_ctx->cct;
142 ldout(cct, 10) << __func__ << ": r=" << *result << dendl;
143
144 if (*result == 0) {
145 bufferlist::iterator it = m_out_bl.begin();
146 *result = cls_client::get_id_finish(&it, &m_image_ctx->id);
147 }
148 if (*result < 0) {
149 lderr(cct) << "failed to retrieve image id: " << cpp_strerror(*result)
150 << dendl;
151 send_close_image(*result);
152 } else {
153 send_v2_get_immutable_metadata();
154 }
155 return nullptr;
156}
157
158template <typename I>
159void OpenRequest<I>::send_v2_get_name() {
160 CephContext *cct = m_image_ctx->cct;
161 ldout(cct, 10) << this << " " << __func__ << dendl;
162
163 librados::ObjectReadOperation op;
164 cls_client::dir_get_name_start(&op, m_image_ctx->id);
165
166 using klass = OpenRequest<I>;
167 librados::AioCompletion *comp = create_rados_callback<
168 klass, &klass::handle_v2_get_name>(this);
169 m_out_bl.clear();
170 m_image_ctx->md_ctx.aio_operate(RBD_DIRECTORY, comp, &op, &m_out_bl);
171 comp->release();
172}
173
174template <typename I>
175Context *OpenRequest<I>::handle_v2_get_name(int *result) {
176 CephContext *cct = m_image_ctx->cct;
177 ldout(cct, 10) << __func__ << ": r=" << *result << dendl;
178
179 if (*result == 0) {
180 bufferlist::iterator it = m_out_bl.begin();
181 *result = cls_client::dir_get_name_finish(&it, &m_image_ctx->name);
182 }
183 if (*result < 0 && *result != -ENOENT) {
184 lderr(cct) << "failed to retreive name: "
185 << cpp_strerror(*result) << dendl;
186 send_close_image(*result);
187 } else if (*result == -ENOENT) {
188 // image does not exist in directory, look in the trash bin
189 ldout(cct, 10) << "image id " << m_image_ctx->id << " does not exist in "
190 << "rbd directory, searching in rbd trash..." << dendl;
191 send_v2_get_name_from_trash();
192 } else {
193 send_v2_get_immutable_metadata();
194 }
195
196 return nullptr;
197}
198
199template <typename I>
200void OpenRequest<I>::send_v2_get_name_from_trash() {
201 CephContext *cct = m_image_ctx->cct;
202 ldout(cct, 10) << this << " " << __func__ << dendl;
203
204 librados::ObjectReadOperation op;
205 cls_client::trash_get_start(&op, m_image_ctx->id);
206
207 using klass = OpenRequest<I>;
208 librados::AioCompletion *comp = create_rados_callback<
209 klass, &klass::handle_v2_get_name_from_trash>(this);
210 m_out_bl.clear();
211 m_image_ctx->md_ctx.aio_operate(RBD_TRASH, comp, &op, &m_out_bl);
212 comp->release();
213}
214
215template <typename I>
216Context *OpenRequest<I>::handle_v2_get_name_from_trash(int *result) {
217 CephContext *cct = m_image_ctx->cct;
218 ldout(cct, 10) << __func__ << ": r=" << *result << dendl;
219
220 cls::rbd::TrashImageSpec trash_spec;
221 if (*result == 0) {
222 bufferlist::iterator it = m_out_bl.begin();
223 *result = cls_client::trash_get_finish(&it, &trash_spec);
224 m_image_ctx->name = trash_spec.name;
225 }
226 if (*result < 0) {
227 if (*result == -EOPNOTSUPP) {
228 *result = -ENOENT;
229 } else if (*result == -ENOENT) {
230 lderr(cct) << "image id " << m_image_ctx->id << " does not exist in rbd "
231 << "trash, failed to retrieve image name: "
232 << cpp_strerror(*result) << dendl;
233 } else {
234 lderr(cct) << "failed to retreive name from trash: "
235 << cpp_strerror(*result) << dendl;
236 }
237 send_close_image(*result);
238 } else {
239 send_v2_get_immutable_metadata();
240 }
241
242 return nullptr;
243}
244
245template <typename I>
246void OpenRequest<I>::send_v2_get_immutable_metadata() {
247 CephContext *cct = m_image_ctx->cct;
248 ldout(cct, 10) << this << " " << __func__ << dendl;
249
250 m_image_ctx->old_format = false;
251 m_image_ctx->header_oid = util::header_name(m_image_ctx->id);
252
253 librados::ObjectReadOperation op;
254 cls_client::get_immutable_metadata_start(&op);
255
256 using klass = OpenRequest<I>;
257 librados::AioCompletion *comp = create_rados_callback<
258 klass, &klass::handle_v2_get_immutable_metadata>(this);
259 m_out_bl.clear();
260 m_image_ctx->md_ctx.aio_operate(m_image_ctx->header_oid, comp, &op,
261 &m_out_bl);
262 comp->release();
263}
264
265template <typename I>
266Context *OpenRequest<I>::handle_v2_get_immutable_metadata(int *result) {
267 CephContext *cct = m_image_ctx->cct;
268 ldout(cct, 10) << __func__ << ": r=" << *result << dendl;
269
270 if (*result == 0) {
271 bufferlist::iterator it = m_out_bl.begin();
272 *result = cls_client::get_immutable_metadata_finish(
273 &it, &m_image_ctx->object_prefix, &m_image_ctx->order);
274 }
275 if (*result < 0) {
276 lderr(cct) << "failed to retreive immutable metadata: "
277 << cpp_strerror(*result) << dendl;
278 send_close_image(*result);
279 } else {
280 send_v2_get_stripe_unit_count();
281 }
282
283 return nullptr;
284}
285
286template <typename I>
287void OpenRequest<I>::send_v2_get_stripe_unit_count() {
288 CephContext *cct = m_image_ctx->cct;
289 ldout(cct, 10) << this << " " << __func__ << dendl;
290
291 librados::ObjectReadOperation op;
292 cls_client::get_stripe_unit_count_start(&op);
293
294 using klass = OpenRequest<I>;
295 librados::AioCompletion *comp = create_rados_callback<
296 klass, &klass::handle_v2_get_stripe_unit_count>(this);
297 m_out_bl.clear();
298 m_image_ctx->md_ctx.aio_operate(m_image_ctx->header_oid, comp, &op,
299 &m_out_bl);
300 comp->release();
301}
302
303template <typename I>
304Context *OpenRequest<I>::handle_v2_get_stripe_unit_count(int *result) {
305 CephContext *cct = m_image_ctx->cct;
306 ldout(cct, 10) << __func__ << ": r=" << *result << dendl;
307
308 if (*result == 0) {
309 bufferlist::iterator it = m_out_bl.begin();
310 *result = cls_client::get_stripe_unit_count_finish(
311 &it, &m_image_ctx->stripe_unit, &m_image_ctx->stripe_count);
312 }
313
314 if (*result == -ENOEXEC || *result == -EINVAL) {
315 *result = 0;
316 }
317
318 if (*result < 0) {
319 lderr(cct) << "failed to read striping metadata: " << cpp_strerror(*result)
320 << dendl;
321 send_close_image(*result);
322 return nullptr;
323 }
324
325 send_v2_get_data_pool();
326 return nullptr;
327}
328
329template <typename I>
330void OpenRequest<I>::send_v2_get_data_pool() {
331 CephContext *cct = m_image_ctx->cct;
332 ldout(cct, 10) << this << " " << __func__ << dendl;
333
334 librados::ObjectReadOperation op;
335 cls_client::get_data_pool_start(&op);
336
337 using klass = OpenRequest<I>;
338 librados::AioCompletion *comp = create_rados_callback<
339 klass, &klass::handle_v2_get_data_pool>(this);
340 m_out_bl.clear();
341 m_image_ctx->md_ctx.aio_operate(m_image_ctx->header_oid, comp, &op,
342 &m_out_bl);
343 comp->release();
344}
345
346template <typename I>
347Context *OpenRequest<I>::handle_v2_get_data_pool(int *result) {
348 CephContext *cct = m_image_ctx->cct;
349 ldout(cct, 10) << this << " " << __func__ << ": r=" << *result << dendl;
350
351 int64_t data_pool_id = -1;
352 if (*result == 0) {
353 bufferlist::iterator it = m_out_bl.begin();
354 *result = cls_client::get_data_pool_finish(&it, &data_pool_id);
355 } else if (*result == -EOPNOTSUPP) {
356 *result = 0;
357 }
358
359 if (*result < 0) {
360 lderr(cct) << "failed to read data pool: " << cpp_strerror(*result)
361 << dendl;
362 send_close_image(*result);
363 return nullptr;
364 }
365
366 if (data_pool_id != -1) {
367 librados::Rados rados(m_image_ctx->md_ctx);
368 *result = rados.ioctx_create2(data_pool_id, m_image_ctx->data_ctx);
369 if (*result < 0) {
370 lderr(cct) << "failed to initialize data pool IO context: "
371 << cpp_strerror(*result) << dendl;
372 send_close_image(*result);
373 return nullptr;
374 }
375 }
376
377 m_image_ctx->init_layout();
378 send_v2_apply_metadata();
379 return nullptr;
380}
381
382template <typename I>
383void OpenRequest<I>::send_v2_apply_metadata() {
384 CephContext *cct = m_image_ctx->cct;
385 ldout(cct, 10) << this << " " << __func__ << ": "
386 << "start_key=" << m_last_metadata_key << dendl;
387
388 librados::ObjectReadOperation op;
389 cls_client::metadata_list_start(&op, m_last_metadata_key, MAX_METADATA_ITEMS);
390
391 using klass = OpenRequest<I>;
392 librados::AioCompletion *comp =
393 create_rados_callback<klass, &klass::handle_v2_apply_metadata>(this);
394 m_out_bl.clear();
395 m_image_ctx->md_ctx.aio_operate(m_image_ctx->header_oid, comp, &op,
396 &m_out_bl);
397 comp->release();
398}
399
400template <typename I>
401Context *OpenRequest<I>::handle_v2_apply_metadata(int *result) {
402 CephContext *cct = m_image_ctx->cct;
403 ldout(cct, 10) << this << " " << __func__ << ": r=" << *result << dendl;
404
405 std::map<std::string, bufferlist> metadata;
406 if (*result == 0) {
407 bufferlist::iterator it = m_out_bl.begin();
408 *result = cls_client::metadata_list_finish(&it, &metadata);
409 }
410
411 if (*result == -EOPNOTSUPP || *result == -EIO) {
412 ldout(cct, 10) << "config metadata not supported by OSD" << dendl;
413 } else if (*result < 0) {
414 lderr(cct) << "failed to retrieve metadata: " << cpp_strerror(*result)
415 << dendl;
416 send_close_image(*result);
417 return nullptr;
418 }
419
420 if (!metadata.empty()) {
421 m_metadata.insert(metadata.begin(), metadata.end());
422 m_last_metadata_key = metadata.rbegin()->first;
423 if (boost::starts_with(m_last_metadata_key,
424 ImageCtx::METADATA_CONF_PREFIX)) {
425 send_v2_apply_metadata();
426 return nullptr;
427 }
428 }
429
430 m_image_ctx->apply_metadata(m_metadata);
431
432 send_register_watch();
433 return nullptr;
434}
435
436template <typename I>
437void OpenRequest<I>::send_register_watch() {
438 m_image_ctx->init();
439
440 if (m_image_ctx->read_only) {
441 send_refresh();
442 return;
443 }
444
445 CephContext *cct = m_image_ctx->cct;
446 ldout(cct, 10) << this << " " << __func__ << dendl;
447
448 using klass = OpenRequest<I>;
449 Context *ctx = create_context_callback<
450 klass, &klass::handle_register_watch>(this);
451 m_image_ctx->register_watch(ctx);
452}
453
454template <typename I>
455Context *OpenRequest<I>::handle_register_watch(int *result) {
456 CephContext *cct = m_image_ctx->cct;
457 ldout(cct, 10) << this << " " << __func__ << ": r=" << *result << dendl;
458
459 if (*result < 0) {
460 lderr(cct) << "failed to register watch: " << cpp_strerror(*result)
461 << dendl;
462 send_close_image(*result);
463 } else {
464 send_refresh();
465 }
466 return nullptr;
467}
468
469template <typename I>
470void OpenRequest<I>::send_refresh() {
471 CephContext *cct = m_image_ctx->cct;
472 ldout(cct, 10) << this << " " << __func__ << dendl;
473
474 using klass = OpenRequest<I>;
475 RefreshRequest<I> *req = RefreshRequest<I>::create(
476 *m_image_ctx, false, m_skip_open_parent_image,
477 create_context_callback<klass, &klass::handle_refresh>(this));
478 req->send();
479}
480
481template <typename I>
482Context *OpenRequest<I>::handle_refresh(int *result) {
483 CephContext *cct = m_image_ctx->cct;
484 ldout(cct, 10) << __func__ << ": r=" << *result << dendl;
485
486 if (*result < 0) {
487 lderr(cct) << "failed to refresh image: " << cpp_strerror(*result)
488 << dendl;
489 send_close_image(*result);
490 return nullptr;
491 } else {
492 return send_set_snap(result);
493 }
494}
495
496template <typename I>
497Context *OpenRequest<I>::send_set_snap(int *result) {
498 if (m_image_ctx->snap_name.empty()) {
499 *result = 0;
500 return m_on_finish;
501 }
502
503 CephContext *cct = m_image_ctx->cct;
504 ldout(cct, 10) << this << " " << __func__ << dendl;
505
506 using klass = OpenRequest<I>;
507 SetSnapRequest<I> *req = SetSnapRequest<I>::create(
508 *m_image_ctx, m_image_ctx->snap_namespace, m_image_ctx->snap_name,
509 create_context_callback<klass, &klass::handle_set_snap>(this));
510 req->send();
511 return nullptr;
512}
513
514template <typename I>
515Context *OpenRequest<I>::handle_set_snap(int *result) {
516 CephContext *cct = m_image_ctx->cct;
517 ldout(cct, 10) << __func__ << ": r=" << *result << dendl;
518
519 if (*result < 0) {
520 lderr(cct) << "failed to set image snapshot: " << cpp_strerror(*result)
521 << dendl;
522 send_close_image(*result);
523 return nullptr;
524 }
525
526 return m_on_finish;
527}
528
529template <typename I>
530void OpenRequest<I>::send_close_image(int error_result) {
531 CephContext *cct = m_image_ctx->cct;
532 ldout(cct, 10) << this << " " << __func__ << dendl;
533
534 m_error_result = error_result;
535
536 using klass = OpenRequest<I>;
537 Context *ctx = create_context_callback<klass, &klass::handle_close_image>(
538 this);
539 CloseRequest<I> *req = CloseRequest<I>::create(m_image_ctx, ctx);
540 req->send();
541}
542
543template <typename I>
544Context *OpenRequest<I>::handle_close_image(int *result) {
545 CephContext *cct = m_image_ctx->cct;
546 ldout(cct, 10) << __func__ << ": r=" << *result << dendl;
547
548 if (*result < 0) {
549 lderr(cct) << "failed to close image: " << cpp_strerror(*result) << dendl;
550 }
551 if (m_error_result < 0) {
552 *result = m_error_result;
553 }
554 return m_on_finish;
555}
556
557} // namespace image
558} // namespace librbd
559
560template class librbd::image::OpenRequest<librbd::ImageCtx>;