Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / ceph / src / librbd / operation / DisableFeaturesRequest.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/DisableFeaturesRequest.h"
5 #include "common/dout.h"
6 #include "common/errno.h"
7 #include "cls/rbd/cls_rbd_client.h"
8 #include "librbd/ExclusiveLock.h"
9 #include "librbd/ImageCtx.h"
10 #include "librbd/ImageState.h"
11 #include "librbd/Journal.h"
12 #include "librbd/Utils.h"
13 #include "librbd/image/SetFlagsRequest.h"
14 #include "librbd/io/ImageRequestWQ.h"
15 #include "librbd/journal/RemoveRequest.h"
16 #include "librbd/mirror/DisableRequest.h"
17 #include "librbd/object_map/RemoveRequest.h"
18
19 #define dout_subsys ceph_subsys_rbd
20 #undef dout_prefix
21 #define dout_prefix *_dout << "librbd::DisableFeaturesRequest: "
22
23 namespace librbd {
24 namespace operation {
25
26 using util::create_async_context_callback;
27 using util::create_context_callback;
28 using util::create_rados_callback;
29
30 template <typename I>
31 DisableFeaturesRequest<I>::DisableFeaturesRequest(I &image_ctx,
32                                                   Context *on_finish,
33                                                   uint64_t journal_op_tid,
34                                                   uint64_t features,
35                                                   bool force)
36   : Request<I>(image_ctx, on_finish, journal_op_tid), m_features(features),
37     m_force(force) {
38 }
39
40 template <typename I>
41 void DisableFeaturesRequest<I>::send_op() {
42   I &image_ctx = this->m_image_ctx;
43   CephContext *cct = image_ctx.cct;
44   assert(image_ctx.owner_lock.is_locked());
45
46   ldout(cct, 20) << this << " " << __func__ << ": features=" << m_features
47                  << dendl;
48
49   send_prepare_lock();
50 }
51
52 template <typename I>
53 bool DisableFeaturesRequest<I>::should_complete(int r) {
54   I &image_ctx = this->m_image_ctx;
55   CephContext *cct = image_ctx.cct;
56   ldout(cct, 20) << this << " " << __func__ << "r=" << r << dendl;
57
58   if (r < 0) {
59     lderr(cct) << "encountered error: " << cpp_strerror(r) << dendl;
60   }
61   return true;
62 }
63
64 template <typename I>
65 void DisableFeaturesRequest<I>::send_prepare_lock() {
66   I &image_ctx = this->m_image_ctx;
67   CephContext *cct = image_ctx.cct;
68   ldout(cct, 20) << this << " " << __func__ << dendl;
69
70   image_ctx.state->prepare_lock(create_async_context_callback(
71     image_ctx, create_context_callback<
72     DisableFeaturesRequest<I>,
73     &DisableFeaturesRequest<I>::handle_prepare_lock>(this)));
74 }
75
76 template <typename I>
77 Context *DisableFeaturesRequest<I>::handle_prepare_lock(int *result) {
78   I &image_ctx = this->m_image_ctx;
79   CephContext *cct = image_ctx.cct;
80   ldout(cct, 20) << this << " " << __func__ << ": r=" << *result << dendl;
81
82   if (*result < 0) {
83     lderr(cct) << "failed to lock image: " << cpp_strerror(*result) << dendl;
84     return this->create_context_finisher(*result);
85   }
86
87   send_block_writes();
88   return nullptr;
89 }
90
91 template <typename I>
92 void DisableFeaturesRequest<I>::send_block_writes() {
93   I &image_ctx = this->m_image_ctx;
94   CephContext *cct = image_ctx.cct;
95   ldout(cct, 20) << this << " " << __func__ << dendl;
96
97   RWLock::WLocker locker(image_ctx.owner_lock);
98   image_ctx.io_work_queue->block_writes(create_context_callback<
99     DisableFeaturesRequest<I>,
100     &DisableFeaturesRequest<I>::handle_block_writes>(this));
101 }
102
103 template <typename I>
104 Context *DisableFeaturesRequest<I>::handle_block_writes(int *result) {
105   I &image_ctx = this->m_image_ctx;
106   CephContext *cct = image_ctx.cct;
107   ldout(cct, 20) << this << " " << __func__ << ": r=" << *result << dendl;
108
109   if (*result < 0) {
110     lderr(cct) << "failed to block writes: " << cpp_strerror(*result) << dendl;
111     return handle_finish(*result);
112   }
113   m_writes_blocked = true;
114
115   {
116     RWLock::WLocker locker(image_ctx.owner_lock);
117     // avoid accepting new requests from peers while we manipulate
118     // the image features
119     if (image_ctx.exclusive_lock != nullptr &&
120         (image_ctx.journal == nullptr ||
121          !image_ctx.journal->is_journal_replaying())) {
122       image_ctx.exclusive_lock->block_requests(0);
123       m_requests_blocked = true;
124     }
125   }
126
127   send_acquire_exclusive_lock();
128   return nullptr;
129 }
130
131 template <typename I>
132 void DisableFeaturesRequest<I>::send_acquire_exclusive_lock() {
133   I &image_ctx = this->m_image_ctx;
134   CephContext *cct = image_ctx.cct;
135   ldout(cct, 20) << this << " " << __func__ << dendl;
136
137   Context *ctx = create_context_callback<
138     DisableFeaturesRequest<I>,
139     &DisableFeaturesRequest<I>::handle_acquire_exclusive_lock>(this);
140
141   {
142     RWLock::WLocker locker(image_ctx.owner_lock);
143     // if disabling features w/ exclusive lock supported, we need to
144     // acquire the lock to temporarily block IO against the image
145     if (image_ctx.exclusive_lock != nullptr &&
146         !image_ctx.exclusive_lock->is_lock_owner()) {
147       m_acquired_lock = true;
148
149       image_ctx.exclusive_lock->acquire_lock(ctx);
150       return;
151     }
152   }
153
154   ctx->complete(0);
155 }
156
157 template <typename I>
158 Context *DisableFeaturesRequest<I>::handle_acquire_exclusive_lock(int *result) {
159   I &image_ctx = this->m_image_ctx;
160   CephContext *cct = image_ctx.cct;
161   ldout(cct, 20) << this << " " << __func__ << ": r=" << *result << dendl;
162
163   if (*result < 0) {
164     lderr(cct) << "failed to lock image: " << cpp_strerror(*result) << dendl;
165     return handle_finish(*result);
166   } else if (m_acquired_lock && (image_ctx.exclusive_lock == nullptr ||
167                                  !image_ctx.exclusive_lock->is_lock_owner())) {
168     lderr(cct) << "failed to acquire exclusive lock" << dendl;
169     *result = -EROFS;
170     return handle_finish(*result);
171   }
172
173   do {
174     RWLock::WLocker locker(image_ctx.owner_lock);
175
176     m_features &= image_ctx.features;
177     m_new_features = image_ctx.features & ~m_features;
178     m_features_mask = m_features;
179
180     if ((m_features & RBD_FEATURE_EXCLUSIVE_LOCK) != 0) {
181       if ((m_new_features & RBD_FEATURE_OBJECT_MAP) != 0 ||
182           (m_new_features & RBD_FEATURE_JOURNALING) != 0) {
183         lderr(cct) << "cannot disable exclusive-lock. object-map "
184                       "or journaling must be disabled before "
185                       "disabling exclusive-lock." << dendl;
186         *result = -EINVAL;
187         break;
188       }
189       m_features_mask |= (RBD_FEATURE_OBJECT_MAP |
190                           RBD_FEATURE_JOURNALING);
191     }
192     if ((m_features & RBD_FEATURE_FAST_DIFF) != 0) {
193       m_disable_flags |= RBD_FLAG_FAST_DIFF_INVALID;
194     }
195     if ((m_features & RBD_FEATURE_OBJECT_MAP) != 0) {
196       if ((m_new_features & RBD_FEATURE_FAST_DIFF) != 0) {
197         lderr(cct) << "cannot disable object-map. fast-diff must be "
198                       "disabled before disabling object-map." << dendl;
199         *result = -EINVAL;
200         break;
201       }
202       m_disable_flags |= RBD_FLAG_OBJECT_MAP_INVALID;
203     }
204   } while (false);
205
206   if (*result < 0) {
207     return handle_finish(*result);
208   }
209
210   send_get_mirror_mode();
211   return nullptr;
212 }
213
214 template <typename I>
215 void DisableFeaturesRequest<I>::send_get_mirror_mode() {
216   I &image_ctx = this->m_image_ctx;
217   CephContext *cct = image_ctx.cct;
218
219   if ((m_features & RBD_FEATURE_JOURNALING) == 0) {
220     send_append_op_event();
221     return;
222   }
223
224   ldout(cct, 20) << this << " " << __func__ << dendl;
225
226   librados::ObjectReadOperation op;
227   cls_client::mirror_mode_get_start(&op);
228
229   using klass = DisableFeaturesRequest<I>;
230   librados::AioCompletion *comp =
231     create_rados_callback<klass, &klass::handle_get_mirror_mode>(this);
232   m_out_bl.clear();
233   int r = image_ctx.md_ctx.aio_operate(RBD_MIRRORING, comp, &op, &m_out_bl);
234   assert(r == 0);
235   comp->release();
236 }
237
238 template <typename I>
239 Context *DisableFeaturesRequest<I>::handle_get_mirror_mode(int *result) {
240   I &image_ctx = this->m_image_ctx;
241   CephContext *cct = image_ctx.cct;
242   ldout(cct, 20) << this << " " << __func__ << ": r=" << *result << dendl;
243
244   if (*result == 0) {
245     bufferlist::iterator it = m_out_bl.begin();
246     *result = cls_client::mirror_mode_get_finish(&it, &m_mirror_mode);
247   }
248
249   if (*result < 0 && *result != -ENOENT) {
250     lderr(cct) << "failed to retrieve pool mirror mode: "
251                << cpp_strerror(*result) << dendl;
252     return handle_finish(*result);
253   }
254
255   ldout(cct, 20) << this << " " << __func__ << ": m_mirror_mode="
256                  << m_mirror_mode << dendl;
257
258   send_get_mirror_image();
259   return nullptr;
260 }
261
262 template <typename I>
263 void DisableFeaturesRequest<I>::send_get_mirror_image() {
264   I &image_ctx = this->m_image_ctx;
265   CephContext *cct = image_ctx.cct;
266
267   if (m_mirror_mode != cls::rbd::MIRROR_MODE_IMAGE) {
268     send_disable_mirror_image();
269     return;
270   }
271
272   ldout(cct, 20) << this << " " << __func__ << dendl;
273
274   librados::ObjectReadOperation op;
275   cls_client::mirror_image_get_start(&op, image_ctx.id);
276
277   using klass = DisableFeaturesRequest<I>;
278   librados::AioCompletion *comp =
279     create_rados_callback<klass, &klass::handle_get_mirror_image>(this);
280   m_out_bl.clear();
281   int r = image_ctx.md_ctx.aio_operate(RBD_MIRRORING, comp, &op, &m_out_bl);
282   assert(r == 0);
283   comp->release();
284 }
285
286 template <typename I>
287 Context *DisableFeaturesRequest<I>::handle_get_mirror_image(int *result) {
288   I &image_ctx = this->m_image_ctx;
289   CephContext *cct = image_ctx.cct;
290   ldout(cct, 20) << this << " " << __func__ << dendl;
291
292   cls::rbd::MirrorImage mirror_image;
293
294   if (*result == 0) {
295     bufferlist::iterator it = m_out_bl.begin();
296     *result = cls_client::mirror_image_get_finish(&it, &mirror_image);
297   }
298
299   if (*result < 0 && *result != -ENOENT) {
300     lderr(cct) << "failed to retrieve pool mirror image: "
301                << cpp_strerror(*result) << dendl;
302     return handle_finish(*result);
303   }
304
305   if ((mirror_image.state == cls::rbd::MIRROR_IMAGE_STATE_ENABLED) && !m_force) {
306     lderr(cct) << "cannot disable journaling: image mirroring "
307                << "enabled and mirror pool mode set to image"
308                << dendl;
309     *result = -EINVAL;
310     return handle_finish(*result);
311   }
312
313   send_disable_mirror_image();
314   return nullptr;
315 }
316
317 template <typename I>
318 void DisableFeaturesRequest<I>::send_disable_mirror_image() {
319   I &image_ctx = this->m_image_ctx;
320   CephContext *cct = image_ctx.cct;
321
322   ldout(cct, 20) << this << " " << __func__ << dendl;
323
324   Context *ctx = create_context_callback<
325     DisableFeaturesRequest<I>,
326     &DisableFeaturesRequest<I>::handle_disable_mirror_image>(this);
327
328   mirror::DisableRequest<I> *req =
329     mirror::DisableRequest<I>::create(&image_ctx, m_force, true, ctx);
330   req->send();
331 }
332
333 template <typename I>
334 Context *DisableFeaturesRequest<I>::handle_disable_mirror_image(int *result) {
335   I &image_ctx = this->m_image_ctx;
336   CephContext *cct = image_ctx.cct;
337   ldout(cct, 20) << this << " " << __func__ << ": r=" << *result << dendl;
338
339   if (*result < 0) {
340     lderr(cct) << "failed to disable image mirroring: " << cpp_strerror(*result)
341                << dendl;
342     // not fatal
343   }
344
345   send_close_journal();
346   return nullptr;
347 }
348
349 template <typename I>
350 void DisableFeaturesRequest<I>::send_close_journal() {
351   I &image_ctx = this->m_image_ctx;
352   CephContext *cct = image_ctx.cct;
353
354   {
355     RWLock::WLocker locker(image_ctx.owner_lock);
356     if (image_ctx.journal != nullptr) {
357       ldout(cct, 20) << this << " " << __func__ << dendl;
358
359       std::swap(m_journal, image_ctx.journal);
360       Context *ctx = create_context_callback<
361         DisableFeaturesRequest<I>,
362         &DisableFeaturesRequest<I>::handle_close_journal>(this);
363
364       m_journal->close(ctx);
365       return;
366     }
367   }
368
369   send_remove_journal();
370 }
371
372 template <typename I>
373 Context *DisableFeaturesRequest<I>::handle_close_journal(int *result) {
374   I &image_ctx = this->m_image_ctx;
375   CephContext *cct = image_ctx.cct;
376   ldout(cct, 20) << this << " " << __func__ << ": r=" << *result << dendl;
377
378   if (*result < 0) {
379     lderr(cct) << "failed to close image journal: " << cpp_strerror(*result)
380                << dendl;
381   }
382
383   assert(m_journal != nullptr);
384   delete m_journal;
385   m_journal = nullptr;
386
387   send_remove_journal();
388   return nullptr;
389 }
390
391 template <typename I>
392 void DisableFeaturesRequest<I>::send_remove_journal() {
393   I &image_ctx = this->m_image_ctx;
394   CephContext *cct = image_ctx.cct;
395   ldout(cct, 20) << this << " " << __func__ << dendl;
396
397   Context *ctx = create_context_callback<
398     DisableFeaturesRequest<I>,
399     &DisableFeaturesRequest<I>::handle_remove_journal>(this);
400
401   journal::RemoveRequest<I> *req = journal::RemoveRequest<I>::create(
402     image_ctx.md_ctx, image_ctx.id, librbd::Journal<>::IMAGE_CLIENT_ID,
403     image_ctx.op_work_queue, ctx);
404
405   req->send();
406 }
407
408 template <typename I>
409 Context *DisableFeaturesRequest<I>::handle_remove_journal(int *result) {
410   I &image_ctx = this->m_image_ctx;
411   CephContext *cct = image_ctx.cct;
412   ldout(cct, 20) << this << " " << __func__ << ": r=" << *result << dendl;
413
414   if (*result < 0) {
415     lderr(cct) << "failed to remove image journal: " << cpp_strerror(*result)
416                << dendl;
417     return handle_finish(*result);
418   }
419
420   send_append_op_event();
421   return nullptr;
422 }
423
424 template <typename I>
425 void DisableFeaturesRequest<I>::send_append_op_event() {
426   I &image_ctx = this->m_image_ctx;
427   CephContext *cct = image_ctx.cct;
428
429   if (!this->template append_op_event<
430       DisableFeaturesRequest<I>,
431       &DisableFeaturesRequest<I>::handle_append_op_event>(this)) {
432     send_remove_object_map();
433   }
434
435   ldout(cct, 20) << this << " " << __func__ << dendl;
436 }
437
438 template <typename I>
439 Context *DisableFeaturesRequest<I>::handle_append_op_event(int *result) {
440   I &image_ctx = this->m_image_ctx;
441   CephContext *cct = image_ctx.cct;
442   ldout(cct, 20) << this << " " << __func__ << ": r=" << *result << dendl;
443
444   if (*result < 0) {
445     lderr(cct) << "failed to commit journal entry: " << cpp_strerror(*result)
446                << dendl;
447     return handle_finish(*result);
448   }
449
450   send_remove_object_map();
451   return nullptr;
452 }
453
454 template <typename I>
455 void DisableFeaturesRequest<I>::send_remove_object_map() {
456   I &image_ctx = this->m_image_ctx;
457   CephContext *cct = image_ctx.cct;
458   ldout(cct, 20) << this << " " << __func__ << dendl;
459
460   if ((m_features & RBD_FEATURE_OBJECT_MAP) == 0) {
461     send_set_features();
462     return;
463   }
464
465   Context *ctx = create_context_callback<
466     DisableFeaturesRequest<I>,
467     &DisableFeaturesRequest<I>::handle_remove_object_map>(this);
468
469   object_map::RemoveRequest<I> *req =
470     object_map::RemoveRequest<I>::create(&image_ctx, ctx);
471   req->send();
472 }
473
474 template <typename I>
475 Context *DisableFeaturesRequest<I>::handle_remove_object_map(int *result) {
476   I &image_ctx = this->m_image_ctx;
477   CephContext *cct = image_ctx.cct;
478   ldout(cct, 20) << this << " " << __func__ << ": r=" << *result << dendl;
479
480   if (*result < 0) {
481     lderr(cct) << "failed to remove object map: " << cpp_strerror(*result) << dendl;
482     return handle_finish(*result);
483   }
484
485   send_set_features();
486   return nullptr;
487 }
488
489 template <typename I>
490 void DisableFeaturesRequest<I>::send_set_features() {
491   I &image_ctx = this->m_image_ctx;
492   CephContext *cct = image_ctx.cct;
493   ldout(cct, 20) << this << " " << __func__ << ": new_features="
494                  << m_new_features << ", features_mask=" << m_features_mask
495                  << dendl;
496
497   librados::ObjectWriteOperation op;
498   librbd::cls_client::set_features(&op, m_new_features, m_features_mask);
499
500   using klass = DisableFeaturesRequest<I>;
501   librados::AioCompletion *comp =
502     create_rados_callback<klass, &klass::handle_set_features>(this);
503   int r = image_ctx.md_ctx.aio_operate(image_ctx.header_oid, comp, &op);
504   assert(r == 0);
505   comp->release();
506 }
507
508 template <typename I>
509 Context *DisableFeaturesRequest<I>::handle_set_features(int *result) {
510   I &image_ctx = this->m_image_ctx;
511   CephContext *cct = image_ctx.cct;
512   ldout(cct, 20) << this << " " << __func__ << ": r=" << *result << dendl;
513
514   if (*result == -EINVAL && (m_features_mask & RBD_FEATURE_JOURNALING) != 0) {
515     // NOTE: infernalis OSDs will not accept a mask with new features, so
516     // re-attempt with a reduced mask.
517     ldout(cct, 5) << this << " " << __func__
518                   << ": re-attempt with a reduced mask" << dendl;
519     m_features_mask &= ~RBD_FEATURE_JOURNALING;
520     send_set_features();
521   }
522
523   if (*result < 0) {
524     lderr(cct) << "failed to update features: " << cpp_strerror(*result)
525                << dendl;
526     return handle_finish(*result);
527   }
528
529   send_update_flags();
530   return nullptr;
531 }
532
533 template <typename I>
534 void DisableFeaturesRequest<I>::send_update_flags() {
535   I &image_ctx = this->m_image_ctx;
536   CephContext *cct = image_ctx.cct;
537
538   if (m_disable_flags == 0) {
539     send_notify_update();
540     return;
541   }
542
543   ldout(cct, 20) << this << " " << __func__ << ": disable_flags="
544                  << m_disable_flags << dendl;
545
546   Context *ctx = create_context_callback<
547     DisableFeaturesRequest<I>,
548     &DisableFeaturesRequest<I>::handle_update_flags>(this);
549
550   image::SetFlagsRequest<I> *req =
551     image::SetFlagsRequest<I>::create(&image_ctx, 0, m_disable_flags, ctx);
552   req->send();
553 }
554
555 template <typename I>
556 Context *DisableFeaturesRequest<I>::handle_update_flags(int *result) {
557   I &image_ctx = this->m_image_ctx;
558   CephContext *cct = image_ctx.cct;
559   ldout(cct, 20) << this << " " << __func__ << ": r=" << *result << dendl;
560
561   if (*result < 0) {
562     lderr(cct) << "failed to update image flags: " << cpp_strerror(*result)
563                << dendl;
564     return handle_finish(*result);
565   }
566
567   send_notify_update();
568   return nullptr;
569 }
570
571 template <typename I>
572 void DisableFeaturesRequest<I>::send_notify_update() {
573   I &image_ctx = this->m_image_ctx;
574   CephContext *cct = image_ctx.cct;
575   ldout(cct, 20) << this << " " << __func__ << dendl;
576
577   Context *ctx = create_context_callback<
578     DisableFeaturesRequest<I>,
579     &DisableFeaturesRequest<I>::handle_notify_update>(this);
580
581   image_ctx.notify_update(ctx);
582 }
583
584 template <typename I>
585 Context *DisableFeaturesRequest<I>::handle_notify_update(int *result) {
586   I &image_ctx = this->m_image_ctx;
587   CephContext *cct = image_ctx.cct;
588   ldout(cct, 20) << this << " " << __func__ << ": r=" << *result << dendl;
589
590   if (image_ctx.exclusive_lock == nullptr || !m_acquired_lock) {
591     return handle_finish(*result);
592   }
593
594   send_release_exclusive_lock();
595   return nullptr;
596 }
597
598 template <typename I>
599 void DisableFeaturesRequest<I>::send_release_exclusive_lock() {
600   I &image_ctx = this->m_image_ctx;
601   CephContext *cct = image_ctx.cct;
602   ldout(cct, 20) << this << " " << __func__ << dendl;
603
604   Context *ctx = create_context_callback<
605     DisableFeaturesRequest<I>,
606     &DisableFeaturesRequest<I>::handle_release_exclusive_lock>(this);
607
608   image_ctx.exclusive_lock->release_lock(ctx);
609 }
610
611 template <typename I>
612 Context *DisableFeaturesRequest<I>::handle_release_exclusive_lock(int *result) {
613   I &image_ctx = this->m_image_ctx;
614   CephContext *cct = image_ctx.cct;
615   ldout(cct, 20) << this << " " << __func__ << ": r=" << *result << dendl;
616
617   return handle_finish(*result);
618 }
619
620 template <typename I>
621 Context *DisableFeaturesRequest<I>::handle_finish(int r) {
622   I &image_ctx = this->m_image_ctx;
623   CephContext *cct = image_ctx.cct;
624   ldout(cct, 20) << this << " " << __func__ << ": r=" << r << dendl;
625
626   {
627     RWLock::WLocker locker(image_ctx.owner_lock);
628     if (image_ctx.exclusive_lock != nullptr && m_requests_blocked) {
629       image_ctx.exclusive_lock->unblock_requests();
630     }
631
632     image_ctx.io_work_queue->unblock_writes();
633   }
634   image_ctx.state->handle_prepare_lock_complete();
635
636   return this->create_context_finisher(r);
637 }
638
639 } // namespace operation
640 } // namespace librbd
641
642 template class librbd::operation::DisableFeaturesRequest<librbd::ImageCtx>;