Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / ceph / src / librbd / image / RefreshParentRequest.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/RefreshParentRequest.h"
5 #include "include/rados/librados.hpp"
6 #include "common/dout.h"
7 #include "common/errno.h"
8 #include "common/WorkQueue.h"
9 #include "librbd/ImageCtx.h"
10 #include "librbd/Utils.h"
11 #include "librbd/image/CloseRequest.h"
12 #include "librbd/image/OpenRequest.h"
13 #include "librbd/image/SetSnapRequest.h"
14
15 #define dout_subsys ceph_subsys_rbd
16 #undef dout_prefix
17 #define dout_prefix *_dout << "librbd::image::RefreshParentRequest: "
18
19 namespace librbd {
20 namespace image {
21
22 using util::create_async_context_callback;
23 using util::create_context_callback;
24
25 template <typename I>
26 RefreshParentRequest<I>::RefreshParentRequest(I &child_image_ctx,
27                                               const ParentInfo &parent_md,
28                                               Context *on_finish)
29   : m_child_image_ctx(child_image_ctx), m_parent_md(parent_md),
30     m_on_finish(on_finish), m_parent_image_ctx(nullptr),
31     m_parent_snap_id(CEPH_NOSNAP), m_error_result(0) {
32 }
33
34 template <typename I>
35 bool RefreshParentRequest<I>::is_refresh_required(I &child_image_ctx,
36                                                   const ParentInfo &parent_md) {
37   assert(child_image_ctx.snap_lock.is_locked());
38   assert(child_image_ctx.parent_lock.is_locked());
39   return (is_open_required(child_image_ctx, parent_md) ||
40           is_close_required(child_image_ctx, parent_md));
41 }
42
43 template <typename I>
44 bool RefreshParentRequest<I>::is_close_required(I &child_image_ctx,
45                                                 const ParentInfo &parent_md) {
46   return (child_image_ctx.parent != nullptr &&
47           (parent_md.spec.pool_id == -1 || parent_md.overlap == 0));
48 }
49
50 template <typename I>
51 bool RefreshParentRequest<I>::is_open_required(I &child_image_ctx,
52                                                const ParentInfo &parent_md) {
53   return (parent_md.spec.pool_id > -1 && parent_md.overlap > 0 &&
54           (child_image_ctx.parent == nullptr ||
55            child_image_ctx.parent->md_ctx.get_id() != parent_md.spec.pool_id ||
56            child_image_ctx.parent->id != parent_md.spec.image_id ||
57            child_image_ctx.parent->snap_id != parent_md.spec.snap_id));
58 }
59
60 template <typename I>
61 void RefreshParentRequest<I>::send() {
62   if (is_open_required(m_child_image_ctx, m_parent_md)) {
63     send_open_parent();
64   } else {
65     // parent will be closed (if necessary) during finalize
66     send_complete(0);
67   }
68 }
69
70 template <typename I>
71 void RefreshParentRequest<I>::apply() {
72   if (m_child_image_ctx.parent != nullptr) {
73     // closing parent image
74     m_child_image_ctx.clear_nonexistence_cache();
75   }
76   assert(m_child_image_ctx.snap_lock.is_wlocked());
77   assert(m_child_image_ctx.parent_lock.is_wlocked());
78   std::swap(m_child_image_ctx.parent, m_parent_image_ctx);
79 }
80
81 template <typename I>
82 void RefreshParentRequest<I>::finalize(Context *on_finish) {
83   CephContext *cct = m_child_image_ctx.cct;
84   ldout(cct, 10) << this << " " << __func__ << dendl;
85
86   m_on_finish = on_finish;
87   if (m_parent_image_ctx != nullptr) {
88     send_close_parent();
89   } else {
90     send_complete(0);
91   }
92 }
93
94 template <typename I>
95 void RefreshParentRequest<I>::send_open_parent() {
96   assert(m_parent_md.spec.pool_id >= 0);
97
98   CephContext *cct = m_child_image_ctx.cct;
99   ldout(cct, 10) << this << " " << __func__ << dendl;
100
101   librados::Rados rados(m_child_image_ctx.md_ctx);
102
103   librados::IoCtx parent_io_ctx;
104   int r = rados.ioctx_create2(m_parent_md.spec.pool_id, parent_io_ctx);
105   assert(r == 0);
106
107   // since we don't know the image and snapshot name, set their ids and
108   // reset the snap_name and snap_exists fields after we read the header
109   m_parent_image_ctx = new I("", m_parent_md.spec.image_id, NULL, parent_io_ctx,
110                              true);
111
112   // set rados flags for reading the parent image
113   if (m_child_image_ctx.balance_parent_reads) {
114     m_parent_image_ctx->set_read_flag(librados::OPERATION_BALANCE_READS);
115   } else if (m_child_image_ctx.localize_parent_reads) {
116     m_parent_image_ctx->set_read_flag(librados::OPERATION_LOCALIZE_READS);
117   }
118
119   using klass = RefreshParentRequest<I>;
120   Context *ctx = create_async_context_callback(
121     m_child_image_ctx, create_context_callback<
122       klass, &klass::handle_open_parent, false>(this));
123   OpenRequest<I> *req = OpenRequest<I>::create(m_parent_image_ctx, false, ctx);
124   req->send();
125 }
126
127 template <typename I>
128 Context *RefreshParentRequest<I>::handle_open_parent(int *result) {
129   CephContext *cct = m_child_image_ctx.cct;
130   ldout(cct, 10) << this << " " << __func__ << " r=" << *result << dendl;
131
132   save_result(result);
133   if (*result < 0) {
134     lderr(cct) << "failed to open parent image: " << cpp_strerror(*result)
135                << dendl;
136
137     // image already closed by open state machine
138     delete m_parent_image_ctx;
139     m_parent_image_ctx = nullptr;
140
141     return m_on_finish;
142   }
143
144   send_set_parent_snap();
145   return nullptr;
146 }
147
148 template <typename I>
149 void RefreshParentRequest<I>::send_set_parent_snap() {
150   assert(m_parent_md.spec.snap_id != CEPH_NOSNAP);
151
152   CephContext *cct = m_child_image_ctx.cct;
153   ldout(cct, 10) << this << " " << __func__ << dendl;
154
155   cls::rbd::SnapshotNamespace snap_namespace;
156   std::string snap_name;
157   {
158     RWLock::RLocker snap_locker(m_parent_image_ctx->snap_lock);
159     const SnapInfo *info = m_parent_image_ctx->get_snap_info(m_parent_md.spec.snap_id);
160     if (!info) {
161       lderr(cct) << "failed to locate snapshot: Snapshot with this id not found" << dendl;
162       send_complete(-ENOENT);
163       return;
164     }
165     snap_namespace = info->snap_namespace;
166     snap_name = info->name;
167   }
168
169   using klass = RefreshParentRequest<I>;
170   Context *ctx = create_context_callback<
171     klass, &klass::handle_set_parent_snap, false>(this);
172   SetSnapRequest<I> *req = SetSnapRequest<I>::create(
173     *m_parent_image_ctx, snap_namespace, snap_name, ctx);
174   req->send();
175 }
176
177 template <typename I>
178 Context *RefreshParentRequest<I>::handle_set_parent_snap(int *result) {
179   CephContext *cct = m_child_image_ctx.cct;
180   ldout(cct, 10) << this << " " << __func__ << " r=" << *result << dendl;
181
182   save_result(result);
183   if (*result < 0) {
184     lderr(cct) << "failed to set parent snapshot: " << cpp_strerror(*result)
185                << dendl;
186     send_close_parent();
187     return nullptr;
188   }
189
190   return m_on_finish;
191 }
192
193 template <typename I>
194 void RefreshParentRequest<I>::send_close_parent() {
195   assert(m_parent_image_ctx != nullptr);
196
197   CephContext *cct = m_child_image_ctx.cct;
198   ldout(cct, 10) << this << " " << __func__ << dendl;
199
200   using klass = RefreshParentRequest<I>;
201   Context *ctx = create_async_context_callback(
202     m_child_image_ctx, create_context_callback<
203       klass, &klass::handle_close_parent, false>(this));
204   CloseRequest<I> *req = CloseRequest<I>::create(m_parent_image_ctx, ctx);
205   req->send();
206 }
207
208 template <typename I>
209 Context *RefreshParentRequest<I>::handle_close_parent(int *result) {
210   CephContext *cct = m_child_image_ctx.cct;
211   ldout(cct, 10) << this << " " << __func__ << " r=" << *result << dendl;
212
213   delete m_parent_image_ctx;
214   if (*result < 0) {
215     lderr(cct) << "failed to close parent image: " << cpp_strerror(*result)
216                << dendl;
217   }
218
219   if (m_error_result < 0) {
220     // propagate errors from opening the image
221     *result = m_error_result;
222   } else {
223     // ignore errors from closing the image
224     *result = 0;
225   }
226
227   return m_on_finish;
228 }
229
230 template <typename I>
231 void RefreshParentRequest<I>::send_complete(int r) {
232   CephContext *cct = m_child_image_ctx.cct;
233   ldout(cct, 10) << this << " " << __func__ << dendl;
234
235   m_on_finish->complete(r);
236 }
237
238 } // namespace image
239 } // namespace librbd
240
241 template class librbd::image::RefreshParentRequest<librbd::ImageCtx>;