Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / ceph / src / librbd / image / CloneRequest.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 "cls/rbd/cls_rbd_client.h"
5 #include "cls/rbd/cls_rbd_types.h"
6 #include "common/dout.h"
7 #include "common/errno.h"
8 #include "include/assert.h"
9 #include "librbd/ImageState.h"
10 #include "librbd/Journal.h"
11 #include "librbd/image/CloneRequest.h"
12 #include "librbd/image/CreateRequest.h"
13 #include "librbd/image/RemoveRequest.h"
14 #include "librbd/image/RefreshRequest.h"
15 #include "librbd/mirror/EnableRequest.h"
16
17 #define dout_subsys ceph_subsys_rbd
18 #undef dout_prefix
19 #define dout_prefix *_dout << "librbd::image::CloneRequest: "
20
21 namespace librbd {
22 namespace image {
23
24 using util::create_rados_callback;
25 using util::create_context_callback;
26 using util::create_async_context_callback;
27
28 template <typename I>
29 CloneRequest<I>::CloneRequest(I *p_imctx, IoCtx &c_ioctx,
30                               const std::string &c_name,
31                               const std::string &c_id,
32                               ImageOptions c_options,
33                               const std::string &non_primary_global_image_id,
34                               const std::string &primary_mirror_uuid,
35                               ContextWQ *op_work_queue, Context *on_finish)
36   : m_p_imctx(p_imctx), m_ioctx(c_ioctx), m_name(c_name), m_id(c_id),
37     m_opts(c_options),
38     m_pspec(m_p_imctx->md_ctx.get_id(), m_p_imctx->id, m_p_imctx->snap_id),
39     m_non_primary_global_image_id(non_primary_global_image_id),
40     m_primary_mirror_uuid(primary_mirror_uuid),
41     m_op_work_queue(op_work_queue), m_on_finish(on_finish),
42     m_use_p_features(true) {
43
44   m_cct = reinterpret_cast<CephContext *>(m_ioctx.cct());
45
46   bool default_format_set;
47   m_opts.is_set(RBD_IMAGE_OPTION_FORMAT, &default_format_set);
48   if (!default_format_set) {
49     m_opts.set(RBD_IMAGE_OPTION_FORMAT, static_cast<uint64_t>(2));
50   }
51
52   ldout(m_cct, 20) << "clone " << &m_p_imctx->md_ctx << " name " << m_p_imctx->name
53                  << " snap " << m_p_imctx->snap_name << " to child " << &m_ioctx
54                  << " name " << m_name << " opts = " << &m_opts << dendl;
55   return;
56 }
57
58 template <typename I>
59 void CloneRequest<I>::send() {
60   ldout(m_cct, 20) << this << " " << __func__ << dendl;
61   validate_options();
62 }
63
64 template <typename I>
65 void CloneRequest<I>::validate_options() {
66   ldout(m_cct, 20) << this << " " << __func__ << dendl;
67
68   uint64_t format = 0;
69   m_opts.get(RBD_IMAGE_OPTION_FORMAT, &format);
70   if (format < 2) {
71     lderr(m_cct) << "format 2 or later required for clone" << dendl;
72     return complete(-EINVAL);
73   }
74
75   if (m_opts.get(RBD_IMAGE_OPTION_FEATURES, &m_features) == 0) {
76     if (m_features & ~RBD_FEATURES_ALL) {
77       lderr(m_cct) << "librbd does not support requested features" << dendl;
78       return complete(-ENOSYS);
79     }
80     m_use_p_features = false;
81   }
82
83   send_validate_parent();
84 }
85
86 template <typename I>
87 void CloneRequest<I>::send_validate_parent() {
88   ldout(m_cct, 20) << this << " " << __func__ << dendl;
89
90   if (m_p_imctx->snap_id == CEPH_NOSNAP) {
91     lderr(m_cct) << "image to be cloned must be a snapshot" << dendl;
92     return complete(-EINVAL);
93   }
94
95   if (m_p_imctx->old_format) {
96     lderr(m_cct) << "parent image must be in new format" << dendl;
97     return complete(-EINVAL);
98   }
99
100   int r = 0;
101   bool snap_protected;
102   m_p_imctx->snap_lock.get_read();
103   m_p_features = m_p_imctx->features;
104   m_size = m_p_imctx->get_image_size(m_p_imctx->snap_id);
105   r = m_p_imctx->is_snap_protected(m_p_imctx->snap_id, &snap_protected);
106   m_p_imctx->snap_lock.put_read();
107
108   if ((m_p_features & RBD_FEATURE_LAYERING) != RBD_FEATURE_LAYERING) {
109     lderr(m_cct) << "parent image must support layering" << dendl;
110     return complete(-ENOSYS);
111   }
112
113   if (r < 0) {
114     lderr(m_cct) << "unable to locate parent's snapshot" << dendl;
115     return complete(r);
116   }
117
118   if (!snap_protected) {
119     lderr(m_cct) << "parent snapshot must be protected" << dendl;
120     return complete(-EINVAL);
121   }
122
123   if ((m_p_features & RBD_FEATURE_JOURNALING) != 0) {
124     m_force_non_primary = !m_non_primary_global_image_id.empty();
125     using klass = CloneRequest<I>;
126     Context *ctx = create_context_callback<
127         klass, &klass::handle_validate_parent>(this);
128
129     Journal<I>::is_tag_owner(m_p_imctx, &m_is_primary, ctx);
130     return;
131   }
132
133   send_validate_child();
134 }
135
136 template <typename I>
137 void CloneRequest<I>::handle_validate_parent(int r) {
138   ldout(m_cct, 20) << this << " " << __func__ << " r=" << r << dendl;
139
140   if (r < 0) {
141     lderr(m_cct) << "failed to determine tag ownership: " << cpp_strerror(r)
142                << dendl;
143     return complete(r);
144   }
145
146   if ((m_p_features & RBD_FEATURE_JOURNALING) != 0) {
147     if (!m_is_primary && !m_force_non_primary) {
148       lderr(m_cct) << "parent is non-primary mirrored image" << dendl;
149       return complete(-EINVAL);
150     }
151   }
152
153   send_validate_child();
154 }
155
156 template <typename I>
157 void CloneRequest<I>::send_validate_child() {
158   ldout(m_cct, 20) << this << " " << __func__ << dendl;
159
160   using klass = CloneRequest<I>;
161   librados::AioCompletion *comp = create_rados_callback<klass, &klass::handle_validate_child>(this);
162
163   librados::ObjectReadOperation op;
164   op.stat(NULL, NULL, NULL);
165
166   int r = m_ioctx.aio_operate(util::old_header_name(m_name), comp, &op, &m_out_bl);
167   assert(r == 0);
168   comp->release();
169 }
170
171 template <typename I>
172 void CloneRequest<I>::handle_validate_child(int r) {
173   ldout(m_cct, 20) << this << " " << __func__ << " r=" << r << dendl;
174
175   if (r != -ENOENT) {
176     lderr(m_cct) << "rbd image " << m_name << " already exists" << dendl;
177     return complete(r);
178   }
179
180   send_create();
181 }
182
183 template <typename I>
184 void CloneRequest<I>::send_create() {
185   ldout(m_cct, 20) << this << " " << __func__ << dendl;
186
187   if (m_use_p_features) {
188     m_features = m_p_features;
189   }
190
191   uint64_t order = m_p_imctx->order;
192   if (m_opts.get(RBD_IMAGE_OPTION_ORDER, &order) != 0) {
193     m_opts.set(RBD_IMAGE_OPTION_ORDER, order);
194   }
195   if ((m_features & RBD_FEATURE_LAYERING) != RBD_FEATURE_LAYERING) {
196     lderr(m_cct) << "cloning image must support layering" << dendl;
197     return complete(-ENOSYS);
198   }
199   m_opts.set(RBD_IMAGE_OPTION_FEATURES, m_features);
200
201   using klass = CloneRequest<I>;
202   Context *ctx = create_context_callback<klass, &klass::handle_create>(this);
203
204   RWLock::RLocker snap_locker(m_p_imctx->snap_lock);
205   CreateRequest<I> *req = CreateRequest<I>::create(
206     m_ioctx, m_name, m_id, m_size, m_opts, m_non_primary_global_image_id,
207     m_primary_mirror_uuid, true, m_op_work_queue, ctx);
208   req->send();
209 }
210
211 template <typename I>
212 void CloneRequest<I>::handle_create(int r) {
213   ldout(m_cct, 20) << this << " " << __func__ << " r=" << r << dendl;
214
215   if (r < 0) {
216     lderr(m_cct) << "error creating child: " << cpp_strerror(r) << dendl;
217     return complete(r);
218   }
219   send_open();
220 }
221
222 template <typename I>
223 void CloneRequest<I>::send_open() {
224   ldout(m_cct, 20) << this << " " << __func__ << dendl;
225
226   m_imctx = I::create(m_name, "", NULL, m_ioctx, false);
227
228   using klass = CloneRequest<I>;
229   Context *ctx = create_context_callback<klass, &klass::handle_open>(this);
230
231   m_imctx->state->open(true, ctx);
232 }
233
234 template <typename I>
235 void CloneRequest<I>::handle_open(int r) {
236   ldout(m_cct, 20) << this << " " << __func__ << " r=" << r << dendl;
237
238   if (r < 0) {
239     lderr(m_cct) << "Error opening new image: " << cpp_strerror(r) << dendl;
240     m_r_saved = r;
241     return send_remove();
242   }
243
244   send_set_parent();
245 }
246
247 template <typename I>
248 void CloneRequest<I>::send_set_parent() {
249   ldout(m_cct, 20) << this << " " << __func__ << dendl;
250
251   librados::ObjectWriteOperation op;
252   librbd::cls_client::set_parent(&op, m_pspec, m_size);
253
254   using klass = CloneRequest<I>;
255   librados::AioCompletion *comp =
256     create_rados_callback<klass, &klass::handle_set_parent>(this);
257   int r = m_imctx->md_ctx.aio_operate(m_imctx->header_oid,
258                                                 comp, &op);
259   assert(r == 0);
260   comp->release();
261 }
262
263 template <typename I>
264 void CloneRequest<I>::handle_set_parent(int r) {
265   ldout(m_cct, 20) << this << " " << __func__ << " r=" << r << dendl;
266
267   if (r < 0) {
268     lderr(m_cct) << "couldn't set parent: " << cpp_strerror(r) << dendl;
269     m_r_saved = r;
270     return send_close();
271   }
272
273   send_add_child();
274 }
275
276 template <typename I>
277 void CloneRequest<I>::send_add_child() {
278   ldout(m_cct, 20) << this << " " << __func__ << dendl;
279
280   librados::ObjectWriteOperation op;
281   cls_client::add_child(&op, m_pspec, m_id);
282
283   using klass = CloneRequest<I>;
284   librados::AioCompletion *comp =
285     create_rados_callback<klass, &klass::handle_add_child>(this);
286   int r = m_ioctx.aio_operate(RBD_CHILDREN, comp, &op);
287   assert(r == 0);
288   comp->release();
289 }
290
291 template <typename I>
292 void CloneRequest<I>::handle_add_child(int r) {
293   ldout(m_cct, 20) << this << " " << __func__ << " r=" << r << dendl;
294
295   if (r < 0) {
296     lderr(m_cct) << "couldn't add child: " << cpp_strerror(r) << dendl;
297     m_r_saved = r;
298     return send_close();
299   }
300
301   send_refresh();
302 }
303
304 template <typename I>
305 void CloneRequest<I>::send_refresh() {
306   ldout(m_cct, 20) << this << " " << __func__ << dendl;
307
308   using klass = CloneRequest<I>;
309   RefreshRequest<I> *req = RefreshRequest<I>::create(
310     *m_imctx, false, false,
311     create_context_callback<klass, &klass::handle_refresh>(this));
312   req->send();
313 }
314
315 template <typename I>
316 void CloneRequest<I>::handle_refresh(int r) {
317   ldout(m_cct, 20) << this << " " << __func__ << " r=" << r << dendl;
318
319   bool snap_protected = false;
320   if (r == 0) {
321     m_p_imctx->snap_lock.get_read();
322     r = m_p_imctx->is_snap_protected(m_p_imctx->snap_id, &snap_protected);
323     m_p_imctx->snap_lock.put_read();
324   }
325
326   if (r < 0 || !snap_protected) {
327     m_r_saved = -EINVAL;
328     return send_close();
329   }
330
331   send_metadata_list();
332 }
333
334 template <typename I>
335 void CloneRequest<I>::send_metadata_list() {
336   ldout(m_cct, 20) << this << " " << __func__ << dendl;
337
338   librados::ObjectReadOperation op;
339   cls_client::metadata_list_start(&op, "", 0);
340
341   using klass = CloneRequest<I>;
342   librados::AioCompletion *comp =
343     create_rados_callback<klass, &klass::handle_metadata_list>(this);
344   m_out_bl.clear();
345   m_p_imctx->md_ctx.aio_operate(m_p_imctx->header_oid,
346                                 comp, &op, &m_out_bl);
347   comp->release();
348 }
349
350 template <typename I>
351 void CloneRequest<I>::handle_metadata_list(int r) {
352   ldout(m_cct, 20) << this << " " << __func__ << " r=" << r << dendl;
353
354   if (r == 0) {
355     bufferlist::iterator it = m_out_bl.begin();
356     r = cls_client::metadata_list_finish(&it, &m_pairs);
357   }
358
359   if (r < 0 && r != -EOPNOTSUPP && r != -EIO) {
360     lderr(m_cct) << "couldn't list metadata: " << cpp_strerror(r) << dendl;
361     m_r_saved = r;
362     send_remove_child();
363   } else if (r == 0 && !m_pairs.empty()) {
364     send_metadata_set();
365   } else {
366     get_mirror_mode();
367   }
368 }
369
370 template <typename I>
371 void CloneRequest<I>::send_metadata_set() {
372   ldout(m_cct, 20) << this << " " << __func__ << dendl;
373
374   librados::ObjectWriteOperation op;
375   cls_client::metadata_set(&op, m_pairs);
376
377   using klass = CloneRequest<I>;
378   librados::AioCompletion *comp =
379     create_rados_callback<klass, &klass::handle_metadata_set>(this);
380   int r = m_ioctx.aio_operate(m_imctx->header_oid, comp, &op);
381   assert(r == 0);
382   comp->release();
383 }
384
385 template <typename I>
386 void CloneRequest<I>::handle_metadata_set(int r) {
387   ldout(m_cct, 20) << this << " " << __func__ << " r=" << r << dendl;
388
389   if (r < 0) {
390     lderr(m_cct) << "couldn't set metadata: " << cpp_strerror(r) << dendl;
391     m_r_saved = r;
392     send_remove_child();
393   } else {
394     get_mirror_mode();
395   }
396 }
397
398 template <typename I>
399 void CloneRequest<I>::get_mirror_mode() {
400   ldout(m_cct, 20) << this << " " << __func__ << dendl;
401
402   if (!m_imctx->test_features(RBD_FEATURE_JOURNALING)) {
403     send_close();
404     return;
405   }
406
407   librados::ObjectReadOperation op;
408   cls_client::mirror_mode_get_start(&op);
409
410   using klass = CloneRequest<I>;
411   librados::AioCompletion *comp =
412     create_rados_callback<klass, &klass::handle_get_mirror_mode>(this);
413   m_out_bl.clear();
414   m_imctx->md_ctx.aio_operate(RBD_MIRRORING,
415                               comp, &op, &m_out_bl);
416   comp->release();
417 }
418
419 template <typename I>
420 void CloneRequest<I>::handle_get_mirror_mode(int r) {
421   ldout(m_cct, 20) << this << " " << __func__ << " r=" << r << dendl;
422
423   if (r == 0) {
424     bufferlist::iterator it = m_out_bl.begin();
425     r = cls_client::mirror_mode_get_finish(&it, &m_mirror_mode);
426   }
427
428   if (r < 0 && r != -ENOENT) {
429     lderr(m_cct) << "failed to retrieve mirror mode: " << cpp_strerror(r)
430                  << dendl;
431
432     m_r_saved = r;
433     send_remove_child();
434   } else {
435     if (m_mirror_mode == cls::rbd::MIRROR_MODE_POOL ||
436         !m_non_primary_global_image_id.empty()) {
437       send_enable_mirror();
438     } else {
439       send_close();
440     }
441   }
442 }
443
444 template <typename I>
445 void CloneRequest<I>::send_enable_mirror() {
446   ldout(m_cct, 20) << this << " " << __func__ << dendl;
447
448   using klass = CloneRequest<I>;
449   Context *ctx = create_context_callback<klass, &klass::handle_enable_mirror>(this);
450
451   mirror::EnableRequest<I> *req = mirror::EnableRequest<I>::create(
452     m_imctx->md_ctx, m_id, m_non_primary_global_image_id,
453     m_imctx->op_work_queue, ctx);
454   req->send();
455 }
456
457 template <typename I>
458 void CloneRequest<I>::handle_enable_mirror(int r) {
459   ldout(m_cct, 20) << this << " " << __func__ << " r=" << r << dendl;
460
461   if (r < 0) {
462     lderr(m_cct) << "failed to enable mirroring: " << cpp_strerror(r)
463                << dendl;
464     m_r_saved = r;
465     send_remove_child();
466   } else {
467     send_close();
468   }
469 }
470
471 template <typename I>
472 void CloneRequest<I>::send_close() {
473   ldout(m_cct, 20) << this << " " << __func__ << dendl;
474
475   assert(m_imctx != nullptr);
476
477   using klass = CloneRequest<I>;
478   Context *ctx = create_async_context_callback(
479     *m_imctx, create_context_callback<
480       klass, &klass::handle_close>(this));
481   m_imctx->state->close(ctx);
482 }
483
484 template <typename I>
485 void CloneRequest<I>::handle_close(int r) {
486   ldout(m_cct, 20) << this << " " << __func__ << dendl;
487
488   m_imctx->destroy();
489   m_imctx = nullptr;
490
491   if (r < 0) {
492     lderr(m_cct) << "couldn't close image: " << cpp_strerror(r) << dendl;
493     return complete(r);
494   }
495
496   if (m_r_saved == 0) {
497     complete(0);
498   } else {
499     send_remove();
500   }
501 }
502
503 template <typename I>
504 void CloneRequest<I>::send_remove_child() {
505   ldout(m_cct, 20) << this << " " << __func__ << dendl;
506
507   librados::ObjectWriteOperation op;
508   cls_client::remove_child(&op, m_pspec, m_id);
509
510   using klass = CloneRequest<I>;
511   librados::AioCompletion *comp =
512     create_rados_callback<klass, &klass::handle_remove_child>(this);
513   int r = m_p_imctx->md_ctx.aio_operate(RBD_CHILDREN, comp, &op);
514   assert(r == 0);
515   comp->release();
516 }
517
518 template <typename I>
519 void CloneRequest<I>::handle_remove_child(int r) {
520   ldout(m_cct, 20) << this << " " << __func__ << " r=" << r << dendl;
521
522   if (r < 0) {
523      lderr(m_cct) << "Error removing failed clone from list of children: "
524                   << cpp_strerror(r) << dendl;
525   }
526
527   send_close();
528 }
529
530 template <typename I>
531 void CloneRequest<I>::send_remove() {
532   ldout(m_cct, 20) << this << " " << __func__ << dendl;
533
534   using klass = CloneRequest<I>;
535   Context *ctx = create_context_callback<klass, &klass::handle_remove>(this);
536
537   librbd::image::RemoveRequest<> *req = librbd::image::RemoveRequest<>::create(
538    m_ioctx, m_name, m_id, false, false, m_no_op, m_op_work_queue, ctx);
539   req->send();
540 }
541
542 template <typename I>
543 void CloneRequest<I>::handle_remove(int r) {
544   ldout(m_cct, 20) << this << " " << __func__ << " r=" << r << dendl;
545
546   if (r < 0) {
547     lderr(m_cct) << "Error removing failed clone: "
548                  << cpp_strerror(r) << dendl;
549   }
550   complete(r);
551 }
552
553 template <typename I>
554 void CloneRequest<I>::complete(int r) {
555   ldout(m_cct, 20) << this << " " << __func__ << " r=" << r << dendl;
556
557   if (r == 0) {
558     ldout(m_cct, 20) << "done." << dendl;
559   }
560
561   m_on_finish->complete(r);
562   delete this;
563 }
564
565 } //namespace image
566 } //namespace librbd
567
568 template class librbd::image::CloneRequest<librbd::ImageCtx>;