Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / ceph / src / librbd / image / SetSnapRequest.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/SetSnapRequest.h"
5 #include "common/dout.h"
6 #include "common/errno.h"
7 #include "librbd/ExclusiveLock.h"
8 #include "librbd/ImageCtx.h"
9 #include "librbd/ObjectMap.h"
10 #include "librbd/Utils.h"
11 #include "librbd/image/RefreshParentRequest.h"
12 #include "librbd/io/ImageRequestWQ.h"
13
14 #define dout_subsys ceph_subsys_rbd
15 #undef dout_prefix
16 #define dout_prefix *_dout << "librbd::image::SetSnapRequest: "
17
18 namespace librbd {
19 namespace image {
20
21 using util::create_context_callback;
22
23 template <typename I>
24 SetSnapRequest<I>::SetSnapRequest(I &image_ctx, const cls::rbd::SnapshotNamespace& snap_namespace,
25                                   const std::string &snap_name,
26                                   Context *on_finish)
27   : m_image_ctx(image_ctx), m_snap_namespace(snap_namespace),
28     m_snap_name(snap_name), m_on_finish(on_finish),
29     m_snap_id(CEPH_NOSNAP), m_exclusive_lock(nullptr), m_object_map(nullptr),
30     m_refresh_parent(nullptr), m_writes_blocked(false) {
31 }
32
33 template <typename I>
34 SetSnapRequest<I>::~SetSnapRequest() {
35   assert(!m_writes_blocked);
36   delete m_refresh_parent;
37   delete m_object_map;
38   delete m_exclusive_lock;
39 }
40
41 template <typename I>
42 void SetSnapRequest<I>::send() {
43   if (m_snap_name.empty()) {
44     send_init_exclusive_lock();
45   } else {
46     send_block_writes();
47   }
48 }
49
50 template <typename I>
51 void SetSnapRequest<I>::send_init_exclusive_lock() {
52   {
53     RWLock::RLocker snap_locker(m_image_ctx.snap_lock);
54     if (m_image_ctx.exclusive_lock != nullptr) {
55       assert(m_image_ctx.snap_id == CEPH_NOSNAP);
56       send_complete();
57       return;
58     }
59   }
60
61   if (m_image_ctx.read_only ||
62       !m_image_ctx.test_features(RBD_FEATURE_EXCLUSIVE_LOCK)) {
63     int r = 0;
64     if (send_refresh_parent(&r) != nullptr) {
65       send_complete();
66     }
67     return;
68   }
69
70   CephContext *cct = m_image_ctx.cct;
71   ldout(cct, 10) << __func__ << dendl;
72
73   m_exclusive_lock = ExclusiveLock<I>::create(m_image_ctx);
74
75   using klass = SetSnapRequest<I>;
76   Context *ctx = create_context_callback<
77     klass, &klass::handle_init_exclusive_lock>(this);
78
79   RWLock::RLocker owner_locker(m_image_ctx.owner_lock);
80   m_exclusive_lock->init(m_image_ctx.features, ctx);
81 }
82
83 template <typename I>
84 Context *SetSnapRequest<I>::handle_init_exclusive_lock(int *result) {
85   CephContext *cct = m_image_ctx.cct;
86   ldout(cct, 10) << __func__ << ": r=" << *result << dendl;
87
88   if (*result < 0) {
89     lderr(cct) << "failed to initialize exclusive lock: "
90                << cpp_strerror(*result) << dendl;
91     finalize();
92     return m_on_finish;
93   }
94   return send_refresh_parent(result);
95 }
96
97 template <typename I>
98 void SetSnapRequest<I>::send_block_writes() {
99   CephContext *cct = m_image_ctx.cct;
100   ldout(cct, 10) << __func__ << dendl;
101
102   m_writes_blocked = true;
103
104   using klass = SetSnapRequest<I>;
105   Context *ctx = create_context_callback<
106     klass, &klass::handle_block_writes>(this);
107
108   RWLock::RLocker owner_locker(m_image_ctx.owner_lock);
109   m_image_ctx.io_work_queue->block_writes(ctx);
110 }
111
112 template <typename I>
113 Context *SetSnapRequest<I>::handle_block_writes(int *result) {
114   CephContext *cct = m_image_ctx.cct;
115   ldout(cct, 10) << __func__ << ": r=" << *result << dendl;
116
117   if (*result < 0) {
118     lderr(cct) << "failed to block writes: " << cpp_strerror(*result)
119                << dendl;
120     finalize();
121     return m_on_finish;
122   }
123
124   {
125     RWLock::RLocker snap_locker(m_image_ctx.snap_lock);
126     m_snap_id = m_image_ctx.get_snap_id(m_snap_namespace, m_snap_name);
127     if (m_snap_id == CEPH_NOSNAP) {
128       ldout(cct, 5) << "failed to locate snapshot '" << m_snap_name << "'"
129                     << dendl;
130
131       *result = -ENOENT;
132       finalize();
133       return m_on_finish;
134     }
135   }
136
137   return send_shut_down_exclusive_lock(result);
138 }
139
140 template <typename I>
141 Context *SetSnapRequest<I>::send_shut_down_exclusive_lock(int *result) {
142   {
143     RWLock::RLocker snap_locker(m_image_ctx.snap_lock);
144     m_exclusive_lock = m_image_ctx.exclusive_lock;
145   }
146
147   if (m_exclusive_lock == nullptr) {
148     return send_refresh_parent(result);
149   }
150
151   CephContext *cct = m_image_ctx.cct;
152   ldout(cct, 10) << __func__ << dendl;
153
154   using klass = SetSnapRequest<I>;
155   Context *ctx = create_context_callback<
156     klass, &klass::handle_shut_down_exclusive_lock>(this);
157   m_exclusive_lock->shut_down(ctx);
158   return nullptr;
159 }
160
161 template <typename I>
162 Context *SetSnapRequest<I>::handle_shut_down_exclusive_lock(int *result) {
163   CephContext *cct = m_image_ctx.cct;
164   ldout(cct, 10) << __func__ << ": r=" << *result << dendl;
165
166   if (*result < 0) {
167     lderr(cct) << "failed to shut down exclusive lock: "
168                << cpp_strerror(*result) << dendl;
169     finalize();
170     return m_on_finish;
171   }
172
173   return send_refresh_parent(result);
174 }
175
176 template <typename I>
177 Context *SetSnapRequest<I>::send_refresh_parent(int *result) {
178   CephContext *cct = m_image_ctx.cct;
179
180   ParentInfo parent_md;
181   bool refresh_parent;
182   {
183     RWLock::RLocker snap_locker(m_image_ctx.snap_lock);
184     RWLock::RLocker parent_locker(m_image_ctx.parent_lock);
185
186     const ParentInfo *parent_info = m_image_ctx.get_parent_info(m_snap_id);
187     if (parent_info == nullptr) {
188       *result = -ENOENT;
189       lderr(cct) << "failed to retrieve snapshot parent info" << dendl;
190       finalize();
191       return m_on_finish;
192     }
193
194     parent_md = *parent_info;
195     refresh_parent = RefreshParentRequest<I>::is_refresh_required(m_image_ctx,
196                                                                   parent_md);
197   }
198
199   if (!refresh_parent) {
200     if (m_snap_id == CEPH_NOSNAP) {
201       // object map is loaded when exclusive lock is acquired
202       *result = apply();
203       finalize();
204       return m_on_finish;
205     } else {
206       // load snapshot object map
207       return send_open_object_map(result);
208     }
209   }
210
211   ldout(cct, 10) << __func__ << dendl;
212
213   using klass = SetSnapRequest<I>;
214   Context *ctx = create_context_callback<
215     klass, &klass::handle_refresh_parent>(this);
216   m_refresh_parent = RefreshParentRequest<I>::create(m_image_ctx, parent_md,
217                                                      ctx);
218   m_refresh_parent->send();
219   return nullptr;
220 }
221
222 template <typename I>
223 Context *SetSnapRequest<I>::handle_refresh_parent(int *result) {
224   CephContext *cct = m_image_ctx.cct;
225   ldout(cct, 10) << __func__ << ": r=" << *result << dendl;
226
227   if (*result < 0) {
228     lderr(cct) << "failed to refresh snapshot parent: " << cpp_strerror(*result)
229                << dendl;
230     finalize();
231     return m_on_finish;
232   }
233
234   if (m_snap_id == CEPH_NOSNAP) {
235     // object map is loaded when exclusive lock is acquired
236     *result = apply();
237     if (*result < 0) {
238       finalize();
239       return m_on_finish;
240     }
241
242     return send_finalize_refresh_parent(result);
243   } else {
244     // load snapshot object map
245     return send_open_object_map(result);
246   }
247 }
248
249 template <typename I>
250 Context *SetSnapRequest<I>::send_open_object_map(int *result) {
251   if (!m_image_ctx.test_features(RBD_FEATURE_OBJECT_MAP)) {
252     *result = apply();
253     if (*result < 0) {
254       finalize();
255       return m_on_finish;
256     }
257
258     return send_finalize_refresh_parent(result);
259   }
260
261   CephContext *cct = m_image_ctx.cct;
262   ldout(cct, 10) << __func__ << dendl;
263
264   using klass = SetSnapRequest<I>;
265   Context *ctx = create_context_callback<
266     klass, &klass::handle_open_object_map>(this);
267   m_object_map = ObjectMap<I>::create(m_image_ctx, m_snap_id);
268   m_object_map->open(ctx);
269   return nullptr;
270 }
271
272 template <typename I>
273 Context *SetSnapRequest<I>::handle_open_object_map(int *result) {
274   CephContext *cct = m_image_ctx.cct;
275   ldout(cct, 10) << __func__ << ": r=" << *result << dendl;
276
277   if (*result < 0) {
278     lderr(cct) << "failed to open object map: " << cpp_strerror(*result)
279                << dendl;
280     delete m_object_map;
281     m_object_map = nullptr;
282   }
283
284   *result = apply();
285   if (*result < 0) {
286     finalize();
287     return m_on_finish;
288   }
289
290   return send_finalize_refresh_parent(result);
291 }
292
293 template <typename I>
294 Context *SetSnapRequest<I>::send_finalize_refresh_parent(int *result) {
295   if (m_refresh_parent == nullptr) {
296     finalize();
297     return m_on_finish;
298   }
299
300   CephContext *cct = m_image_ctx.cct;
301   ldout(cct, 10) << this << " " << __func__ << dendl;
302
303   using klass = SetSnapRequest<I>;
304   Context *ctx = create_context_callback<
305     klass, &klass::handle_finalize_refresh_parent>(this);
306   m_refresh_parent->finalize(ctx);
307   return nullptr;
308 }
309
310 template <typename I>
311 Context *SetSnapRequest<I>::handle_finalize_refresh_parent(int *result) {
312   CephContext *cct = m_image_ctx.cct;
313   ldout(cct, 10) << this << " " << __func__ << ": r=" << *result << dendl;
314
315   if (*result < 0) {
316     lderr(cct) << "failed to close parent image: " << cpp_strerror(*result)
317                << dendl;
318   }
319   finalize();
320   return m_on_finish;
321 }
322
323 template <typename I>
324 int SetSnapRequest<I>::apply() {
325   CephContext *cct = m_image_ctx.cct;
326   ldout(cct, 10) << __func__ << dendl;
327
328   RWLock::WLocker owner_locker(m_image_ctx.owner_lock);
329   RWLock::WLocker snap_locker(m_image_ctx.snap_lock);
330   RWLock::WLocker parent_locker(m_image_ctx.parent_lock);
331   if (m_snap_id != CEPH_NOSNAP) {
332     assert(m_image_ctx.exclusive_lock == nullptr);
333     int r = m_image_ctx.snap_set(m_snap_namespace, m_snap_name);
334     if (r < 0) {
335       return r;
336     }
337   } else {
338     std::swap(m_image_ctx.exclusive_lock, m_exclusive_lock);
339     m_image_ctx.snap_unset();
340   }
341
342   if (m_refresh_parent != nullptr) {
343     m_refresh_parent->apply();
344   }
345
346   std::swap(m_object_map, m_image_ctx.object_map);
347   return 0;
348 }
349
350 template <typename I>
351 void SetSnapRequest<I>::finalize() {
352   if (m_writes_blocked) {
353     m_image_ctx.io_work_queue->unblock_writes();
354     m_writes_blocked = false;
355   }
356 }
357
358 template <typename I>
359 void SetSnapRequest<I>::send_complete() {
360   finalize();
361   m_on_finish->complete(0);
362   delete this;
363 }
364
365 } // namespace image
366 } // namespace librbd
367
368 template class librbd::image::SetSnapRequest<librbd::ImageCtx>;