Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / ceph / src / librbd / image / OpenRequest.cc
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
20 namespace librbd {
21 namespace image {
22
23 namespace {
24
25 static uint64_t MAX_METADATA_ITEMS = 128;
26
27 }
28
29 using util::create_context_callback;
30 using util::create_rados_callback;
31
32 template <typename I>
33 OpenRequest<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
40 template <typename I>
41 void OpenRequest<I>::send() {
42   send_v2_detect_header();
43 }
44
45 template <typename I>
46 void 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
59 template <typename I>
60 Context *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
83 template <typename I>
84 void 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
104 template <typename I>
105 Context *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
122 template <typename I>
123 void 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
139 template <typename I>
140 Context *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
158 template <typename I>
159 void 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
174 template <typename I>
175 Context *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
199 template <typename I>
200 void 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
215 template <typename I>
216 Context *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     }
230     if (*result == -ENOENT) {
231       ldout(cct, 5) << "failed to retrieve name for image id "
232                     << m_image_ctx->id << 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
245 template <typename I>
246 void 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
265 template <typename I>
266 Context *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
286 template <typename I>
287 void 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
303 template <typename I>
304 Context *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_create_timestamp();
326   return nullptr;
327 }
328
329 template <typename I>
330 void 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
346 template <typename I>
347 Context *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
364   send_v2_get_data_pool();
365   return nullptr;
366 }
367
368 template <typename I>
369 void 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
385 template <typename I>
386 Context *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
421 template <typename I>
422 void 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
439 template <typename I>
440 Context *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
475 template <typename I>
476 void 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
493 template <typename I>
494 Context *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
508 template <typename I>
509 void 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
520 template <typename I>
521 Context *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
535 template <typename I>
536 Context *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
553 template <typename I>
554 Context *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
568 template <typename I>
569 void 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
582 template <typename I>
583 Context *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
599 template class librbd::image::OpenRequest<librbd::ImageCtx>;