Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / ceph / src / librbd / mirror / DisableRequest.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/mirror/DisableRequest.h"
5 #include "common/WorkQueue.h"
6 #include "common/dout.h"
7 #include "common/errno.h"
8 #include "cls/journal/cls_journal_client.h"
9 #include "cls/rbd/cls_rbd_client.h"
10 #include "journal/Journaler.h"
11 #include "librbd/ImageState.h"
12 #include "librbd/Journal.h"
13 #include "librbd/MirroringWatcher.h"
14 #include "librbd/Operations.h"
15 #include "librbd/Utils.h"
16 #include "librbd/journal/PromoteRequest.h"
17
18 #define dout_subsys ceph_subsys_rbd
19 #undef dout_prefix
20 #define dout_prefix *_dout << "librbd::mirror::DisableRequest: "
21
22 namespace librbd {
23 namespace mirror {
24
25 using util::create_rados_callback;
26
27 template <typename I>
28 DisableRequest<I>::DisableRequest(I *image_ctx, bool force, bool remove,
29                                   Context *on_finish)
30   : m_image_ctx(image_ctx), m_force(force), m_remove(remove),
31     m_on_finish(on_finish), m_lock("mirror::DisableRequest::m_lock") {
32 }
33
34 template <typename I>
35 void DisableRequest<I>::send() {
36   send_get_mirror_image();
37 }
38
39 template <typename I>
40 void DisableRequest<I>::send_get_mirror_image() {
41   CephContext *cct = m_image_ctx->cct;
42   ldout(cct, 10) << this << " " << __func__ << dendl;
43
44   librados::ObjectReadOperation op;
45   cls_client::mirror_image_get_start(&op, m_image_ctx->id);
46
47   using klass = DisableRequest<I>;
48   librados::AioCompletion *comp =
49     create_rados_callback<klass, &klass::handle_get_mirror_image>(this);
50   m_out_bl.clear();
51   int r = m_image_ctx->md_ctx.aio_operate(RBD_MIRRORING, comp, &op, &m_out_bl);
52   assert(r == 0);
53   comp->release();
54 }
55
56 template <typename I>
57 Context *DisableRequest<I>::handle_get_mirror_image(int *result) {
58   CephContext *cct = m_image_ctx->cct;
59   ldout(cct, 10) << this << " " << __func__ << ": r=" << *result << dendl;
60
61   if (*result == 0) {
62     bufferlist::iterator iter = m_out_bl.begin();
63     *result = cls_client::mirror_image_get_finish(&iter, &m_mirror_image);
64   }
65
66   if (*result < 0) {
67     if (*result == -ENOENT) {
68       ldout(cct, 20) << this << " " << __func__
69                      << ": mirroring is not enabled for this image" << dendl;
70       *result = 0;
71     } else if (*result == -EOPNOTSUPP) {
72       ldout(cct, 5) << this << " " << __func__
73                     << ": mirroring is not supported by OSD" << dendl;
74     } else {
75       lderr(cct) << "failed to retreive mirror image: " << cpp_strerror(*result)
76                  << dendl;
77     }
78     return m_on_finish;
79   }
80
81   send_get_tag_owner();
82   return nullptr;
83 }
84
85 template <typename I>
86 void DisableRequest<I>::send_get_tag_owner() {
87   CephContext *cct = m_image_ctx->cct;
88   ldout(cct, 10) << this << " " << __func__ << dendl;
89
90   using klass = DisableRequest<I>;
91   Context *ctx = util::create_context_callback<
92       klass, &klass::handle_get_tag_owner>(this);
93
94   Journal<I>::is_tag_owner(m_image_ctx, &m_is_primary, ctx);
95 }
96
97 template <typename I>
98 Context *DisableRequest<I>::handle_get_tag_owner(int *result) {
99   CephContext *cct = m_image_ctx->cct;
100   ldout(cct, 10) << this << " " << __func__ << ": r=" << *result << dendl;
101
102   if (*result < 0) {
103     lderr(cct) << "failed to check tag ownership: " << cpp_strerror(*result)
104                << dendl;
105     return m_on_finish;
106   }
107
108   if (!m_is_primary && !m_force) {
109     lderr(cct) << "mirrored image is not primary, "
110                << "add force option to disable mirroring" << dendl;
111     *result = -EINVAL;
112     return m_on_finish;
113   }
114
115   send_set_mirror_image();
116   return nullptr;
117 }
118
119 template <typename I>
120 void DisableRequest<I>::send_set_mirror_image() {
121   CephContext *cct = m_image_ctx->cct;
122   ldout(cct, 10) << this << " " << __func__ << dendl;
123
124   m_mirror_image.state = cls::rbd::MIRROR_IMAGE_STATE_DISABLING;
125
126   librados::ObjectWriteOperation op;
127   cls_client::mirror_image_set(&op, m_image_ctx->id, m_mirror_image);
128
129   using klass = DisableRequest<I>;
130   librados::AioCompletion *comp =
131     create_rados_callback<klass, &klass::handle_set_mirror_image>(this);
132   m_out_bl.clear();
133   int r = m_image_ctx->md_ctx.aio_operate(RBD_MIRRORING, comp, &op);
134   assert(r == 0);
135   comp->release();
136 }
137
138 template <typename I>
139 Context *DisableRequest<I>::handle_set_mirror_image(int *result) {
140   CephContext *cct = m_image_ctx->cct;
141   ldout(cct, 10) << this << " " << __func__ << ": r=" << *result << dendl;
142
143   if (*result < 0) {
144     lderr(cct) << "failed to disable mirroring: " << cpp_strerror(*result)
145                << dendl;
146     return m_on_finish;
147   }
148
149   send_notify_mirroring_watcher();
150   return nullptr;
151 }
152
153 template <typename I>
154 void DisableRequest<I>::send_notify_mirroring_watcher() {
155   CephContext *cct = m_image_ctx->cct;
156   ldout(cct, 10) << this << " " << __func__ << dendl;
157
158   using klass = DisableRequest<I>;
159   Context *ctx = util::create_context_callback<
160     klass, &klass::handle_notify_mirroring_watcher>(this);
161
162   MirroringWatcher<I>::notify_image_updated(
163     m_image_ctx->md_ctx, cls::rbd::MIRROR_IMAGE_STATE_DISABLING,
164     m_image_ctx->id, m_mirror_image.global_image_id, ctx);
165 }
166
167 template <typename I>
168 Context *DisableRequest<I>::handle_notify_mirroring_watcher(int *result) {
169   CephContext *cct = m_image_ctx->cct;
170   ldout(cct, 10) << this << " " << __func__ << ": r=" << *result << dendl;
171
172   if (*result < 0) {
173     lderr(cct) << "failed to send update notification: "
174                << cpp_strerror(*result) << dendl;
175     *result = 0;
176   }
177
178   send_promote_image();
179   return nullptr;
180 }
181
182 template <typename I>
183 void DisableRequest<I>::send_promote_image() {
184   if (m_is_primary) {
185     send_get_clients();
186     return;
187   }
188
189   CephContext *cct = m_image_ctx->cct;
190   ldout(cct, 10) << this << " " << __func__ << dendl;
191
192   // Not primary -- shouldn't have the journal open
193   assert(m_image_ctx->journal == nullptr);
194
195   using klass = DisableRequest<I>;
196   Context *ctx = util::create_context_callback<
197     klass, &klass::handle_promote_image>(this);
198   auto req = journal::PromoteRequest<I>::create(m_image_ctx, true, ctx);
199   req->send();
200 }
201
202 template <typename I>
203 Context *DisableRequest<I>::handle_promote_image(int *result) {
204   CephContext *cct = m_image_ctx->cct;
205   ldout(cct, 10) << this << " " << __func__ << ": r=" << *result << dendl;
206
207   if (*result < 0) {
208     lderr(cct) << "failed to promote image: " << cpp_strerror(*result) << dendl;
209     return m_on_finish;
210   }
211
212   send_get_clients();
213   return nullptr;
214 }
215
216 template <typename I>
217 void DisableRequest<I>::send_get_clients() {
218   CephContext *cct = m_image_ctx->cct;
219   ldout(cct, 10) << this << " " << __func__ << dendl;
220
221   using klass = DisableRequest<I>;
222   Context *ctx = util::create_context_callback<
223     klass, &klass::handle_get_clients>(this);
224
225   std::string header_oid = ::journal::Journaler::header_oid(m_image_ctx->id);
226   m_clients.clear();
227   cls::journal::client::client_list(m_image_ctx->md_ctx, header_oid, &m_clients,
228                                     ctx);
229 }
230
231 template <typename I>
232 Context *DisableRequest<I>::handle_get_clients(int *result) {
233   CephContext *cct = m_image_ctx->cct;
234   ldout(cct, 10) << this << " " << __func__ << ": r=" << *result << dendl;
235
236   if (*result < 0) {
237     lderr(cct) << "failed to get registered clients: " << cpp_strerror(*result)
238                << dendl;
239     return m_on_finish;
240   }
241
242   Mutex::Locker locker(m_lock);
243
244   assert(m_current_ops.empty());
245
246   for (auto client : m_clients) {
247     journal::ClientData client_data;
248     bufferlist::iterator bl_it = client.data.begin();
249     try {
250       ::decode(client_data, bl_it);
251     } catch (const buffer::error &err) {
252       lderr(cct) << "failed to decode client data" << dendl;
253       m_error_result = -EBADMSG;
254       continue;
255     }
256
257     journal::ClientMetaType type = client_data.get_client_meta_type();
258     if (type != journal::ClientMetaType::MIRROR_PEER_CLIENT_META_TYPE) {
259       continue;
260     }
261
262     if (m_current_ops.find(client.id) != m_current_ops.end()) {
263       // Should not happen.
264       lderr(cct) << this << " " << __func__ << ": clients with the same id "
265                  << client.id << dendl;
266       continue;
267     }
268
269     m_current_ops[client.id] = 0;
270     m_ret[client.id] = 0;
271
272     journal::MirrorPeerClientMeta client_meta =
273       boost::get<journal::MirrorPeerClientMeta>(client_data.client_meta);
274
275     for (const auto& sync : client_meta.sync_points) {
276       send_remove_snap(client.id, sync.snap_namespace, sync.snap_name);
277     }
278
279     if (m_current_ops[client.id] == 0) {
280       // no snaps to remove
281       send_unregister_client(client.id);
282     }
283   }
284
285   if (m_current_ops.empty()) {
286     if (m_error_result < 0) {
287       *result = m_error_result;
288       return m_on_finish;
289     } else if (!m_remove) {
290       return m_on_finish;
291     }
292
293     // no mirror clients to unregister
294     send_remove_mirror_image();
295   }
296
297   return nullptr;
298 }
299
300 template <typename I>
301 void DisableRequest<I>::send_remove_snap(const std::string &client_id,
302                                          const cls::rbd::SnapshotNamespace &snap_namespace,
303                                          const std::string &snap_name) {
304   CephContext *cct = m_image_ctx->cct;
305   ldout(cct, 10) << this << " " << __func__ << ": client_id=" << client_id
306                  << ", snap_name=" << snap_name << dendl;
307
308   assert(m_lock.is_locked());
309
310   m_current_ops[client_id]++;
311
312   Context *ctx = create_context_callback(
313     &DisableRequest<I>::handle_remove_snap, client_id);
314
315   ctx = new FunctionContext([this, snap_namespace, snap_name, ctx](int r) {
316       RWLock::WLocker owner_locker(m_image_ctx->owner_lock);
317       m_image_ctx->operations->execute_snap_remove(snap_namespace,
318                                                    snap_name.c_str(),
319                                                    ctx);
320     });
321
322   m_image_ctx->op_work_queue->queue(ctx, 0);
323 }
324
325 template <typename I>
326 Context *DisableRequest<I>::handle_remove_snap(int *result,
327     const std::string &client_id) {
328   CephContext *cct = m_image_ctx->cct;
329   ldout(cct, 10) << this << " " << __func__ << ": r=" << *result << dendl;
330
331   Mutex::Locker locker(m_lock);
332
333   assert(m_current_ops[client_id] > 0);
334   m_current_ops[client_id]--;
335
336   if (*result < 0 && *result != -ENOENT) {
337     lderr(cct) <<
338       "failed to remove temporary snapshot created by remote peer: "
339                << cpp_strerror(*result) << dendl;
340     m_ret[client_id] = *result;
341   }
342
343   if (m_current_ops[client_id] == 0) {
344     send_unregister_client(client_id);
345   }
346
347   return nullptr;
348 }
349
350 template <typename I>
351 void DisableRequest<I>::send_unregister_client(
352   const std::string &client_id) {
353   CephContext *cct = m_image_ctx->cct;
354   ldout(cct, 10) << this << " " << __func__ << dendl;
355
356   assert(m_lock.is_locked());
357   assert(m_current_ops[client_id] == 0);
358
359   Context *ctx = create_context_callback(
360     &DisableRequest<I>::handle_unregister_client, client_id);
361
362   if (m_ret[client_id] < 0) {
363     m_image_ctx->op_work_queue->queue(ctx, m_ret[client_id]);
364     return;
365   }
366
367   librados::ObjectWriteOperation op;
368   cls::journal::client::client_unregister(&op, client_id);
369   std::string header_oid = ::journal::Journaler::header_oid(m_image_ctx->id);
370   librados::AioCompletion *comp = create_rados_callback(ctx);
371
372   int r = m_image_ctx->md_ctx.aio_operate(header_oid, comp, &op);
373   assert(r == 0);
374   comp->release();
375 }
376
377 template <typename I>
378 Context *DisableRequest<I>::handle_unregister_client(
379   int *result, const std::string &client_id) {
380
381   CephContext *cct = m_image_ctx->cct;
382   ldout(cct, 10) << this << " " << __func__ << ": r=" << *result << dendl;
383
384   Mutex::Locker locker(m_lock);
385   assert(m_current_ops[client_id] == 0);
386   m_current_ops.erase(client_id);
387
388   if (*result < 0 && *result != -ENOENT) {
389     lderr(cct) << "failed to unregister remote journal client: "
390                << cpp_strerror(*result) << dendl;
391     m_error_result = *result;
392   }
393
394   if (!m_current_ops.empty()) {
395     return nullptr;
396   }
397
398   if (m_error_result < 0) {
399     *result = m_error_result;
400     return m_on_finish;
401   }
402
403   send_get_clients();
404   return nullptr;
405 }
406
407 template <typename I>
408 void DisableRequest<I>::send_remove_mirror_image() {
409   CephContext *cct = m_image_ctx->cct;
410   ldout(cct, 10) << this << " " << __func__ << dendl;
411
412   librados::ObjectWriteOperation op;
413   cls_client::mirror_image_remove(&op, m_image_ctx->id);
414
415   using klass = DisableRequest<I>;
416   librados::AioCompletion *comp =
417     create_rados_callback<klass, &klass::handle_remove_mirror_image>(this);
418   m_out_bl.clear();
419   int r = m_image_ctx->md_ctx.aio_operate(RBD_MIRRORING, comp, &op);
420   assert(r == 0);
421   comp->release();
422 }
423
424 template <typename I>
425 Context *DisableRequest<I>::handle_remove_mirror_image(int *result) {
426   CephContext *cct = m_image_ctx->cct;
427   ldout(cct, 10) << this << " " << __func__ << ": r=" << *result << dendl;
428
429   if (*result == -ENOENT) {
430     *result = 0;
431   }
432
433   if (*result < 0) {
434     lderr(cct) << "failed to remove mirror image: " << cpp_strerror(*result)
435                << dendl;
436     return m_on_finish;
437   }
438
439   ldout(cct, 20) << this << " " << __func__
440                  <<  ": removed image state from rbd_mirroring object" << dendl;
441
442   send_notify_mirroring_watcher_removed();
443   return nullptr;
444 }
445
446 template <typename I>
447 void DisableRequest<I>::send_notify_mirroring_watcher_removed() {
448   CephContext *cct = m_image_ctx->cct;
449   ldout(cct, 10) << this << " " << __func__ << dendl;
450
451   using klass = DisableRequest<I>;
452   Context *ctx = util::create_context_callback<
453     klass, &klass::handle_notify_mirroring_watcher_removed>(this);
454
455   MirroringWatcher<I>::notify_image_updated(
456     m_image_ctx->md_ctx, cls::rbd::MIRROR_IMAGE_STATE_DISABLED, m_image_ctx->id,
457     m_mirror_image.global_image_id, ctx);
458 }
459
460 template <typename I>
461 Context *DisableRequest<I>::handle_notify_mirroring_watcher_removed(
462   int *result) {
463   CephContext *cct = m_image_ctx->cct;
464   ldout(cct, 10) << this << " " << __func__ << ": r=" << *result << dendl;
465
466   if (*result < 0) {
467     lderr(cct) << "failed to send update notification: "
468                << cpp_strerror(*result) << dendl;
469     *result = 0;
470   }
471
472   return m_on_finish;
473 }
474
475 template <typename I>
476 Context *DisableRequest<I>::create_context_callback(
477   Context*(DisableRequest<I>::*handle)(int*, const std::string &client_id),
478   const std::string &client_id) {
479
480   return new FunctionContext([this, handle, client_id](int r) {
481       Context *on_finish = (this->*handle)(&r, client_id);
482       if (on_finish != nullptr) {
483         on_finish->complete(r);
484         delete this;
485       }
486     });
487 }
488
489 } // namespace mirror
490 } // namespace librbd
491
492 template class librbd::mirror::DisableRequest<librbd::ImageCtx>;