]> git.proxmox.com Git - ceph.git/blame - ceph/src/librbd/image/OpenRequest.cc
update sources to v12.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"
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
31f18b77
FG
325 send_v2_get_create_timestamp();
326 return nullptr;
327}
328
329template <typename I>
330void OpenRequest<I>::send_v2_get_create_timestamp() {
331 CephContext *cct = m_image_ctx->cct;
332 ldout(cct, 10) << this << " " << __func__ << dendl;
333
334 librados::ObjectReadOperation op;
335 cls_client::get_create_timestamp_start(&op);
336
337 using klass = OpenRequest<I>;
338 librados::AioCompletion *comp = create_rados_callback<
339 klass, &klass::handle_v2_get_create_timestamp>(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_create_timestamp(int *result) {
348 CephContext *cct = m_image_ctx->cct;
349 ldout(cct, 10) << this << " " << __func__ << ": r=" << *result << dendl;
350
351 if (*result == 0) {
352 bufferlist::iterator it = m_out_bl.begin();
353 *result = cls_client::get_create_timestamp_finish(&it,
354 &m_image_ctx->create_timestamp);
355 }
356 if (*result < 0 && *result != -EOPNOTSUPP) {
357 lderr(cct) << "failed to retrieve create_timestamp: "
358 << cpp_strerror(*result)
359 << dendl;
360 send_close_image(*result);
361 return nullptr;
362 }
363
7c673cae
FG
364 send_v2_get_data_pool();
365 return nullptr;
366}
367
368template <typename I>
369void OpenRequest<I>::send_v2_get_data_pool() {
370 CephContext *cct = m_image_ctx->cct;
371 ldout(cct, 10) << this << " " << __func__ << dendl;
372
373 librados::ObjectReadOperation op;
374 cls_client::get_data_pool_start(&op);
375
376 using klass = OpenRequest<I>;
377 librados::AioCompletion *comp = create_rados_callback<
378 klass, &klass::handle_v2_get_data_pool>(this);
379 m_out_bl.clear();
380 m_image_ctx->md_ctx.aio_operate(m_image_ctx->header_oid, comp, &op,
381 &m_out_bl);
382 comp->release();
383}
384
385template <typename I>
386Context *OpenRequest<I>::handle_v2_get_data_pool(int *result) {
387 CephContext *cct = m_image_ctx->cct;
388 ldout(cct, 10) << this << " " << __func__ << ": r=" << *result << dendl;
389
390 int64_t data_pool_id = -1;
391 if (*result == 0) {
392 bufferlist::iterator it = m_out_bl.begin();
393 *result = cls_client::get_data_pool_finish(&it, &data_pool_id);
394 } else if (*result == -EOPNOTSUPP) {
395 *result = 0;
396 }
397
398 if (*result < 0) {
399 lderr(cct) << "failed to read data pool: " << cpp_strerror(*result)
400 << dendl;
401 send_close_image(*result);
402 return nullptr;
403 }
404
405 if (data_pool_id != -1) {
406 librados::Rados rados(m_image_ctx->md_ctx);
407 *result = rados.ioctx_create2(data_pool_id, m_image_ctx->data_ctx);
408 if (*result < 0) {
409 lderr(cct) << "failed to initialize data pool IO context: "
410 << cpp_strerror(*result) << dendl;
411 send_close_image(*result);
412 return nullptr;
413 }
414 }
415
416 m_image_ctx->init_layout();
417 send_v2_apply_metadata();
418 return nullptr;
419}
420
421template <typename I>
422void OpenRequest<I>::send_v2_apply_metadata() {
423 CephContext *cct = m_image_ctx->cct;
424 ldout(cct, 10) << this << " " << __func__ << ": "
425 << "start_key=" << m_last_metadata_key << dendl;
426
427 librados::ObjectReadOperation op;
428 cls_client::metadata_list_start(&op, m_last_metadata_key, MAX_METADATA_ITEMS);
429
430 using klass = OpenRequest<I>;
431 librados::AioCompletion *comp =
432 create_rados_callback<klass, &klass::handle_v2_apply_metadata>(this);
433 m_out_bl.clear();
434 m_image_ctx->md_ctx.aio_operate(m_image_ctx->header_oid, comp, &op,
435 &m_out_bl);
436 comp->release();
437}
438
439template <typename I>
440Context *OpenRequest<I>::handle_v2_apply_metadata(int *result) {
441 CephContext *cct = m_image_ctx->cct;
442 ldout(cct, 10) << this << " " << __func__ << ": r=" << *result << dendl;
443
444 std::map<std::string, bufferlist> metadata;
445 if (*result == 0) {
446 bufferlist::iterator it = m_out_bl.begin();
447 *result = cls_client::metadata_list_finish(&it, &metadata);
448 }
449
450 if (*result == -EOPNOTSUPP || *result == -EIO) {
451 ldout(cct, 10) << "config metadata not supported by OSD" << dendl;
452 } else if (*result < 0) {
453 lderr(cct) << "failed to retrieve metadata: " << cpp_strerror(*result)
454 << dendl;
455 send_close_image(*result);
456 return nullptr;
457 }
458
459 if (!metadata.empty()) {
460 m_metadata.insert(metadata.begin(), metadata.end());
461 m_last_metadata_key = metadata.rbegin()->first;
462 if (boost::starts_with(m_last_metadata_key,
463 ImageCtx::METADATA_CONF_PREFIX)) {
464 send_v2_apply_metadata();
465 return nullptr;
466 }
467 }
468
469 m_image_ctx->apply_metadata(m_metadata);
470
471 send_register_watch();
472 return nullptr;
473}
474
475template <typename I>
476void OpenRequest<I>::send_register_watch() {
477 m_image_ctx->init();
478
479 if (m_image_ctx->read_only) {
480 send_refresh();
481 return;
482 }
483
484 CephContext *cct = m_image_ctx->cct;
485 ldout(cct, 10) << this << " " << __func__ << dendl;
486
487 using klass = OpenRequest<I>;
488 Context *ctx = create_context_callback<
489 klass, &klass::handle_register_watch>(this);
490 m_image_ctx->register_watch(ctx);
491}
492
493template <typename I>
494Context *OpenRequest<I>::handle_register_watch(int *result) {
495 CephContext *cct = m_image_ctx->cct;
496 ldout(cct, 10) << this << " " << __func__ << ": r=" << *result << dendl;
497
498 if (*result < 0) {
499 lderr(cct) << "failed to register watch: " << cpp_strerror(*result)
500 << dendl;
501 send_close_image(*result);
502 } else {
503 send_refresh();
504 }
505 return nullptr;
506}
507
508template <typename I>
509void OpenRequest<I>::send_refresh() {
510 CephContext *cct = m_image_ctx->cct;
511 ldout(cct, 10) << this << " " << __func__ << dendl;
512
513 using klass = OpenRequest<I>;
514 RefreshRequest<I> *req = RefreshRequest<I>::create(
515 *m_image_ctx, false, m_skip_open_parent_image,
516 create_context_callback<klass, &klass::handle_refresh>(this));
517 req->send();
518}
519
520template <typename I>
521Context *OpenRequest<I>::handle_refresh(int *result) {
522 CephContext *cct = m_image_ctx->cct;
523 ldout(cct, 10) << __func__ << ": r=" << *result << dendl;
524
525 if (*result < 0) {
526 lderr(cct) << "failed to refresh image: " << cpp_strerror(*result)
527 << dendl;
528 send_close_image(*result);
529 return nullptr;
530 } else {
531 return send_set_snap(result);
532 }
533}
534
535template <typename I>
536Context *OpenRequest<I>::send_set_snap(int *result) {
537 if (m_image_ctx->snap_name.empty()) {
538 *result = 0;
539 return m_on_finish;
540 }
541
542 CephContext *cct = m_image_ctx->cct;
543 ldout(cct, 10) << this << " " << __func__ << dendl;
544
545 using klass = OpenRequest<I>;
546 SetSnapRequest<I> *req = SetSnapRequest<I>::create(
547 *m_image_ctx, m_image_ctx->snap_namespace, m_image_ctx->snap_name,
548 create_context_callback<klass, &klass::handle_set_snap>(this));
549 req->send();
550 return nullptr;
551}
552
553template <typename I>
554Context *OpenRequest<I>::handle_set_snap(int *result) {
555 CephContext *cct = m_image_ctx->cct;
556 ldout(cct, 10) << __func__ << ": r=" << *result << dendl;
557
558 if (*result < 0) {
559 lderr(cct) << "failed to set image snapshot: " << cpp_strerror(*result)
560 << dendl;
561 send_close_image(*result);
562 return nullptr;
563 }
564
565 return m_on_finish;
566}
567
568template <typename I>
569void OpenRequest<I>::send_close_image(int error_result) {
570 CephContext *cct = m_image_ctx->cct;
571 ldout(cct, 10) << this << " " << __func__ << dendl;
572
573 m_error_result = error_result;
574
575 using klass = OpenRequest<I>;
576 Context *ctx = create_context_callback<klass, &klass::handle_close_image>(
577 this);
578 CloseRequest<I> *req = CloseRequest<I>::create(m_image_ctx, ctx);
579 req->send();
580}
581
582template <typename I>
583Context *OpenRequest<I>::handle_close_image(int *result) {
584 CephContext *cct = m_image_ctx->cct;
585 ldout(cct, 10) << __func__ << ": r=" << *result << dendl;
586
587 if (*result < 0) {
588 lderr(cct) << "failed to close image: " << cpp_strerror(*result) << dendl;
589 }
590 if (m_error_result < 0) {
591 *result = m_error_result;
592 }
593 return m_on_finish;
594}
595
596} // namespace image
597} // namespace librbd
598
599template class librbd::image::OpenRequest<librbd::ImageCtx>;