Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / ceph / src / librbd / operation / EnableFeaturesRequest.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/operation/EnableFeaturesRequest.h"
5 #include "common/dout.h"
6 #include "common/errno.h"
7 #include "librbd/ExclusiveLock.h"
8 #include "librbd/ImageCtx.h"
9 #include "librbd/ImageState.h"
10 #include "librbd/Journal.h"
11 #include "librbd/Utils.h"
12 #include "librbd/image/SetFlagsRequest.h"
13 #include "librbd/io/ImageRequestWQ.h"
14 #include "librbd/journal/CreateRequest.h"
15 #include "librbd/mirror/EnableRequest.h"
16 #include "librbd/object_map/CreateRequest.h"
17
18 #define dout_subsys ceph_subsys_rbd
19 #undef dout_prefix
20 #define dout_prefix *_dout << "librbd::EnableFeaturesRequest: "
21
22 namespace librbd {
23 namespace operation {
24
25 using util::create_async_context_callback;
26 using util::create_context_callback;
27 using util::create_rados_callback;
28
29 template <typename I>
30 EnableFeaturesRequest<I>::EnableFeaturesRequest(I &image_ctx,
31                                                 Context *on_finish,
32                                                 uint64_t journal_op_tid,
33                                                 uint64_t features)
34   : Request<I>(image_ctx, on_finish, journal_op_tid), m_features(features) {
35 }
36
37 template <typename I>
38 void EnableFeaturesRequest<I>::send_op() {
39   I &image_ctx = this->m_image_ctx;
40   CephContext *cct = image_ctx.cct;
41   assert(image_ctx.owner_lock.is_locked());
42
43   ldout(cct, 20) << this << " " << __func__ << ": features=" << m_features
44                  << dendl;
45   send_prepare_lock();
46 }
47
48 template <typename I>
49 bool EnableFeaturesRequest<I>::should_complete(int r) {
50   I &image_ctx = this->m_image_ctx;
51   CephContext *cct = image_ctx.cct;
52   ldout(cct, 20) << this << " " << __func__ << "r=" << r << dendl;
53
54   if (r < 0) {
55     lderr(cct) << "encountered error: " << cpp_strerror(r) << dendl;
56   }
57   return true;
58 }
59
60 template <typename I>
61 void EnableFeaturesRequest<I>::send_prepare_lock() {
62   I &image_ctx = this->m_image_ctx;
63   CephContext *cct = image_ctx.cct;
64   ldout(cct, 20) << this << " " << __func__ << dendl;
65
66   image_ctx.state->prepare_lock(create_async_context_callback(
67     image_ctx, create_context_callback<
68     EnableFeaturesRequest<I>,
69     &EnableFeaturesRequest<I>::handle_prepare_lock>(this)));
70 }
71
72 template <typename I>
73 Context *EnableFeaturesRequest<I>::handle_prepare_lock(int *result) {
74   I &image_ctx = this->m_image_ctx;
75   CephContext *cct = image_ctx.cct;
76   ldout(cct, 20) << this << " " << __func__ << ": r=" << *result << dendl;
77
78   if (*result < 0) {
79     lderr(cct) << "failed to lock image: " << cpp_strerror(*result) << dendl;
80     return this->create_context_finisher(*result);
81   }
82
83   send_block_writes();
84   return nullptr;
85 }
86
87 template <typename I>
88 void EnableFeaturesRequest<I>::send_block_writes() {
89   I &image_ctx = this->m_image_ctx;
90   CephContext *cct = image_ctx.cct;
91   ldout(cct, 20) << this << " " << __func__ << dendl;
92
93   RWLock::WLocker locker(image_ctx.owner_lock);
94   image_ctx.io_work_queue->block_writes(create_context_callback<
95     EnableFeaturesRequest<I>,
96     &EnableFeaturesRequest<I>::handle_block_writes>(this));
97 }
98
99 template <typename I>
100 Context *EnableFeaturesRequest<I>::handle_block_writes(int *result) {
101   I &image_ctx = this->m_image_ctx;
102   CephContext *cct = image_ctx.cct;
103   ldout(cct, 20) << this << " " << __func__ << ": r=" << *result << dendl;
104
105   if (*result < 0) {
106     lderr(cct) << "failed to block writes: " << cpp_strerror(*result) << dendl;
107     return handle_finish(*result);
108   }
109   m_writes_blocked = true;
110
111   send_get_mirror_mode();
112   return nullptr;
113 }
114
115 template <typename I>
116 void EnableFeaturesRequest<I>::send_get_mirror_mode() {
117   I &image_ctx = this->m_image_ctx;
118   CephContext *cct = image_ctx.cct;
119
120   if ((m_features & RBD_FEATURE_JOURNALING) == 0) {
121     Context *ctx = create_context_callback<
122       EnableFeaturesRequest<I>,
123       &EnableFeaturesRequest<I>::handle_get_mirror_mode>(this);
124     ctx->complete(-ENOENT);
125     return;
126   }
127
128   ldout(cct, 20) << this << " " << __func__ << dendl;
129
130   librados::ObjectReadOperation op;
131   cls_client::mirror_mode_get_start(&op);
132
133   using klass = EnableFeaturesRequest<I>;
134   librados::AioCompletion *comp =
135     create_rados_callback<klass, &klass::handle_get_mirror_mode>(this);
136   m_out_bl.clear();
137   int r = image_ctx.md_ctx.aio_operate(RBD_MIRRORING, comp, &op, &m_out_bl);
138   assert(r == 0);
139   comp->release();
140 }
141
142 template <typename I>
143 Context *EnableFeaturesRequest<I>::handle_get_mirror_mode(int *result) {
144   I &image_ctx = this->m_image_ctx;
145   CephContext *cct = image_ctx.cct;
146   ldout(cct, 20) << this << " " << __func__ << ": r=" << *result << dendl;
147
148   cls::rbd::MirrorMode mirror_mode = cls::rbd::MIRROR_MODE_DISABLED;
149   if (*result == 0) {
150     bufferlist::iterator it = m_out_bl.begin();
151     *result = cls_client::mirror_mode_get_finish(&it, &mirror_mode);
152   } else if (*result == -ENOENT) {
153     *result = 0;
154   }
155
156   if (*result < 0) {
157     lderr(cct) << "failed to retrieve pool mirror mode: "
158                << cpp_strerror(*result) << dendl;
159     return handle_finish(*result);
160   }
161
162   m_enable_mirroring = (mirror_mode == cls::rbd::MIRROR_MODE_POOL);
163
164   bool create_journal = false;
165   do {
166     RWLock::WLocker locker(image_ctx.owner_lock);
167
168     // avoid accepting new requests from peers while we manipulate
169     // the image features
170     if (image_ctx.exclusive_lock != nullptr &&
171         (image_ctx.journal == nullptr ||
172          !image_ctx.journal->is_journal_replaying())) {
173       image_ctx.exclusive_lock->block_requests(0);
174       m_requests_blocked = true;
175     }
176
177     m_features &= ~image_ctx.features;
178     m_new_features = image_ctx.features | m_features;
179     m_features_mask = m_features;
180
181     if ((m_features & RBD_FEATURE_OBJECT_MAP) != 0) {
182       if ((m_new_features & RBD_FEATURE_EXCLUSIVE_LOCK) == 0) {
183         lderr(cct) << "cannot enable object-map. exclusive-lock must be "
184                       "enabled before enabling object-map." << dendl;
185         *result = -EINVAL;
186         break;
187       }
188       m_enable_flags |= RBD_FLAG_OBJECT_MAP_INVALID;
189       m_features_mask |= RBD_FEATURE_EXCLUSIVE_LOCK;
190     }
191     if ((m_features & RBD_FEATURE_FAST_DIFF) != 0) {
192       if ((m_new_features & RBD_FEATURE_OBJECT_MAP) == 0) {
193         lderr(cct) << "cannot enable fast-diff. object-map must be "
194                       "enabled before enabling fast-diff." << dendl;
195         *result = -EINVAL;
196         break;
197       }
198       m_enable_flags |= RBD_FLAG_FAST_DIFF_INVALID;
199       m_features_mask |= (RBD_FEATURE_OBJECT_MAP | RBD_FEATURE_EXCLUSIVE_LOCK);
200     }
201     if ((m_features & RBD_FEATURE_JOURNALING) != 0) {
202       if ((m_new_features & RBD_FEATURE_EXCLUSIVE_LOCK) == 0) {
203         lderr(cct) << "cannot enable journaling. exclusive-lock must be "
204                       "enabled before enabling journaling." << dendl;
205         *result = -EINVAL;
206         break;
207       }
208       m_features_mask |= RBD_FEATURE_EXCLUSIVE_LOCK;
209       create_journal = true;
210     }
211   } while (false);
212
213   if (*result < 0) {
214     return handle_finish(*result);
215   }
216   if (create_journal) {
217     send_create_journal();
218     return nullptr;
219   }
220   send_append_op_event();
221   return nullptr;
222 }
223
224 template <typename I>
225 void EnableFeaturesRequest<I>::send_create_journal() {
226   I &image_ctx = this->m_image_ctx;
227   CephContext *cct = image_ctx.cct;
228
229   ldout(cct, 20) << this << " " << __func__ << dendl;
230
231   journal::TagData tag_data(librbd::Journal<>::LOCAL_MIRROR_UUID);
232   Context *ctx = create_context_callback<
233     EnableFeaturesRequest<I>,
234     &EnableFeaturesRequest<I>::handle_create_journal>(this);
235
236   journal::CreateRequest<I> *req = journal::CreateRequest<I>::create(
237     image_ctx.md_ctx, image_ctx.id, image_ctx.journal_order,
238     image_ctx.journal_splay_width, image_ctx.journal_pool,
239     cls::journal::Tag::TAG_CLASS_NEW, tag_data,
240     librbd::Journal<>::IMAGE_CLIENT_ID, image_ctx.op_work_queue, ctx);
241
242   req->send();
243 }
244
245 template <typename I>
246 Context *EnableFeaturesRequest<I>::handle_create_journal(int *result) {
247   I &image_ctx = this->m_image_ctx;
248   CephContext *cct = image_ctx.cct;
249   ldout(cct, 20) << this << " " << __func__ << ": r=" << *result << dendl;
250
251   if (*result < 0) {
252     lderr(cct) << "failed to create journal: " << cpp_strerror(*result)
253                << dendl;
254     return handle_finish(*result);
255   }
256
257   send_append_op_event();
258   return nullptr;
259 }
260
261 template <typename I>
262 void EnableFeaturesRequest<I>::send_append_op_event() {
263   I &image_ctx = this->m_image_ctx;
264   CephContext *cct = image_ctx.cct;
265
266   if (!this->template append_op_event<
267       EnableFeaturesRequest<I>,
268       &EnableFeaturesRequest<I>::handle_append_op_event>(this)) {
269     send_update_flags();
270   }
271
272   ldout(cct, 20) << this << " " << __func__ << dendl;
273 }
274
275 template <typename I>
276 Context *EnableFeaturesRequest<I>::handle_append_op_event(int *result) {
277   I &image_ctx = this->m_image_ctx;
278   CephContext *cct = image_ctx.cct;
279   ldout(cct, 20) << this << " " << __func__ << ": r=" << *result << dendl;
280
281   if (*result < 0) {
282     lderr(cct) << "failed to commit journal entry: " << cpp_strerror(*result)
283                << dendl;
284     return handle_finish(*result);
285   }
286
287   send_update_flags();
288   return nullptr;
289 }
290
291 template <typename I>
292 void EnableFeaturesRequest<I>::send_update_flags() {
293   I &image_ctx = this->m_image_ctx;
294   CephContext *cct = image_ctx.cct;
295
296   if (m_enable_flags == 0) {
297     send_set_features();
298     return;
299   }
300
301   ldout(cct, 20) << this << " " << __func__ << ": enable_flags="
302                  << m_enable_flags << dendl;
303
304   Context *ctx = create_context_callback<
305     EnableFeaturesRequest<I>,
306     &EnableFeaturesRequest<I>::handle_update_flags>(this);
307
308   image::SetFlagsRequest<I> *req =
309     image::SetFlagsRequest<I>::create(&image_ctx, m_enable_flags,
310                                       m_enable_flags, ctx);
311   req->send();
312 }
313
314 template <typename I>
315 Context *EnableFeaturesRequest<I>::handle_update_flags(int *result) {
316   I &image_ctx = this->m_image_ctx;
317   CephContext *cct = image_ctx.cct;
318   ldout(cct, 20) << this << " " << __func__ << ": r=" << *result << dendl;
319
320   if (*result < 0) {
321     lderr(cct) << "failed to update image flags: " << cpp_strerror(*result)
322                << dendl;
323     return handle_finish(*result);
324   }
325
326   send_set_features();
327   return nullptr;
328 }
329
330 template <typename I>
331 void EnableFeaturesRequest<I>::send_set_features() {
332   I &image_ctx = this->m_image_ctx;
333   CephContext *cct = image_ctx.cct;
334   ldout(cct, 20) << this << " " << __func__ << ": new_features="
335                  << m_new_features << ", features_mask=" << m_features_mask
336                  << dendl;
337
338   librados::ObjectWriteOperation op;
339   librbd::cls_client::set_features(&op, m_new_features, m_features_mask);
340
341   using klass = EnableFeaturesRequest<I>;
342   librados::AioCompletion *comp =
343     create_rados_callback<klass, &klass::handle_set_features>(this);
344   int r = image_ctx.md_ctx.aio_operate(image_ctx.header_oid, comp, &op);
345   assert(r == 0);
346   comp->release();
347 }
348
349 template <typename I>
350 Context *EnableFeaturesRequest<I>::handle_set_features(int *result) {
351   I &image_ctx = this->m_image_ctx;
352   CephContext *cct = image_ctx.cct;
353   ldout(cct, 20) << this << " " << __func__ << ": r=" << *result << dendl;
354
355   if (*result < 0) {
356     lderr(cct) << "failed to update features: " << cpp_strerror(*result)
357                << dendl;
358     return handle_finish(*result);
359   }
360
361   send_create_object_map();
362   return nullptr;
363 }
364
365 template <typename I>
366 void EnableFeaturesRequest<I>::send_create_object_map() {
367   I &image_ctx = this->m_image_ctx;
368   CephContext *cct = image_ctx.cct;
369
370   if (((image_ctx.features & RBD_FEATURE_OBJECT_MAP) != 0) ||
371       ((m_features & RBD_FEATURE_OBJECT_MAP) == 0)) {
372     send_enable_mirror_image();
373     return;
374   }
375
376   ldout(cct, 20) << this << " " << __func__ << dendl;
377
378   Context *ctx = create_context_callback<
379     EnableFeaturesRequest<I>,
380     &EnableFeaturesRequest<I>::handle_create_object_map>(this);
381
382   object_map::CreateRequest<I> *req =
383     object_map::CreateRequest<I>::create(&image_ctx, ctx);
384   req->send();
385 }
386
387 template <typename I>
388 Context *EnableFeaturesRequest<I>::handle_create_object_map(int *result) {
389   I &image_ctx = this->m_image_ctx;
390   CephContext *cct = image_ctx.cct;
391   ldout(cct, 20) << this << " " << __func__ << ": r=" << *result << dendl;
392
393   if (*result < 0) {
394     lderr(cct) << "failed to create object map: " << cpp_strerror(*result)
395                << dendl;
396     return handle_finish(*result);
397   }
398
399   send_enable_mirror_image();
400   return nullptr;
401 }
402
403 template <typename I>
404 void EnableFeaturesRequest<I>::send_enable_mirror_image() {
405   I &image_ctx = this->m_image_ctx;
406   CephContext *cct = image_ctx.cct;
407   ldout(cct, 20) << this << " " << __func__ << dendl;
408
409   if (!m_enable_mirroring) {
410     send_notify_update();
411     return;
412   }
413
414   Context *ctx = create_context_callback<
415     EnableFeaturesRequest<I>,
416     &EnableFeaturesRequest<I>::handle_enable_mirror_image>(this);
417
418   mirror::EnableRequest<I> *req =
419     mirror::EnableRequest<I>::create(&image_ctx, ctx);
420   req->send();
421 }
422
423 template <typename I>
424 Context *EnableFeaturesRequest<I>::handle_enable_mirror_image(int *result) {
425   I &image_ctx = this->m_image_ctx;
426   CephContext *cct = image_ctx.cct;
427   ldout(cct, 20) << this << " " << __func__ << ": r=" << *result << dendl;
428
429   if (*result < 0) {
430     lderr(cct) << "failed to enable mirroring: " << cpp_strerror(*result)
431                << dendl;
432     // not fatal
433   }
434
435   send_notify_update();
436   return nullptr;
437 }
438
439 template <typename I>
440 void EnableFeaturesRequest<I>::send_notify_update() {
441   I &image_ctx = this->m_image_ctx;
442   CephContext *cct = image_ctx.cct;
443   ldout(cct, 20) << this << " " << __func__ << dendl;
444
445   Context *ctx = create_context_callback<
446     EnableFeaturesRequest<I>,
447     &EnableFeaturesRequest<I>::handle_notify_update>(this);
448
449   image_ctx.notify_update(ctx);
450 }
451
452 template <typename I>
453 Context *EnableFeaturesRequest<I>::handle_notify_update(int *result) {
454   I &image_ctx = this->m_image_ctx;
455   CephContext *cct = image_ctx.cct;
456   ldout(cct, 20) << this << " " << __func__ << ": r=" << *result << dendl;
457
458   return handle_finish(*result);
459 }
460
461 template <typename I>
462 Context *EnableFeaturesRequest<I>::handle_finish(int r) {
463   I &image_ctx = this->m_image_ctx;
464   CephContext *cct = image_ctx.cct;
465   ldout(cct, 20) << this << " " << __func__ << ": r=" << r << dendl;
466
467   {
468     RWLock::WLocker locker(image_ctx.owner_lock);
469
470     if (image_ctx.exclusive_lock != nullptr && m_requests_blocked) {
471       image_ctx.exclusive_lock->unblock_requests();
472     }
473     if (m_writes_blocked) {
474       image_ctx.io_work_queue->unblock_writes();
475     }
476   }
477   image_ctx.state->handle_prepare_lock_complete();
478
479   return this->create_context_finisher(r);
480 }
481
482 } // namespace operation
483 } // namespace librbd
484
485 template class librbd::operation::EnableFeaturesRequest<librbd::ImageCtx>;